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