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 | |