]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/esp_chachapoly.c
0970f698319e1b26e7aaf84dca73ef7ebcc68179
[apple/xnu.git] / bsd / netinet6 / esp_chachapoly.c
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/socket.h>
32 #include <sys/queue.h>
33 #include <sys/syslog.h>
34 #include <sys/errno.h>
35 #include <sys/mbuf.h>
36 #include <sys/mcache.h>
37 #include <mach/vm_param.h>
38 #include <kern/locks.h>
39 #include <string.h>
40 #include <net/if.h>
41 #include <net/route.h>
42 #include <net/net_osdep.h>
43 #include <netinet6/ipsec.h>
44 #include <netinet6/esp.h>
45 #include <netinet6/esp_chachapoly.h>
46 #include <netkey/key.h>
47 #include <netkey/keydb.h>
48 #include <corecrypto/cc.h>
49 #include <libkern/crypto/chacha20poly1305.h>
50
51 #define ESP_CHACHAPOLY_SALT_LEN 4
52 #define ESP_CHACHAPOLY_KEY_LEN 32
53 #define ESP_CHACHAPOLY_NONCE_LEN 12
54
55 // The minimum alignment is documented in KALLOC_LOG2_MINALIGN
56 // which isn't accessible from here. Current minimum is 8.
57 _Static_assert(_Alignof(chacha20poly1305_ctx) <= 8,
58 "Alignment guarantee is broken");
59
60 #if ((( 8 * (ESP_CHACHAPOLY_KEY_LEN + ESP_CHACHAPOLY_SALT_LEN)) != ESP_CHACHAPOLY_KEYBITS_WITH_SALT) || \
61 (ESP_CHACHAPOLY_KEY_LEN != CCCHACHA20_KEY_NBYTES) || \
62 (ESP_CHACHAPOLY_NONCE_LEN != CCCHACHA20POLY1305_NONCE_NBYTES))
63 #error "Invalid sizes"
64 #endif
65
66 extern lck_mtx_t *sadb_mutex;
67
68 typedef struct _esp_chachapoly_ctx {
69 chacha20poly1305_ctx ccp_ctx;
70 uint8_t ccp_salt[ESP_CHACHAPOLY_SALT_LEN];
71 bool ccp_implicit_iv;
72 } esp_chachapoly_ctx_s, *esp_chachapoly_ctx_t;
73
74
75 #define ESP_ASSERT(_cond, _format, ...) \
76 do { \
77 if (!(_cond)) { \
78 panic("%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
79 } \
80 } while (0)
81
82 #define ESP_CHECK_ARG(_arg) ESP_ASSERT(_arg != NULL, #_arg "is NULL")
83
84 #define _esp_log(_level, _format, ...) \
85 log(_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
86 #define esp_log_err(_format, ...) _esp_log(LOG_ERR, _format, ##__VA_ARGS__)
87
88 #define _esp_packet_log(_level, _format, ...) \
89 ipseclog((_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__))
90 #define esp_packet_log_err(_format, ...) _esp_packet_log(LOG_ERR, _format, ##__VA_ARGS__)
91
92 int
93 esp_chachapoly_mature(struct secasvar *sav)
94 {
95 const struct esp_algorithm *algo;
96
97 ESP_CHECK_ARG(sav);
98
99 if ((sav->flags & SADB_X_EXT_OLD) != 0) {
100 esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_OLD");
101 return 1;
102 }
103 if ((sav->flags & SADB_X_EXT_DERIV) != 0) {
104 esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_DERIV");
105 return 1;
106 }
107
108 if (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305) {
109 esp_log_err("ChaChaPoly unsupported algorithm %d",
110 sav->alg_enc);
111 return 1;
112 }
113
114 if (sav->key_enc == NULL) {
115 esp_log_err("ChaChaPoly key is missing");
116 return 1;
117 }
118
119 algo = esp_algorithm_lookup(sav->alg_enc);
120 if (algo == NULL) {
121 esp_log_err("ChaChaPoly lookup failed for algorithm %d",
122 sav->alg_enc);
123 return 1;
124 }
125
126 if (sav->key_enc->sadb_key_bits != ESP_CHACHAPOLY_KEYBITS_WITH_SALT) {
127 esp_log_err("ChaChaPoly invalid key length %d bits",
128 sav->key_enc->sadb_key_bits);
129 return 1;
130 }
131
132 return 0;
133 }
134
135 int
136 esp_chachapoly_schedlen(__unused const struct esp_algorithm *algo)
137 {
138 return sizeof(esp_chachapoly_ctx_s);
139 }
140
141 int
142 esp_chachapoly_schedule(__unused const struct esp_algorithm *algo,
143 struct secasvar *sav)
144 {
145 esp_chachapoly_ctx_t esp_ccp_ctx;
146 int rc = 0;
147
148 ESP_CHECK_ARG(sav);
149 if (sav->ivlen != ESP_CHACHAPOLY_IV_LEN) {
150 esp_log_err("Invalid ivlen %u", sav->ivlen);
151 return EINVAL;
152 }
153 if (_KEYLEN(sav->key_enc) != ESP_CHACHAPOLY_KEY_LEN + ESP_CHACHAPOLY_SALT_LEN) {
154 esp_log_err("Invalid key len %u", _KEYLEN(sav->key_enc));
155 return EINVAL;
156 }
157 LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
158
159 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
160
161 rc = chacha20poly1305_init(&esp_ccp_ctx->ccp_ctx,
162 (const uint8_t *)_KEYBUF(sav->key_enc));
163 if (rc != 0) {
164 esp_log_err("chacha20poly1305_init returned %d", rc);
165 return rc;
166 }
167
168 memcpy(esp_ccp_ctx->ccp_salt,
169 (const uint8_t *)_KEYBUF(sav->key_enc) + ESP_CHACHAPOLY_KEY_LEN,
170 sizeof(esp_ccp_ctx->ccp_salt));
171
172 esp_ccp_ctx->ccp_implicit_iv = ((sav->flags & SADB_X_EXT_IIV) != 0);
173
174 return 0;
175 }
176
177 int
178 esp_chachapoly_encrypt_finalize(struct secasvar *sav,
179 unsigned char *tag,
180 unsigned int tag_bytes)
181 {
182 esp_chachapoly_ctx_t esp_ccp_ctx;
183 int rc = 0;
184
185 ESP_CHECK_ARG(sav);
186 ESP_CHECK_ARG(tag);
187 if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
188 esp_log_err("Invalid tag_bytes %u", tag_bytes);
189 return EINVAL;
190 }
191
192 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
193 rc = chacha20poly1305_finalize(&esp_ccp_ctx->ccp_ctx, tag);
194 if (rc != 0) {
195 esp_log_err("chacha20poly1305_finalize returned %d", rc);
196 return rc;
197 }
198 return 0;
199 }
200
201 int
202 esp_chachapoly_decrypt_finalize(struct secasvar *sav,
203 unsigned char *tag,
204 unsigned int tag_bytes)
205 {
206 esp_chachapoly_ctx_t esp_ccp_ctx;
207 int rc = 0;
208
209 ESP_CHECK_ARG(sav);
210 ESP_CHECK_ARG(tag);
211 if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
212 esp_log_err("Invalid tag_bytes %u", tag_bytes);
213 return EINVAL;
214 }
215
216 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
217 rc = chacha20poly1305_verify(&esp_ccp_ctx->ccp_ctx, tag);
218 if (rc != 0) {
219 esp_log_err("chacha20poly1305_finalize returned %d", rc);
220 return rc;
221 }
222 return 0;
223 }
224
225 int
226 esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
227 size_t off, // offset to ESP header
228 __unused size_t plen,
229 struct secasvar *sav,
230 __unused const struct esp_algorithm *algo,
231 int ivlen)
232 {
233 struct mbuf *s = m; // this mbuf
234 int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
235 int32_t sn = 0; // offset from the head of this mbuf (s) to the body
236 uint8_t *sp; // buffer of a given encryption round
237 size_t len; // length of a given encryption round
238 const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
239 int32_t bodyoff; // body offset
240 int rc = 0; // return code of corecrypto operations
241 struct newesp esp_hdr; // ESP header for AAD
242 _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
243 uint8_t nonce[ESP_CHACHAPOLY_NONCE_LEN];
244 esp_chachapoly_ctx_t esp_ccp_ctx;
245
246 ESP_CHECK_ARG(m);
247 ESP_CHECK_ARG(sav);
248 if (ivlen != ESP_CHACHAPOLY_IV_LEN) {
249 m_freem(m);
250 esp_log_err("Invalid ivlen %u", ivlen);
251 return EINVAL;
252 }
253 if (sav->ivlen != ESP_CHACHAPOLY_IV_LEN) {
254 m_freem(m);
255 esp_log_err("Invalid sav->ivlen %u", sav->ivlen);
256 return EINVAL;
257 }
258
259 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
260 if (esp_ccp_ctx->ccp_implicit_iv) {
261 bodyoff = ivoff;
262 } else {
263 bodyoff = ivoff + ivlen;
264 }
265 // check if total packet length is enough to contain ESP + IV
266 if (m->m_pkthdr.len < bodyoff) {
267 esp_log_err("Packet too short %d < %zu", m->m_pkthdr.len, bodyoff);
268 m_freem(m);
269 return EINVAL;
270 }
271
272 rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
273 if (rc != 0) {
274 m_freem(m);
275 esp_log_err("chacha20poly1305_reset failed %d", rc);
276 return rc;
277 }
278
279 // RFC 7634 dictates that the 12 byte nonce must be
280 // the 4 byte salt followed by the 8 byte IV.
281 // The IV MUST be non-repeating but does not need to be unpredictable,
282 // so we use 4 bytes of 0 followed by the 4 byte ESP sequence number.
283 // this allows us to use implicit IV -- draft-mglt-ipsecme-implicit-iv
284 memset(sav->iv, 0, 4);
285 memcpy(sav->iv + 4, &sav->seq, sizeof(sav->seq));
286 _Static_assert(4 + sizeof(sav->seq) == ESP_CHACHAPOLY_IV_LEN,
287 "Bad IV length");
288 memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
289 memcpy(nonce + ESP_CHACHAPOLY_SALT_LEN, sav->iv, ESP_CHACHAPOLY_IV_LEN);
290 _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
291 "Bad nonce length");
292
293 rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, nonce);
294 if (rc != 0) {
295 m_freem(m);
296 esp_log_err("chacha20poly1305_setnonce failed %d", rc);
297 return rc;
298 }
299
300 if (!esp_ccp_ctx->ccp_implicit_iv) {
301 m_copyback(m, ivoff, ivlen, sav->iv);
302 }
303 cc_clear(sizeof(nonce), nonce);
304
305 // Set Additional Authentication Data (AAD)
306 m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
307
308 rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
309 sizeof(esp_hdr),
310 (void *)&esp_hdr);
311 if (rc != 0) {
312 m_freem(m);
313 esp_log_err("chacha20poly1305_aad failed %d", rc);
314 return rc;
315 }
316
317 // skip headers/IV
318 while (s != NULL && soff < bodyoff) {
319 if (soff + s->m_len > bodyoff) {
320 sn = bodyoff - soff;
321 break;
322 }
323
324 soff += s->m_len;
325 s = s->m_next;
326 }
327
328 while (s != NULL && soff < m->m_pkthdr.len) {
329 len = (size_t)(s->m_len - sn);
330 if (len == 0) {
331 // skip empty mbufs
332 continue;
333 }
334 sp = mtod(s, uint8_t *) + sn;
335
336 rc = chacha20poly1305_encrypt(&esp_ccp_ctx->ccp_ctx,
337 len, sp, sp);
338 if (rc != 0) {
339 m_freem(m);
340 esp_log_err("chacha20poly1305_encrypt failed %d", rc);
341 return rc;
342 }
343
344 sn = 0;
345 soff += s->m_len;
346 s = s->m_next;
347 }
348 if (s == NULL && soff != m->m_pkthdr.len) {
349 m_freem(m);
350 esp_log_err("not enough mbufs %d %d", soff, m->m_pkthdr.len);
351 return EFBIG;
352 }
353 return 0;
354 }
355
356 int
357 esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
358 size_t off, // offset to ESP header
359 struct secasvar *sav,
360 __unused const struct esp_algorithm *algo,
361 int ivlen)
362 {
363 struct mbuf *s = m; // this mbuf
364 int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
365 int32_t sn = 0; // offset from the head of this mbuf (s) to the body
366 uint8_t *sp; // buffer of a given encryption round
367 size_t len; // length of a given encryption round
368 const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
369 int32_t bodyoff; // body offset
370 int rc = 0; // return code of corecrypto operations
371 struct newesp esp_hdr; // ESP header for AAD
372 _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
373 uint8_t nonce[ESP_CHACHAPOLY_NONCE_LEN];
374 esp_chachapoly_ctx_t esp_ccp_ctx;
375
376 ESP_CHECK_ARG(m);
377 ESP_CHECK_ARG(sav);
378 if (ivlen != ESP_CHACHAPOLY_IV_LEN) {
379 m_freem(m);
380 esp_log_err("Invalid ivlen %u", ivlen);
381 return EINVAL;
382 }
383 if (sav->ivlen != ESP_CHACHAPOLY_IV_LEN) {
384 m_freem(m);
385 esp_log_err("Invalid sav->ivlen %u", sav->ivlen);
386 return EINVAL;
387 }
388
389 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
390 if (esp_ccp_ctx->ccp_implicit_iv) {
391 bodyoff = ivoff;
392 } else {
393 bodyoff = ivoff + ivlen;
394 }
395 // check if total packet length is enough to contain ESP + IV
396 if (m->m_pkthdr.len < bodyoff) {
397 esp_packet_log_err("Packet too short %d < %zu", m->m_pkthdr.len, bodyoff);
398 m_freem(m);
399 return EINVAL;
400 }
401
402 rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
403 if (rc != 0) {
404 m_freem(m);
405 esp_log_err("chacha20poly1305_reset failed %d", rc);
406 return rc;
407 }
408
409 m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
410
411 // RFC 7634 dictates that the 12 byte nonce must be
412 // the 4 byte salt followed by the 8 byte IV.
413 memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
414 if (esp_ccp_ctx->ccp_implicit_iv) {
415 // IV is implicit (4 zero bytes followed by the ESP sequence number)
416 memset(nonce + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
417 memcpy(nonce + ESP_CHACHAPOLY_SALT_LEN + 4, &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
418 _Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN, "Bad IV length");
419 } else {
420 // copy IV from packet
421 m_copydata(m, ivoff, ESP_CHACHAPOLY_IV_LEN, nonce + ESP_CHACHAPOLY_SALT_LEN);
422 }
423 _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
424 "Bad nonce length");
425
426 rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, nonce);
427 if (rc != 0) {
428 m_freem(m);
429 esp_log_err("chacha20poly1305_setnonce failed %d", rc);
430 return rc;
431 }
432 cc_clear(sizeof(nonce), nonce);
433
434 // Set Additional Authentication Data (AAD)
435 rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
436 sizeof(esp_hdr),
437 (void *)&esp_hdr);
438 if (rc != 0) {
439 m_freem(m);
440 esp_log_err("chacha20poly1305_aad failed %d", rc);
441 return rc;
442 }
443
444 // skip headers/IV
445 while (s != NULL && soff < bodyoff) {
446 if (soff + s->m_len > bodyoff) {
447 sn = bodyoff - soff;
448 break;
449 }
450
451 soff += s->m_len;
452 s = s->m_next;
453 }
454
455 while (s != NULL && soff < m->m_pkthdr.len) {
456 len = (size_t)(s->m_len - sn);
457 if (len == 0) {
458 // skip empty mbufs
459 continue;
460 }
461 sp = mtod(s, uint8_t *) + sn;
462
463 rc = chacha20poly1305_decrypt(&esp_ccp_ctx->ccp_ctx,
464 len, sp, sp);
465 if (rc != 0) {
466 m_freem(m);
467 esp_packet_log_err("chacha20poly1305_decrypt failed %d", rc);
468 return rc;
469 }
470
471 sn = 0;
472 soff += s->m_len;
473 s = s->m_next;
474 }
475 if (s == NULL && soff != m->m_pkthdr.len) {
476 m_freem(m);
477 esp_packet_log_err("not enough mbufs %d %d", soff, m->m_pkthdr.len);
478 return EFBIG;
479 }
480 return 0;
481 }