]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/netinet6/esp_core.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_core.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2008-2019 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/* $FreeBSD: src/sys/netinet6/esp_core.c,v 1.1.2.4 2002/03/26 10:12:29 ume Exp $ */
30/* $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $ */
31
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61#define _IP_VHL
62
63#include <sys/param.h>
64#include <sys/systm.h>
65#include <sys/malloc.h>
66#include <sys/mbuf.h>
67#include <sys/domain.h>
68#include <sys/protosw.h>
69#include <sys/socket.h>
70#include <sys/errno.h>
71#include <sys/time.h>
72#include <sys/kernel.h>
73#include <sys/syslog.h>
74
75#include <kern/locks.h>
76
77#include <net/if.h>
78#include <net/route.h>
79
80#include <netinet/in.h>
81#include <netinet/in_var.h>
82#include <netinet/ip6.h>
83#include <netinet6/ip6_var.h>
84#include <netinet/icmp6.h>
85
86#include <netinet6/ipsec.h>
87#include <netinet6/ipsec6.h>
88#include <netinet6/ah.h>
89#include <netinet6/ah6.h>
90#include <netinet6/esp.h>
91#include <netinet6/esp6.h>
92#include <netinet6/esp_rijndael.h>
93#include <netinet6/esp_chachapoly.h>
94#include <net/pfkeyv2.h>
95#include <netkey/keydb.h>
96#include <netkey/key.h>
97#include <libkern/crypto/des.h>
98
99#include <net/net_osdep.h>
100
101#include <sys/kdebug.h>
102#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1)
103#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3)
104#define DBG_FNC_ESPAUTH NETDBG_CODE(DBG_NETIPSEC, (8 << 8))
105#define MAX_SBUF_LEN 2000
106
107extern lck_mtx_t *sadb_mutex;
108os_log_t esp_mpkl_log_object = NULL;
109
110static int esp_null_mature(struct secasvar *);
111static int esp_null_decrypt(struct mbuf *, size_t,
112 struct secasvar *, const struct esp_algorithm *, int);
113static int esp_null_encrypt(struct mbuf *, size_t, size_t,
114 struct secasvar *, const struct esp_algorithm *, int);
115static int esp_descbc_mature(struct secasvar *);
116static int esp_descbc_ivlen(const struct esp_algorithm *,
117 struct secasvar *);
118static int esp_des_schedule(const struct esp_algorithm *,
119 struct secasvar *);
120static size_t esp_des_schedlen(const struct esp_algorithm *);
121static int esp_des_blockdecrypt(const struct esp_algorithm *,
122 struct secasvar *, u_int8_t *, u_int8_t *);
123static int esp_des_blockencrypt(const struct esp_algorithm *,
124 struct secasvar *, u_int8_t *, u_int8_t *);
125static int esp_cbc_mature(struct secasvar *);
126static int esp_3des_schedule(const struct esp_algorithm *,
127 struct secasvar *);
128static size_t esp_3des_schedlen(const struct esp_algorithm *);
129static int esp_3des_blockdecrypt(const struct esp_algorithm *,
130 struct secasvar *, u_int8_t *, u_int8_t *);
131static int esp_3des_blockencrypt(const struct esp_algorithm *,
132 struct secasvar *, u_int8_t *, u_int8_t *);
133static int esp_common_ivlen(const struct esp_algorithm *,
134 struct secasvar *);
135static int esp_cbc_decrypt(struct mbuf *, size_t,
136 struct secasvar *, const struct esp_algorithm *, int);
137static int esp_cbc_encrypt(struct mbuf *, size_t, size_t,
138 struct secasvar *, const struct esp_algorithm *, int);
139static int esp_gcm_mature(struct secasvar *);
140
141#define MAXIVLEN 16
142
143#define ESP_AESGCM_KEYLEN128 160 // 16-bytes key + 4 bytes salt
144#define ESP_AESGCM_KEYLEN192 224 // 24-bytes key + 4 bytes salt
145#define ESP_AESGCM_KEYLEN256 288 // 32-bytes key + 4 bytes salt
146
147static const struct esp_algorithm des_cbc = {
148 .padbound = 8,
149 .ivlenval = -1,
150 .mature = esp_descbc_mature,
151 .keymin = 64,
152 .keymax = 64,
153 .schedlen = esp_des_schedlen,
154 .name = "des-cbc",
155 .ivlen = esp_descbc_ivlen,
156 .decrypt = esp_cbc_decrypt,
157 .encrypt = esp_cbc_encrypt,
158 .schedule = esp_des_schedule,
159 .blockdecrypt = esp_des_blockdecrypt,
160 .blockencrypt = esp_des_blockencrypt,
161 .icvlen = 0,
162 .finalizedecrypt = NULL,
163 .finalizeencrypt = NULL
164};
165
166static const struct esp_algorithm des3_cbc = {
167 .padbound = 8,
168 .ivlenval = 8,
169 .mature = esp_cbc_mature,
170 .keymin = 192,
171 .keymax = 192,
172 .schedlen = esp_3des_schedlen,
173 .name = "3des-cbc",
174 .ivlen = esp_common_ivlen,
175 .decrypt = esp_cbc_decrypt,
176 .encrypt = esp_cbc_encrypt,
177 .schedule = esp_3des_schedule,
178 .blockdecrypt = esp_3des_blockdecrypt,
179 .blockencrypt = esp_3des_blockencrypt,
180 .icvlen = 0,
181 .finalizedecrypt = NULL,
182 .finalizeencrypt = NULL
183};
184
185static const struct esp_algorithm null_esp = {
186 .padbound = 1,
187 .ivlenval = 0,
188 .mature = esp_null_mature,
189 .keymin = 0,
190 .keymax = 2048,
191 .schedlen = NULL,
192 .name = "null",
193 .ivlen = esp_common_ivlen,
194 .decrypt = esp_null_decrypt,
195 .encrypt = esp_null_encrypt,
196 .schedule = NULL,
197 .blockdecrypt = NULL,
198 .blockencrypt = NULL,
199 .icvlen = 0,
200 .finalizedecrypt = NULL,
201 .finalizeencrypt = NULL
202};
203
204static const struct esp_algorithm aes_cbc = {
205 .padbound = 16,
206 .ivlenval = 16,
207 .mature = esp_cbc_mature,
208 .keymin = 128,
209 .keymax = 256,
210 .schedlen = esp_aes_schedlen,
211 .name = "aes-cbc",
212 .ivlen = esp_common_ivlen,
213 .decrypt = esp_cbc_decrypt_aes,
214 .encrypt = esp_cbc_encrypt_aes,
215 .schedule = esp_aes_schedule,
216 .blockdecrypt = NULL,
217 .blockencrypt = NULL,
218 .icvlen = 0,
219 .finalizedecrypt = NULL,
220 .finalizeencrypt = NULL
221};
222
223static const struct esp_algorithm aes_gcm = {
224 .padbound = 4,
225 .ivlenval = 8,
226 .mature = esp_gcm_mature,
227 .keymin = ESP_AESGCM_KEYLEN128,
228 .keymax = ESP_AESGCM_KEYLEN256,
229 .schedlen = esp_gcm_schedlen,
230 .name = "aes-gcm",
231 .ivlen = esp_common_ivlen,
232 .decrypt = esp_gcm_decrypt_aes,
233 .encrypt = esp_gcm_encrypt_aes,
234 .schedule = esp_gcm_schedule,
235 .blockdecrypt = NULL,
236 .blockencrypt = NULL,
237 .icvlen = 16,
238 .finalizedecrypt = esp_gcm_decrypt_finalize,
239 .finalizeencrypt = esp_gcm_encrypt_finalize
240};
241
242static const struct esp_algorithm chacha_poly = {
243 .padbound = ESP_CHACHAPOLY_PAD_BOUND,
244 .ivlenval = ESP_CHACHAPOLY_IV_LEN,
245 .mature = esp_chachapoly_mature,
246 .keymin = ESP_CHACHAPOLY_KEYBITS_WITH_SALT,
247 .keymax = ESP_CHACHAPOLY_KEYBITS_WITH_SALT,
248 .schedlen = esp_chachapoly_schedlen,
249 .name = "chacha-poly",
250 .ivlen = esp_chachapoly_ivlen,
251 .decrypt = esp_chachapoly_decrypt,
252 .encrypt = esp_chachapoly_encrypt,
253 .schedule = esp_chachapoly_schedule,
254 .blockdecrypt = NULL,
255 .blockencrypt = NULL,
256 .icvlen = ESP_CHACHAPOLY_ICV_LEN,
257 .finalizedecrypt = esp_chachapoly_decrypt_finalize,
258 .finalizeencrypt = esp_chachapoly_encrypt_finalize
259};
260
261static const struct esp_algorithm *esp_algorithms[] = {
262 &des_cbc,
263 &des3_cbc,
264 &null_esp,
265 &aes_cbc,
266 &aes_gcm,
267 &chacha_poly,
268};
269
270const struct esp_algorithm *
271esp_algorithm_lookup(int idx)
272{
273 switch (idx) {
274 case SADB_EALG_DESCBC:
275 return &des_cbc;
276 case SADB_EALG_3DESCBC:
277 return &des3_cbc;
278 case SADB_EALG_NULL:
279 return &null_esp;
280 case SADB_X_EALG_RIJNDAELCBC:
281 return &aes_cbc;
282 case SADB_X_EALG_AES_GCM:
283 return &aes_gcm;
284 case SADB_X_EALG_CHACHA20POLY1305:
285 return &chacha_poly;
286 default:
287 return NULL;
288 }
289}
290
291int
292esp_max_ivlen(void)
293{
294 int idx;
295 int ivlen;
296
297 ivlen = 0;
298 for (idx = 0; idx < sizeof(esp_algorithms) / sizeof(esp_algorithms[0]);
299 idx++) {
300 if (esp_algorithms[idx]->ivlenval > ivlen) {
301 ivlen = esp_algorithms[idx]->ivlenval;
302 }
303 }
304
305 return ivlen;
306}
307
308int
309esp_schedule(const struct esp_algorithm *algo, struct secasvar *sav)
310{
311 int error;
312
313 /* check for key length */
314 if (_KEYBITS(sav->key_enc) < algo->keymin ||
315 _KEYBITS(sav->key_enc) > algo->keymax) {
316 ipseclog((LOG_ERR,
317 "esp_schedule %s: unsupported key length %d: "
318 "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc),
319 algo->keymin, algo->keymax));
320 return EINVAL;
321 }
322
323 lck_mtx_lock(sadb_mutex);
324 /* already allocated */
325 if (sav->sched && sav->schedlen != 0) {
326 lck_mtx_unlock(sadb_mutex);
327 return 0;
328 }
329
330 /* prevent disallowed implicit IV */
331 if (((sav->flags & SADB_X_EXT_IIV) != 0) &&
332 (sav->alg_enc != SADB_X_EALG_AES_GCM) &&
333 (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305)) {
334 ipseclog((LOG_ERR,
335 "esp_schedule %s: implicit IV not allowed\n",
336 algo->name));
337 lck_mtx_unlock(sadb_mutex);
338 return EINVAL;
339 }
340
341 /* no schedule necessary */
342 if (!algo->schedule || !algo->schedlen) {
343 lck_mtx_unlock(sadb_mutex);
344 return 0;
345 }
346
347 sav->schedlen = (*algo->schedlen)(algo);
348 if ((signed) sav->schedlen < 0) {
349 lck_mtx_unlock(sadb_mutex);
350 return EINVAL;
351 }
352
353//#### that malloc should be replaced by a saved buffer...
354 sav->sched = _MALLOC(sav->schedlen, M_SECA, M_DONTWAIT);
355 if (!sav->sched) {
356 sav->schedlen = 0;
357 lck_mtx_unlock(sadb_mutex);
358 return ENOBUFS;
359 }
360
361 error = (*algo->schedule)(algo, sav);
362 if (error) {
363 ipseclog((LOG_ERR, "esp_schedule %s: error %d\n",
364 algo->name, error));
365 bzero(sav->sched, sav->schedlen);
366 FREE(sav->sched, M_SECA);
367 sav->sched = NULL;
368 sav->schedlen = 0;
369 }
370 lck_mtx_unlock(sadb_mutex);
371 return error;
372}
373
374static int
375esp_null_mature(
376 __unused struct secasvar *sav)
377{
378 /* anything is okay */
379 return 0;
380}
381
382static int
383esp_null_decrypt(
384 __unused struct mbuf *m,
385 __unused size_t off, /* offset to ESP header */
386 __unused struct secasvar *sav,
387 __unused const struct esp_algorithm *algo,
388 __unused int ivlen)
389{
390 return 0; /* do nothing */
391}
392
393static int
394esp_null_encrypt(
395 __unused struct mbuf *m,
396 __unused size_t off, /* offset to ESP header */
397 __unused size_t plen, /* payload length (to be encrypted) */
398 __unused struct secasvar *sav,
399 __unused const struct esp_algorithm *algo,
400 __unused int ivlen)
401{
402 return 0; /* do nothing */
403}
404
405static int
406esp_descbc_mature(struct secasvar *sav)
407{
408 const struct esp_algorithm *algo;
409
410 if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) {
411 ipseclog((LOG_ERR, "esp_cbc_mature: "
412 "algorithm incompatible with 4 octets IV length\n"));
413 return 1;
414 }
415
416 if (!sav->key_enc) {
417 ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n"));
418 return 1;
419 }
420
421 algo = esp_algorithm_lookup(sav->alg_enc);
422 if (!algo) {
423 ipseclog((LOG_ERR,
424 "esp_descbc_mature: unsupported algorithm.\n"));
425 return 1;
426 }
427
428 if (_KEYBITS(sav->key_enc) < algo->keymin ||
429 _KEYBITS(sav->key_enc) > algo->keymax) {
430 ipseclog((LOG_ERR,
431 "esp_descbc_mature: invalid key length %d.\n",
432 _KEYBITS(sav->key_enc)));
433 return 1;
434 }
435
436 /* weak key check */
437 if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) {
438 ipseclog((LOG_ERR,
439 "esp_descbc_mature: weak key was passed.\n"));
440 return 1;
441 }
442
443 return 0;
444}
445
446static int
447esp_descbc_ivlen(
448 __unused const struct esp_algorithm *algo,
449 struct secasvar *sav)
450{
451 if (!sav) {
452 return 8;
453 }
454 if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) {
455 return 4;
456 }
457 if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) {
458 return 4;
459 }
460 return 8;
461}
462
463static size_t
464esp_des_schedlen(
465 __unused const struct esp_algorithm *algo)
466{
467 return sizeof(des_ecb_key_schedule);
468}
469
470static int
471esp_des_schedule(
472 __unused const struct esp_algorithm *algo,
473 struct secasvar *sav)
474{
475 LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
476 if (des_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
477 (des_ecb_key_schedule *)sav->sched)) {
478 return EINVAL;
479 } else {
480 return 0;
481 }
482}
483
484static int
485esp_des_blockdecrypt(
486 __unused const struct esp_algorithm *algo,
487 struct secasvar *sav,
488 u_int8_t *s,
489 u_int8_t *d)
490{
491 /* assumption: d has a good alignment */
492 bcopy(s, d, sizeof(DES_LONG) * 2);
493 return des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
494 (des_ecb_key_schedule *)sav->sched, DES_DECRYPT);
495}
496
497static int
498esp_des_blockencrypt(
499 __unused const struct esp_algorithm *algo,
500 struct secasvar *sav,
501 u_int8_t *s,
502 u_int8_t *d)
503{
504 /* assumption: d has a good alignment */
505 bcopy(s, d, sizeof(DES_LONG) * 2);
506 return des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
507 (des_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
508}
509
510static int
511esp_cbc_mature(struct secasvar *sav)
512{
513 int keylen;
514 const struct esp_algorithm *algo;
515
516 if (sav->flags & SADB_X_EXT_OLD) {
517 ipseclog((LOG_ERR,
518 "esp_cbc_mature: algorithm incompatible with esp-old\n"));
519 return 1;
520 }
521 if (sav->flags & SADB_X_EXT_DERIV) {
522 ipseclog((LOG_ERR,
523 "esp_cbc_mature: algorithm incompatible with derived\n"));
524 return 1;
525 }
526
527 if (!sav->key_enc) {
528 ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n"));
529 return 1;
530 }
531
532 algo = esp_algorithm_lookup(sav->alg_enc);
533 if (!algo) {
534 ipseclog((LOG_ERR,
535 "esp_cbc_mature: unsupported algorithm.\n"));
536 return 1;
537 }
538
539 keylen = sav->key_enc->sadb_key_bits;
540 if (keylen < algo->keymin || algo->keymax < keylen) {
541 ipseclog((LOG_ERR,
542 "esp_cbc_mature %s: invalid key length %d.\n",
543 algo->name, sav->key_enc->sadb_key_bits));
544 return 1;
545 }
546 switch (sav->alg_enc) {
547 case SADB_EALG_3DESCBC:
548 /* weak key check */
549 if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) ||
550 des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) ||
551 des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) {
552 ipseclog((LOG_ERR,
553 "esp_cbc_mature %s: weak key was passed.\n",
554 algo->name));
555 return 1;
556 }
557 break;
558 case SADB_X_EALG_RIJNDAELCBC:
559 /* allows specific key sizes only */
560 if (!(keylen == 128 || keylen == 192 || keylen == 256)) {
561 ipseclog((LOG_ERR,
562 "esp_cbc_mature %s: invalid key length %d.\n",
563 algo->name, keylen));
564 return 1;
565 }
566 break;
567 }
568
569 return 0;
570}
571
572static int
573esp_gcm_mature(struct secasvar *sav)
574{
575 int keylen;
576 const struct esp_algorithm *algo;
577
578 if (sav->flags & SADB_X_EXT_OLD) {
579 ipseclog((LOG_ERR,
580 "esp_gcm_mature: algorithm incompatible with esp-old\n"));
581 return 1;
582 }
583 if (sav->flags & SADB_X_EXT_DERIV) {
584 ipseclog((LOG_ERR,
585 "esp_gcm_mature: algorithm incompatible with derived\n"));
586 return 1;
587 }
588 if (sav->flags & SADB_X_EXT_IIV) {
589 ipseclog((LOG_ERR,
590 "esp_gcm_mature: implicit IV not currently implemented\n"));
591 return 1;
592 }
593
594 if (!sav->key_enc) {
595 ipseclog((LOG_ERR, "esp_gcm_mature: no key is given.\n"));
596 return 1;
597 }
598
599 algo = esp_algorithm_lookup(sav->alg_enc);
600 if (!algo) {
601 ipseclog((LOG_ERR,
602 "esp_gcm_mature: unsupported algorithm.\n"));
603 return 1;
604 }
605
606 keylen = sav->key_enc->sadb_key_bits;
607 if (keylen < algo->keymin || algo->keymax < keylen) {
608 ipseclog((LOG_ERR,
609 "esp_gcm_mature %s: invalid key length %d.\n",
610 algo->name, sav->key_enc->sadb_key_bits));
611 return 1;
612 }
613 switch (sav->alg_enc) {
614 case SADB_X_EALG_AES_GCM:
615 /* allows specific key sizes only */
616 if (!(keylen == ESP_AESGCM_KEYLEN128 || keylen == ESP_AESGCM_KEYLEN192 || keylen == ESP_AESGCM_KEYLEN256)) {
617 ipseclog((LOG_ERR,
618 "esp_gcm_mature %s: invalid key length %d.\n",
619 algo->name, keylen));
620 return 1;
621 }
622 break;
623 default:
624 ipseclog((LOG_ERR,
625 "esp_gcm_mature %s: invalid algo %d.\n", algo->name, sav->alg_enc));
626 return 1;
627 }
628
629 return 0;
630}
631
632static size_t
633esp_3des_schedlen(
634 __unused const struct esp_algorithm *algo)
635{
636 return sizeof(des3_ecb_key_schedule);
637}
638
639static int
640esp_3des_schedule(
641 __unused const struct esp_algorithm *algo,
642 struct secasvar *sav)
643{
644 LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
645
646 if (des3_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
647 (des3_ecb_key_schedule *)sav->sched)) {
648 return EINVAL;
649 } else {
650 return 0;
651 }
652}
653
654static int
655esp_3des_blockdecrypt(
656 __unused const struct esp_algorithm *algo,
657 struct secasvar *sav,
658 u_int8_t *s,
659 u_int8_t *d)
660{
661 /* assumption: d has a good alignment */
662 bcopy(s, d, sizeof(DES_LONG) * 2);
663 return des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
664 (des3_ecb_key_schedule *)sav->sched, DES_DECRYPT);
665}
666
667static int
668esp_3des_blockencrypt(
669 __unused const struct esp_algorithm *algo,
670 struct secasvar *sav,
671 u_int8_t *s,
672 u_int8_t *d)
673{
674 /* assumption: d has a good alignment */
675 bcopy(s, d, sizeof(DES_LONG) * 2);
676 return des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
677 (des3_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
678}
679
680static int
681esp_common_ivlen(
682 const struct esp_algorithm *algo,
683 __unused struct secasvar *sav)
684{
685 if (!algo) {
686 panic("esp_common_ivlen: unknown algorithm");
687 }
688 return algo->ivlenval;
689}
690
691static int
692esp_cbc_decrypt(struct mbuf *m, size_t off, struct secasvar *sav,
693 const struct esp_algorithm *algo, int ivlen)
694{
695 struct mbuf *s;
696 struct mbuf *d, *d0, *dp;
697 int soff, doff; /* offset from the head of chain, to head of this mbuf */
698 int sn, dn; /* offset from the head of the mbuf, to meat */
699 size_t ivoff, bodyoff;
700 u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
701 u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
702 u_int8_t *p, *q;
703 struct mbuf *scut;
704 int scutoff;
705 int i, result = 0;
706 int blocklen;
707 int derived;
708
709 if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
710 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
711 "unsupported ivlen %d\n", algo->name, ivlen));
712 m_freem(m);
713 return EINVAL;
714 }
715
716 /* assumes blocklen == padbound */
717 blocklen = algo->padbound;
718
719#if DIAGNOSTIC
720 if (blocklen > sizeof(iv)) {
721 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
722 "unsupported blocklen %d\n", algo->name, blocklen));
723 m_freem(m);
724 return EINVAL;
725 }
726#endif
727
728 if (sav->flags & SADB_X_EXT_OLD) {
729 /* RFC 1827 */
730 ivoff = off + sizeof(struct esp);
731 bodyoff = off + sizeof(struct esp) + ivlen;
732 derived = 0;
733 } else {
734 /* RFC 2406 */
735 if (sav->flags & SADB_X_EXT_DERIV) {
736 /*
737 * draft-ietf-ipsec-ciph-des-derived-00.txt
738 * uses sequence number field as IV field.
739 */
740 ivoff = off + sizeof(struct esp);
741 bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
742 ivlen = sizeof(u_int32_t);
743 derived = 1;
744 } else {
745 ivoff = off + sizeof(struct newesp);
746 bodyoff = off + sizeof(struct newesp) + ivlen;
747 derived = 0;
748 }
749 }
750
751 VERIFY(ivoff <= INT_MAX);
752 /* grab iv */
753 m_copydata(m, (int)ivoff, ivlen, (caddr_t) iv);
754
755 /* extend iv */
756 if (ivlen == blocklen) {
757 ;
758 } else if (ivlen == 4 && blocklen == 8) {
759 bcopy(&iv[0], &iv[4], 4);
760 iv[4] ^= 0xff;
761 iv[5] ^= 0xff;
762 iv[6] ^= 0xff;
763 iv[7] ^= 0xff;
764 } else {
765 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
766 "unsupported ivlen/blocklen: %d %d\n",
767 algo->name, ivlen, blocklen));
768 m_freem(m);
769 return EINVAL;
770 }
771
772 if (m->m_pkthdr.len < bodyoff) {
773 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%u\n",
774 algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
775 m_freem(m);
776 return EINVAL;
777 }
778 if ((m->m_pkthdr.len - bodyoff) % blocklen) {
779 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
780 "payload length must be multiple of %d\n",
781 algo->name, blocklen));
782 m_freem(m);
783 return EINVAL;
784 }
785
786 s = m;
787 d = d0 = dp = NULL;
788 soff = doff = sn = dn = 0;
789 ivp = sp = NULL;
790
791 /* skip bodyoff */
792 while (soff < bodyoff) {
793 if (soff + s->m_len > bodyoff) {
794 sn = (int)(bodyoff - soff);
795 break;
796 }
797
798 soff += s->m_len;
799 s = s->m_next;
800 }
801 scut = s;
802 scutoff = sn;
803
804 /* skip over empty mbuf */
805 while (s && s->m_len == 0) {
806 s = s->m_next;
807 }
808
809 // Allocate blocksized buffer for unaligned or non-contiguous access
810 sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT);
811 if (sbuf == NULL) {
812 return ENOBUFS;
813 }
814 while (soff < m->m_pkthdr.len) {
815 /* source */
816 if (sn + blocklen <= s->m_len) {
817 /* body is continuous */
818 sp = mtod(s, u_int8_t *) + sn;
819 } else {
820 /* body is non-continuous */
821 m_copydata(s, sn, blocklen, (caddr_t) sbuf);
822 sp = sbuf;
823 }
824
825 /* destination */
826 if (!d || dn + blocklen > d->m_len) {
827 if (d) {
828 dp = d;
829 }
830 MGET(d, M_DONTWAIT, MT_DATA);
831 i = m->m_pkthdr.len - (soff + sn);
832 if (d && i > MLEN) {
833 MCLGET(d, M_DONTWAIT);
834 if ((d->m_flags & M_EXT) == 0) {
835 m_free(d);
836 d = NULL;
837 }
838 }
839 if (!d) {
840 m_freem(m);
841 if (d0) {
842 m_freem(d0);
843 }
844 result = ENOBUFS;
845 goto end;
846 }
847 if (!d0) {
848 d0 = d;
849 }
850 if (dp) {
851 dp->m_next = d;
852 }
853
854 // try to make mbuf data aligned
855 if (!IPSEC_IS_P2ALIGNED(d->m_data)) {
856 m_adj(d, IPSEC_GET_P2UNALIGNED_OFS(d->m_data));
857 }
858
859 d->m_len = 0;
860 d->m_len = (int)((M_TRAILINGSPACE(d) / blocklen) * blocklen);
861 if (d->m_len > i) {
862 d->m_len = i;
863 }
864 dn = 0;
865 }
866
867 /* decrypt */
868 // check input pointer alignment and use a separate aligned buffer (if sp is unaligned on 4-byte boundary).
869 if (IPSEC_IS_P2ALIGNED(sp)) {
870 sp_unaligned = NULL;
871 } else {
872 sp_unaligned = sp;
873 sp = sbuf;
874 memcpy(sp, sp_unaligned, blocklen);
875 }
876 // no need to check output pointer alignment
877 (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
878
879 // update unaligned pointers
880 if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
881 sp = sp_unaligned;
882 }
883
884 /* xor */
885 p = ivp ? ivp : iv;
886 q = mtod(d, u_int8_t *) + dn;
887 for (i = 0; i < blocklen; i++) {
888 q[i] ^= p[i];
889 }
890
891 /* next iv */
892 if (sp == sbuf) {
893 bcopy(sbuf, iv, blocklen);
894 ivp = NULL;
895 } else {
896 ivp = sp;
897 }
898
899 sn += blocklen;
900 dn += blocklen;
901
902 /* find the next source block */
903 while (s && sn >= s->m_len) {
904 sn -= s->m_len;
905 soff += s->m_len;
906 s = s->m_next;
907 }
908 }
909
910 m_freem(scut->m_next);
911 scut->m_len = scutoff;
912 scut->m_next = d0;
913
914 /* just in case */
915 bzero(iv, sizeof(iv));
916 bzero(sbuf, blocklen);
917end:
918 if (sbuf != NULL) {
919 FREE(sbuf, M_SECA);
920 }
921 return result;
922}
923
924static int
925esp_cbc_encrypt(
926 struct mbuf *m,
927 size_t off,
928 __unused size_t plen,
929 struct secasvar *sav,
930 const struct esp_algorithm *algo,
931 int ivlen)
932{
933 struct mbuf *s;
934 struct mbuf *d, *d0, *dp;
935 int soff, doff; /* offset from the head of chain, to head of this mbuf */
936 int sn, dn; /* offset from the head of the mbuf, to meat */
937 size_t ivoff, bodyoff;
938 u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
939 u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
940 u_int8_t *p, *q;
941 struct mbuf *scut;
942 int scutoff;
943 int i, result = 0;
944 int blocklen;
945 int derived;
946
947 if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
948 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
949 "unsupported ivlen %d\n", algo->name, ivlen));
950 m_freem(m);
951 return EINVAL;
952 }
953
954 /* assumes blocklen == padbound */
955 blocklen = algo->padbound;
956
957#if DIAGNOSTIC
958 if (blocklen > sizeof(iv)) {
959 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
960 "unsupported blocklen %d\n", algo->name, blocklen));
961 m_freem(m);
962 return EINVAL;
963 }
964#endif
965
966 if (sav->flags & SADB_X_EXT_OLD) {
967 /* RFC 1827 */
968 ivoff = off + sizeof(struct esp);
969 bodyoff = off + sizeof(struct esp) + ivlen;
970 derived = 0;
971 } else {
972 /* RFC 2406 */
973 if (sav->flags & SADB_X_EXT_DERIV) {
974 /*
975 * draft-ietf-ipsec-ciph-des-derived-00.txt
976 * uses sequence number field as IV field.
977 */
978 ivoff = off + sizeof(struct esp);
979 bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
980 ivlen = sizeof(u_int32_t);
981 derived = 1;
982 } else {
983 ivoff = off + sizeof(struct newesp);
984 bodyoff = off + sizeof(struct newesp) + ivlen;
985 derived = 0;
986 }
987 }
988
989 VERIFY(ivoff <= INT_MAX);
990
991 /* put iv into the packet. if we are in derived mode, use seqno. */
992 if (derived) {
993 m_copydata(m, (int)ivoff, ivlen, (caddr_t) iv);
994 } else {
995 bcopy(sav->iv, iv, ivlen);
996 /* maybe it is better to overwrite dest, not source */
997 m_copyback(m, (int)ivoff, ivlen, (caddr_t) iv);
998 }
999
1000 /* extend iv */
1001 if (ivlen == blocklen) {
1002 ;
1003 } else if (ivlen == 4 && blocklen == 8) {
1004 bcopy(&iv[0], &iv[4], 4);
1005 iv[4] ^= 0xff;
1006 iv[5] ^= 0xff;
1007 iv[6] ^= 0xff;
1008 iv[7] ^= 0xff;
1009 } else {
1010 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
1011 "unsupported ivlen/blocklen: %d %d\n",
1012 algo->name, ivlen, blocklen));
1013 m_freem(m);
1014 return EINVAL;
1015 }
1016
1017 if (m->m_pkthdr.len < bodyoff) {
1018 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%u\n",
1019 algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
1020 m_freem(m);
1021 return EINVAL;
1022 }
1023 if ((m->m_pkthdr.len - bodyoff) % blocklen) {
1024 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
1025 "payload length must be multiple of %u\n",
1026 algo->name, (u_int32_t)algo->padbound));
1027 m_freem(m);
1028 return EINVAL;
1029 }
1030
1031 s = m;
1032 d = d0 = dp = NULL;
1033 soff = doff = sn = dn = 0;
1034 ivp = sp = NULL;
1035
1036 /* skip bodyoff */
1037 while (soff < bodyoff) {
1038 if (soff + s->m_len > bodyoff) {
1039 sn = (int)(bodyoff - soff);
1040 break;
1041 }
1042
1043 soff += s->m_len;
1044 s = s->m_next;
1045 }
1046 scut = s;
1047 scutoff = sn;
1048
1049 /* skip over empty mbuf */
1050 while (s && s->m_len == 0) {
1051 s = s->m_next;
1052 }
1053
1054 // Allocate blocksized buffer for unaligned or non-contiguous access
1055 sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT);
1056 if (sbuf == NULL) {
1057 return ENOBUFS;
1058 }
1059 while (soff < m->m_pkthdr.len) {
1060 /* source */
1061 if (sn + blocklen <= s->m_len) {
1062 /* body is continuous */
1063 sp = mtod(s, u_int8_t *) + sn;
1064 } else {
1065 /* body is non-continuous */
1066 m_copydata(s, sn, blocklen, (caddr_t) sbuf);
1067 sp = sbuf;
1068 }
1069
1070 /* destination */
1071 if (!d || dn + blocklen > d->m_len) {
1072 if (d) {
1073 dp = d;
1074 }
1075 MGET(d, M_DONTWAIT, MT_DATA);
1076 i = m->m_pkthdr.len - (soff + sn);
1077 if (d && i > MLEN) {
1078 MCLGET(d, M_DONTWAIT);
1079 if ((d->m_flags & M_EXT) == 0) {
1080 m_free(d);
1081 d = NULL;
1082 }
1083 }
1084 if (!d) {
1085 m_freem(m);
1086 if (d0) {
1087 m_freem(d0);
1088 }
1089 result = ENOBUFS;
1090 goto end;
1091 }
1092 if (!d0) {
1093 d0 = d;
1094 }
1095 if (dp) {
1096 dp->m_next = d;
1097 }
1098
1099 // try to make mbuf data aligned
1100 if (!IPSEC_IS_P2ALIGNED(d->m_data)) {
1101 m_adj(d, IPSEC_GET_P2UNALIGNED_OFS(d->m_data));
1102 }
1103
1104 d->m_len = 0;
1105 d->m_len = (int)((M_TRAILINGSPACE(d) / blocklen) * blocklen);
1106 if (d->m_len > i) {
1107 d->m_len = i;
1108 }
1109 dn = 0;
1110 }
1111
1112 /* xor */
1113 p = ivp ? ivp : iv;
1114 q = sp;
1115 for (i = 0; i < blocklen; i++) {
1116 q[i] ^= p[i];
1117 }
1118
1119 /* encrypt */
1120 // check input pointer alignment and use a separate aligned buffer (if sp is not aligned on 4-byte boundary).
1121 if (IPSEC_IS_P2ALIGNED(sp)) {
1122 sp_unaligned = NULL;
1123 } else {
1124 sp_unaligned = sp;
1125 sp = sbuf;
1126 memcpy(sp, sp_unaligned, blocklen);
1127 }
1128 // no need to check output pointer alignment
1129 (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
1130
1131 // update unaligned pointers
1132 if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
1133 sp = sp_unaligned;
1134 }
1135
1136 /* next iv */
1137 ivp = mtod(d, u_int8_t *) + dn;
1138
1139 sn += blocklen;
1140 dn += blocklen;
1141
1142 /* find the next source block */
1143 while (s && sn >= s->m_len) {
1144 sn -= s->m_len;
1145 soff += s->m_len;
1146 s = s->m_next;
1147 }
1148 }
1149
1150 m_freem(scut->m_next);
1151 scut->m_len = scutoff;
1152 scut->m_next = d0;
1153
1154 /* just in case */
1155 bzero(iv, sizeof(iv));
1156 bzero(sbuf, blocklen);
1157
1158 key_sa_stir_iv(sav);
1159end:
1160 if (sbuf != NULL) {
1161 FREE(sbuf, M_SECA);
1162 }
1163 return result;
1164}
1165
1166/*------------------------------------------------------------*/
1167
1168/* does not free m0 on error */
1169int
1170esp_auth(
1171 struct mbuf *m0,
1172 size_t skip, /* offset to ESP header */
1173 size_t length, /* payload length */
1174 struct secasvar *sav,
1175 u_char *sum)
1176{
1177 struct mbuf *m;
1178 size_t off;
1179 struct ah_algorithm_state s;
1180 u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4)));
1181 const struct ah_algorithm *algo;
1182 size_t siz;
1183 int error;
1184
1185 /* sanity checks */
1186 if (m0->m_pkthdr.len < skip) {
1187 ipseclog((LOG_DEBUG, "esp_auth: mbuf length < skip\n"));
1188 return EINVAL;
1189 }
1190 if (m0->m_pkthdr.len < skip + length) {
1191 ipseclog((LOG_DEBUG,
1192 "esp_auth: mbuf length < skip + length\n"));
1193 return EINVAL;
1194 }
1195
1196 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_START, skip, length, 0, 0, 0);
1197 /*
1198 * length of esp part (excluding authentication data) must be 4n,
1199 * since nexthdr must be at offset 4n+3.
1200 */
1201 if (length % 4) {
1202 ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n"));
1203 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 1, 0, 0, 0, 0);
1204 return EINVAL;
1205 }
1206 if (!sav) {
1207 ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));
1208 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 2, 0, 0, 0, 0);
1209 return EINVAL;
1210 }
1211 algo = ah_algorithm_lookup(sav->alg_auth);
1212 if (!algo) {
1213 ipseclog((LOG_ERR,
1214 "esp_auth: bad ESP auth algorithm passed: %d\n",
1215 sav->alg_auth));
1216 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 3, 0, 0, 0, 0);
1217 return EINVAL;
1218 }
1219
1220 m = m0;
1221 off = 0;
1222
1223 siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1));
1224 if (sizeof(sumbuf) < siz) {
1225 ipseclog((LOG_DEBUG,
1226 "esp_auth: AH_MAXSUMSIZE is too small: siz=%u\n",
1227 (u_int32_t)siz));
1228 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 4, 0, 0, 0, 0);
1229 return EINVAL;
1230 }
1231
1232 /* skip the header */
1233 while (skip) {
1234 if (!m) {
1235 panic("mbuf chain?");
1236 }
1237 if (m->m_len <= skip) {
1238 skip -= m->m_len;
1239 m = m->m_next;
1240 off = 0;
1241 } else {
1242 off = skip;
1243 skip = 0;
1244 }
1245 }
1246
1247 error = (*algo->init)(&s, sav);
1248 if (error) {
1249 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 5, 0, 0, 0, 0);
1250 return error;
1251 }
1252 while (0 < length) {
1253 if (!m) {
1254 panic("mbuf chain?");
1255 }
1256
1257 if (m->m_len - off < length) {
1258 (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off),
1259 m->m_len - off);
1260 length -= m->m_len - off;
1261 m = m->m_next;
1262 off = 0;
1263 } else {
1264 (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off), length);
1265 break;
1266 }
1267 }
1268 (*algo->result)(&s, (caddr_t) sumbuf, sizeof(sumbuf));
1269 bcopy(sumbuf, sum, siz); /*XXX*/
1270 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 6, 0, 0, 0, 0);
1271 return 0;
1272}
1273
1274void
1275esp_init(void)
1276{
1277 static int esp_initialized = 0;
1278
1279 if (esp_initialized) {
1280 return;
1281 }
1282
1283 esp_initialized = 1;
1284
1285 esp_mpkl_log_object = MPKL_CREATE_LOGOBJECT("com.apple.xnu.esp");
1286 if (esp_mpkl_log_object == NULL) {
1287 panic("MPKL_CREATE_LOGOBJECT for ESP failed");
1288 }
1289
1290 return;
1291}