2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
36 #include <sys/mcache.h>
37 #include <mach/vm_param.h>
38 #include <kern/locks.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>
51 #define ESP_CHACHAPOLY_SALT_LEN 4
52 #define ESP_CHACHAPOLY_KEY_LEN 32
53 #define ESP_CHACHAPOLY_NONCE_LEN 12
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");
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"
66 extern lck_mtx_t
*sadb_mutex
;
68 typedef struct _esp_chachapoly_ctx
{
69 chacha20poly1305_ctx ccp_ctx
;
70 uint8_t ccp_salt
[ESP_CHACHAPOLY_SALT_LEN
];
72 } esp_chachapoly_ctx_s
, *esp_chachapoly_ctx_t
;
75 #define ESP_ASSERT(_cond, _format, ...) \
78 panic("%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
82 #define ESP_CHECK_ARG(_arg) ESP_ASSERT(_arg != NULL, #_arg " is NULL")
84 #define _esp_log(_level, _format, ...) \
85 log(_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
86 #define esp_log_err(_format, ...) _esp_log(LOG_ERR, _format, ##__VA_ARGS__)
87 #define esp_log_default(_format, ...) _esp_log(LOG_NOTICE, _format, ##__VA_ARGS__)
89 #define _esp_packet_log(_level, _format, ...) \
90 ipseclog((_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__))
91 #define esp_packet_log_err(_format, ...) _esp_packet_log(LOG_ERR, _format, ##__VA_ARGS__)
94 esp_chachapoly_mature(struct secasvar
*sav
)
96 const struct esp_algorithm
*algo
;
100 if ((sav
->flags
& SADB_X_EXT_OLD
) != 0) {
101 esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_OLD, SPI 0x%08x",
105 if ((sav
->flags
& SADB_X_EXT_DERIV
) != 0) {
106 esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_DERIV, SPI 0x%08x",
111 if (sav
->alg_enc
!= SADB_X_EALG_CHACHA20POLY1305
) {
112 esp_log_err("ChaChaPoly unsupported algorithm %d, SPI 0x%08x",
113 sav
->alg_enc
, ntohl(sav
->spi
));
117 if (sav
->key_enc
== NULL
) {
118 esp_log_err("ChaChaPoly key is missing, SPI 0x%08x",
123 algo
= esp_algorithm_lookup(sav
->alg_enc
);
125 esp_log_err("ChaChaPoly lookup failed for algorithm %d, SPI 0x%08x",
126 sav
->alg_enc
, ntohl(sav
->spi
));
130 if (sav
->key_enc
->sadb_key_bits
!= ESP_CHACHAPOLY_KEYBITS_WITH_SALT
) {
131 esp_log_err("ChaChaPoly invalid key length %d bits, SPI 0x%08x",
132 sav
->key_enc
->sadb_key_bits
, ntohl(sav
->spi
));
136 esp_log_default("ChaChaPoly Mature SPI 0x%08x%s %s dir %u state %u mode %u",
138 (((sav
->flags
& SADB_X_EXT_IIV
) != 0) ? " IIV" : ""),
139 ((sav
->sah
->ipsec_if
!= NULL
) ? if_name(sav
->sah
->ipsec_if
) : "NONE"),
140 sav
->sah
->dir
, sav
->sah
->state
, sav
->sah
->saidx
.mode
);
146 esp_chachapoly_schedlen(__unused
const struct esp_algorithm
*algo
)
148 return sizeof(esp_chachapoly_ctx_s
);
152 esp_chachapoly_schedule(__unused
const struct esp_algorithm
*algo
,
153 struct secasvar
*sav
)
155 esp_chachapoly_ctx_t esp_ccp_ctx
;
159 if (_KEYLEN(sav
->key_enc
) != ESP_CHACHAPOLY_KEY_LEN
+ ESP_CHACHAPOLY_SALT_LEN
) {
160 esp_log_err("ChaChaPoly Invalid key len %u, SPI 0x%08x",
161 _KEYLEN(sav
->key_enc
), ntohl(sav
->spi
));
164 LCK_MTX_ASSERT(sadb_mutex
, LCK_MTX_ASSERT_OWNED
);
166 esp_ccp_ctx
= (esp_chachapoly_ctx_t
)sav
->sched
;
167 esp_ccp_ctx
->ccp_implicit_iv
= ((sav
->flags
& SADB_X_EXT_IIV
) != 0);
169 if (sav
->ivlen
!= (esp_ccp_ctx
->ccp_implicit_iv
? 0 : ESP_CHACHAPOLY_IV_LEN
)) {
170 esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
171 sav
->ivlen
, ntohl(sav
->spi
));
175 rc
= chacha20poly1305_init(&esp_ccp_ctx
->ccp_ctx
,
176 (const uint8_t *)_KEYBUF(sav
->key_enc
));
178 esp_log_err("ChaChaPoly chacha20poly1305_init failed %d, SPI 0x%08x",
179 rc
, ntohl(sav
->spi
));
183 memcpy(esp_ccp_ctx
->ccp_salt
,
184 (const uint8_t *)_KEYBUF(sav
->key_enc
) + ESP_CHACHAPOLY_KEY_LEN
,
185 sizeof(esp_ccp_ctx
->ccp_salt
));
188 esp_log_default("ChaChaPoly Schedule SPI 0x%08x%s %s dir %u state %u mode %u",
189 ntohl(sav
->spi
), (esp_ccp_ctx
->ccp_implicit_iv
? " IIV" : ""),
190 ((sav
->sah
->ipsec_if
!= NULL
) ? if_name(sav
->sah
->ipsec_if
) : "NONE"),
191 sav
->sah
->dir
, sav
->sah
->state
, sav
->sah
->saidx
.mode
);
197 esp_chachapoly_ivlen(const struct esp_algorithm
*algo
,
198 struct secasvar
*sav
)
203 ((sav
->sched
!= NULL
&& ((esp_chachapoly_ctx_t
)sav
->sched
)->ccp_implicit_iv
) ||
204 ((sav
->flags
& SADB_X_EXT_IIV
) != 0))) {
207 return algo
->ivlenval
;
212 esp_chachapoly_encrypt_finalize(struct secasvar
*sav
,
216 esp_chachapoly_ctx_t esp_ccp_ctx
;
221 if (tag_bytes
!= ESP_CHACHAPOLY_ICV_LEN
) {
222 esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
223 tag_bytes
, ntohl(sav
->spi
));
227 esp_ccp_ctx
= (esp_chachapoly_ctx_t
)sav
->sched
;
228 rc
= chacha20poly1305_finalize(&esp_ccp_ctx
->ccp_ctx
, tag
);
230 esp_log_err("ChaChaPoly chacha20poly1305_finalize failed %d, SPI 0x%08x",
231 rc
, ntohl(sav
->spi
));
238 esp_chachapoly_decrypt_finalize(struct secasvar
*sav
,
242 esp_chachapoly_ctx_t esp_ccp_ctx
;
247 if (tag_bytes
!= ESP_CHACHAPOLY_ICV_LEN
) {
248 esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
249 tag_bytes
, ntohl(sav
->spi
));
253 esp_ccp_ctx
= (esp_chachapoly_ctx_t
)sav
->sched
;
254 rc
= chacha20poly1305_verify(&esp_ccp_ctx
->ccp_ctx
, tag
);
256 esp_packet_log_err("ChaChaPoly chacha20poly1305_verify failed %d, SPI 0x%08x",
257 rc
, ntohl(sav
->spi
));
264 esp_chachapoly_encrypt(struct mbuf
*m
, // head of mbuf chain
265 size_t off
, // offset to ESP header
266 __unused
size_t plen
,
267 struct secasvar
*sav
,
268 __unused
const struct esp_algorithm
*algo
,
271 struct mbuf
*s
= m
; // this mbuf
272 int32_t soff
= 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
273 int32_t sn
= 0; // offset from the head of this mbuf (s) to the body
274 uint8_t *sp
; // buffer of a given encryption round
275 size_t len
; // length of a given encryption round
276 const int32_t ivoff
= (int32_t)off
+ (int32_t)sizeof(struct newesp
); // IV offset
277 const size_t bodyoff
= ivoff
+ ivlen
; // body offset
278 int rc
= 0; // return code of corecrypto operations
279 struct newesp esp_hdr
; // ESP header for AAD
280 _Static_assert(sizeof(esp_hdr
) == 8, "Bad size");
281 uint32_t nonce
[ESP_CHACHAPOLY_NONCE_LEN
/ 4]; // ensure 32bit alignment
282 _Static_assert(sizeof(nonce
) == ESP_CHACHAPOLY_NONCE_LEN
, "Bad nonce length");
283 esp_chachapoly_ctx_t esp_ccp_ctx
;
288 esp_ccp_ctx
= (esp_chachapoly_ctx_t
)sav
->sched
;
290 if (ivlen
!= (esp_ccp_ctx
->ccp_implicit_iv
? 0 : ESP_CHACHAPOLY_IV_LEN
)) {
292 esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
293 ivlen
, ntohl(sav
->spi
));
296 if (sav
->ivlen
!= ivlen
) {
298 esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
299 sav
->ivlen
, ntohl(sav
->spi
));
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
));
311 rc
= chacha20poly1305_reset(&esp_ccp_ctx
->ccp_ctx
);
314 esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
315 rc
, ntohl(sav
->spi
));
319 // esp_hdr is used for nonce and AAD
320 m_copydata(m
, (int)off
, sizeof(esp_hdr
), (void *)&esp_hdr
);
322 // RFC 7634 dictates that the 12 byte nonce must be
323 // the 4 byte salt followed by the 8 byte IV.
324 // The IV MUST be non-repeating but does not need to be unpredictable,
325 // so we use 4 bytes of 0 followed by the 4 byte ESP sequence number.
326 // this allows us to use implicit IV -- draft-ietf-ipsecme-implicit-iv
327 // Note that sav->seq is zero here so we must get esp_seq from esp_hdr
328 memcpy(nonce
, esp_ccp_ctx
->ccp_salt
, ESP_CHACHAPOLY_SALT_LEN
);
329 memset(((uint8_t *)nonce
) + ESP_CHACHAPOLY_SALT_LEN
, 0, 4);
330 memcpy(((uint8_t *)nonce
) + ESP_CHACHAPOLY_SALT_LEN
+ 4,
331 &esp_hdr
.esp_seq
, sizeof(esp_hdr
.esp_seq
));
333 _Static_assert(4 + sizeof(esp_hdr
.esp_seq
) == ESP_CHACHAPOLY_IV_LEN
,
335 _Static_assert(ESP_CHACHAPOLY_SALT_LEN
+ ESP_CHACHAPOLY_IV_LEN
== sizeof(nonce
),
338 rc
= chacha20poly1305_setnonce(&esp_ccp_ctx
->ccp_ctx
, (uint8_t *)nonce
);
341 esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
342 rc
, ntohl(sav
->spi
));
346 if (!esp_ccp_ctx
->ccp_implicit_iv
) {
347 memcpy(sav
->iv
, ((uint8_t *)nonce
) + ESP_CHACHAPOLY_SALT_LEN
, ESP_CHACHAPOLY_IV_LEN
);
348 m_copyback(m
, ivoff
, ivlen
, sav
->iv
);
350 cc_clear(sizeof(nonce
), nonce
);
352 // Set Additional Authentication Data (AAD)
353 rc
= chacha20poly1305_aad(&esp_ccp_ctx
->ccp_ctx
,
358 esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
359 rc
, ntohl(sav
->spi
));
364 while (s
!= NULL
&& soff
< bodyoff
) {
365 if (soff
+ s
->m_len
> bodyoff
) {
374 while (s
!= NULL
&& soff
< m
->m_pkthdr
.len
) {
375 len
= (size_t)(s
->m_len
- sn
);
380 sp
= mtod(s
, uint8_t *) + sn
;
382 rc
= chacha20poly1305_encrypt(&esp_ccp_ctx
->ccp_ctx
,
386 esp_log_err("ChaChaPoly chacha20poly1305_encrypt failed %d, SPI 0x%08x",
387 rc
, ntohl(sav
->spi
));
395 if (s
== NULL
&& soff
!= m
->m_pkthdr
.len
) {
397 esp_log_err("ChaChaPoly not enough mbufs %d %d, SPI 0x%08x",
398 soff
, m
->m_pkthdr
.len
, ntohl(sav
->spi
));
405 esp_chachapoly_decrypt(struct mbuf
*m
, // head of mbuf chain
406 size_t off
, // offset to ESP header
407 struct secasvar
*sav
,
408 __unused
const struct esp_algorithm
*algo
,
411 struct mbuf
*s
= m
; // this mbuf
412 int32_t soff
= 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
413 int32_t sn
= 0; // offset from the head of this mbuf (s) to the body
414 uint8_t *sp
; // buffer of a given encryption round
415 size_t len
; // length of a given encryption round
416 const int32_t ivoff
= (int32_t)off
+ (int32_t)sizeof(struct newesp
); // IV offset
417 const int32_t bodyoff
= ivoff
+ ivlen
; // body offset
418 int rc
= 0; // return code of corecrypto operations
419 struct newesp esp_hdr
; // ESP header for AAD
420 _Static_assert(sizeof(esp_hdr
) == 8, "Bad size");
421 uint32_t nonce
[ESP_CHACHAPOLY_NONCE_LEN
/ 4]; // ensure 32bit alignment
422 _Static_assert(sizeof(nonce
) == ESP_CHACHAPOLY_NONCE_LEN
, "Bad nonce length");
423 esp_chachapoly_ctx_t esp_ccp_ctx
;
428 esp_ccp_ctx
= (esp_chachapoly_ctx_t
)sav
->sched
;
430 if (ivlen
!= (esp_ccp_ctx
->ccp_implicit_iv
? 0 : ESP_CHACHAPOLY_IV_LEN
)) {
432 esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
433 ivlen
, ntohl(sav
->spi
));
436 if (sav
->ivlen
!= ivlen
) {
438 esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
439 sav
->ivlen
, ntohl(sav
->spi
));
443 // check if total packet length is enough to contain ESP + IV
444 if (m
->m_pkthdr
.len
< bodyoff
) {
445 esp_packet_log_err("ChaChaPoly Packet too short %d < %u, SPI 0x%08x",
446 m
->m_pkthdr
.len
, bodyoff
, ntohl(sav
->spi
));
451 rc
= chacha20poly1305_reset(&esp_ccp_ctx
->ccp_ctx
);
454 esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
455 rc
, ntohl(sav
->spi
));
459 m_copydata(m
, (int)off
, sizeof(esp_hdr
), (void *)&esp_hdr
);
461 // RFC 7634 dictates that the 12 byte nonce must be
462 // the 4 byte salt followed by the 8 byte IV.
463 memcpy(nonce
, esp_ccp_ctx
->ccp_salt
, ESP_CHACHAPOLY_SALT_LEN
);
464 if (esp_ccp_ctx
->ccp_implicit_iv
) {
465 // IV is implicit (4 zero bytes followed by the ESP sequence number)
466 memset(((uint8_t *)nonce
) + ESP_CHACHAPOLY_SALT_LEN
, 0, 4);
467 memcpy(((uint8_t *)nonce
) + ESP_CHACHAPOLY_SALT_LEN
+ 4,
468 &esp_hdr
.esp_seq
, sizeof(esp_hdr
.esp_seq
));
469 _Static_assert(4 + sizeof(esp_hdr
.esp_seq
) == ESP_CHACHAPOLY_IV_LEN
, "Bad IV length");
471 // copy IV from packet
472 m_copydata(m
, ivoff
, ESP_CHACHAPOLY_IV_LEN
, ((uint8_t *)nonce
) + ESP_CHACHAPOLY_SALT_LEN
);
474 _Static_assert(ESP_CHACHAPOLY_SALT_LEN
+ ESP_CHACHAPOLY_IV_LEN
== sizeof(nonce
),
477 rc
= chacha20poly1305_setnonce(&esp_ccp_ctx
->ccp_ctx
, (uint8_t *)nonce
);
480 esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
481 rc
, ntohl(sav
->spi
));
484 cc_clear(sizeof(nonce
), nonce
);
486 // Set Additional Authentication Data (AAD)
487 rc
= chacha20poly1305_aad(&esp_ccp_ctx
->ccp_ctx
,
492 esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
493 rc
, ntohl(sav
->spi
));
498 while (s
!= NULL
&& soff
< bodyoff
) {
499 if (soff
+ s
->m_len
> bodyoff
) {
508 while (s
!= NULL
&& soff
< m
->m_pkthdr
.len
) {
509 len
= (size_t)(s
->m_len
- sn
);
514 sp
= mtod(s
, uint8_t *) + sn
;
516 rc
= chacha20poly1305_decrypt(&esp_ccp_ctx
->ccp_ctx
,
520 esp_packet_log_err("chacha20poly1305_decrypt failed %d, SPI 0x%08x",
521 rc
, ntohl(sav
->spi
));
529 if (s
== NULL
&& soff
!= m
->m_pkthdr
.len
) {
531 esp_packet_log_err("not enough mbufs %d %d, SPI 0x%08x",
532 soff
, m
->m_pkthdr
.len
, ntohl(sav
->spi
));