1 /*
2 * Copyright (c) 2017, 2021-2023 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 typedef struct _esp_chachapoly_ctx {
67 chacha20poly1305_ctx ccp_ctx;
68 uint8_t ccp_salt[ESP_CHACHAPOLY_SALT_LEN];
69 bool ccp_implicit_iv;
70 } esp_chachapoly_ctx_s, *esp_chachapoly_ctx_t;
71
72 int
esp_chachapoly_mature(struct secasvar * sav)73 esp_chachapoly_mature(struct secasvar *sav)
74 {
75 const struct esp_algorithm *algo;
76
77 ESP_CHECK_ARG(sav);
78
79 if ((sav->flags & SADB_X_EXT_OLD) != 0) {
80 esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_OLD, SPI 0x%08x",
81 ntohl(sav->spi));
82 return 1;
83 }
84 if ((sav->flags & SADB_X_EXT_DERIV) != 0) {
85 esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_DERIV, SPI 0x%08x",
86 ntohl(sav->spi));
87 return 1;
88 }
89
90 if (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305) {
91 esp_log_err("ChaChaPoly unsupported algorithm %d, SPI 0x%08x",
92 sav->alg_enc, ntohl(sav->spi));
93 return 1;
94 }
95
96 if (sav->key_enc == NULL) {
97 esp_log_err("ChaChaPoly key is missing, SPI 0x%08x",
98 ntohl(sav->spi));
99 return 1;
100 }
101
102 algo = esp_algorithm_lookup(sav->alg_enc);
103 if (algo == NULL) {
104 esp_log_err("ChaChaPoly lookup failed for algorithm %d, SPI 0x%08x",
105 sav->alg_enc, ntohl(sav->spi));
106 return 1;
107 }
108
109 if (sav->key_enc->sadb_key_bits != ESP_CHACHAPOLY_KEYBITS_WITH_SALT) {
110 esp_log_err("ChaChaPoly invalid key length %d bits, SPI 0x%08x",
111 sav->key_enc->sadb_key_bits, ntohl(sav->spi));
112 return 1;
113 }
114
115 esp_log_default("ChaChaPoly Mature SPI 0x%08x%s %s dir %u state %u mode %u",
116 ntohl(sav->spi),
117 (((sav->flags & SADB_X_EXT_IIV) != 0) ? " IIV" : ""),
118 ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
119 sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
120
121 return 0;
122 }
123
124 size_t
esp_chachapoly_schedlen(__unused const struct esp_algorithm * algo)125 esp_chachapoly_schedlen(__unused const struct esp_algorithm *algo)
126 {
127 return sizeof(esp_chachapoly_ctx_s);
128 }
129
130 int
esp_chachapoly_schedule(__unused const struct esp_algorithm * algo,struct secasvar * sav)131 esp_chachapoly_schedule(__unused const struct esp_algorithm *algo,
132 struct secasvar *sav)
133 {
134 esp_chachapoly_ctx_t esp_ccp_ctx;
135 int rc = 0;
136
137 ESP_CHECK_ARG(sav);
138 if (_KEYLEN(sav->key_enc) != ESP_CHACHAPOLY_KEY_LEN + ESP_CHACHAPOLY_SALT_LEN) {
139 esp_log_err("ChaChaPoly Invalid key len %u, SPI 0x%08x",
140 _KEYLEN(sav->key_enc), ntohl(sav->spi));
141 return EINVAL;
142 }
143 LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
144
145 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
146 esp_ccp_ctx->ccp_implicit_iv = ((sav->flags & SADB_X_EXT_IIV) != 0);
147
148 if (sav->ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
149 esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
150 sav->ivlen, ntohl(sav->spi));
151 return EINVAL;
152 }
153
154 rc = chacha20poly1305_init(&esp_ccp_ctx->ccp_ctx,
155 (const uint8_t *)_KEYBUF(sav->key_enc));
156 if (rc != 0) {
157 esp_log_err("ChaChaPoly chacha20poly1305_init failed %d, SPI 0x%08x",
158 rc, ntohl(sav->spi));
159 return rc;
160 }
161
162 memcpy(esp_ccp_ctx->ccp_salt,
163 (const uint8_t *)_KEYBUF(sav->key_enc) + ESP_CHACHAPOLY_KEY_LEN,
164 sizeof(esp_ccp_ctx->ccp_salt));
165
166
167 esp_log_default("ChaChaPoly Schedule SPI 0x%08x%s %s dir %u state %u mode %u",
168 ntohl(sav->spi), (esp_ccp_ctx->ccp_implicit_iv ? " IIV" : ""),
169 ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
170 sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
171
172 return 0;
173 }
174
175 int
esp_chachapoly_ivlen(const struct esp_algorithm * algo,struct secasvar * sav)176 esp_chachapoly_ivlen(const struct esp_algorithm *algo,
177 struct secasvar *sav)
178 {
179 ESP_CHECK_ARG(algo);
180
181 if (sav != NULL &&
182 ((sav->sched_enc != NULL && ((esp_chachapoly_ctx_t)sav->sched_enc)->ccp_implicit_iv) ||
183 ((sav->flags & SADB_X_EXT_IIV) != 0))) {
184 return 0;
185 } else {
186 return algo->ivlenval;
187 }
188 }
189
190
191 int
esp_chachapoly_encrypt_finalize(struct secasvar * sav,unsigned char * tag,size_t tag_bytes)192 esp_chachapoly_encrypt_finalize(struct secasvar *sav,
193 unsigned char *tag,
194 size_t tag_bytes)
195 {
196 esp_chachapoly_ctx_t esp_ccp_ctx;
197 int rc = 0;
198
199 ESP_CHECK_ARG(sav);
200 ESP_CHECK_ARG(tag);
201 if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
202 esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
203 tag_bytes, ntohl(sav->spi));
204 return EINVAL;
205 }
206
207 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
208 rc = chacha20poly1305_finalize(&esp_ccp_ctx->ccp_ctx, tag);
209 if (rc != 0) {
210 esp_log_err("ChaChaPoly chacha20poly1305_finalize failed %d, SPI 0x%08x",
211 rc, ntohl(sav->spi));
212 return rc;
213 }
214 return 0;
215 }
216
217 int
esp_chachapoly_decrypt_finalize(struct secasvar * sav,unsigned char * tag,size_t tag_bytes)218 esp_chachapoly_decrypt_finalize(struct secasvar *sav,
219 unsigned char *tag,
220 size_t tag_bytes)
221 {
222 esp_chachapoly_ctx_t esp_ccp_ctx;
223 int rc = 0;
224
225 ESP_CHECK_ARG(sav);
226 ESP_CHECK_ARG(tag);
227 if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
228 esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
229 tag_bytes, ntohl(sav->spi));
230 return EINVAL;
231 }
232
233 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
234 rc = chacha20poly1305_verify(&esp_ccp_ctx->ccp_ctx, tag);
235 if (rc != 0) {
236 esp_packet_log_err("ChaChaPoly chacha20poly1305_verify failed %d, SPI 0x%08x",
237 rc, ntohl(sav->spi));
238 return rc;
239 }
240 return 0;
241 }
242
243 int
esp_chachapoly_encrypt(struct mbuf * m,size_t off,__unused size_t plen,struct secasvar * sav,__unused const struct esp_algorithm * algo,int ivlen)244 esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
245 size_t off, // offset to ESP header
246 __unused size_t plen,
247 struct secasvar *sav,
248 __unused const struct esp_algorithm *algo,
249 int ivlen)
250 {
251 struct mbuf *s = m; // this mbuf
252 int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
253 int32_t sn = 0; // offset from the head of this mbuf (s) to the body
254 uint8_t *sp; // buffer of a given encryption round
255 size_t len; // length of a given encryption round
256 const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
257 const size_t bodyoff = ivoff + ivlen; // body offset
258 int rc = 0; // return code of corecrypto operations
259 struct newesp esp_hdr; // ESP header for AAD
260 _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
261 uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
262 _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
263 _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
264 "Bad nonce length");
265 esp_chachapoly_ctx_t esp_ccp_ctx;
266
267 ESP_CHECK_ARG(m);
268 ESP_CHECK_ARG(sav);
269
270 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
271
272 if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
273 esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
274 ivlen, ntohl(sav->spi));
275 m_freem(m);
276 return EINVAL;
277 }
278 if (sav->ivlen != ivlen) {
279 esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
280 sav->ivlen, ntohl(sav->spi));
281 m_freem(m);
282 return EINVAL;
283 }
284
285 // check if total packet length is enough to contain ESP + IV
286 if (m->m_pkthdr.len < bodyoff) {
287 esp_log_err("ChaChaPoly Packet too short %d < %zu, SPI 0x%08x",
288 m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
289 m_freem(m);
290 return EINVAL;
291 }
292
293 rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
294 if (rc != 0) {
295 esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
296 rc, ntohl(sav->spi));
297 m_freem(m);
298 return rc;
299 }
300
301 // esp_hdr is used for nonce and AAD
302 m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
303
304 // RFC 7634 dictates that the 12 byte nonce must be
305 // the 4 byte salt followed by the 8 byte IV.
306 memset(nonce, 0, ESP_CHACHAPOLY_NONCE_LEN);
307 memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
308 if (!esp_ccp_ctx->ccp_implicit_iv) {
309 // Increment IV and save back new value
310 uint64_t iv = 0;
311 _Static_assert(ESP_CHACHAPOLY_IV_LEN == sizeof(iv), "Bad IV length");
312 memcpy(&iv, sav->iv, sizeof(iv));
313 iv++;
314 memcpy(sav->iv, &iv, sizeof(iv));
315
316 // Copy the new IV into the nonce and the packet
317 memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, &iv, sizeof(iv));
318 m_copyback(m, ivoff, ivlen, sav->iv);
319 } else {
320 // Use the sequence number in the ESP header to form the
321 // nonce according to RFC 8750. The first 4 bytes are the
322 // salt value, the next 4 bytes are zeroes, and the final
323 // 4 bytes are the ESP sequence number.
324 _Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN,
325 "Bad IV length");
326 memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
327 &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
328 }
329
330 rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
331 cc_clear(sizeof(nonce), nonce);
332 if (rc != 0) {
333 esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
334 rc, ntohl(sav->spi));
335 m_freem(m);
336 return rc;
337 }
338
339 // Set Additional Authentication Data (AAD)
340 rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
341 sizeof(esp_hdr),
342 (void *)&esp_hdr);
343 if (rc != 0) {
344 esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
345 rc, ntohl(sav->spi));
346 m_freem(m);
347 return rc;
348 }
349
350 // skip headers/IV
351 while (s != NULL && soff < bodyoff) {
352 if (soff + s->m_len > bodyoff) {
353 sn = bodyoff - soff;
354 break;
355 }
356
357 soff += s->m_len;
358 s = s->m_next;
359 }
360
361 while (s != NULL && soff < m->m_pkthdr.len) {
362 // skip empty mbufs
363 if ((len = (size_t)(s->m_len - sn)) != 0) {
364 sp = mtod(s, uint8_t *) + sn;
365
366 rc = chacha20poly1305_encrypt(&esp_ccp_ctx->ccp_ctx,
367 len, sp, sp);
368 if (rc != 0) {
369 m_freem(m);
370 esp_log_err("ChaChaPoly chacha20poly1305_encrypt failed %d, SPI 0x%08x",
371 rc, ntohl(sav->spi));
372 return rc;
373 }
374 }
375
376 sn = 0;
377 soff += s->m_len;
378 s = s->m_next;
379 }
380 if (s == NULL && soff != m->m_pkthdr.len) {
381 esp_log_err("ChaChaPoly not enough mbufs %d %d, SPI 0x%08x",
382 soff, m->m_pkthdr.len, ntohl(sav->spi));
383 m_freem(m);
384 return EFBIG;
385 }
386 return 0;
387 }
388
389 int
esp_chachapoly_decrypt(struct mbuf * m,size_t off,struct secasvar * sav,__unused const struct esp_algorithm * algo,int ivlen)390 esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
391 size_t off, // offset to ESP header
392 struct secasvar *sav,
393 __unused const struct esp_algorithm *algo,
394 int ivlen)
395 {
396 struct mbuf *s = m; // this mbuf
397 int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
398 int32_t sn = 0; // offset from the head of this mbuf (s) to the body
399 uint8_t *sp; // buffer of a given encryption round
400 size_t len; // length of a given encryption round
401 const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
402 const int32_t bodyoff = ivoff + ivlen; // body offset
403 int rc = 0; // return code of corecrypto operations
404 struct newesp esp_hdr; // ESP header for AAD
405 _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
406 uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
407 _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
408 esp_chachapoly_ctx_t esp_ccp_ctx;
409
410 ESP_CHECK_ARG(m);
411 ESP_CHECK_ARG(sav);
412
413 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
414
415 if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
416 esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
417 ivlen, ntohl(sav->spi));
418 m_freem(m);
419 return EINVAL;
420 }
421 if (sav->ivlen != ivlen) {
422 esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
423 sav->ivlen, ntohl(sav->spi));
424 m_freem(m);
425 return EINVAL;
426 }
427
428 // check if total packet length is enough to contain ESP + IV
429 if (m->m_pkthdr.len < bodyoff) {
430 esp_packet_log_err("ChaChaPoly Packet too short %d < %u, SPI 0x%08x",
431 m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
432 m_freem(m);
433 return EINVAL;
434 }
435
436 rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
437 if (rc != 0) {
438 esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
439 rc, ntohl(sav->spi));
440 m_freem(m);
441 return rc;
442 }
443
444 m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
445
446 // RFC 7634 dictates that the 12 byte nonce must be
447 // the 4 byte salt followed by the 8 byte IV.
448 memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
449 if (esp_ccp_ctx->ccp_implicit_iv) {
450 // IV is implicit (4 zero bytes followed by the ESP sequence number)
451 memset(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
452 memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
453 &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
454 _Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN, "Bad IV length");
455 } else {
456 // copy IV from packet
457 m_copydata(m, ivoff, ESP_CHACHAPOLY_IV_LEN, ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN);
458 }
459 _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
460 "Bad nonce length");
461
462 rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
463 if (rc != 0) {
464 esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
465 rc, ntohl(sav->spi));
466 m_freem(m);
467 return rc;
468 }
469 cc_clear(sizeof(nonce), nonce);
470
471 // Set Additional Authentication Data (AAD)
472 rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
473 sizeof(esp_hdr),
474 (void *)&esp_hdr);
475 if (rc != 0) {
476 esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
477 rc, ntohl(sav->spi));
478 m_freem(m);
479 return rc;
480 }
481
482 // skip headers/IV
483 while (s != NULL && soff < bodyoff) {
484 if (soff + s->m_len > bodyoff) {
485 sn = bodyoff - soff;
486 break;
487 }
488
489 soff += s->m_len;
490 s = s->m_next;
491 }
492
493 while (s != NULL && soff < m->m_pkthdr.len) {
494 // skip empty mbufs
495 if ((len = (size_t)(s->m_len - sn)) != 0) {
496 sp = mtod(s, uint8_t *) + sn;
497
498 rc = chacha20poly1305_decrypt(&esp_ccp_ctx->ccp_ctx,
499 len, sp, sp);
500 if (rc != 0) {
501 m_freem(m);
502 esp_packet_log_err("chacha20poly1305_decrypt failed %d, SPI 0x%08x",
503 rc, ntohl(sav->spi));
504 return rc;
505 }
506 }
507
508 sn = 0;
509 soff += s->m_len;
510 s = s->m_next;
511 }
512 if (s == NULL && soff != m->m_pkthdr.len) {
513 esp_packet_log_err("not enough mbufs %d %d, SPI 0x%08x",
514 soff, m->m_pkthdr.len, ntohl(sav->spi));
515 m_freem(m);
516 return EFBIG;
517 }
518 return 0;
519 }
520
521 int
esp_chachapoly_encrypt_data(struct secasvar * sav,uint8_t * __sized_by (input_data_len)input_data,size_t input_data_len,struct newesp * esp_hdr,uint8_t * __sized_by (out_ivlen)out_iv,size_t out_ivlen,uint8_t * __sized_by (output_data_len)output_data,size_t output_data_len)522 esp_chachapoly_encrypt_data(struct secasvar *sav,
523 uint8_t *__sized_by(input_data_len)input_data, size_t input_data_len,
524 struct newesp *esp_hdr,
525 uint8_t *__sized_by(out_ivlen)out_iv, size_t out_ivlen,
526 uint8_t *__sized_by(output_data_len)output_data, size_t output_data_len)
527 {
528 uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
529 esp_chachapoly_ctx_t esp_ccp_ctx = NULL;
530 int rc = 0; // return code of corecrypto operations
531
532 _Static_assert(sizeof(*esp_hdr) == 8, "Bad size");
533 _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
534 _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
535 "Bad nonce length");
536
537 ESP_CHECK_ARG(sav);
538 ESP_CHECK_ARG(input_data);
539 ESP_CHECK_ARG(esp_hdr);
540 ESP_CHECK_ARG(output_data);
541
542 VERIFY(input_data_len != 0);
543 VERIFY(output_data_len >= input_data_len);
544
545 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
546 ESP_CHECK_ARG(esp_ccp_ctx);
547
548 rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
549 if (rc != 0) {
550 esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
551 rc, ntohl(sav->spi));
552 return rc;
553 }
554
555 // RFC 7634 dictates that the 12 byte nonce must be
556 // the 4 byte salt followed by the 8 byte IV.
557 memset(nonce, 0, ESP_CHACHAPOLY_NONCE_LEN);
558 memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
559
560 if (!esp_ccp_ctx->ccp_implicit_iv) {
561 // Increment IV and save back new value
562 uint64_t iv = os_atomic_inc(sav->iv, relaxed);
563 _Static_assert(ESP_CHACHAPOLY_IV_LEN == sizeof(iv), "Bad IV length");
564
565 ESP_CHECK_ARG(out_iv);
566 if (__improbable(out_ivlen != ESP_CHACHAPOLY_IV_LEN)) {
567 cc_clear(sizeof(nonce), nonce);
568 esp_log_err("ChaChaPoly Invalid ivlen %zu, SPI 0x%08x",
569 out_ivlen, ntohl(sav->spi));
570 return EINVAL;
571 }
572
573 // Copy the new IV into the nonce and the packet
574 memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, &iv, sizeof(iv));
575 memcpy(out_iv, &iv, ESP_CHACHAPOLY_IV_LEN);
576 } else {
577 VERIFY(out_iv == NULL);
578 // Use the sequence number in the ESP header to form the
579 // nonce according to RFC 8750. The first 4 bytes are the
580 // salt value, the next 4 bytes are zeroes, and the final
581 // 4 bytes are the ESP sequence number.
582 _Static_assert(4 + sizeof(esp_hdr->esp_seq) == ESP_CHACHAPOLY_IV_LEN,
583 "Bad IV length");
584 memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
585 &esp_hdr->esp_seq, sizeof(esp_hdr->esp_seq));
586 }
587
588 rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
589 cc_clear(sizeof(nonce), nonce);
590 if (rc != 0) {
591 esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
592 rc, ntohl(sav->spi));
593 return rc;
594 }
595
596 // Set Additional Authentication Data (AAD)
597 rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx, sizeof(*esp_hdr), (void *)esp_hdr);
598 if (rc != 0) {
599 esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
600 rc, ntohl(sav->spi));
601 return rc;
602 }
603
604 rc = chacha20poly1305_encrypt(&esp_ccp_ctx->ccp_ctx, input_data_len, input_data, output_data);
605 if (rc != 0) {
606 esp_log_err("ChaChaPoly chacha20poly1305_encrypt failed %d, SPI 0x%08x",
607 rc, ntohl(sav->spi));
608 return rc;
609 }
610
611 return 0;
612 }
613
614 int
esp_chachapoly_decrypt_data(struct secasvar * sav,uint8_t * __sized_by (input_data_len)input_data,size_t input_data_len,struct newesp * esp_hdr,uint8_t * __sized_by (ivlen)iv,size_t ivlen,uint8_t * __sized_by (output_data_len)output_data,size_t output_data_len)615 esp_chachapoly_decrypt_data(struct secasvar *sav,
616 uint8_t *__sized_by(input_data_len)input_data, size_t input_data_len,
617 struct newesp *esp_hdr,
618 uint8_t *__sized_by(ivlen)iv, size_t ivlen,
619 uint8_t *__sized_by(output_data_len)output_data, size_t output_data_len)
620 {
621 uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
622 esp_chachapoly_ctx_t esp_ccp_ctx = NULL;
623 int rc = 0; // return code of corecrypto operations
624
625 _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
626 _Static_assert(sizeof(*esp_hdr) == 8, "Bad size");
627
628 ESP_CHECK_ARG(sav);
629 ESP_CHECK_ARG(input_data);
630 ESP_CHECK_ARG(esp_hdr);
631 ESP_CHECK_ARG(output_data);
632
633 VERIFY(input_data_len > 0);
634 VERIFY(output_data_len >= input_data_len);
635
636 esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
637
638 rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
639 if (rc != 0) {
640 esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
641 rc, ntohl(sav->spi));
642 return rc;
643 }
644
645 // RFC 7634 dictates that the 12 byte nonce must be
646 // the 4 byte salt followed by the 8 byte IV.
647 memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
648 if (esp_ccp_ctx->ccp_implicit_iv) {
649 VERIFY(iv == NULL);
650 VERIFY(ivlen == 0);
651 // IV is implicit (4 zero bytes followed by the ESP sequence number)
652 memset(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
653 memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
654 &esp_hdr->esp_seq, sizeof(esp_hdr->esp_seq));
655 _Static_assert(4 + sizeof(esp_hdr->esp_seq) == ESP_CHACHAPOLY_IV_LEN, "Bad IV length");
656 } else {
657 // copy IV from packet
658 if (ivlen != ESP_CHACHAPOLY_IV_LEN) {
659 esp_log_err("ChaChaPoly Invalid ivlen %zu, SPI 0x%08x",
660 ivlen, ntohl(sav->spi));
661 return EINVAL;
662 }
663 memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, iv, ESP_CHACHAPOLY_IV_LEN);
664 }
665
666 rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
667 if (rc != 0) {
668 esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
669 rc, ntohl(sav->spi));
670 cc_clear(sizeof(nonce), nonce);
671 return rc;
672 }
673 cc_clear(sizeof(nonce), nonce);
674
675 // Set Additional Authentication Data (AAD)
676 rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx, sizeof(*esp_hdr), (void *)esp_hdr);
677 if (rc != 0) {
678 esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
679 rc, ntohl(sav->spi));
680 return rc;
681 }
682
683 rc = chacha20poly1305_decrypt(&esp_ccp_ctx->ccp_ctx, input_data_len, input_data, output_data);
684 if (rc != 0) {
685 esp_log_err("chacha20poly1305_decrypt failed %d, SPI 0x%08x",
686 rc, ntohl(sav->spi));
687 return rc;
688 }
689
690 return 0;
691 }
692