xref: /xnu-10002.41.9/bsd/net/content_filter_crypto.c (revision 699cd48037512bf4380799317ca44ca453c82f57)
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
cfil_crypto_print_data(cfil_crypto_data_t data,const char * prefix)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
cfil_crypto_init_client(cfil_crypto_key client_key)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(state->key, client_key, 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
cfil_crypto_cleanup_state(cfil_crypto_state_t state)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
cfil_crypto_update_context(const struct ccdigest_info * di,cchmac_ctx_t ctx,cfil_crypto_data_t data,const struct iovec * extra_data,size_t extra_data_count)114 cfil_crypto_update_context(const struct ccdigest_info *di,
115     cchmac_ctx_t ctx, cfil_crypto_data_t data,
116     const struct iovec *extra_data, size_t extra_data_count)
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, sizeof(context), context);
122 	cchmac_update(di, ctx, strlen(context_string), context_string);
123 	cchmac_update(di, ctx, sizeof(separator), &separator);
124 	cchmac_update(di, ctx, sizeof(struct cfil_crypto_data), data);
125 	for (size_t extra_idx = 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, extra_data[extra_idx].iov_len, extra_data[extra_idx].iov_base);
128 		}
129 	}
130 }
131 
132 int
cfil_crypto_sign_data(cfil_crypto_state_t state,cfil_crypto_data_t data,const struct iovec * extra_data,size_t extra_data_count,cfil_crypto_signature signature,u_int32_t * signature_length)133 cfil_crypto_sign_data(cfil_crypto_state_t state, cfil_crypto_data_t data,
134     const struct iovec *extra_data, size_t extra_data_count,
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(state->digest_info, ctx,
159 	    sizeof(state->key),
160 	    state->key);
161 	cfil_crypto_update_context(state->digest_info, ctx, data, extra_data, extra_data_count);
162 	cchmac_final(state->digest_info, ctx, signature);
163 
164 	if (cfil_log_level >= LOG_DEBUG) {
165 		cfil_crypto_print_data(data, "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