]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/esp_core.c
xnu-7195.101.1.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>
1c79356b
A
82#include <netinet/ip6.h>
83#include <netinet6/ip6_var.h>
84#include <netinet/icmp6.h>
1c79356b
A
85
86#include <netinet6/ipsec.h>
9bccf70c 87#include <netinet6/ipsec6.h>
1c79356b 88#include <netinet6/ah.h>
9bccf70c 89#include <netinet6/ah6.h>
1c79356b 90#include <netinet6/esp.h>
9bccf70c 91#include <netinet6/esp6.h>
9bccf70c 92#include <netinet6/esp_rijndael.h>
5ba3f43e 93#include <netinet6/esp_chachapoly.h>
1c79356b
A
94#include <net/pfkeyv2.h>
95#include <netkey/keydb.h>
9bccf70c 96#include <netkey/key.h>
316670eb 97#include <libkern/crypto/des.h>
1c79356b
A
98
99#include <net/net_osdep.h>
100
55e303ae 101#include <sys/kdebug.h>
0a7de745
A
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))
316670eb 105#define MAX_SBUF_LEN 2000
55e303ae 106
91447636 107extern lck_mtx_t *sadb_mutex;
cb323159 108os_log_t esp_mpkl_log_object = NULL;
91447636
A
109
110static int esp_null_mature(struct secasvar *);
111static int esp_null_decrypt(struct mbuf *, size_t,
0a7de745 112 struct secasvar *, const struct esp_algorithm *, int);
91447636 113static int esp_null_encrypt(struct mbuf *, size_t, size_t,
0a7de745 114 struct secasvar *, const struct esp_algorithm *, int);
91447636
A
115static int esp_descbc_mature(struct secasvar *);
116static int esp_descbc_ivlen(const struct esp_algorithm *,
0a7de745 117 struct secasvar *);
91447636 118static int esp_des_schedule(const struct esp_algorithm *,
0a7de745 119 struct secasvar *);
f427ee49 120static size_t esp_des_schedlen(const struct esp_algorithm *);
91447636 121static int esp_des_blockdecrypt(const struct esp_algorithm *,
0a7de745 122 struct secasvar *, u_int8_t *, u_int8_t *);
91447636 123static int esp_des_blockencrypt(const struct esp_algorithm *,
0a7de745 124 struct secasvar *, u_int8_t *, u_int8_t *);
91447636 125static int esp_cbc_mature(struct secasvar *);
91447636 126static int esp_3des_schedule(const struct esp_algorithm *,
0a7de745 127 struct secasvar *);
f427ee49 128static size_t esp_3des_schedlen(const struct esp_algorithm *);
91447636 129static int esp_3des_blockdecrypt(const struct esp_algorithm *,
0a7de745 130 struct secasvar *, u_int8_t *, u_int8_t *);
91447636 131static int esp_3des_blockencrypt(const struct esp_algorithm *,
0a7de745 132 struct secasvar *, u_int8_t *, u_int8_t *);
91447636 133static int esp_common_ivlen(const struct esp_algorithm *,
0a7de745 134 struct secasvar *);
91447636 135static int esp_cbc_decrypt(struct mbuf *, size_t,
0a7de745 136 struct secasvar *, const struct esp_algorithm *, int);
91447636 137static int esp_cbc_encrypt(struct mbuf *, size_t, size_t,
0a7de745 138 struct secasvar *, const struct esp_algorithm *, int);
3e170ce0 139static int esp_gcm_mature(struct secasvar *);
9bccf70c 140
0a7de745 141#define MAXIVLEN 16
9bccf70c 142
3e170ce0
A
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
cb323159
A
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};
2d21ac55
A
260
261static const struct esp_algorithm *esp_algorithms[] = {
262 &des_cbc,
263 &des3_cbc,
264 &null_esp,
3e170ce0
A
265 &aes_cbc,
266 &aes_gcm,
5ba3f43e 267 &chacha_poly,
1c79356b
A
268};
269
9bccf70c 270const struct esp_algorithm *
39037602 271esp_algorithm_lookup(int idx)
9bccf70c 272{
9bccf70c
A
273 switch (idx) {
274 case SADB_EALG_DESCBC:
2d21ac55 275 return &des_cbc;
9bccf70c 276 case SADB_EALG_3DESCBC:
2d21ac55 277 return &des3_cbc;
9bccf70c 278 case SADB_EALG_NULL:
2d21ac55 279 return &null_esp;
9bccf70c 280 case SADB_X_EALG_RIJNDAELCBC:
2d21ac55 281 return &aes_cbc;
3e170ce0
A
282 case SADB_X_EALG_AES_GCM:
283 return &aes_gcm;
5ba3f43e
A
284 case SADB_X_EALG_CHACHA20POLY1305:
285 return &chacha_poly;
9bccf70c
A
286 default:
287 return NULL;
288 }
289}
290
291int
39037602 292esp_max_ivlen(void)
9bccf70c
A
293{
294 int idx;
295 int ivlen;
296
297 ivlen = 0;
0a7de745
A
298 for (idx = 0; idx < sizeof(esp_algorithms) / sizeof(esp_algorithms[0]);
299 idx++) {
300 if (esp_algorithms[idx]->ivlenval > ivlen) {
2d21ac55 301 ivlen = esp_algorithms[idx]->ivlenval;
0a7de745 302 }
9bccf70c
A
303 }
304
305 return ivlen;
306}
307
308int
39037602 309esp_schedule(const struct esp_algorithm *algo, struct secasvar *sav)
1c79356b 310{
9bccf70c
A
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
2d21ac55 323 lck_mtx_lock(sadb_mutex);
9bccf70c 324 /* already allocated */
2d21ac55
A
325 if (sav->sched && sav->schedlen != 0) {
326 lck_mtx_unlock(sadb_mutex);
9bccf70c 327 return 0;
2d21ac55 328 }
5ba3f43e
A
329
330 /* prevent disallowed implicit IV */
331 if (((sav->flags & SADB_X_EXT_IIV) != 0) &&
0a7de745
A
332 (sav->alg_enc != SADB_X_EALG_AES_GCM) &&
333 (sav->alg_enc != SADB_X_EALG_CHACHA20POLY1305)) {
5ba3f43e
A
334 ipseclog((LOG_ERR,
335 "esp_schedule %s: implicit IV not allowed\n",
0a7de745 336 algo->name));
d9a64523 337 lck_mtx_unlock(sadb_mutex);
5ba3f43e
A
338 return EINVAL;
339 }
340
9bccf70c 341 /* no schedule necessary */
2d21ac55
A
342 if (!algo->schedule || !algo->schedlen) {
343 lck_mtx_unlock(sadb_mutex);
9bccf70c 344 return 0;
2d21ac55 345 }
0a7de745 346
9bccf70c 347 sav->schedlen = (*algo->schedlen)(algo);
b0d623f7 348 if ((signed) sav->schedlen < 0) {
2d21ac55 349 lck_mtx_unlock(sadb_mutex);
9bccf70c 350 return EINVAL;
2d21ac55 351 }
55e303ae
A
352
353//#### that malloc should be replaced by a saved buffer...
9bccf70c
A
354 sav->sched = _MALLOC(sav->schedlen, M_SECA, M_DONTWAIT);
355 if (!sav->sched) {
356 sav->schedlen = 0;
2d21ac55 357 lck_mtx_unlock(sadb_mutex);
9bccf70c
A
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));
55e303ae 365 bzero(sav->sched, sav->schedlen);
9bccf70c
A
366 FREE(sav->sched, M_SECA);
367 sav->sched = NULL;
368 sav->schedlen = 0;
369 }
2d21ac55 370 lck_mtx_unlock(sadb_mutex);
9bccf70c 371 return error;
1c79356b
A
372}
373
374static int
2d21ac55
A
375esp_null_mature(
376 __unused struct secasvar *sav)
1c79356b 377{
9bccf70c 378 /* anything is okay */
1c79356b
A
379 return 0;
380}
381
382static int
2d21ac55
A
383esp_null_decrypt(
384 __unused struct mbuf *m,
0a7de745 385 __unused size_t off, /* offset to ESP header */
2d21ac55
A
386 __unused struct secasvar *sav,
387 __unused const struct esp_algorithm *algo,
388 __unused int ivlen)
1c79356b
A
389{
390 return 0; /* do nothing */
391}
392
393static int
2d21ac55
A
394esp_null_encrypt(
395 __unused struct mbuf *m,
0a7de745
A
396 __unused size_t off, /* offset to ESP header */
397 __unused size_t plen, /* payload length (to be encrypted) */
2d21ac55
A
398 __unused struct secasvar *sav,
399 __unused const struct esp_algorithm *algo,
400 __unused int ivlen)
1c79356b
A
401{
402 return 0; /* do nothing */
403}
404
405static int
39037602 406esp_descbc_mature(struct secasvar *sav)
1c79356b 407{
9bccf70c 408 const struct esp_algorithm *algo;
1c79356b
A
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 }
9bccf70c
A
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) {
1c79356b
A
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 */
9bccf70c 437 if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) {
1c79356b
A
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
2d21ac55
A
447esp_descbc_ivlen(
448 __unused const struct esp_algorithm *algo,
449 struct secasvar *sav)
1c79356b 450{
0a7de745 451 if (!sav) {
1c79356b 452 return 8;
0a7de745
A
453 }
454 if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) {
9bccf70c 455 return 4;
0a7de745
A
456 }
457 if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) {
9bccf70c 458 return 4;
0a7de745 459 }
9bccf70c 460 return 8;
1c79356b
A
461}
462
f427ee49 463static size_t
2d21ac55
A
464esp_des_schedlen(
465 __unused const struct esp_algorithm *algo)
1c79356b 466{
316670eb 467 return sizeof(des_ecb_key_schedule);
9bccf70c 468}
1c79356b 469
9bccf70c 470static int
2d21ac55
A
471esp_des_schedule(
472 __unused const struct esp_algorithm *algo,
473 struct secasvar *sav)
9bccf70c 474{
5ba3f43e 475 LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
316670eb 476 if (des_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
0a7de745 477 (des_ecb_key_schedule *)sav->sched)) {
1c79356b 478 return EINVAL;
0a7de745 479 } else {
9bccf70c 480 return 0;
0a7de745 481 }
9bccf70c 482}
1c79356b 483
9bccf70c 484static int
2d21ac55
A
485esp_des_blockdecrypt(
486 __unused const struct esp_algorithm *algo,
487 struct secasvar *sav,
488 u_int8_t *s,
489 u_int8_t *d)
9bccf70c 490{
9bccf70c
A
491 /* assumption: d has a good alignment */
492 bcopy(s, d, sizeof(DES_LONG) * 2);
cb323159
A
493 return des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
494 (des_ecb_key_schedule *)sav->sched, DES_DECRYPT);
1c79356b
A
495}
496
497static int
2d21ac55
A
498esp_des_blockencrypt(
499 __unused const struct esp_algorithm *algo,
500 struct secasvar *sav,
501 u_int8_t *s,
502 u_int8_t *d)
1c79356b 503{
9bccf70c
A
504 /* assumption: d has a good alignment */
505 bcopy(s, d, sizeof(DES_LONG) * 2);
cb323159
A
506 return des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
507 (des_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
1c79356b
A
508}
509
510static int
39037602 511esp_cbc_mature(struct secasvar *sav)
1c79356b
A
512{
513 int keylen;
9bccf70c 514 const struct esp_algorithm *algo;
1c79356b
A
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) {
9bccf70c
A
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) {
1c79356b 534 ipseclog((LOG_ERR,
fe8ab488 535 "esp_cbc_mature: unsupported algorithm.\n"));
1c79356b
A
536 return 1;
537 }
9bccf70c 538
1c79356b
A
539 keylen = sav->key_enc->sadb_key_bits;
540 if (keylen < algo->keymin || algo->keymax < keylen) {
9bccf70c
A
541 ipseclog((LOG_ERR,
542 "esp_cbc_mature %s: invalid key length %d.\n",
543 algo->name, sav->key_enc->sadb_key_bits));
1c79356b
A
544 return 1;
545 }
546 switch (sav->alg_enc) {
547 case SADB_EALG_3DESCBC:
548 /* weak key check */
9bccf70c
A
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))) {
1c79356b 552 ipseclog((LOG_ERR,
9bccf70c
A
553 "esp_cbc_mature %s: weak key was passed.\n",
554 algo->name));
1c79356b
A
555 return 1;
556 }
557 break;
9bccf70c
A
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 }
1c79356b
A
566 break;
567 }
568
569 return 0;
570}
571
3e170ce0 572static int
39037602 573esp_gcm_mature(struct secasvar *sav)
3e170ce0
A
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 }
5ba3f43e
A
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 }
3e170ce0
A
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,
94ff46dc 625 "esp_gcm_mature %s: invalid algo %d.\n", algo->name, sav->alg_enc));
3e170ce0
A
626 return 1;
627 }
628
629 return 0;
630}
631
f427ee49 632static size_t
2d21ac55
A
633esp_3des_schedlen(
634 __unused const struct esp_algorithm *algo)
9bccf70c 635{
316670eb 636 return sizeof(des3_ecb_key_schedule);
9bccf70c 637}
1c79356b 638
9bccf70c 639static int
2d21ac55
A
640esp_3des_schedule(
641 __unused const struct esp_algorithm *algo,
642 struct secasvar *sav)
9bccf70c 643{
5ba3f43e 644 LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
316670eb
A
645
646 if (des3_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
0a7de745 647 (des3_ecb_key_schedule *)sav->sched)) {
316670eb 648 return EINVAL;
0a7de745 649 } else {
316670eb 650 return 0;
0a7de745 651 }
9bccf70c 652}
1c79356b 653
9bccf70c 654static int
2d21ac55
A
655esp_3des_blockdecrypt(
656 __unused const struct esp_algorithm *algo,
657 struct secasvar *sav,
658 u_int8_t *s,
659 u_int8_t *d)
9bccf70c 660{
9bccf70c 661 /* assumption: d has a good alignment */
9bccf70c 662 bcopy(s, d, sizeof(DES_LONG) * 2);
cb323159
A
663 return des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
664 (des3_ecb_key_schedule *)sav->sched, DES_DECRYPT);
9bccf70c 665}
1c79356b 666
9bccf70c 667static int
2d21ac55
A
668esp_3des_blockencrypt(
669 __unused const struct esp_algorithm *algo,
670 struct secasvar *sav,
671 u_int8_t *s,
672 u_int8_t *d)
9bccf70c 673{
9bccf70c 674 /* assumption: d has a good alignment */
9bccf70c 675 bcopy(s, d, sizeof(DES_LONG) * 2);
cb323159
A
676 return des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
677 (des3_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
1c79356b
A
678}
679
680static int
2d21ac55
A
681esp_common_ivlen(
682 const struct esp_algorithm *algo,
683 __unused struct secasvar *sav)
1c79356b 684{
0a7de745 685 if (!algo) {
9bccf70c 686 panic("esp_common_ivlen: unknown algorithm");
0a7de745 687 }
9bccf70c 688 return algo->ivlenval;
1c79356b
A
689}
690
691static int
39037602 692esp_cbc_decrypt(struct mbuf *m, size_t off, struct secasvar *sav,
0a7de745 693 const struct esp_algorithm *algo, int ivlen)
1c79356b 694{
9bccf70c
A
695 struct mbuf *s;
696 struct mbuf *d, *d0, *dp;
0a7de745
A
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 */
9bccf70c 699 size_t ivoff, bodyoff;
316670eb
A
700 u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
701 u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
9bccf70c
A
702 u_int8_t *p, *q;
703 struct mbuf *scut;
704 int scutoff;
316670eb 705 int i, result = 0;
9bccf70c
A
706 int blocklen;
707 int derived;
1c79356b 708
9bccf70c
A
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);
1c79356b
A
713 return EINVAL;
714 }
715
9bccf70c
A
716 /* assumes blocklen == padbound */
717 blocklen = algo->padbound;
1c79356b 718
9bccf70c
A
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);
1c79356b
A
724 return EINVAL;
725 }
9bccf70c 726#endif
1c79356b 727
9bccf70c
A
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 }
1c79356b
A
749 }
750
f427ee49 751 VERIFY(ivoff <= INT_MAX);
9bccf70c 752 /* grab iv */
f427ee49 753 m_copydata(m, (int)ivoff, ivlen, (caddr_t) iv);
1c79356b 754
9bccf70c 755 /* extend iv */
0a7de745 756 if (ivlen == blocklen) {
9bccf70c 757 ;
0a7de745 758 } else if (ivlen == 4 && blocklen == 8) {
9bccf70c
A
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);
1c79356b
A
769 return EINVAL;
770 }
9bccf70c
A
771
772 if (m->m_pkthdr.len < bodyoff) {
94ff46dc 773 ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%u\n",
b0d623f7 774 algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
9bccf70c 775 m_freem(m);
1c79356b
A
776 return EINVAL;
777 }
9bccf70c
A
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);
1c79356b
A
783 return EINVAL;
784 }
785
9bccf70c
A
786 s = m;
787 d = d0 = dp = NULL;
788 soff = doff = sn = dn = 0;
789 ivp = sp = NULL;
1c79356b 790
9bccf70c
A
791 /* skip bodyoff */
792 while (soff < bodyoff) {
793 if (soff + s->m_len > bodyoff) {
f427ee49 794 sn = (int)(bodyoff - soff);
9bccf70c
A
795 break;
796 }
1c79356b 797
9bccf70c
A
798 soff += s->m_len;
799 s = s->m_next;
1c79356b 800 }
9bccf70c
A
801 scut = s;
802 scutoff = sn;
1c79356b 803
9bccf70c 804 /* skip over empty mbuf */
0a7de745 805 while (s && s->m_len == 0) {
9bccf70c 806 s = s->m_next;
0a7de745 807 }
1c79356b 808
316670eb
A
809 // Allocate blocksized buffer for unaligned or non-contiguous access
810 sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT);
0a7de745 811 if (sbuf == NULL) {
316670eb 812 return ENOBUFS;
0a7de745 813 }
9bccf70c
A
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 */
b0d623f7 821 m_copydata(s, sn, blocklen, (caddr_t) sbuf);
9bccf70c
A
822 sp = sbuf;
823 }
1c79356b 824
9bccf70c
A
825 /* destination */
826 if (!d || dn + blocklen > d->m_len) {
0a7de745 827 if (d) {
9bccf70c 828 dp = d;
0a7de745 829 }
9bccf70c
A
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);
0a7de745 841 if (d0) {
9bccf70c 842 m_freem(d0);
0a7de745 843 }
316670eb
A
844 result = ENOBUFS;
845 goto end;
9bccf70c 846 }
0a7de745 847 if (!d0) {
9bccf70c 848 d0 = d;
0a7de745
A
849 }
850 if (dp) {
9bccf70c 851 dp->m_next = d;
0a7de745 852 }
316670eb
A
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
9bccf70c 859 d->m_len = 0;
f427ee49 860 d->m_len = (int)((M_TRAILINGSPACE(d) / blocklen) * blocklen);
0a7de745 861 if (d->m_len > i) {
9bccf70c 862 d->m_len = i;
0a7de745 863 }
9bccf70c
A
864 dn = 0;
865 }
1c79356b 866
9bccf70c 867 /* decrypt */
316670eb
A
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
9bccf70c 877 (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
1c79356b 878
316670eb
A
879 // update unaligned pointers
880 if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
881 sp = sp_unaligned;
882 }
883
9bccf70c
A
884 /* xor */
885 p = ivp ? ivp : iv;
886 q = mtod(d, u_int8_t *) + dn;
0a7de745 887 for (i = 0; i < blocklen; i++) {
9bccf70c 888 q[i] ^= p[i];
0a7de745 889 }
1c79356b 890
9bccf70c
A
891 /* next iv */
892 if (sp == sbuf) {
893 bcopy(sbuf, iv, blocklen);
894 ivp = NULL;
0a7de745 895 } else {
9bccf70c 896 ivp = sp;
0a7de745 897 }
1c79356b 898
9bccf70c
A
899 sn += blocklen;
900 dn += blocklen;
1c79356b 901
9bccf70c
A
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 }
1c79356b
A
908 }
909
9bccf70c
A
910 m_freem(scut->m_next);
911 scut->m_len = scutoff;
912 scut->m_next = d0;
1c79356b 913
9bccf70c
A
914 /* just in case */
915 bzero(iv, sizeof(iv));
fe8ab488 916 bzero(sbuf, blocklen);
316670eb 917end:
0a7de745 918 if (sbuf != NULL) {
316670eb 919 FREE(sbuf, M_SECA);
0a7de745 920 }
316670eb 921 return result;
1c79356b
A
922}
923
924static int
2d21ac55
A
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)
1c79356b 932{
9bccf70c
A
933 struct mbuf *s;
934 struct mbuf *d, *d0, *dp;
0a7de745
A
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 */
9bccf70c 937 size_t ivoff, bodyoff;
316670eb
A
938 u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
939 u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
9bccf70c
A
940 u_int8_t *p, *q;
941 struct mbuf *scut;
942 int scutoff;
316670eb 943 int i, result = 0;
9bccf70c
A
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);
1c79356b
A
951 return EINVAL;
952 }
9bccf70c
A
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);
1c79356b
A
962 return EINVAL;
963 }
9bccf70c
A
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
f427ee49
A
989 VERIFY(ivoff <= INT_MAX);
990
9bccf70c 991 /* put iv into the packet. if we are in derived mode, use seqno. */
0a7de745 992 if (derived) {
f427ee49 993 m_copydata(m, (int)ivoff, ivlen, (caddr_t) iv);
0a7de745 994 } else {
9bccf70c
A
995 bcopy(sav->iv, iv, ivlen);
996 /* maybe it is better to overwrite dest, not source */
f427ee49 997 m_copyback(m, (int)ivoff, ivlen, (caddr_t) iv);
9bccf70c
A
998 }
999
1000 /* extend iv */
0a7de745 1001 if (ivlen == blocklen) {
9bccf70c 1002 ;
0a7de745 1003 } else if (ivlen == 4 && blocklen == 8) {
9bccf70c
A
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);
1c79356b
A
1014 return EINVAL;
1015 }
9bccf70c
A
1016
1017 if (m->m_pkthdr.len < bodyoff) {
94ff46dc 1018 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%u\n",
b0d623f7 1019 algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
9bccf70c 1020 m_freem(m);
1c79356b
A
1021 return EINVAL;
1022 }
9bccf70c
A
1023 if ((m->m_pkthdr.len - bodyoff) % blocklen) {
1024 ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
94ff46dc 1025 "payload length must be multiple of %u\n",
b0d623f7 1026 algo->name, (u_int32_t)algo->padbound));
9bccf70c 1027 m_freem(m);
1c79356b
A
1028 return EINVAL;
1029 }
1030
9bccf70c
A
1031 s = m;
1032 d = d0 = dp = NULL;
1033 soff = doff = sn = dn = 0;
1034 ivp = sp = NULL;
1c79356b 1035
9bccf70c
A
1036 /* skip bodyoff */
1037 while (soff < bodyoff) {
1038 if (soff + s->m_len > bodyoff) {
f427ee49 1039 sn = (int)(bodyoff - soff);
9bccf70c
A
1040 break;
1041 }
1c79356b 1042
9bccf70c
A
1043 soff += s->m_len;
1044 s = s->m_next;
1045 }
1046 scut = s;
1047 scutoff = sn;
1c79356b 1048
9bccf70c 1049 /* skip over empty mbuf */
0a7de745 1050 while (s && s->m_len == 0) {
9bccf70c 1051 s = s->m_next;
0a7de745 1052 }
1c79356b 1053
316670eb 1054 // Allocate blocksized buffer for unaligned or non-contiguous access
0a7de745
A
1055 sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT);
1056 if (sbuf == NULL) {
1057 return ENOBUFS;
1058 }
9bccf70c
A
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 */
b0d623f7 1066 m_copydata(s, sn, blocklen, (caddr_t) sbuf);
9bccf70c
A
1067 sp = sbuf;
1068 }
1c79356b 1069
9bccf70c
A
1070 /* destination */
1071 if (!d || dn + blocklen > d->m_len) {
0a7de745 1072 if (d) {
9bccf70c 1073 dp = d;
0a7de745 1074 }
9bccf70c
A
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);
0a7de745 1086 if (d0) {
9bccf70c 1087 m_freem(d0);
0a7de745 1088 }
316670eb
A
1089 result = ENOBUFS;
1090 goto end;
9bccf70c 1091 }
0a7de745 1092 if (!d0) {
9bccf70c 1093 d0 = d;
0a7de745
A
1094 }
1095 if (dp) {
9bccf70c 1096 dp->m_next = d;
0a7de745 1097 }
316670eb
A
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
9bccf70c 1104 d->m_len = 0;
f427ee49 1105 d->m_len = (int)((M_TRAILINGSPACE(d) / blocklen) * blocklen);
0a7de745 1106 if (d->m_len > i) {
9bccf70c 1107 d->m_len = i;
0a7de745 1108 }
9bccf70c
A
1109 dn = 0;
1110 }
1c79356b 1111
9bccf70c
A
1112 /* xor */
1113 p = ivp ? ivp : iv;
1114 q = sp;
0a7de745 1115 for (i = 0; i < blocklen; i++) {
9bccf70c 1116 q[i] ^= p[i];
0a7de745 1117 }
1c79356b 1118
9bccf70c 1119 /* encrypt */
316670eb
A
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
9bccf70c 1129 (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
1c79356b 1130
316670eb
A
1131 // update unaligned pointers
1132 if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
1133 sp = sp_unaligned;
1134 }
1135
9bccf70c
A
1136 /* next iv */
1137 ivp = mtod(d, u_int8_t *) + dn;
1c79356b 1138
9bccf70c
A
1139 sn += blocklen;
1140 dn += blocklen;
1c79356b 1141
9bccf70c
A
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;
1c79356b 1147 }
1c79356b 1148 }
9bccf70c
A
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));
fe8ab488 1156 bzero(sbuf, blocklen);
9bccf70c
A
1157
1158 key_sa_stir_iv(sav);
316670eb 1159end:
0a7de745 1160 if (sbuf != NULL) {
316670eb 1161 FREE(sbuf, M_SECA);
0a7de745 1162 }
316670eb 1163 return result;
1c79356b
A
1164}
1165
1166/*------------------------------------------------------------*/
1167
9bccf70c 1168/* does not free m0 on error */
1c79356b 1169int
39037602
A
1170esp_auth(
1171 struct mbuf *m0,
0a7de745
A
1172 size_t skip, /* offset to ESP header */
1173 size_t length, /* payload length */
39037602
A
1174 struct secasvar *sav,
1175 u_char *sum)
1c79356b
A
1176{
1177 struct mbuf *m;
1178 size_t off;
1179 struct ah_algorithm_state s;
316670eb 1180 u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4)));
9bccf70c 1181 const struct ah_algorithm *algo;
1c79356b 1182 size_t siz;
9bccf70c 1183 int error;
1c79356b
A
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 }
55e303ae 1195
0a7de745 1196 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_START, skip, length, 0, 0, 0);
1c79356b
A
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"));
0a7de745 1203 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 1, 0, 0, 0, 0);
1c79356b
A
1204 return EINVAL;
1205 }
1206 if (!sav) {
1207 ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));
0a7de745 1208 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 2, 0, 0, 0, 0);
1c79356b
A
1209 return EINVAL;
1210 }
9bccf70c
A
1211 algo = ah_algorithm_lookup(sav->alg_auth);
1212 if (!algo) {
1c79356b
A
1213 ipseclog((LOG_ERR,
1214 "esp_auth: bad ESP auth algorithm passed: %d\n",
1215 sav->alg_auth));
0a7de745 1216 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 3, 0, 0, 0, 0);
1c79356b
A
1217 return EINVAL;
1218 }
1219
1220 m = m0;
1221 off = 0;
1222
1c79356b
A
1223 siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1));
1224 if (sizeof(sumbuf) < siz) {
1225 ipseclog((LOG_DEBUG,
94ff46dc 1226 "esp_auth: AH_MAXSUMSIZE is too small: siz=%u\n",
b0d623f7 1227 (u_int32_t)siz));
0a7de745 1228 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 4, 0, 0, 0, 0);
1c79356b
A
1229 return EINVAL;
1230 }
1231
1232 /* skip the header */
1233 while (skip) {
0a7de745 1234 if (!m) {
1c79356b 1235 panic("mbuf chain?");
0a7de745 1236 }
1c79356b
A
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
9bccf70c 1247 error = (*algo->init)(&s, sav);
55e303ae 1248 if (error) {
0a7de745 1249 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 5, 0, 0, 0, 0);
9bccf70c 1250 return error;
55e303ae 1251 }
1c79356b 1252 while (0 < length) {
0a7de745 1253 if (!m) {
1c79356b 1254 panic("mbuf chain?");
0a7de745 1255 }
1c79356b
A
1256
1257 if (m->m_len - off < length) {
b0d623f7 1258 (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off),
0a7de745 1259 m->m_len - off);
1c79356b
A
1260 length -= m->m_len - off;
1261 m = m->m_next;
1262 off = 0;
1263 } else {
b0d623f7 1264 (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off), length);
1c79356b
A
1265 break;
1266 }
1267 }
6d2010ae 1268 (*algo->result)(&s, (caddr_t) sumbuf, sizeof(sumbuf));
0a7de745
A
1269 bcopy(sumbuf, sum, siz); /*XXX*/
1270 KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 6, 0, 0, 0, 0);
1c79356b
A
1271 return 0;
1272}
cb323159
A
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}