1*19c3b8c2SApple OSS Distributions /*
2*19c3b8c2SApple OSS Distributions * Copyright (c) 2017, 2021 Apple Inc. All rights reserved.
3*19c3b8c2SApple OSS Distributions *
4*19c3b8c2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*19c3b8c2SApple OSS Distributions *
6*19c3b8c2SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*19c3b8c2SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*19c3b8c2SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*19c3b8c2SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*19c3b8c2SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*19c3b8c2SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*19c3b8c2SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*19c3b8c2SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*19c3b8c2SApple OSS Distributions *
15*19c3b8c2SApple OSS Distributions * Please obtain a copy of the License at
16*19c3b8c2SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*19c3b8c2SApple OSS Distributions *
18*19c3b8c2SApple OSS Distributions * The Original Code and all software distributed under the License are
19*19c3b8c2SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*19c3b8c2SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*19c3b8c2SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*19c3b8c2SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*19c3b8c2SApple OSS Distributions * Please see the License for the specific language governing rights and
24*19c3b8c2SApple OSS Distributions * limitations under the License.
25*19c3b8c2SApple OSS Distributions *
26*19c3b8c2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*19c3b8c2SApple OSS Distributions */
28*19c3b8c2SApple OSS Distributions
29*19c3b8c2SApple OSS Distributions #include <sys/param.h>
30*19c3b8c2SApple OSS Distributions #include <sys/systm.h>
31*19c3b8c2SApple OSS Distributions #include <sys/socket.h>
32*19c3b8c2SApple OSS Distributions #include <sys/queue.h>
33*19c3b8c2SApple OSS Distributions #include <sys/syslog.h>
34*19c3b8c2SApple OSS Distributions #include <sys/errno.h>
35*19c3b8c2SApple OSS Distributions #include <sys/mbuf.h>
36*19c3b8c2SApple OSS Distributions #include <sys/mcache.h>
37*19c3b8c2SApple OSS Distributions #include <mach/vm_param.h>
38*19c3b8c2SApple OSS Distributions #include <kern/locks.h>
39*19c3b8c2SApple OSS Distributions #include <string.h>
40*19c3b8c2SApple OSS Distributions #include <net/if.h>
41*19c3b8c2SApple OSS Distributions #include <net/route.h>
42*19c3b8c2SApple OSS Distributions #include <net/net_osdep.h>
43*19c3b8c2SApple OSS Distributions #include <netinet6/ipsec.h>
44*19c3b8c2SApple OSS Distributions #include <netinet6/esp.h>
45*19c3b8c2SApple OSS Distributions #include <netinet6/esp_chachapoly.h>
46*19c3b8c2SApple OSS Distributions #include <netkey/key.h>
47*19c3b8c2SApple OSS Distributions #include <netkey/keydb.h>
48*19c3b8c2SApple OSS Distributions #include <corecrypto/cc.h>
49*19c3b8c2SApple OSS Distributions #include <libkern/crypto/chacha20poly1305.h>
50*19c3b8c2SApple OSS Distributions
51*19c3b8c2SApple OSS Distributions #define ESP_CHACHAPOLY_SALT_LEN 4
52*19c3b8c2SApple OSS Distributions #define ESP_CHACHAPOLY_KEY_LEN 32
53*19c3b8c2SApple OSS Distributions #define ESP_CHACHAPOLY_NONCE_LEN 12
54*19c3b8c2SApple OSS Distributions
55*19c3b8c2SApple OSS Distributions // The minimum alignment is documented in KALLOC_LOG2_MINALIGN
56*19c3b8c2SApple OSS Distributions // which isn't accessible from here. Current minimum is 8.
57*19c3b8c2SApple OSS Distributions _Static_assert(_Alignof(chacha20poly1305_ctx) <= 8,
58*19c3b8c2SApple OSS Distributions "Alignment guarantee is broken");
59*19c3b8c2SApple OSS Distributions
60*19c3b8c2SApple OSS Distributions #if (((8 * (ESP_CHACHAPOLY_KEY_LEN + ESP_CHACHAPOLY_SALT_LEN)) != ESP_CHACHAPOLY_KEYBITS_WITH_SALT) || \
61*19c3b8c2SApple OSS Distributions (ESP_CHACHAPOLY_KEY_LEN != CCCHACHA20_KEY_NBYTES) || \
62*19c3b8c2SApple OSS Distributions (ESP_CHACHAPOLY_NONCE_LEN != CCCHACHA20POLY1305_NONCE_NBYTES))
63*19c3b8c2SApple OSS Distributions #error "Invalid sizes"
64*19c3b8c2SApple OSS Distributions #endif
65*19c3b8c2SApple OSS Distributions
66*19c3b8c2SApple OSS Distributions typedef struct _esp_chachapoly_ctx {
67*19c3b8c2SApple OSS Distributions chacha20poly1305_ctx ccp_ctx;
68*19c3b8c2SApple OSS Distributions uint8_t ccp_salt[ESP_CHACHAPOLY_SALT_LEN];
69*19c3b8c2SApple OSS Distributions bool ccp_implicit_iv;
70*19c3b8c2SApple OSS Distributions } esp_chachapoly_ctx_s, *esp_chachapoly_ctx_t;
71*19c3b8c2SApple OSS Distributions
72*19c3b8c2SApple OSS Distributions
73*19c3b8c2SApple OSS Distributions #define ESP_ASSERT(_cond, _format, ...) \
74*19c3b8c2SApple OSS Distributions do { \
75*19c3b8c2SApple OSS Distributions if (!(_cond)) { \
76*19c3b8c2SApple OSS Distributions panic("%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
77*19c3b8c2SApple OSS Distributions } \
78*19c3b8c2SApple OSS Distributions } while (0)
79*19c3b8c2SApple OSS Distributions
80*19c3b8c2SApple OSS Distributions #define ESP_CHECK_ARG(_arg) ESP_ASSERT(_arg != NULL, #_arg " is NULL")
81*19c3b8c2SApple OSS Distributions
82*19c3b8c2SApple OSS Distributions #define _esp_log(_level, _format, ...) \
83*19c3b8c2SApple OSS Distributions log(_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__)
84*19c3b8c2SApple OSS Distributions #define esp_log_err(_format, ...) _esp_log(LOG_ERR, _format, ##__VA_ARGS__)
85*19c3b8c2SApple OSS Distributions #define esp_log_default(_format, ...) _esp_log(LOG_NOTICE, _format, ##__VA_ARGS__)
86*19c3b8c2SApple OSS Distributions
87*19c3b8c2SApple OSS Distributions #define _esp_packet_log(_level, _format, ...) \
88*19c3b8c2SApple OSS Distributions ipseclog((_level, "%s:%d " _format, __FUNCTION__, __LINE__, ##__VA_ARGS__))
89*19c3b8c2SApple OSS Distributions #define esp_packet_log_err(_format, ...) _esp_packet_log(LOG_ERR, _format, ##__VA_ARGS__)
90*19c3b8c2SApple OSS Distributions
91*19c3b8c2SApple OSS Distributions int
esp_chachapoly_mature(struct secasvar * sav)92*19c3b8c2SApple OSS Distributions esp_chachapoly_mature(struct secasvar *sav)
93*19c3b8c2SApple OSS Distributions {
94*19c3b8c2SApple OSS Distributions const struct esp_algorithm *algo;
95*19c3b8c2SApple OSS Distributions
96*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(sav);
97*19c3b8c2SApple OSS Distributions
98*19c3b8c2SApple OSS Distributions if ((sav->flags & SADB_X_EXT_OLD) != 0) {
99*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_OLD, SPI 0x%08x",
100*19c3b8c2SApple OSS Distributions ntohl(sav->spi));
101*19c3b8c2SApple OSS Distributions return 1;
102*19c3b8c2SApple OSS Distributions }
103*19c3b8c2SApple OSS Distributions if ((sav->flags & SADB_X_EXT_DERIV) != 0) {
104*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly is incompatible with SADB_X_EXT_DERIV, SPI 0x%08x",
105*19c3b8c2SApple OSS Distributions ntohl(sav->spi));
106*19c3b8c2SApple OSS Distributions return 1;
107*19c3b8c2SApple OSS Distributions }
108*19c3b8c2SApple OSS Distributions
109*19c3b8c2SApple OSS Distributions if (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305) {
110*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly unsupported algorithm %d, SPI 0x%08x",
111*19c3b8c2SApple OSS Distributions sav->alg_enc, ntohl(sav->spi));
112*19c3b8c2SApple OSS Distributions return 1;
113*19c3b8c2SApple OSS Distributions }
114*19c3b8c2SApple OSS Distributions
115*19c3b8c2SApple OSS Distributions if (sav->key_enc == NULL) {
116*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly key is missing, SPI 0x%08x",
117*19c3b8c2SApple OSS Distributions ntohl(sav->spi));
118*19c3b8c2SApple OSS Distributions return 1;
119*19c3b8c2SApple OSS Distributions }
120*19c3b8c2SApple OSS Distributions
121*19c3b8c2SApple OSS Distributions algo = esp_algorithm_lookup(sav->alg_enc);
122*19c3b8c2SApple OSS Distributions if (algo == NULL) {
123*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly lookup failed for algorithm %d, SPI 0x%08x",
124*19c3b8c2SApple OSS Distributions sav->alg_enc, ntohl(sav->spi));
125*19c3b8c2SApple OSS Distributions return 1;
126*19c3b8c2SApple OSS Distributions }
127*19c3b8c2SApple OSS Distributions
128*19c3b8c2SApple OSS Distributions if (sav->key_enc->sadb_key_bits != ESP_CHACHAPOLY_KEYBITS_WITH_SALT) {
129*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly invalid key length %d bits, SPI 0x%08x",
130*19c3b8c2SApple OSS Distributions sav->key_enc->sadb_key_bits, ntohl(sav->spi));
131*19c3b8c2SApple OSS Distributions return 1;
132*19c3b8c2SApple OSS Distributions }
133*19c3b8c2SApple OSS Distributions
134*19c3b8c2SApple OSS Distributions esp_log_default("ChaChaPoly Mature SPI 0x%08x%s %s dir %u state %u mode %u",
135*19c3b8c2SApple OSS Distributions ntohl(sav->spi),
136*19c3b8c2SApple OSS Distributions (((sav->flags & SADB_X_EXT_IIV) != 0) ? " IIV" : ""),
137*19c3b8c2SApple OSS Distributions ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
138*19c3b8c2SApple OSS Distributions sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
139*19c3b8c2SApple OSS Distributions
140*19c3b8c2SApple OSS Distributions return 0;
141*19c3b8c2SApple OSS Distributions }
142*19c3b8c2SApple OSS Distributions
143*19c3b8c2SApple OSS Distributions size_t
esp_chachapoly_schedlen(__unused const struct esp_algorithm * algo)144*19c3b8c2SApple OSS Distributions esp_chachapoly_schedlen(__unused const struct esp_algorithm *algo)
145*19c3b8c2SApple OSS Distributions {
146*19c3b8c2SApple OSS Distributions return sizeof(esp_chachapoly_ctx_s);
147*19c3b8c2SApple OSS Distributions }
148*19c3b8c2SApple OSS Distributions
149*19c3b8c2SApple OSS Distributions int
esp_chachapoly_schedule(__unused const struct esp_algorithm * algo,struct secasvar * sav)150*19c3b8c2SApple OSS Distributions esp_chachapoly_schedule(__unused const struct esp_algorithm *algo,
151*19c3b8c2SApple OSS Distributions struct secasvar *sav)
152*19c3b8c2SApple OSS Distributions {
153*19c3b8c2SApple OSS Distributions esp_chachapoly_ctx_t esp_ccp_ctx;
154*19c3b8c2SApple OSS Distributions int rc = 0;
155*19c3b8c2SApple OSS Distributions
156*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(sav);
157*19c3b8c2SApple OSS Distributions if (_KEYLEN(sav->key_enc) != ESP_CHACHAPOLY_KEY_LEN + ESP_CHACHAPOLY_SALT_LEN) {
158*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid key len %u, SPI 0x%08x",
159*19c3b8c2SApple OSS Distributions _KEYLEN(sav->key_enc), ntohl(sav->spi));
160*19c3b8c2SApple OSS Distributions return EINVAL;
161*19c3b8c2SApple OSS Distributions }
162*19c3b8c2SApple OSS Distributions LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
163*19c3b8c2SApple OSS Distributions
164*19c3b8c2SApple OSS Distributions esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
165*19c3b8c2SApple OSS Distributions esp_ccp_ctx->ccp_implicit_iv = ((sav->flags & SADB_X_EXT_IIV) != 0);
166*19c3b8c2SApple OSS Distributions
167*19c3b8c2SApple OSS Distributions if (sav->ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
168*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
169*19c3b8c2SApple OSS Distributions sav->ivlen, ntohl(sav->spi));
170*19c3b8c2SApple OSS Distributions return EINVAL;
171*19c3b8c2SApple OSS Distributions }
172*19c3b8c2SApple OSS Distributions
173*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_init(&esp_ccp_ctx->ccp_ctx,
174*19c3b8c2SApple OSS Distributions (const uint8_t *)_KEYBUF(sav->key_enc));
175*19c3b8c2SApple OSS Distributions if (rc != 0) {
176*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_init failed %d, SPI 0x%08x",
177*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
178*19c3b8c2SApple OSS Distributions return rc;
179*19c3b8c2SApple OSS Distributions }
180*19c3b8c2SApple OSS Distributions
181*19c3b8c2SApple OSS Distributions memcpy(esp_ccp_ctx->ccp_salt,
182*19c3b8c2SApple OSS Distributions (const uint8_t *)_KEYBUF(sav->key_enc) + ESP_CHACHAPOLY_KEY_LEN,
183*19c3b8c2SApple OSS Distributions sizeof(esp_ccp_ctx->ccp_salt));
184*19c3b8c2SApple OSS Distributions
185*19c3b8c2SApple OSS Distributions
186*19c3b8c2SApple OSS Distributions esp_log_default("ChaChaPoly Schedule SPI 0x%08x%s %s dir %u state %u mode %u",
187*19c3b8c2SApple OSS Distributions ntohl(sav->spi), (esp_ccp_ctx->ccp_implicit_iv ? " IIV" : ""),
188*19c3b8c2SApple OSS Distributions ((sav->sah->ipsec_if != NULL) ? if_name(sav->sah->ipsec_if) : "NONE"),
189*19c3b8c2SApple OSS Distributions sav->sah->dir, sav->sah->state, sav->sah->saidx.mode);
190*19c3b8c2SApple OSS Distributions
191*19c3b8c2SApple OSS Distributions return 0;
192*19c3b8c2SApple OSS Distributions }
193*19c3b8c2SApple OSS Distributions
194*19c3b8c2SApple OSS Distributions int
esp_chachapoly_ivlen(const struct esp_algorithm * algo,struct secasvar * sav)195*19c3b8c2SApple OSS Distributions esp_chachapoly_ivlen(const struct esp_algorithm *algo,
196*19c3b8c2SApple OSS Distributions struct secasvar *sav)
197*19c3b8c2SApple OSS Distributions {
198*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(algo);
199*19c3b8c2SApple OSS Distributions
200*19c3b8c2SApple OSS Distributions if (sav != NULL &&
201*19c3b8c2SApple OSS Distributions ((sav->sched != NULL && ((esp_chachapoly_ctx_t)sav->sched)->ccp_implicit_iv) ||
202*19c3b8c2SApple OSS Distributions ((sav->flags & SADB_X_EXT_IIV) != 0))) {
203*19c3b8c2SApple OSS Distributions return 0;
204*19c3b8c2SApple OSS Distributions } else {
205*19c3b8c2SApple OSS Distributions return algo->ivlenval;
206*19c3b8c2SApple OSS Distributions }
207*19c3b8c2SApple OSS Distributions }
208*19c3b8c2SApple OSS Distributions
209*19c3b8c2SApple OSS Distributions int
esp_chachapoly_encrypt_finalize(struct secasvar * sav,unsigned char * tag,size_t tag_bytes)210*19c3b8c2SApple OSS Distributions esp_chachapoly_encrypt_finalize(struct secasvar *sav,
211*19c3b8c2SApple OSS Distributions unsigned char *tag,
212*19c3b8c2SApple OSS Distributions size_t tag_bytes)
213*19c3b8c2SApple OSS Distributions {
214*19c3b8c2SApple OSS Distributions esp_chachapoly_ctx_t esp_ccp_ctx;
215*19c3b8c2SApple OSS Distributions int rc = 0;
216*19c3b8c2SApple OSS Distributions
217*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(sav);
218*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(tag);
219*19c3b8c2SApple OSS Distributions if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
220*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
221*19c3b8c2SApple OSS Distributions tag_bytes, ntohl(sav->spi));
222*19c3b8c2SApple OSS Distributions return EINVAL;
223*19c3b8c2SApple OSS Distributions }
224*19c3b8c2SApple OSS Distributions
225*19c3b8c2SApple OSS Distributions esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
226*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_finalize(&esp_ccp_ctx->ccp_ctx, tag);
227*19c3b8c2SApple OSS Distributions if (rc != 0) {
228*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_finalize failed %d, SPI 0x%08x",
229*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
230*19c3b8c2SApple OSS Distributions return rc;
231*19c3b8c2SApple OSS Distributions }
232*19c3b8c2SApple OSS Distributions return 0;
233*19c3b8c2SApple OSS Distributions }
234*19c3b8c2SApple OSS Distributions
235*19c3b8c2SApple OSS Distributions int
esp_chachapoly_decrypt_finalize(struct secasvar * sav,unsigned char * tag,size_t tag_bytes)236*19c3b8c2SApple OSS Distributions esp_chachapoly_decrypt_finalize(struct secasvar *sav,
237*19c3b8c2SApple OSS Distributions unsigned char *tag,
238*19c3b8c2SApple OSS Distributions size_t tag_bytes)
239*19c3b8c2SApple OSS Distributions {
240*19c3b8c2SApple OSS Distributions esp_chachapoly_ctx_t esp_ccp_ctx;
241*19c3b8c2SApple OSS Distributions int rc = 0;
242*19c3b8c2SApple OSS Distributions
243*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(sav);
244*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(tag);
245*19c3b8c2SApple OSS Distributions if (tag_bytes != ESP_CHACHAPOLY_ICV_LEN) {
246*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid tag_bytes %zu, SPI 0x%08x",
247*19c3b8c2SApple OSS Distributions tag_bytes, ntohl(sav->spi));
248*19c3b8c2SApple OSS Distributions return EINVAL;
249*19c3b8c2SApple OSS Distributions }
250*19c3b8c2SApple OSS Distributions
251*19c3b8c2SApple OSS Distributions esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
252*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_verify(&esp_ccp_ctx->ccp_ctx, tag);
253*19c3b8c2SApple OSS Distributions if (rc != 0) {
254*19c3b8c2SApple OSS Distributions esp_packet_log_err("ChaChaPoly chacha20poly1305_verify failed %d, SPI 0x%08x",
255*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
256*19c3b8c2SApple OSS Distributions return rc;
257*19c3b8c2SApple OSS Distributions }
258*19c3b8c2SApple OSS Distributions return 0;
259*19c3b8c2SApple OSS Distributions }
260*19c3b8c2SApple OSS Distributions
261*19c3b8c2SApple OSS Distributions 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*19c3b8c2SApple OSS Distributions esp_chachapoly_encrypt(struct mbuf *m, // head of mbuf chain
263*19c3b8c2SApple OSS Distributions size_t off, // offset to ESP header
264*19c3b8c2SApple OSS Distributions __unused size_t plen,
265*19c3b8c2SApple OSS Distributions struct secasvar *sav,
266*19c3b8c2SApple OSS Distributions __unused const struct esp_algorithm *algo,
267*19c3b8c2SApple OSS Distributions int ivlen)
268*19c3b8c2SApple OSS Distributions {
269*19c3b8c2SApple OSS Distributions struct mbuf *s = m; // this mbuf
270*19c3b8c2SApple OSS Distributions int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
271*19c3b8c2SApple OSS Distributions int32_t sn = 0; // offset from the head of this mbuf (s) to the body
272*19c3b8c2SApple OSS Distributions uint8_t *sp; // buffer of a given encryption round
273*19c3b8c2SApple OSS Distributions size_t len; // length of a given encryption round
274*19c3b8c2SApple OSS Distributions const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
275*19c3b8c2SApple OSS Distributions const size_t bodyoff = ivoff + ivlen; // body offset
276*19c3b8c2SApple OSS Distributions int rc = 0; // return code of corecrypto operations
277*19c3b8c2SApple OSS Distributions struct newesp esp_hdr; // ESP header for AAD
278*19c3b8c2SApple OSS Distributions _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
279*19c3b8c2SApple OSS Distributions uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
280*19c3b8c2SApple OSS Distributions _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
281*19c3b8c2SApple OSS Distributions _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
282*19c3b8c2SApple OSS Distributions "Bad nonce length");
283*19c3b8c2SApple OSS Distributions esp_chachapoly_ctx_t esp_ccp_ctx;
284*19c3b8c2SApple OSS Distributions
285*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(m);
286*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(sav);
287*19c3b8c2SApple OSS Distributions
288*19c3b8c2SApple OSS Distributions esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
289*19c3b8c2SApple OSS Distributions
290*19c3b8c2SApple OSS Distributions if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
291*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
292*19c3b8c2SApple OSS Distributions ivlen, ntohl(sav->spi));
293*19c3b8c2SApple OSS Distributions m_freem(m);
294*19c3b8c2SApple OSS Distributions return EINVAL;
295*19c3b8c2SApple OSS Distributions }
296*19c3b8c2SApple OSS Distributions if (sav->ivlen != ivlen) {
297*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
298*19c3b8c2SApple OSS Distributions sav->ivlen, ntohl(sav->spi));
299*19c3b8c2SApple OSS Distributions m_freem(m);
300*19c3b8c2SApple OSS Distributions return EINVAL;
301*19c3b8c2SApple OSS Distributions }
302*19c3b8c2SApple OSS Distributions
303*19c3b8c2SApple OSS Distributions // check if total packet length is enough to contain ESP + IV
304*19c3b8c2SApple OSS Distributions if (m->m_pkthdr.len < bodyoff) {
305*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Packet too short %d < %zu, SPI 0x%08x",
306*19c3b8c2SApple OSS Distributions m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
307*19c3b8c2SApple OSS Distributions m_freem(m);
308*19c3b8c2SApple OSS Distributions return EINVAL;
309*19c3b8c2SApple OSS Distributions }
310*19c3b8c2SApple OSS Distributions
311*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
312*19c3b8c2SApple OSS Distributions if (rc != 0) {
313*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
314*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
315*19c3b8c2SApple OSS Distributions m_freem(m);
316*19c3b8c2SApple OSS Distributions return rc;
317*19c3b8c2SApple OSS Distributions }
318*19c3b8c2SApple OSS Distributions
319*19c3b8c2SApple OSS Distributions // esp_hdr is used for nonce and AAD
320*19c3b8c2SApple OSS Distributions m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
321*19c3b8c2SApple OSS Distributions
322*19c3b8c2SApple OSS Distributions // RFC 7634 dictates that the 12 byte nonce must be
323*19c3b8c2SApple OSS Distributions // the 4 byte salt followed by the 8 byte IV.
324*19c3b8c2SApple OSS Distributions memset(nonce, 0, ESP_CHACHAPOLY_NONCE_LEN);
325*19c3b8c2SApple OSS Distributions memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
326*19c3b8c2SApple OSS Distributions if (!esp_ccp_ctx->ccp_implicit_iv) {
327*19c3b8c2SApple OSS Distributions // Increment IV and save back new value
328*19c3b8c2SApple OSS Distributions uint64_t iv = 0;
329*19c3b8c2SApple OSS Distributions _Static_assert(ESP_CHACHAPOLY_IV_LEN == sizeof(iv), "Bad IV length");
330*19c3b8c2SApple OSS Distributions memcpy(&iv, sav->iv, sizeof(iv));
331*19c3b8c2SApple OSS Distributions iv++;
332*19c3b8c2SApple OSS Distributions memcpy(sav->iv, &iv, sizeof(iv));
333*19c3b8c2SApple OSS Distributions
334*19c3b8c2SApple OSS Distributions // Copy the new IV into the nonce and the packet
335*19c3b8c2SApple OSS Distributions memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, &iv, sizeof(iv));
336*19c3b8c2SApple OSS Distributions m_copyback(m, ivoff, ivlen, sav->iv);
337*19c3b8c2SApple OSS Distributions } else {
338*19c3b8c2SApple OSS Distributions // Use the sequence number in the ESP header to form the
339*19c3b8c2SApple OSS Distributions // nonce according to RFC 8750. The first 4 bytes are the
340*19c3b8c2SApple OSS Distributions // salt value, the next 4 bytes are zeroes, and the final
341*19c3b8c2SApple OSS Distributions // 4 bytes are the ESP sequence number.
342*19c3b8c2SApple OSS Distributions _Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN,
343*19c3b8c2SApple OSS Distributions "Bad IV length");
344*19c3b8c2SApple OSS Distributions memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
345*19c3b8c2SApple OSS Distributions &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
346*19c3b8c2SApple OSS Distributions }
347*19c3b8c2SApple OSS Distributions
348*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
349*19c3b8c2SApple OSS Distributions cc_clear(sizeof(nonce), nonce);
350*19c3b8c2SApple OSS Distributions if (rc != 0) {
351*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
352*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
353*19c3b8c2SApple OSS Distributions m_freem(m);
354*19c3b8c2SApple OSS Distributions return rc;
355*19c3b8c2SApple OSS Distributions }
356*19c3b8c2SApple OSS Distributions
357*19c3b8c2SApple OSS Distributions // Set Additional Authentication Data (AAD)
358*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
359*19c3b8c2SApple OSS Distributions sizeof(esp_hdr),
360*19c3b8c2SApple OSS Distributions (void *)&esp_hdr);
361*19c3b8c2SApple OSS Distributions if (rc != 0) {
362*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
363*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
364*19c3b8c2SApple OSS Distributions m_freem(m);
365*19c3b8c2SApple OSS Distributions return rc;
366*19c3b8c2SApple OSS Distributions }
367*19c3b8c2SApple OSS Distributions
368*19c3b8c2SApple OSS Distributions // skip headers/IV
369*19c3b8c2SApple OSS Distributions while (s != NULL && soff < bodyoff) {
370*19c3b8c2SApple OSS Distributions if (soff + s->m_len > bodyoff) {
371*19c3b8c2SApple OSS Distributions sn = bodyoff - soff;
372*19c3b8c2SApple OSS Distributions break;
373*19c3b8c2SApple OSS Distributions }
374*19c3b8c2SApple OSS Distributions
375*19c3b8c2SApple OSS Distributions soff += s->m_len;
376*19c3b8c2SApple OSS Distributions s = s->m_next;
377*19c3b8c2SApple OSS Distributions }
378*19c3b8c2SApple OSS Distributions
379*19c3b8c2SApple OSS Distributions while (s != NULL && soff < m->m_pkthdr.len) {
380*19c3b8c2SApple OSS Distributions len = (size_t)(s->m_len - sn);
381*19c3b8c2SApple OSS Distributions if (len == 0) {
382*19c3b8c2SApple OSS Distributions // skip empty mbufs
383*19c3b8c2SApple OSS Distributions continue;
384*19c3b8c2SApple OSS Distributions }
385*19c3b8c2SApple OSS Distributions sp = mtod(s, uint8_t *) + sn;
386*19c3b8c2SApple OSS Distributions
387*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_encrypt(&esp_ccp_ctx->ccp_ctx,
388*19c3b8c2SApple OSS Distributions len, sp, sp);
389*19c3b8c2SApple OSS Distributions if (rc != 0) {
390*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_encrypt failed %d, SPI 0x%08x",
391*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
392*19c3b8c2SApple OSS Distributions m_freem(m);
393*19c3b8c2SApple OSS Distributions return rc;
394*19c3b8c2SApple OSS Distributions }
395*19c3b8c2SApple OSS Distributions
396*19c3b8c2SApple OSS Distributions sn = 0;
397*19c3b8c2SApple OSS Distributions soff += s->m_len;
398*19c3b8c2SApple OSS Distributions s = s->m_next;
399*19c3b8c2SApple OSS Distributions }
400*19c3b8c2SApple OSS Distributions if (s == NULL && soff != m->m_pkthdr.len) {
401*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly not enough mbufs %d %d, SPI 0x%08x",
402*19c3b8c2SApple OSS Distributions soff, m->m_pkthdr.len, ntohl(sav->spi));
403*19c3b8c2SApple OSS Distributions m_freem(m);
404*19c3b8c2SApple OSS Distributions return EFBIG;
405*19c3b8c2SApple OSS Distributions }
406*19c3b8c2SApple OSS Distributions return 0;
407*19c3b8c2SApple OSS Distributions }
408*19c3b8c2SApple OSS Distributions
409*19c3b8c2SApple OSS Distributions int
esp_chachapoly_decrypt(struct mbuf * m,size_t off,struct secasvar * sav,__unused const struct esp_algorithm * algo,int ivlen)410*19c3b8c2SApple OSS Distributions esp_chachapoly_decrypt(struct mbuf *m, // head of mbuf chain
411*19c3b8c2SApple OSS Distributions size_t off, // offset to ESP header
412*19c3b8c2SApple OSS Distributions struct secasvar *sav,
413*19c3b8c2SApple OSS Distributions __unused const struct esp_algorithm *algo,
414*19c3b8c2SApple OSS Distributions int ivlen)
415*19c3b8c2SApple OSS Distributions {
416*19c3b8c2SApple OSS Distributions struct mbuf *s = m; // this mbuf
417*19c3b8c2SApple OSS Distributions int32_t soff = 0; // offset from the head of mbuf chain (m) to head of this mbuf (s)
418*19c3b8c2SApple OSS Distributions int32_t sn = 0; // offset from the head of this mbuf (s) to the body
419*19c3b8c2SApple OSS Distributions uint8_t *sp; // buffer of a given encryption round
420*19c3b8c2SApple OSS Distributions size_t len; // length of a given encryption round
421*19c3b8c2SApple OSS Distributions const int32_t ivoff = (int32_t)off + (int32_t)sizeof(struct newesp); // IV offset
422*19c3b8c2SApple OSS Distributions const int32_t bodyoff = ivoff + ivlen; // body offset
423*19c3b8c2SApple OSS Distributions int rc = 0; // return code of corecrypto operations
424*19c3b8c2SApple OSS Distributions struct newesp esp_hdr; // ESP header for AAD
425*19c3b8c2SApple OSS Distributions _Static_assert(sizeof(esp_hdr) == 8, "Bad size");
426*19c3b8c2SApple OSS Distributions uint32_t nonce[ESP_CHACHAPOLY_NONCE_LEN / 4]; // ensure 32bit alignment
427*19c3b8c2SApple OSS Distributions _Static_assert(sizeof(nonce) == ESP_CHACHAPOLY_NONCE_LEN, "Bad nonce length");
428*19c3b8c2SApple OSS Distributions esp_chachapoly_ctx_t esp_ccp_ctx;
429*19c3b8c2SApple OSS Distributions
430*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(m);
431*19c3b8c2SApple OSS Distributions ESP_CHECK_ARG(sav);
432*19c3b8c2SApple OSS Distributions
433*19c3b8c2SApple OSS Distributions esp_ccp_ctx = (esp_chachapoly_ctx_t)sav->sched;
434*19c3b8c2SApple OSS Distributions
435*19c3b8c2SApple OSS Distributions if (ivlen != (esp_ccp_ctx->ccp_implicit_iv ? 0 : ESP_CHACHAPOLY_IV_LEN)) {
436*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid ivlen %u, SPI 0x%08x",
437*19c3b8c2SApple OSS Distributions ivlen, ntohl(sav->spi));
438*19c3b8c2SApple OSS Distributions m_freem(m);
439*19c3b8c2SApple OSS Distributions return EINVAL;
440*19c3b8c2SApple OSS Distributions }
441*19c3b8c2SApple OSS Distributions if (sav->ivlen != ivlen) {
442*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly Invalid sav->ivlen %u, SPI 0x%08x",
443*19c3b8c2SApple OSS Distributions sav->ivlen, ntohl(sav->spi));
444*19c3b8c2SApple OSS Distributions m_freem(m);
445*19c3b8c2SApple OSS Distributions return EINVAL;
446*19c3b8c2SApple OSS Distributions }
447*19c3b8c2SApple OSS Distributions
448*19c3b8c2SApple OSS Distributions // check if total packet length is enough to contain ESP + IV
449*19c3b8c2SApple OSS Distributions if (m->m_pkthdr.len < bodyoff) {
450*19c3b8c2SApple OSS Distributions esp_packet_log_err("ChaChaPoly Packet too short %d < %u, SPI 0x%08x",
451*19c3b8c2SApple OSS Distributions m->m_pkthdr.len, bodyoff, ntohl(sav->spi));
452*19c3b8c2SApple OSS Distributions m_freem(m);
453*19c3b8c2SApple OSS Distributions return EINVAL;
454*19c3b8c2SApple OSS Distributions }
455*19c3b8c2SApple OSS Distributions
456*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_reset(&esp_ccp_ctx->ccp_ctx);
457*19c3b8c2SApple OSS Distributions if (rc != 0) {
458*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_reset failed %d, SPI 0x%08x",
459*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
460*19c3b8c2SApple OSS Distributions m_freem(m);
461*19c3b8c2SApple OSS Distributions return rc;
462*19c3b8c2SApple OSS Distributions }
463*19c3b8c2SApple OSS Distributions
464*19c3b8c2SApple OSS Distributions m_copydata(m, (int)off, sizeof(esp_hdr), (void *)&esp_hdr);
465*19c3b8c2SApple OSS Distributions
466*19c3b8c2SApple OSS Distributions // RFC 7634 dictates that the 12 byte nonce must be
467*19c3b8c2SApple OSS Distributions // the 4 byte salt followed by the 8 byte IV.
468*19c3b8c2SApple OSS Distributions memcpy(nonce, esp_ccp_ctx->ccp_salt, ESP_CHACHAPOLY_SALT_LEN);
469*19c3b8c2SApple OSS Distributions if (esp_ccp_ctx->ccp_implicit_iv) {
470*19c3b8c2SApple OSS Distributions // IV is implicit (4 zero bytes followed by the ESP sequence number)
471*19c3b8c2SApple OSS Distributions memset(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN, 0, 4);
472*19c3b8c2SApple OSS Distributions memcpy(((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN + 4,
473*19c3b8c2SApple OSS Distributions &esp_hdr.esp_seq, sizeof(esp_hdr.esp_seq));
474*19c3b8c2SApple OSS Distributions _Static_assert(4 + sizeof(esp_hdr.esp_seq) == ESP_CHACHAPOLY_IV_LEN, "Bad IV length");
475*19c3b8c2SApple OSS Distributions } else {
476*19c3b8c2SApple OSS Distributions // copy IV from packet
477*19c3b8c2SApple OSS Distributions m_copydata(m, ivoff, ESP_CHACHAPOLY_IV_LEN, ((uint8_t *)nonce) + ESP_CHACHAPOLY_SALT_LEN);
478*19c3b8c2SApple OSS Distributions }
479*19c3b8c2SApple OSS Distributions _Static_assert(ESP_CHACHAPOLY_SALT_LEN + ESP_CHACHAPOLY_IV_LEN == sizeof(nonce),
480*19c3b8c2SApple OSS Distributions "Bad nonce length");
481*19c3b8c2SApple OSS Distributions
482*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_setnonce(&esp_ccp_ctx->ccp_ctx, (uint8_t *)nonce);
483*19c3b8c2SApple OSS Distributions if (rc != 0) {
484*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_setnonce failed %d, SPI 0x%08x",
485*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
486*19c3b8c2SApple OSS Distributions m_freem(m);
487*19c3b8c2SApple OSS Distributions return rc;
488*19c3b8c2SApple OSS Distributions }
489*19c3b8c2SApple OSS Distributions cc_clear(sizeof(nonce), nonce);
490*19c3b8c2SApple OSS Distributions
491*19c3b8c2SApple OSS Distributions // Set Additional Authentication Data (AAD)
492*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_aad(&esp_ccp_ctx->ccp_ctx,
493*19c3b8c2SApple OSS Distributions sizeof(esp_hdr),
494*19c3b8c2SApple OSS Distributions (void *)&esp_hdr);
495*19c3b8c2SApple OSS Distributions if (rc != 0) {
496*19c3b8c2SApple OSS Distributions esp_log_err("ChaChaPoly chacha20poly1305_aad failed %d, SPI 0x%08x",
497*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
498*19c3b8c2SApple OSS Distributions m_freem(m);
499*19c3b8c2SApple OSS Distributions return rc;
500*19c3b8c2SApple OSS Distributions }
501*19c3b8c2SApple OSS Distributions
502*19c3b8c2SApple OSS Distributions // skip headers/IV
503*19c3b8c2SApple OSS Distributions while (s != NULL && soff < bodyoff) {
504*19c3b8c2SApple OSS Distributions if (soff + s->m_len > bodyoff) {
505*19c3b8c2SApple OSS Distributions sn = bodyoff - soff;
506*19c3b8c2SApple OSS Distributions break;
507*19c3b8c2SApple OSS Distributions }
508*19c3b8c2SApple OSS Distributions
509*19c3b8c2SApple OSS Distributions soff += s->m_len;
510*19c3b8c2SApple OSS Distributions s = s->m_next;
511*19c3b8c2SApple OSS Distributions }
512*19c3b8c2SApple OSS Distributions
513*19c3b8c2SApple OSS Distributions while (s != NULL && soff < m->m_pkthdr.len) {
514*19c3b8c2SApple OSS Distributions len = (size_t)(s->m_len - sn);
515*19c3b8c2SApple OSS Distributions if (len == 0) {
516*19c3b8c2SApple OSS Distributions // skip empty mbufs
517*19c3b8c2SApple OSS Distributions continue;
518*19c3b8c2SApple OSS Distributions }
519*19c3b8c2SApple OSS Distributions sp = mtod(s, uint8_t *) + sn;
520*19c3b8c2SApple OSS Distributions
521*19c3b8c2SApple OSS Distributions rc = chacha20poly1305_decrypt(&esp_ccp_ctx->ccp_ctx,
522*19c3b8c2SApple OSS Distributions len, sp, sp);
523*19c3b8c2SApple OSS Distributions if (rc != 0) {
524*19c3b8c2SApple OSS Distributions esp_packet_log_err("chacha20poly1305_decrypt failed %d, SPI 0x%08x",
525*19c3b8c2SApple OSS Distributions rc, ntohl(sav->spi));
526*19c3b8c2SApple OSS Distributions m_freem(m);
527*19c3b8c2SApple OSS Distributions return rc;
528*19c3b8c2SApple OSS Distributions }
529*19c3b8c2SApple OSS Distributions
530*19c3b8c2SApple OSS Distributions sn = 0;
531*19c3b8c2SApple OSS Distributions soff += s->m_len;
532*19c3b8c2SApple OSS Distributions s = s->m_next;
533*19c3b8c2SApple OSS Distributions }
534*19c3b8c2SApple OSS Distributions if (s == NULL && soff != m->m_pkthdr.len) {
535*19c3b8c2SApple OSS Distributions esp_packet_log_err("not enough mbufs %d %d, SPI 0x%08x",
536*19c3b8c2SApple OSS Distributions soff, m->m_pkthdr.len, ntohl(sav->spi));
537*19c3b8c2SApple OSS Distributions m_freem(m);
538*19c3b8c2SApple OSS Distributions return EFBIG;
539*19c3b8c2SApple OSS Distributions }
540*19c3b8c2SApple OSS Distributions return 0;
541*19c3b8c2SApple OSS Distributions }
542