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