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
12extern int cfil_log_level;
13
14#define CFIL_CRYPTO_LOG(level, fmt, ...) \
15do { \
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
46static void
47cfil_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
87cfil_crypto_state_t
88cfil_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
105void
106cfil_crypto_cleanup_state(cfil_crypto_state_t state)
107{
108 if (state != NULL) {
109 kfree_type(struct cfil_crypto_state, state);
110 }
111}
112
113static void
114cfil_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, 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 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, data_len: extra_data[extra_idx].iov_len, data: extra_data[extra_idx].iov_base);
128 }
129 }
130}
131
132int
133cfil_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(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