| 1 | /* |
| 2 | * Copyright (c) 2019-2022 Apple Inc. |
| 3 | * All rights reserved. |
| 4 | */ |
| 5 | |
| 6 | #include <sys/systm.h> |
| 7 | #include <sys/errno.h> |
| 8 | #include <corecrypto/cchmac.h> |
| 9 | #include <net/content_filter.h> |
| 10 | #include <net/content_filter_crypto.h> |
| 11 | |
| 12 | extern int cfil_log_level; |
| 13 | |
| 14 | #define CFIL_CRYPTO_LOG(level, fmt, ...) \ |
| 15 | do { \ |
| 16 | if (cfil_log_level >= level) \ |
| 17 | printf("%s:%d " fmt "\n",\ |
| 18 | __FUNCTION__, __LINE__, ##__VA_ARGS__); \ |
| 19 | } while (0) |
| 20 | |
| 21 | #define CFIL_CRYPTO_LOG_4BYTES(name) \ |
| 22 | CFIL_CRYPTO_LOG(LOG_DEBUG, \ |
| 23 | "%s \t%s: %hhX %hhX %hhX %hhX", \ |
| 24 | prefix, name, ptr[0], ptr[1], ptr[2], ptr[3]) |
| 25 | |
| 26 | #define CFIL_CRYPTO_LOG_8BYTES(name) \ |
| 27 | CFIL_CRYPTO_LOG(LOG_DEBUG, \ |
| 28 | "%s \t%s: %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX", \ |
| 29 | prefix, name, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]) |
| 30 | |
| 31 | #define CFIL_CRYPTO_LOG_16BYTES(name) \ |
| 32 | CFIL_CRYPTO_LOG(LOG_DEBUG, \ |
| 33 | "%s \t%s: %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX", \ |
| 34 | prefix, name, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]) |
| 35 | |
| 36 | #define CFIL_CRYPTO_LOG_28BYTES(name) \ |
| 37 | CFIL_CRYPTO_LOG(LOG_DEBUG, \ |
| 38 | "%s \t%s: %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX", \ |
| 39 | prefix, name, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19], ptr[20], ptr[21], ptr[22], ptr[23], ptr[24], ptr[25], ptr[26], ptr[27]) |
| 40 | |
| 41 | #define CFIL_CRYPTO_LOG_32BYTES(name, prefix) \ |
| 42 | CFIL_CRYPTO_LOG(LOG_DEBUG, \ |
| 43 | "%s \t%s: %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX", \ |
| 44 | prefix, name, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19], ptr[20], ptr[21], ptr[22], ptr[23], ptr[24], ptr[25], ptr[26], ptr[27], ptr[28], ptr[29], ptr[30], ptr[31]) |
| 45 | |
| 46 | static void |
| 47 | cfil_crypto_print_data(cfil_crypto_data_t data, const char *prefix) |
| 48 | { |
| 49 | u_int8_t *ptr = NULL; |
| 50 | CFIL_CRYPTO_LOG(LOG_DEBUG, "%s NE Filter crypto data:" , prefix); |
| 51 | |
| 52 | ptr = (u_int8_t *)&data->flow_id; |
| 53 | CFIL_CRYPTO_LOG_16BYTES("flow_id" ); |
| 54 | |
| 55 | ptr = (u_int8_t *)&data->sock_id; |
| 56 | CFIL_CRYPTO_LOG_8BYTES("sock_id" ); |
| 57 | |
| 58 | ptr = (u_int8_t *)&data->direction; |
| 59 | CFIL_CRYPTO_LOG_4BYTES("direction" ); |
| 60 | |
| 61 | ptr = (u_int8_t *)&data->remote; |
| 62 | CFIL_CRYPTO_LOG_28BYTES("remote" ); |
| 63 | ptr = (u_int8_t *)&data->local; |
| 64 | CFIL_CRYPTO_LOG_28BYTES("local" ); |
| 65 | |
| 66 | ptr = (u_int8_t *)&data->socketProtocol; |
| 67 | CFIL_CRYPTO_LOG_4BYTES("socketProtocol" ); |
| 68 | |
| 69 | ptr = (u_int8_t *)&data->pid; |
| 70 | CFIL_CRYPTO_LOG_4BYTES("pid" ); |
| 71 | |
| 72 | ptr = (u_int8_t *)&data->effective_pid; |
| 73 | CFIL_CRYPTO_LOG_4BYTES("effective_pid" ); |
| 74 | |
| 75 | ptr = (u_int8_t *)&data->uuid; |
| 76 | CFIL_CRYPTO_LOG_16BYTES("uuid" ); |
| 77 | ptr = (u_int8_t *)&data->effective_uuid; |
| 78 | CFIL_CRYPTO_LOG_16BYTES("effective_uuid" ); |
| 79 | |
| 80 | ptr = (u_int8_t *)&data->byte_count_in; |
| 81 | CFIL_CRYPTO_LOG_8BYTES("byte_count_in" ); |
| 82 | |
| 83 | ptr = (u_int8_t *)&data->byte_count_out; |
| 84 | CFIL_CRYPTO_LOG_8BYTES("byte_count_out" ); |
| 85 | } |
| 86 | |
| 87 | cfil_crypto_state_t |
| 88 | cfil_crypto_init_client(cfil_crypto_key client_key) |
| 89 | { |
| 90 | if (client_key == NULL) { |
| 91 | return NULL; |
| 92 | } |
| 93 | |
| 94 | struct cfil_crypto_state *state; |
| 95 | state = kalloc_type(struct cfil_crypto_state, |
| 96 | Z_WAITOK | Z_ZERO | Z_NOFAIL); |
| 97 | |
| 98 | memcpy(dst: state->key, src: client_key, n: sizeof(cfil_crypto_key)); |
| 99 | state->digest_info = ccsha256_di(); |
| 100 | |
| 101 | CFIL_CRYPTO_LOG(LOG_DEBUG, "Inited client key" ); |
| 102 | return state; |
| 103 | } |
| 104 | |
| 105 | void |
| 106 | cfil_crypto_cleanup_state(cfil_crypto_state_t state) |
| 107 | { |
| 108 | if (state != NULL) { |
| 109 | kfree_type(struct cfil_crypto_state, state); |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | static void |
| 114 | cfil_crypto_update_context(const struct ccdigest_info *di, |
| 115 | cchmac_ctx_t ctx, cfil_crypto_data_t data, |
| 116 | const struct iovec *, size_t ) |
| 117 | { |
| 118 | const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times |
| 119 | const char *context_string = "NEFilterCrypto" ; |
| 120 | uint8_t separator = 0; |
| 121 | cchmac_update(di, ctx, data_len: sizeof(context), data: context); |
| 122 | cchmac_update(di, ctx, data_len: strlen(s: context_string), data: context_string); |
| 123 | cchmac_update(di, ctx, data_len: sizeof(separator), data: &separator); |
| 124 | cchmac_update(di, ctx, data_len: sizeof(struct cfil_crypto_data), data); |
| 125 | for (size_t = 0; extra_idx < extra_data_count; extra_idx++) { |
| 126 | if (extra_data[extra_idx].iov_base != NULL && extra_data[extra_idx].iov_len > 0) { |
| 127 | cchmac_update(di, ctx, data_len: extra_data[extra_idx].iov_len, data: extra_data[extra_idx].iov_base); |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | int |
| 133 | cfil_crypto_sign_data(cfil_crypto_state_t state, cfil_crypto_data_t data, |
| 134 | const struct iovec *, size_t , |
| 135 | cfil_crypto_signature signature, u_int32_t *signature_length) |
| 136 | { |
| 137 | u_int8_t *ptr = NULL; |
| 138 | |
| 139 | if (state->digest_info == NULL) { |
| 140 | return EINVAL; |
| 141 | } |
| 142 | |
| 143 | if (data == NULL || |
| 144 | signature == NULL || |
| 145 | signature_length == NULL) { |
| 146 | return EINVAL; |
| 147 | } |
| 148 | |
| 149 | size_t required_tag_length = state->digest_info->output_size; |
| 150 | if (*signature_length < required_tag_length) { |
| 151 | return ERANGE; |
| 152 | } |
| 153 | |
| 154 | *signature_length = (u_int32_t)required_tag_length; |
| 155 | |
| 156 | cchmac_ctx_decl(state->digest_info->state_size, |
| 157 | state->digest_info->block_size, ctx); |
| 158 | cchmac_init(di: state->digest_info, ctx, |
| 159 | key_len: sizeof(state->key), |
| 160 | key: state->key); |
| 161 | cfil_crypto_update_context(di: state->digest_info, ctx, data, extra_data, extra_data_count); |
| 162 | cchmac_final(di: state->digest_info, ctx, mac: signature); |
| 163 | |
| 164 | if (cfil_log_level >= LOG_DEBUG) { |
| 165 | cfil_crypto_print_data(data, prefix: "SIGN" ); |
| 166 | CFIL_CRYPTO_LOG(LOG_DEBUG, "Signed data: datalen %lu" , sizeof(struct cfil_crypto_data)); |
| 167 | ptr = (u_int8_t *)signature; |
| 168 | CFIL_CRYPTO_LOG_32BYTES("Signature" , "SIGN" ); |
| 169 | } |
| 170 | |
| 171 | return 0; |
| 172 | } |
| 173 | |