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 |
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 |
125 | esp_chachapoly_schedlen(__unused const struct esp_algorithm *algo) |
126 | { |
127 | return sizeof(esp_chachapoly_ctx_s); |
128 | } |
129 | |
130 | int |
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(ctx: &esp_ccp_ctx->ccp_ctx, |
155 | key: (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(dst: esp_ccp_ctx->ccp_salt, |
163 | src: (const uint8_t *)_KEYBUF(sav->key_enc) + ESP_CHACHAPOLY_KEY_LEN, |
164 | n: 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 |
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 |
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(ctx: &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 |
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(ctx: &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 |
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(ctx: &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(s: nonce, c: 0, ESP_CHACHAPOLY_NONCE_LEN); |
307 | memcpy(dst: nonce, src: 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(dst: &iv, src: sav->iv, n: sizeof(iv)); |
313 | iv++; |
314 | memcpy(dst: sav->iv, src: &iv, n: sizeof(iv)); |
315 | |
316 | // Copy the new IV into the nonce and the packet |
317 | memcpy(dst: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, src: &iv, n: 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(dst: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4, |
327 | src: &esp_hdr.esp_seq, n: sizeof(esp_hdr.esp_seq)); |
328 | } |
329 | |
330 | rc = chacha20poly1305_setnonce(ctx: &esp_ccp_ctx->ccp_ctx, nonce: (uint8_t *)nonce); |
331 | cc_clear(len: sizeof(nonce), dst: 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(ctx: &esp_ccp_ctx->ccp_ctx, |
341 | nbytes: sizeof(esp_hdr), |
342 | aad: (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(ctx: &esp_ccp_ctx->ccp_ctx, |
367 | nbytes: len, ptext: sp, ctext: 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 |
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(ctx: &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(dst: nonce, src: 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(s: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, c: 0, n: 4); |
452 | memcpy(dst: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4, |
453 | src: &esp_hdr.esp_seq, n: 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(ctx: &esp_ccp_ctx->ccp_ctx, nonce: (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(len: sizeof(nonce), dst: nonce); |
470 | |
471 | // Set Additional Authentication Data (AAD) |
472 | rc = chacha20poly1305_aad(ctx: &esp_ccp_ctx->ccp_ctx, |
473 | nbytes: sizeof(esp_hdr), |
474 | aad: (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(ctx: &esp_ccp_ctx->ccp_ctx, |
499 | nbytes: len, ctext: sp, ptext: 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 |
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(ctx: &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(s: nonce, c: 0, ESP_CHACHAPOLY_NONCE_LEN); |
556 | memcpy(dst: nonce, src: 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(len: sizeof(nonce), dst: 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(dst: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, src: &iv, n: sizeof(iv)); |
573 | memcpy(dst: out_iv, src: &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(dst: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4, |
583 | src: &esp_hdr->esp_seq, n: sizeof(esp_hdr->esp_seq)); |
584 | } |
585 | |
586 | rc = chacha20poly1305_setnonce(ctx: &esp_ccp_ctx->ccp_ctx, nonce: (uint8_t *)nonce); |
587 | cc_clear(len: sizeof(nonce), dst: 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(ctx: &esp_ccp_ctx->ccp_ctx, nbytes: sizeof(*esp_hdr), aad: (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(ctx: &esp_ccp_ctx->ccp_ctx, nbytes: input_data_len, ptext: input_data, ctext: 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 |
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(ctx: &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(dst: nonce, src: 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(s: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, c: 0, n: 4); |
649 | memcpy(dst: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4, |
650 | src: &esp_hdr->esp_seq, n: 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(dst: ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, src: iv, ESP_CHACHAPOLY_IV_LEN); |
660 | } |
661 | |
662 | rc = chacha20poly1305_setnonce(ctx: &esp_ccp_ctx->ccp_ctx, nonce: (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(len: sizeof(nonce), dst: nonce); |
667 | return rc; |
668 | } |
669 | cc_clear(len: sizeof(nonce), dst: nonce); |
670 | |
671 | // Set Additional Authentication Data (AAD) |
672 | rc = chacha20poly1305_aad(ctx: &esp_ccp_ctx->ccp_ctx, nbytes: sizeof(*esp_hdr), aad: (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(ctx: &esp_ccp_ctx->ccp_ctx, nbytes: input_data_len, ctext: input_data, ptext: 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 | |