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
29/*	$FreeBSD: src/sys/netinet6/esp_core.c,v 1.1.2.4 2002/03/26 10:12:29 ume Exp $	*/
30/*	$KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $	*/
31
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 *    may be used to endorse or promote products derived from this software
46 *    without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61#define _IP_VHL
62
63#include <sys/param.h>
64#include <sys/systm.h>
65#include <sys/malloc.h>
66#include <sys/mbuf.h>
67#include <sys/domain.h>
68#include <sys/protosw.h>
69#include <sys/socket.h>
70#include <sys/errno.h>
71#include <sys/time.h>
72#include <sys/kernel.h>
73#include <sys/syslog.h>
74
75#include <kern/locks.h>
76
77#include <net/if.h>
78#include <net/route.h>
79
80#include <netinet/in.h>
81#include <netinet/in_var.h>
82#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>
89#if INET6
90#include <netinet6/ipsec6.h>
91#endif
92#include <netinet6/ah.h>
93#if INET6
94#include <netinet6/ah6.h>
95#endif
96#include <netinet6/esp.h>
97#if INET6
98#include <netinet6/esp6.h>
99#endif
100#include <netinet6/esp_rijndael.h>
101#include <net/pfkeyv2.h>
102#include <netkey/keydb.h>
103#include <netkey/key.h>
104#include <libkern/crypto/des.h>
105
106#include <net/net_osdep.h>
107
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))
112#define MAX_SBUF_LEN            2000
113
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 *);
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);
145
146#define MAXIVLEN	16
147
148static const struct esp_algorithm des_cbc =
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,
153		esp_des_blockdecrypt, esp_des_blockencrypt, };
154static const struct esp_algorithm des3_cbc =
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,
159		esp_3des_blockdecrypt, esp_3des_blockencrypt, };
160static const struct esp_algorithm null_esp =
161	{ 1, 0, esp_null_mature, 0, 2048, 0, "null",
162		esp_common_ivlen, esp_null_decrypt,
163		esp_null_encrypt, NULL, NULL, NULL };
164static const struct esp_algorithm aes_cbc =
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,
169		0, 0 };
170
171static const struct esp_algorithm *esp_algorithms[] = {
172	&des_cbc,
173	&des3_cbc,
174	&null_esp,
175	&aes_cbc
176};
177
178const struct esp_algorithm *
179esp_algorithm_lookup(idx)
180	int idx;
181{
182	switch (idx) {
183	case SADB_EALG_DESCBC:
184		return &des_cbc;
185	case SADB_EALG_3DESCBC:
186		return &des3_cbc;
187	case SADB_EALG_NULL:
188		return &null_esp;
189	case SADB_X_EALG_RIJNDAELCBC:
190		return &aes_cbc;
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++) {
205		if (esp_algorithms[idx]->ivlenval > ivlen)
206			ivlen = esp_algorithms[idx]->ivlenval;
207	}
208
209	return ivlen;
210}
211
212int
213esp_schedule(algo, sav)
214	const struct esp_algorithm *algo;
215	struct secasvar *sav;
216{
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
229	lck_mtx_lock(sadb_mutex);
230	/* already allocated */
231	if (sav->sched && sav->schedlen != 0) {
232		lck_mtx_unlock(sadb_mutex);
233		return 0;
234	}
235	/* no schedule necessary */
236	if (!algo->schedule || !algo->schedlen) {
237		lck_mtx_unlock(sadb_mutex);
238		return 0;
239	}
240
241	sav->schedlen = (*algo->schedlen)(algo);
242	if ((signed) sav->schedlen < 0) {
243		lck_mtx_unlock(sadb_mutex);
244		return EINVAL;
245	}
246
247//#### that malloc should be replaced by a saved buffer...
248	sav->sched = _MALLOC(sav->schedlen, M_SECA, M_DONTWAIT);
249	if (!sav->sched) {
250		sav->schedlen = 0;
251		lck_mtx_unlock(sadb_mutex);
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));
259		bzero(sav->sched, sav->schedlen);
260		FREE(sav->sched, M_SECA);
261		sav->sched = NULL;
262		sav->schedlen = 0;
263	}
264	lck_mtx_unlock(sadb_mutex);
265	return error;
266}
267
268static int
269esp_null_mature(
270	__unused struct secasvar *sav)
271{
272
273	/* anything is okay */
274	return 0;
275}
276
277static int
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)
284{
285
286	return 0; /* do nothing */
287}
288
289static int
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)
297{
298
299	return 0; /* do nothing */
300}
301
302static int
303esp_descbc_mature(sav)
304	struct secasvar *sav;
305{
306	const struct esp_algorithm *algo;
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	}
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) {
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 */
335	if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) {
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
345esp_descbc_ivlen(
346	__unused const struct esp_algorithm *algo,
347	struct secasvar *sav)
348{
349
350	if (!sav)
351		return 8;
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;
357}
358
359static int
360esp_des_schedlen(
361	__unused const struct esp_algorithm *algo)
362{
363	return sizeof(des_ecb_key_schedule);
364}
365
366static int
367esp_des_schedule(
368	__unused const struct esp_algorithm *algo,
369	struct secasvar *sav)
370{
371
372	lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
373	if (des_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
374	    (des_ecb_key_schedule *)sav->sched))
375		return EINVAL;
376	else
377		return 0;
378}
379
380static int
381esp_des_blockdecrypt(
382	__unused const struct esp_algorithm *algo,
383	struct secasvar *sav,
384	u_int8_t *s,
385	u_int8_t *d)
386{
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,
390	    (des_ecb_key_schedule *)sav->sched, DES_DECRYPT);
391	return 0;
392}
393
394static int
395esp_des_blockencrypt(
396	__unused const struct esp_algorithm *algo,
397	struct secasvar *sav,
398	u_int8_t *s,
399	u_int8_t *d)
400{
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,
404	    (des_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
405	return 0;
406}
407
408static int
409esp_cbc_mature(sav)
410	struct secasvar *sav;
411{
412	int keylen;
413	const struct esp_algorithm *algo;
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) {
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) {
433		ipseclog((LOG_ERR,
434		    "esp_cbc_mature: unsupported algorithm.\n"));
435		return 1;
436	}
437
438	keylen = sav->key_enc->sadb_key_bits;
439	if (keylen < algo->keymin || algo->keymax < keylen) {
440		ipseclog((LOG_ERR,
441		    "esp_cbc_mature %s: invalid key length %d.\n",
442		    algo->name, sav->key_enc->sadb_key_bits));
443		return 1;
444	}
445	switch (sav->alg_enc) {
446	case SADB_EALG_3DESCBC:
447		/* weak key check */
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))) {
451			ipseclog((LOG_ERR,
452			    "esp_cbc_mature %s: weak key was passed.\n",
453			    algo->name));
454			return 1;
455		}
456		break;
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		}
465		break;
466	}
467
468	return 0;
469}
470
471static int
472esp_3des_schedlen(
473	__unused const struct esp_algorithm *algo)
474{
475
476	return sizeof(des3_ecb_key_schedule);
477}
478
479static int
480esp_3des_schedule(
481	__unused const struct esp_algorithm *algo,
482	struct secasvar *sav)
483{
484	lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
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;
491}
492
493static int
494esp_3des_blockdecrypt(
495	__unused const struct esp_algorithm *algo,
496	struct secasvar *sav,
497	u_int8_t *s,
498	u_int8_t *d)
499{
500	/* assumption: d has a good alignment */
501	bcopy(s, d, sizeof(DES_LONG) * 2);
502	des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
503			 (des3_ecb_key_schedule *)sav->sched, DES_DECRYPT);
504	return 0;
505}
506
507static int
508esp_3des_blockencrypt(
509	__unused const struct esp_algorithm *algo,
510	struct secasvar *sav,
511	u_int8_t *s,
512	u_int8_t *d)
513{
514	/* assumption: d has a good alignment */
515	bcopy(s, d, sizeof(DES_LONG) * 2);
516	des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
517			 (des3_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
518	return 0;
519}
520
521static int
522esp_common_ivlen(
523	const struct esp_algorithm *algo,
524	__unused struct secasvar *sav)
525{
526
527	if (!algo)
528		panic("esp_common_ivlen: unknown algorithm");
529	return algo->ivlenval;
530}
531
532static int
533esp_cbc_decrypt(m, off, sav, algo, ivlen)
534	struct mbuf *m;
535	size_t off;
536	struct secasvar *sav;
537	const struct esp_algorithm *algo;
538	int ivlen;
539{
540	struct mbuf *s;
541	struct mbuf *d, *d0, *dp;
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 */
544	size_t ivoff, bodyoff;
545	u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
546	u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
547	u_int8_t *p, *q;
548	struct mbuf *scut;
549	int scutoff;
550	int i, result = 0;
551	int blocklen;
552	int derived;
553
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);
558		return EINVAL;
559	}
560
561	/* assumes blocklen == padbound */
562	blocklen = algo->padbound;
563
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);
569		return EINVAL;
570	}
571#endif
572
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		}
594	}
595
596	/* grab iv */
597	m_copydata(m, ivoff, ivlen, (caddr_t) iv);
598
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);
613		return EINVAL;
614	}
615
616	if (m->m_pkthdr.len < bodyoff) {
617		ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n",
618		    algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
619		m_freem(m);
620		return EINVAL;
621	}
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);
627		return EINVAL;
628	}
629
630	s = m;
631	d = d0 = dp = NULL;
632	soff = doff = sn = dn = 0;
633	ivp = sp = NULL;
634
635	/* skip bodyoff */
636	while (soff < bodyoff) {
637		if (soff + s->m_len > bodyoff) {
638			sn = bodyoff - soff;
639			break;
640		}
641
642		soff += s->m_len;
643		s = s->m_next;
644	}
645	scut = s;
646	scutoff = sn;
647
648	/* skip over empty mbuf */
649	while (s && s->m_len == 0)
650		s = s->m_next;
651
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;
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 */
663			m_copydata(s, sn, blocklen, (caddr_t) sbuf);
664			sp = sbuf;
665		}
666
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);
684				result = ENOBUFS;
685				goto end;
686			}
687			if (!d0)
688				d0 = d;
689			if (dp)
690				dp->m_next = d;
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
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		}
703
704		/* decrypt */
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
714		(*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
715
716		// update unaligned pointers
717		if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
718			sp = sp_unaligned;
719		}
720
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];
726
727		/* next iv */
728		if (sp == sbuf) {
729			bcopy(sbuf, iv, blocklen);
730			ivp = NULL;
731		} else
732			ivp = sp;
733
734		sn += blocklen;
735		dn += blocklen;
736
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		}
743	}
744
745	m_freem(scut->m_next);
746	scut->m_len = scutoff;
747	scut->m_next = d0;
748
749	/* just in case */
750	bzero(iv, sizeof(iv));
751	bzero(sbuf, blocklen);
752end:
753	if (sbuf != NULL)
754		FREE(sbuf, M_SECA);
755	return result;
756}
757
758static int
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)
766{
767	struct mbuf *s;
768	struct mbuf *d, *d0, *dp;
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 */
771	size_t ivoff, bodyoff;
772	u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
773	u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
774	u_int8_t *p, *q;
775	struct mbuf *scut;
776	int scutoff;
777	int i, result = 0;
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);
785		return EINVAL;
786	}
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);
796		return EINVAL;
797	}
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)
825		m_copydata(m, ivoff, ivlen, (caddr_t) iv);
826	else {
827		bcopy(sav->iv, iv, ivlen);
828		/* maybe it is better to overwrite dest, not source */
829		m_copyback(m, ivoff, ivlen, (caddr_t) iv);
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);
846		return EINVAL;
847	}
848
849	if (m->m_pkthdr.len < bodyoff) {
850		ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n",
851		    algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
852		m_freem(m);
853		return EINVAL;
854	}
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",
858		    algo->name, (u_int32_t)algo->padbound));
859		m_freem(m);
860		return EINVAL;
861	}
862
863	s = m;
864	d = d0 = dp = NULL;
865	soff = doff = sn = dn = 0;
866	ivp = sp = NULL;
867
868	/* skip bodyoff */
869	while (soff < bodyoff) {
870		if (soff + s->m_len > bodyoff) {
871			sn = bodyoff - soff;
872			break;
873		}
874
875		soff += s->m_len;
876		s = s->m_next;
877	}
878	scut = s;
879	scutoff = sn;
880
881	/* skip over empty mbuf */
882	while (s && s->m_len == 0)
883		s = s->m_next;
884
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;
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 */
896			m_copydata(s, sn, blocklen, (caddr_t) sbuf);
897			sp = sbuf;
898		}
899
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);
917				result = ENOBUFS;
918				goto end;
919			}
920			if (!d0)
921				d0 = d;
922			if (dp)
923				dp->m_next = d;
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
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		}
936
937		/* xor */
938		p = ivp ? ivp : iv;
939		q = sp;
940		for (i = 0; i < blocklen; i++)
941			q[i] ^= p[i];
942
943		/* encrypt */
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
953		(*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
954
955		// update unaligned pointers
956		if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
957			sp = sp_unaligned;
958		}
959
960		/* next iv */
961		ivp = mtod(d, u_int8_t *) + dn;
962
963		sn += blocklen;
964		dn += blocklen;
965
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;
971		}
972	}
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, blocklen);
981
982	key_sa_stir_iv(sav);
983end:
984	if (sbuf != NULL)
985		FREE(sbuf, M_SECA);
986	return result;
987}
988
989/*------------------------------------------------------------*/
990
991/* does not free m0 on error */
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;
1003	u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4)));
1004	const struct ah_algorithm *algo;
1005	size_t siz;
1006	int error;
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	}
1018
1019	KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_START, skip,length,0,0,0);
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"));
1026		KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 1,0,0,0,0);
1027		return EINVAL;
1028	}
1029	if (!sav) {
1030		ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));
1031		KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 2,0,0,0,0);
1032		return EINVAL;
1033	}
1034	algo = ah_algorithm_lookup(sav->alg_auth);
1035	if (!algo) {
1036		ipseclog((LOG_ERR,
1037		    "esp_auth: bad ESP auth algorithm passed: %d\n",
1038		    sav->alg_auth));
1039		KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 3,0,0,0,0);
1040		return EINVAL;
1041	}
1042
1043	m = m0;
1044	off = 0;
1045
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",
1050		    (u_int32_t)siz));
1051		KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 4,0,0,0,0);
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
1069	error = (*algo->init)(&s, sav);
1070	if (error) {
1071		KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 5,0,0,0,0);
1072		return error;
1073	}
1074	while (0 < length) {
1075		if (!m)
1076			panic("mbuf chain?");
1077
1078		if (m->m_len - off < length) {
1079			(*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off),
1080				m->m_len - off);
1081			length -= m->m_len - off;
1082			m = m->m_next;
1083			off = 0;
1084		} else {
1085			(*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off), length);
1086			break;
1087		}
1088	}
1089	(*algo->result)(&s, (caddr_t) sumbuf, sizeof(sumbuf));
1090	bcopy(sumbuf, sum, siz);	/*XXX*/
1091	KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 6,0,0,0,0);
1092	return 0;
1093}
1094