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