xref: /xnu-10063.121.3/bsd/netinet6/esp_chachapoly.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
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 * input_data,size_t input_data_len,struct newesp * esp_hdr,uint8_t * out_iv,size_t out_ivlen,uint8_t * output_data,size_t output_data_len)522 esp_chachapoly_encrypt_data(struct secasvar *sav, uint8_t *input_data,
523     size_t input_data_len, struct newesp *esp_hdr, uint8_t *out_iv,
524     size_t out_ivlen, uint8_t *output_data, size_t output_data_len)
525 {
526 	uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
527 	esp_chachapoly_ctx_t esp_ccp_ctx = NULL;
528 	int rc = 0; // return code of corecrypto operations
529 
530 	_Static_assert(sizeof(*esp_hdr) == 8, "Bad size");
531 	_Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
532 	_Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
533 	    "Bad nonce length");
534 
535 	ESP_CHECK_ARG(sav);
536 	ESP_CHECK_ARG(input_data);
537 	ESP_CHECK_ARG(esp_hdr);
538 	ESP_CHECK_ARG(output_data);
539 
540 	VERIFY(input_data_len != 0);
541 	VERIFY(output_data_len >= input_data_len);
542 
543 	esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
544 	ESP_CHECK_ARG(esp_ccp_ctx);
545 
546 	rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
547 	if (rc != 0) {
548 		esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
549 		    rc, ntohl(sav->spi));
550 		return rc;
551 	}
552 
553 	// RFC 7634 dictates that the 12 byte nonce must be
554 	// the 4 byte salt followed by the 8 byte IV.
555 	memset(nonce, 0, ESP_CHACHAPOLY_NONCE_LEN);
556 	memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
557 
558 	if (!esp_ccp_ctx->ccp_implicit_iv) {
559 		// Increment IV and save back new value
560 		uint64_t iv = os_atomic_inc(sav->iv, relaxed);
561 		_Static_assert(ESP_CHACHAPOLY_IV_LEN == sizeof(iv), "Bad IV length");
562 
563 		ESP_CHECK_ARG(out_iv);
564 		if (__improbable(out_ivlen != ESP_CHACHAPOLY_IV_LEN)) {
565 			cc_clear(sizeof(nonce), nonce);
566 			esp_log_err("ChaChaPoly Invalid ivlen %zu, SPI 0x%08x",
567 			    out_ivlen, ntohl(sav->spi));
568 			return EINVAL;
569 		}
570 
571 		// Copy the new IV into the nonce and the packet
572 		memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, &iv, sizeof(iv));
573 		memcpy(out_iv, &iv, ESP_CHACHAPOLY_IV_LEN);
574 	} else {
575 		VERIFY(out_iv == NULL);
576 		// Use the sequence number in the ESP header to form the
577 		// nonce according to RFC 8750. The first 4 bytes are the
578 		// salt value, the next 4 bytes are zeroes, and the final
579 		// 4 bytes are the ESP sequence number.
580 		_Static_assert(4 + sizeof(esp_hdr->esp_seq) == ESP_CHACHAPOLY_IV_LEN,
581 		    "Bad IV length");
582 		memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
583 		    &esp_hdr->esp_seq, sizeof(esp_hdr->esp_seq));
584 	}
585 
586 	rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
587 	cc_clear(sizeof(nonce), nonce);
588 	if (rc != 0) {
589 		esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
590 		    rc, ntohl(sav->spi));
591 		return rc;
592 	}
593 
594 	// Set Additional Authentication Data (AAD)
595 	rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx, sizeof(*esp_hdr), (void *)esp_hdr);
596 	if (rc != 0) {
597 		esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
598 		    rc, ntohl(sav->spi));
599 		return rc;
600 	}
601 
602 	rc = chacha20poly1305_encrypt(&esp_ccp_ctx->ccp_ctx, input_data_len, input_data, output_data);
603 	if (rc != 0) {
604 		esp_log_err("ChaChaPoly chacha20poly1305_encrypt failed %d, SPI 0x%08x",
605 		    rc, ntohl(sav->spi));
606 		return rc;
607 	}
608 
609 	return 0;
610 }
611 
612 int
esp_chachapoly_decrypt_data(struct secasvar * sav,uint8_t * input_data,size_t input_data_len,struct newesp * esp_hdr,uint8_t * iv,size_t ivlen,uint8_t * output_data,size_t output_data_len)613 esp_chachapoly_decrypt_data(struct secasvar *sav, uint8_t *input_data,
614     size_t input_data_len, struct newesp *esp_hdr, uint8_t *iv, size_t ivlen,
615     uint8_t *output_data, size_t output_data_len)
616 {
617 	uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
618 	esp_chachapoly_ctx_t esp_ccp_ctx = NULL;
619 	int rc = 0; // return code of corecrypto operations
620 
621 	_Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
622 	_Static_assert(sizeof(*esp_hdr) == 8, "Bad size");
623 
624 	ESP_CHECK_ARG(sav);
625 	ESP_CHECK_ARG(input_data);
626 	ESP_CHECK_ARG(esp_hdr);
627 	ESP_CHECK_ARG(output_data);
628 
629 	VERIFY(input_data_len > 0);
630 	VERIFY(output_data_len >= input_data_len);
631 
632 	esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched_enc;
633 
634 	rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
635 	if (rc != 0) {
636 		esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
637 		    rc, ntohl(sav->spi));
638 		return rc;
639 	}
640 
641 	// RFC 7634 dictates that the 12 byte nonce must be
642 	// the 4 byte salt followed by the 8 byte IV.
643 	memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
644 	if (esp_ccp_ctx->ccp_implicit_iv) {
645 		VERIFY(iv == NULL);
646 		VERIFY(ivlen == 0);
647 		// IV is implicit (4 zero bytes followed by the ESP sequence number)
648 		memset(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
649 		memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
650 		    &esp_hdr->esp_seq, sizeof(esp_hdr->esp_seq));
651 		_Static_assert(4 + sizeof(esp_hdr->esp_seq) == ESP_CHACHAPOLY_IV_LEN, "Bad IV length");
652 	} else {
653 		// copy IV from packet
654 		if (ivlen != ESP_CHACHAPOLY_IV_LEN) {
655 			esp_log_err("ChaChaPoly Invalid ivlen %zu, SPI 0x%08x",
656 			    ivlen, ntohl(sav->spi));
657 			return EINVAL;
658 		}
659 		memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, iv, ESP_CHACHAPOLY_IV_LEN);
660 	}
661 
662 	rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
663 	if (rc != 0) {
664 		esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
665 		    rc, ntohl(sav->spi));
666 		cc_clear(sizeof(nonce), nonce);
667 		return rc;
668 	}
669 	cc_clear(sizeof(nonce), nonce);
670 
671 	// Set Additional Authentication Data (AAD)
672 	rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx, sizeof(*esp_hdr), (void *)esp_hdr);
673 	if (rc != 0) {
674 		esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
675 		    rc, ntohl(sav->spi));
676 		return rc;
677 	}
678 
679 	rc = chacha20poly1305_decrypt(&esp_ccp_ctx->ccp_ctx, input_data_len, input_data, output_data);
680 	if (rc != 0) {
681 		esp_log_err("chacha20poly1305_decrypt failed %d, SPI 0x%08x",
682 		    rc, ntohl(sav->spi));
683 		return rc;
684 	}
685 
686 	return 0;
687 }
688