xref: /xnu-8792.61.2/bsd/netinet6/esp_chachapoly.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1 /*
2  * Copyright (c) 2017, 2021 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 
73 #define ESP_ASSERT(_cond, _format, ...)                                                                                 \
74 	do {                                                                                                                                            \
75 	        if (!(_cond)) {                                                                                                                 \
76 	                panic("%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__);         \
77 	        }                                                                                                                                               \
78 	} while (0)
79 
80 #define ESP_CHECK_ARG(_arg) ESP_ASSERT(_arg != NULL, #_arg " is NULL")
81 
82 #define _esp_log(_level, _format, ...)  \
83 	log(_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
84 #define esp_log_err(_format, ...) _esp_log(LOG_ERR, _format, ##__VA_ARGS__)
85 #define esp_log_default(_format, ...) _esp_log(LOG_NOTICE, _format, ##__VA_ARGS__)
86 
87 #define _esp_packet_log(_level, _format, ...)  \
88 	ipseclog((_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__))
89 #define esp_packet_log_err(_format, ...) _esp_packet_log(LOG_ERR, _format, ##__VA_ARGS__)
90 
91 int
esp_chachapoly_mature(struct secasvar * sav)92 esp_chachapoly_mature(struct secasvar *sav)
93 {
94 	const struct esp_algorithm *algo;
95 
96 	ESP_CHECK_ARG(sav);
97 
98 	if ((sav->flags & SADB_X_EXT_OLD) != 0) {
99 		esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_OLD, SPI 0x%08x",
100 		    ntohl(sav->spi));
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, SPI 0x%08x",
105 		    ntohl(sav->spi));
106 		return 1;
107 	}
108 
109 	if (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305) {
110 		esp_log_err("ChaChaPoly unsupported algorithm %d, SPI 0x%08x",
111 		    sav->alg_enc, ntohl(sav->spi));
112 		return 1;
113 	}
114 
115 	if (sav->key_enc == NULL) {
116 		esp_log_err("ChaChaPoly key is missing, SPI 0x%08x",
117 		    ntohl(sav->spi));
118 		return 1;
119 	}
120 
121 	algo = esp_algorithm_lookup(sav->alg_enc);
122 	if (algo == NULL) {
123 		esp_log_err("ChaChaPoly lookup failed for algorithm %d, SPI 0x%08x",
124 		    sav->alg_enc, ntohl(sav->spi));
125 		return 1;
126 	}
127 
128 	if (sav->key_enc->sadb_key_bits != ESP_CHACHAPOLY_KEYBITS_WITH_SALT) {
129 		esp_log_err("ChaChaPoly invalid key length %d bits, SPI 0x%08x",
130 		    sav->key_enc->sadb_key_bits, ntohl(sav->spi));
131 		return 1;
132 	}
133 
134 	esp_log_default("ChaChaPoly Mature SPI 0x%08x%s %s dir %u state %u mode %u",
135 	    ntohl(sav->spi),
136 	    (((sav->flags & SADB_X_EXT_IIV) != 0) ? " IIV" : ""),
137 	    ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
138 	    sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
139 
140 	return 0;
141 }
142 
143 size_t
esp_chachapoly_schedlen(__unused const struct esp_algorithm * algo)144 esp_chachapoly_schedlen(__unused const struct esp_algorithm *algo)
145 {
146 	return sizeof(esp_chachapoly_ctx_s);
147 }
148 
149 int
esp_chachapoly_schedule(__unused const struct esp_algorithm * algo,struct secasvar * sav)150 esp_chachapoly_schedule(__unused const struct esp_algorithm *algo,
151     struct secasvar *sav)
152 {
153 	esp_chachapoly_ctx_t esp_ccp_ctx;
154 	int rc = 0;
155 
156 	ESP_CHECK_ARG(sav);
157 	if (_KEYLEN(sav->key_enc) != ESP_CHACHAPOLY_KEY_LEN + ESP_CHACHAPOLY_SALT_LEN) {
158 		esp_log_err("ChaChaPoly Invalid key len %u, SPI 0x%08x",
159 		    _KEYLEN(sav->key_enc), ntohl(sav->spi));
160 		return EINVAL;
161 	}
162 	LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
163 
164 	esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
165 	esp_ccp_ctx->ccp_implicit_iv = ((sav->flags & SADB_X_EXT_IIV) != 0);
166 
167 	if (sav->ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
168 		esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
169 		    sav->ivlen, ntohl(sav->spi));
170 		return EINVAL;
171 	}
172 
173 	rc = chacha20poly1305_init(&esp_ccp_ctx->ccp_ctx,
174 	    (const uint8_t *)_KEYBUF(sav->key_enc));
175 	if (rc != 0) {
176 		esp_log_err("ChaChaPoly chacha20poly1305_init failed %d, SPI 0x%08x",
177 		    rc, ntohl(sav->spi));
178 		return rc;
179 	}
180 
181 	memcpy(esp_ccp_ctx->ccp_salt,
182 	    (const uint8_t *)_KEYBUF(sav->key_enc) + ESP_CHACHAPOLY_KEY_LEN,
183 	    sizeof(esp_ccp_ctx->ccp_salt));
184 
185 
186 	esp_log_default("ChaChaPoly Schedule SPI 0x%08x%s %s dir %u state %u mode %u",
187 	    ntohl(sav->spi), (esp_ccp_ctx->ccp_implicit_iv ? " IIV" : ""),
188 	    ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
189 	    sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
190 
191 	return 0;
192 }
193 
194 int
esp_chachapoly_ivlen(const struct esp_algorithm * algo,struct secasvar * sav)195 esp_chachapoly_ivlen(const struct esp_algorithm *algo,
196     struct secasvar *sav)
197 {
198 	ESP_CHECK_ARG(algo);
199 
200 	if (sav != NULL &&
201 	    ((sav->sched != NULL && ((esp_chachapoly_ctx_t)sav->sched)->ccp_implicit_iv) ||
202 	    ((sav->flags & SADB_X_EXT_IIV) != 0))) {
203 		return 0;
204 	} else {
205 		return algo->ivlenval;
206 	}
207 }
208 
209 int
esp_chachapoly_encrypt_finalize(struct secasvar * sav,unsigned char * tag,size_t tag_bytes)210 esp_chachapoly_encrypt_finalize(struct secasvar *sav,
211     unsigned char *tag,
212     size_t tag_bytes)
213 {
214 	esp_chachapoly_ctx_t esp_ccp_ctx;
215 	int rc = 0;
216 
217 	ESP_CHECK_ARG(sav);
218 	ESP_CHECK_ARG(tag);
219 	if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
220 		esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
221 		    tag_bytes, ntohl(sav->spi));
222 		return EINVAL;
223 	}
224 
225 	esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
226 	rc = chacha20poly1305_finalize(&esp_ccp_ctx->ccp_ctx, tag);
227 	if (rc != 0) {
228 		esp_log_err("ChaChaPoly chacha20poly1305_finalize failed %d, SPI 0x%08x",
229 		    rc, ntohl(sav->spi));
230 		return rc;
231 	}
232 	return 0;
233 }
234 
235 int
esp_chachapoly_decrypt_finalize(struct secasvar * sav,unsigned char * tag,size_t tag_bytes)236 esp_chachapoly_decrypt_finalize(struct secasvar *sav,
237     unsigned char *tag,
238     size_t tag_bytes)
239 {
240 	esp_chachapoly_ctx_t esp_ccp_ctx;
241 	int rc = 0;
242 
243 	ESP_CHECK_ARG(sav);
244 	ESP_CHECK_ARG(tag);
245 	if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
246 		esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
247 		    tag_bytes, ntohl(sav->spi));
248 		return EINVAL;
249 	}
250 
251 	esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
252 	rc = chacha20poly1305_verify(&esp_ccp_ctx->ccp_ctx, tag);
253 	if (rc != 0) {
254 		esp_packet_log_err("ChaChaPoly chacha20poly1305_verify failed %d, SPI 0x%08x",
255 		    rc, ntohl(sav->spi));
256 		return rc;
257 	}
258 	return 0;
259 }
260 
261 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)262 esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
263     size_t off,                                        // offset to ESP header
264     __unused size_t plen,
265     struct secasvar *sav,
266     __unused const struct esp_algorithm *algo,
267     int ivlen)
268 {
269 	struct mbuf *s = m; // this mbuf
270 	int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
271 	int32_t sn = 0; // offset from the head of this mbuf (s) to the body
272 	uint8_t *sp; // buffer of a given encryption round
273 	size_t len; // length of a given encryption round
274 	const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
275 	const size_t bodyoff = ivoff + ivlen; // body offset
276 	int rc = 0; // return code of corecrypto operations
277 	struct newesp esp_hdr; // ESP header for AAD
278 	_Static_assert(sizeof(esp_hdr) == 8, "Bad size");
279 	uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
280 	_Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
281 	_Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
282 	    "Bad nonce length");
283 	esp_chachapoly_ctx_t esp_ccp_ctx;
284 
285 	ESP_CHECK_ARG(m);
286 	ESP_CHECK_ARG(sav);
287 
288 	esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
289 
290 	if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
291 		esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
292 		    ivlen, ntohl(sav->spi));
293 		m_freem(m);
294 		return EINVAL;
295 	}
296 	if (sav->ivlen != ivlen) {
297 		esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
298 		    sav->ivlen, ntohl(sav->spi));
299 		m_freem(m);
300 		return EINVAL;
301 	}
302 
303 	// check if total packet length is enough to contain ESP + IV
304 	if (m->m_pkthdr.len < bodyoff) {
305 		esp_log_err("ChaChaPoly Packet too short %d < %zu, SPI 0x%08x",
306 		    m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
307 		m_freem(m);
308 		return EINVAL;
309 	}
310 
311 	rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
312 	if (rc != 0) {
313 		esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
314 		    rc, ntohl(sav->spi));
315 		m_freem(m);
316 		return rc;
317 	}
318 
319 	// esp_hdr is used for nonce and AAD
320 	m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
321 
322 	// RFC 7634 dictates that the 12 byte nonce must be
323 	// the 4 byte salt followed by the 8 byte IV.
324 	memset(nonce, 0, ESP_CHACHAPOLY_NONCE_LEN);
325 	memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
326 	if (!esp_ccp_ctx->ccp_implicit_iv) {
327 		// Increment IV and save back new value
328 		uint64_t iv = 0;
329 		_Static_assert(ESP_CHACHAPOLY_IV_LEN == sizeof(iv), "Bad IV length");
330 		memcpy(&iv, sav->iv, sizeof(iv));
331 		iv++;
332 		memcpy(sav->iv, &iv, sizeof(iv));
333 
334 		// Copy the new IV into the nonce and the packet
335 		memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, &iv, sizeof(iv));
336 		m_copyback(m, ivoff, ivlen, sav->iv);
337 	} else {
338 		// Use the sequence number in the ESP header to form the
339 		// nonce according to RFC 8750. The first 4 bytes are the
340 		// salt value, the next 4 bytes are zeroes, and the final
341 		// 4 bytes are the ESP sequence number.
342 		_Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN,
343 		    "Bad IV length");
344 		memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
345 		    &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
346 	}
347 
348 	rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
349 	cc_clear(sizeof(nonce), nonce);
350 	if (rc != 0) {
351 		esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
352 		    rc, ntohl(sav->spi));
353 		m_freem(m);
354 		return rc;
355 	}
356 
357 	// Set Additional Authentication Data (AAD)
358 	rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
359 	    sizeof(esp_hdr),
360 	    (void *)&esp_hdr);
361 	if (rc != 0) {
362 		esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
363 		    rc, ntohl(sav->spi));
364 		m_freem(m);
365 		return rc;
366 	}
367 
368 	// skip headers/IV
369 	while (s != NULL && soff < bodyoff) {
370 		if (soff + s->m_len > bodyoff) {
371 			sn = bodyoff - soff;
372 			break;
373 		}
374 
375 		soff += s->m_len;
376 		s = s->m_next;
377 	}
378 
379 	while (s != NULL && soff < m->m_pkthdr.len) {
380 		len = (size_t)(s->m_len - sn);
381 		if (len == 0) {
382 			// skip empty mbufs
383 			continue;
384 		}
385 		sp = mtod(s, uint8_t *) + sn;
386 
387 		rc = chacha20poly1305_encrypt(&esp_ccp_ctx->ccp_ctx,
388 		    len, sp, sp);
389 		if (rc != 0) {
390 			esp_log_err("ChaChaPoly chacha20poly1305_encrypt failed %d, SPI 0x%08x",
391 			    rc, ntohl(sav->spi));
392 			m_freem(m);
393 			return rc;
394 		}
395 
396 		sn = 0;
397 		soff += s->m_len;
398 		s = s->m_next;
399 	}
400 	if (s == NULL && soff != m->m_pkthdr.len) {
401 		esp_log_err("ChaChaPoly not enough mbufs %d %d, SPI 0x%08x",
402 		    soff, m->m_pkthdr.len, ntohl(sav->spi));
403 		m_freem(m);
404 		return EFBIG;
405 	}
406 	return 0;
407 }
408 
409 int
esp_chachapoly_decrypt(struct mbuf * m,size_t off,struct secasvar * sav,__unused const struct esp_algorithm * algo,int ivlen)410 esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
411     size_t off,                                        // offset to ESP header
412     struct secasvar *sav,
413     __unused const struct esp_algorithm *algo,
414     int ivlen)
415 {
416 	struct mbuf *s = m; // this mbuf
417 	int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
418 	int32_t sn = 0; // offset from the head of this mbuf (s) to the body
419 	uint8_t *sp; // buffer of a given encryption round
420 	size_t len; // length of a given encryption round
421 	const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
422 	const int32_t bodyoff = ivoff + ivlen; // body offset
423 	int rc = 0; // return code of corecrypto operations
424 	struct newesp esp_hdr; // ESP header for AAD
425 	_Static_assert(sizeof(esp_hdr) == 8, "Bad size");
426 	uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
427 	_Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
428 	esp_chachapoly_ctx_t esp_ccp_ctx;
429 
430 	ESP_CHECK_ARG(m);
431 	ESP_CHECK_ARG(sav);
432 
433 	esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
434 
435 	if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
436 		esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
437 		    ivlen, ntohl(sav->spi));
438 		m_freem(m);
439 		return EINVAL;
440 	}
441 	if (sav->ivlen != ivlen) {
442 		esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
443 		    sav->ivlen, ntohl(sav->spi));
444 		m_freem(m);
445 		return EINVAL;
446 	}
447 
448 	// check if total packet length is enough to contain ESP + IV
449 	if (m->m_pkthdr.len < bodyoff) {
450 		esp_packet_log_err("ChaChaPoly Packet too short %d < %u, SPI 0x%08x",
451 		    m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
452 		m_freem(m);
453 		return EINVAL;
454 	}
455 
456 	rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
457 	if (rc != 0) {
458 		esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
459 		    rc, ntohl(sav->spi));
460 		m_freem(m);
461 		return rc;
462 	}
463 
464 	m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
465 
466 	// RFC 7634 dictates that the 12 byte nonce must be
467 	// the 4 byte salt followed by the 8 byte IV.
468 	memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
469 	if (esp_ccp_ctx->ccp_implicit_iv) {
470 		// IV is implicit (4 zero bytes followed by the ESP sequence number)
471 		memset(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
472 		memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
473 		    &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
474 		_Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN, "Bad IV length");
475 	} else {
476 		// copy IV from packet
477 		m_copydata(m, ivoff, ESP_CHACHAPOLY_IV_LEN, ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN);
478 	}
479 	_Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
480 	    "Bad nonce length");
481 
482 	rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
483 	if (rc != 0) {
484 		esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
485 		    rc, ntohl(sav->spi));
486 		m_freem(m);
487 		return rc;
488 	}
489 	cc_clear(sizeof(nonce), nonce);
490 
491 	// Set Additional Authentication Data (AAD)
492 	rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
493 	    sizeof(esp_hdr),
494 	    (void *)&esp_hdr);
495 	if (rc != 0) {
496 		esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
497 		    rc, ntohl(sav->spi));
498 		m_freem(m);
499 		return rc;
500 	}
501 
502 	// skip headers/IV
503 	while (s != NULL && soff < bodyoff) {
504 		if (soff + s->m_len > bodyoff) {
505 			sn = bodyoff - soff;
506 			break;
507 		}
508 
509 		soff += s->m_len;
510 		s = s->m_next;
511 	}
512 
513 	while (s != NULL && soff < m->m_pkthdr.len) {
514 		len = (size_t)(s->m_len - sn);
515 		if (len == 0) {
516 			// skip empty mbufs
517 			continue;
518 		}
519 		sp = mtod(s, uint8_t *) + sn;
520 
521 		rc = chacha20poly1305_decrypt(&esp_ccp_ctx->ccp_ctx,
522 		    len, sp, sp);
523 		if (rc != 0) {
524 			esp_packet_log_err("chacha20poly1305_decrypt failed %d, SPI 0x%08x",
525 			    rc, ntohl(sav->spi));
526 			m_freem(m);
527 			return rc;
528 		}
529 
530 		sn = 0;
531 		soff += s->m_len;
532 		s = s->m_next;
533 	}
534 	if (s == NULL && soff != m->m_pkthdr.len) {
535 		esp_packet_log_err("not enough mbufs %d %d, SPI 0x%08x",
536 		    soff, m->m_pkthdr.len, ntohl(sav->spi));
537 		m_freem(m);
538 		return EFBIG;
539 	}
540 	return 0;
541 }
542