xref: /xnu-11215.61.5/bsd/netinet6/ah_core.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1*4f1223e8SApple OSS Distributions /*
2*4f1223e8SApple OSS Distributions  * Copyright (c) 2008-2021, 2023 Apple Inc. All rights reserved.
3*4f1223e8SApple OSS Distributions  *
4*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*4f1223e8SApple OSS Distributions  *
6*4f1223e8SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*4f1223e8SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*4f1223e8SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*4f1223e8SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*4f1223e8SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*4f1223e8SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*4f1223e8SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*4f1223e8SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*4f1223e8SApple OSS Distributions  *
15*4f1223e8SApple OSS Distributions  * Please obtain a copy of the License at
16*4f1223e8SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*4f1223e8SApple OSS Distributions  *
18*4f1223e8SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*4f1223e8SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*4f1223e8SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*4f1223e8SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*4f1223e8SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*4f1223e8SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*4f1223e8SApple OSS Distributions  * limitations under the License.
25*4f1223e8SApple OSS Distributions  *
26*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*4f1223e8SApple OSS Distributions  */
28*4f1223e8SApple OSS Distributions 
29*4f1223e8SApple OSS Distributions /*	$FreeBSD: src/sys/netinet6/ah_core.c,v 1.2.2.4 2001/07/03 11:01:49 ume Exp $	*/
30*4f1223e8SApple OSS Distributions /*	$KAME: ah_core.c,v 1.44 2001/03/12 11:24:39 itojun Exp $	*/
31*4f1223e8SApple OSS Distributions 
32*4f1223e8SApple OSS Distributions /*
33*4f1223e8SApple OSS Distributions  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34*4f1223e8SApple OSS Distributions  * All rights reserved.
35*4f1223e8SApple OSS Distributions  *
36*4f1223e8SApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
37*4f1223e8SApple OSS Distributions  * modification, are permitted provided that the following conditions
38*4f1223e8SApple OSS Distributions  * are met:
39*4f1223e8SApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
40*4f1223e8SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
41*4f1223e8SApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
42*4f1223e8SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
43*4f1223e8SApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
44*4f1223e8SApple OSS Distributions  * 3. Neither the name of the project nor the names of its contributors
45*4f1223e8SApple OSS Distributions  *    may be used to endorse or promote products derived from this software
46*4f1223e8SApple OSS Distributions  *    without specific prior written permission.
47*4f1223e8SApple OSS Distributions  *
48*4f1223e8SApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49*4f1223e8SApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50*4f1223e8SApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51*4f1223e8SApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52*4f1223e8SApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53*4f1223e8SApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54*4f1223e8SApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55*4f1223e8SApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56*4f1223e8SApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57*4f1223e8SApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58*4f1223e8SApple OSS Distributions  * SUCH DAMAGE.
59*4f1223e8SApple OSS Distributions  */
60*4f1223e8SApple OSS Distributions 
61*4f1223e8SApple OSS Distributions /*
62*4f1223e8SApple OSS Distributions  * RFC1826/2402 authentication header.
63*4f1223e8SApple OSS Distributions  */
64*4f1223e8SApple OSS Distributions 
65*4f1223e8SApple OSS Distributions /* TODO: have shared routines  for hmac-* algorithms */
66*4f1223e8SApple OSS Distributions 
67*4f1223e8SApple OSS Distributions #include <sys/param.h>
68*4f1223e8SApple OSS Distributions #include <sys/systm.h>
69*4f1223e8SApple OSS Distributions #include <sys/malloc.h>
70*4f1223e8SApple OSS Distributions #include <sys/mbuf.h>
71*4f1223e8SApple OSS Distributions #include <sys/domain.h>
72*4f1223e8SApple OSS Distributions #include <sys/protosw.h>
73*4f1223e8SApple OSS Distributions #include <sys/socket.h>
74*4f1223e8SApple OSS Distributions #include <sys/socketvar.h>
75*4f1223e8SApple OSS Distributions #include <sys/errno.h>
76*4f1223e8SApple OSS Distributions #include <sys/time.h>
77*4f1223e8SApple OSS Distributions #include <sys/syslog.h>
78*4f1223e8SApple OSS Distributions 
79*4f1223e8SApple OSS Distributions #include <net/if.h>
80*4f1223e8SApple OSS Distributions #include <net/route.h>
81*4f1223e8SApple OSS Distributions 
82*4f1223e8SApple OSS Distributions #include <netinet/in.h>
83*4f1223e8SApple OSS Distributions #include <netinet/in_systm.h>
84*4f1223e8SApple OSS Distributions #include <netinet/ip.h>
85*4f1223e8SApple OSS Distributions #include <netinet/in_var.h>
86*4f1223e8SApple OSS Distributions 
87*4f1223e8SApple OSS Distributions #include <netinet/ip6.h>
88*4f1223e8SApple OSS Distributions #include <netinet6/ip6_var.h>
89*4f1223e8SApple OSS Distributions #include <netinet/icmp6.h>
90*4f1223e8SApple OSS Distributions 
91*4f1223e8SApple OSS Distributions #include <netinet6/ipsec.h>
92*4f1223e8SApple OSS Distributions #include <netinet6/ipsec6.h>
93*4f1223e8SApple OSS Distributions #include <netinet6/ah.h>
94*4f1223e8SApple OSS Distributions #include <netinet6/ah6.h>
95*4f1223e8SApple OSS Distributions #if IPSEC_ESP
96*4f1223e8SApple OSS Distributions #include <netinet6/esp.h>
97*4f1223e8SApple OSS Distributions #include <netinet6/esp6.h>
98*4f1223e8SApple OSS Distributions #endif
99*4f1223e8SApple OSS Distributions #include <net/pfkeyv2.h>
100*4f1223e8SApple OSS Distributions #include <netkey/key.h>
101*4f1223e8SApple OSS Distributions #include <netkey/keydb.h>
102*4f1223e8SApple OSS Distributions #include <libkern/crypto/crypto_internal.h>
103*4f1223e8SApple OSS Distributions #include <libkern/crypto/md5.h>
104*4f1223e8SApple OSS Distributions #include <libkern/crypto/sha1.h>
105*4f1223e8SApple OSS Distributions #include <libkern/crypto/sha2.h>
106*4f1223e8SApple OSS Distributions 
107*4f1223e8SApple OSS Distributions #include <net/net_osdep.h>
108*4f1223e8SApple OSS Distributions 
109*4f1223e8SApple OSS Distributions static int ah_hmac_mature(struct secasvar *);
110*4f1223e8SApple OSS Distributions static int ah_hmac_state_init(struct ah_algorithm_state *, struct secasvar *);
111*4f1223e8SApple OSS Distributions static size_t ah_hmac_schedlen(const struct ah_algorithm *);
112*4f1223e8SApple OSS Distributions static int ah_hmac_schedule(const struct ah_algorithm *, struct secasvar *);
113*4f1223e8SApple OSS Distributions static void ah_hmac_loop(struct ah_algorithm_state *,
114*4f1223e8SApple OSS Distributions     caddr_t __sized_by(len), size_t len);
115*4f1223e8SApple OSS Distributions static void ah_hmac_result(struct ah_algorithm_state *,
116*4f1223e8SApple OSS Distributions     caddr_t __sized_by(len), size_t len);
117*4f1223e8SApple OSS Distributions 
118*4f1223e8SApple OSS Distributions static int ah_sumsiz_1216(struct secasvar *);
119*4f1223e8SApple OSS Distributions static const struct ccdigest_info *ah_digest_md5(void);
120*4f1223e8SApple OSS Distributions static const struct ccdigest_info *ah_digest_sha1(void);
121*4f1223e8SApple OSS Distributions #if AH_ALL_CRYPTO
122*4f1223e8SApple OSS Distributions static int ah_sumsiz_sha2_256(struct secasvar *);
123*4f1223e8SApple OSS Distributions static const struct ccdigest_info *ah_digest_sha2_256(void);
124*4f1223e8SApple OSS Distributions static int ah_sumsiz_sha2_384(struct secasvar *);
125*4f1223e8SApple OSS Distributions static const struct ccdigest_info *ah_digest_sha2_384(void);
126*4f1223e8SApple OSS Distributions static int ah_sumsiz_sha2_512(struct secasvar *);
127*4f1223e8SApple OSS Distributions static const struct ccdigest_info *ah_digest_sha2_512(void);
128*4f1223e8SApple OSS Distributions #endif /* AH_ALL_CRYPTO */
129*4f1223e8SApple OSS Distributions 
130*4f1223e8SApple OSS Distributions static int ah_sumsiz_zero(struct secasvar *);
131*4f1223e8SApple OSS Distributions static int ah_none_mature(struct secasvar *);
132*4f1223e8SApple OSS Distributions static int ah_none_init(struct ah_algorithm_state *, struct secasvar *);
133*4f1223e8SApple OSS Distributions static void ah_none_loop(struct ah_algorithm_state *,
134*4f1223e8SApple OSS Distributions     caddr_t __sized_by(len), size_t len);
135*4f1223e8SApple OSS Distributions static void ah_none_result(struct ah_algorithm_state *,
136*4f1223e8SApple OSS Distributions     caddr_t __sized_by(len), size_t len);
137*4f1223e8SApple OSS Distributions 
138*4f1223e8SApple OSS Distributions static void ah_update_mbuf(struct mbuf *, int, int,
139*4f1223e8SApple OSS Distributions     const struct ah_algorithm *, struct ah_algorithm_state *);
140*4f1223e8SApple OSS Distributions 
141*4f1223e8SApple OSS Distributions /*
142*4f1223e8SApple OSS Distributions  * If any algorithm requires more than 2048 bits (256 bytes) of key material,
143*4f1223e8SApple OSS Distributions  * update IPSEC_KEY_AUTH_MAX_BYTES in ipsec.h
144*4f1223e8SApple OSS Distributions  */
145*4f1223e8SApple OSS Distributions const struct ah_algorithm *
ah_algorithm_lookup(int idx)146*4f1223e8SApple OSS Distributions ah_algorithm_lookup(int idx)
147*4f1223e8SApple OSS Distributions {
148*4f1223e8SApple OSS Distributions 	/* checksum algorithms */
149*4f1223e8SApple OSS Distributions 	static const struct ah_algorithm hmac_md5 =
150*4f1223e8SApple OSS Distributions 	{ ah_sumsiz_1216, ah_hmac_mature,
151*4f1223e8SApple OSS Distributions 	  128, 128, "hmac-md5", ah_hmac_state_init,
152*4f1223e8SApple OSS Distributions 	  ah_hmac_loop, ah_hmac_result, ah_digest_md5,
153*4f1223e8SApple OSS Distributions 	  ah_hmac_schedlen, ah_hmac_schedule, };
154*4f1223e8SApple OSS Distributions 	static const struct ah_algorithm hmac_sha1 =
155*4f1223e8SApple OSS Distributions 	{ ah_sumsiz_1216, ah_hmac_mature,
156*4f1223e8SApple OSS Distributions 	  160, 160, "hmac-sha1", ah_hmac_state_init,
157*4f1223e8SApple OSS Distributions 	  ah_hmac_loop, ah_hmac_result, ah_digest_sha1,
158*4f1223e8SApple OSS Distributions 	  ah_hmac_schedlen, ah_hmac_schedule, };
159*4f1223e8SApple OSS Distributions 	static const struct ah_algorithm ah_none =
160*4f1223e8SApple OSS Distributions 	{ ah_sumsiz_zero, ah_none_mature,
161*4f1223e8SApple OSS Distributions 	  0, 2048, "none", ah_none_init,
162*4f1223e8SApple OSS Distributions 	  ah_none_loop, ah_none_result,
163*4f1223e8SApple OSS Distributions 	  NULL, NULL, NULL, };
164*4f1223e8SApple OSS Distributions #if AH_ALL_CRYPTO
165*4f1223e8SApple OSS Distributions 	static const struct ah_algorithm hmac_sha2_256 =
166*4f1223e8SApple OSS Distributions 	{ ah_sumsiz_sha2_256, ah_hmac_mature,
167*4f1223e8SApple OSS Distributions 	  256, 256, "hmac-sha2-256", ah_hmac_state_init,
168*4f1223e8SApple OSS Distributions 	  ah_hmac_loop, ah_hmac_result, ah_digest_sha2_256,
169*4f1223e8SApple OSS Distributions 	  ah_hmac_schedlen, ah_hmac_schedule, };
170*4f1223e8SApple OSS Distributions 	static const struct ah_algorithm hmac_sha2_384 =
171*4f1223e8SApple OSS Distributions 	{ ah_sumsiz_sha2_384, ah_hmac_mature,
172*4f1223e8SApple OSS Distributions 	  384, 384, "hmac-sha2-384", ah_hmac_state_init,
173*4f1223e8SApple OSS Distributions 	  ah_hmac_loop, ah_hmac_result, ah_digest_sha2_384,
174*4f1223e8SApple OSS Distributions 	  ah_hmac_schedlen, ah_hmac_schedule, };
175*4f1223e8SApple OSS Distributions 	static const struct ah_algorithm hmac_sha2_512 =
176*4f1223e8SApple OSS Distributions 	{ ah_sumsiz_sha2_512, ah_hmac_mature,
177*4f1223e8SApple OSS Distributions 	  512, 512, "hmac-sha2-512", ah_hmac_state_init,
178*4f1223e8SApple OSS Distributions 	  ah_hmac_loop, ah_hmac_result, ah_digest_sha2_512,
179*4f1223e8SApple OSS Distributions 	  ah_hmac_schedlen, ah_hmac_schedule, };
180*4f1223e8SApple OSS Distributions #endif /* AH_ALL_CRYPTO */
181*4f1223e8SApple OSS Distributions 
182*4f1223e8SApple OSS Distributions 	switch (idx) {
183*4f1223e8SApple OSS Distributions 	case SADB_AALG_MD5HMAC:
184*4f1223e8SApple OSS Distributions 		return &hmac_md5;
185*4f1223e8SApple OSS Distributions 	case SADB_AALG_SHA1HMAC:
186*4f1223e8SApple OSS Distributions 		return &hmac_sha1;
187*4f1223e8SApple OSS Distributions 	case SADB_X_AALG_NULL:
188*4f1223e8SApple OSS Distributions 		return &ah_none;
189*4f1223e8SApple OSS Distributions #if AH_ALL_CRYPTO
190*4f1223e8SApple OSS Distributions 	case SADB_X_AALG_SHA2_256:
191*4f1223e8SApple OSS Distributions 		return &hmac_sha2_256;
192*4f1223e8SApple OSS Distributions 	case SADB_X_AALG_SHA2_384:
193*4f1223e8SApple OSS Distributions 		return &hmac_sha2_384;
194*4f1223e8SApple OSS Distributions 	case SADB_X_AALG_SHA2_512:
195*4f1223e8SApple OSS Distributions 		return &hmac_sha2_512;
196*4f1223e8SApple OSS Distributions #endif /* AH_ALL_CRYPTO */
197*4f1223e8SApple OSS Distributions 	default:
198*4f1223e8SApple OSS Distributions 		return NULL;
199*4f1223e8SApple OSS Distributions 	}
200*4f1223e8SApple OSS Distributions }
201*4f1223e8SApple OSS Distributions 
202*4f1223e8SApple OSS Distributions int
ah_schedule(const struct ah_algorithm * algo,struct secasvar * sav)203*4f1223e8SApple OSS Distributions ah_schedule(
204*4f1223e8SApple OSS Distributions 	const struct ah_algorithm *algo,
205*4f1223e8SApple OSS Distributions 	struct secasvar *sav)
206*4f1223e8SApple OSS Distributions {
207*4f1223e8SApple OSS Distributions 	void *sched = NULL;
208*4f1223e8SApple OSS Distributions 	size_t schedlen = 0;
209*4f1223e8SApple OSS Distributions 	int error;
210*4f1223e8SApple OSS Distributions 
211*4f1223e8SApple OSS Distributions 	lck_mtx_lock(sadb_mutex);
212*4f1223e8SApple OSS Distributions 	/* already allocated */
213*4f1223e8SApple OSS Distributions 	if (sav->sched_auth != NULL && sav->schedlen_auth != 0) {
214*4f1223e8SApple OSS Distributions 		lck_mtx_unlock(sadb_mutex);
215*4f1223e8SApple OSS Distributions 		return 0;
216*4f1223e8SApple OSS Distributions 	}
217*4f1223e8SApple OSS Distributions 
218*4f1223e8SApple OSS Distributions 	/* no schedule necessary */
219*4f1223e8SApple OSS Distributions 	if (algo->schedule == NULL || algo->schedlen == NULL) {
220*4f1223e8SApple OSS Distributions 		lck_mtx_unlock(sadb_mutex);
221*4f1223e8SApple OSS Distributions 		return 0;
222*4f1223e8SApple OSS Distributions 	}
223*4f1223e8SApple OSS Distributions 
224*4f1223e8SApple OSS Distributions 	schedlen = (*algo->schedlen)(algo);
225*4f1223e8SApple OSS Distributions 	if (__improbable((signed)schedlen < 0)) {
226*4f1223e8SApple OSS Distributions 		lck_mtx_unlock(sadb_mutex);
227*4f1223e8SApple OSS Distributions 		return EINVAL;
228*4f1223e8SApple OSS Distributions 	}
229*4f1223e8SApple OSS Distributions 
230*4f1223e8SApple OSS Distributions 	sched = kalloc_data(schedlen, Z_NOWAIT);
231*4f1223e8SApple OSS Distributions 	if (__improbable(sched == NULL)) {
232*4f1223e8SApple OSS Distributions 		lck_mtx_unlock(sadb_mutex);
233*4f1223e8SApple OSS Distributions 		return ENOBUFS;
234*4f1223e8SApple OSS Distributions 	}
235*4f1223e8SApple OSS Distributions 
236*4f1223e8SApple OSS Distributions 	sav->sched_auth = sched;
237*4f1223e8SApple OSS Distributions 	sav->schedlen_auth = schedlen;
238*4f1223e8SApple OSS Distributions 
239*4f1223e8SApple OSS Distributions 	error = (*algo->schedule)(algo, sav);
240*4f1223e8SApple OSS Distributions 	if (__improbable(error != 0)) {
241*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR, "ah_schedule %s: error %d\n",
242*4f1223e8SApple OSS Distributions 		    algo->name, error));
243*4f1223e8SApple OSS Distributions 		memset(sav->sched_auth, 0, sav->schedlen_auth);
244*4f1223e8SApple OSS Distributions 		kfree_data_sized_by(sav->sched_auth, sav->schedlen_auth);
245*4f1223e8SApple OSS Distributions 	}
246*4f1223e8SApple OSS Distributions 	lck_mtx_unlock(sadb_mutex);
247*4f1223e8SApple OSS Distributions 	return error;
248*4f1223e8SApple OSS Distributions }
249*4f1223e8SApple OSS Distributions 
250*4f1223e8SApple OSS Distributions static int
ah_hmac_mature(struct secasvar * sav)251*4f1223e8SApple OSS Distributions ah_hmac_mature(struct secasvar *sav)
252*4f1223e8SApple OSS Distributions {
253*4f1223e8SApple OSS Distributions 	const struct ah_algorithm *algo;
254*4f1223e8SApple OSS Distributions 
255*4f1223e8SApple OSS Distributions 	if (__improbable(sav->key_auth == NULL)) {
256*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR, "ah_hmac_mature: no key is given.\n"));
257*4f1223e8SApple OSS Distributions 		return 1;
258*4f1223e8SApple OSS Distributions 	}
259*4f1223e8SApple OSS Distributions 
260*4f1223e8SApple OSS Distributions 	algo = ah_algorithm_lookup(sav->alg_auth);
261*4f1223e8SApple OSS Distributions 	if (__improbable(algo == NULL)) {
262*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR, "ah_hmac_mature: unsupported algorithm.\n"));
263*4f1223e8SApple OSS Distributions 		return 1;
264*4f1223e8SApple OSS Distributions 	}
265*4f1223e8SApple OSS Distributions 
266*4f1223e8SApple OSS Distributions 	if (sav->key_auth->sadb_key_bits < algo->keymin
267*4f1223e8SApple OSS Distributions 	    || algo->keymax < sav->key_auth->sadb_key_bits) {
268*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR,
269*4f1223e8SApple OSS Distributions 		    "ah_hmac_mature: invalid key length %d.\n",
270*4f1223e8SApple OSS Distributions 		    sav->key_auth->sadb_key_bits));
271*4f1223e8SApple OSS Distributions 		return 1;
272*4f1223e8SApple OSS Distributions 	}
273*4f1223e8SApple OSS Distributions 
274*4f1223e8SApple OSS Distributions 	return 0;
275*4f1223e8SApple OSS Distributions }
276*4f1223e8SApple OSS Distributions 
277*4f1223e8SApple OSS Distributions static int
ah_hmac_state_init(struct ah_algorithm_state * state,struct secasvar * sav)278*4f1223e8SApple OSS Distributions ah_hmac_state_init(struct ah_algorithm_state *state, struct secasvar *sav)
279*4f1223e8SApple OSS Distributions {
280*4f1223e8SApple OSS Distributions 	if (__improbable(state == NULL || sav == NULL)) {
281*4f1223e8SApple OSS Distributions 		panic("ah_hmac_state_init: what?");
282*4f1223e8SApple OSS Distributions 	}
283*4f1223e8SApple OSS Distributions 
284*4f1223e8SApple OSS Distributions 	const struct ah_algorithm *algo = ah_algorithm_lookup(sav->alg_auth);
285*4f1223e8SApple OSS Distributions 	if (__improbable(algo == NULL)) {
286*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR, "ah_hmac_state_init: unsupported algorithm.\n"));
287*4f1223e8SApple OSS Distributions 		return EINVAL;
288*4f1223e8SApple OSS Distributions 	}
289*4f1223e8SApple OSS Distributions 
290*4f1223e8SApple OSS Distributions 	const size_t schedlen = sav->schedlen_auth;
291*4f1223e8SApple OSS Distributions 	memcpy(state->hmac_ctx, sav->sched_auth, schedlen);
292*4f1223e8SApple OSS Distributions 	state->digest = algo->digest();
293*4f1223e8SApple OSS Distributions 
294*4f1223e8SApple OSS Distributions 	return 0;
295*4f1223e8SApple OSS Distributions }
296*4f1223e8SApple OSS Distributions 
297*4f1223e8SApple OSS Distributions static size_t
ah_hmac_schedlen(const struct ah_algorithm * algo)298*4f1223e8SApple OSS Distributions ah_hmac_schedlen(const struct ah_algorithm *algo)
299*4f1223e8SApple OSS Distributions {
300*4f1223e8SApple OSS Distributions 	return cchmac_di_size(algo->digest());
301*4f1223e8SApple OSS Distributions }
302*4f1223e8SApple OSS Distributions 
303*4f1223e8SApple OSS Distributions static int
ah_hmac_schedule(const struct ah_algorithm * algo,struct secasvar * sav)304*4f1223e8SApple OSS Distributions ah_hmac_schedule(
305*4f1223e8SApple OSS Distributions 	const struct ah_algorithm *algo,
306*4f1223e8SApple OSS Distributions 	struct secasvar *sav)
307*4f1223e8SApple OSS Distributions {
308*4f1223e8SApple OSS Distributions 	const struct ccdigest_info *di = algo->digest();
309*4f1223e8SApple OSS Distributions 	cchmac_ctx_t ctx = (cchmac_ctx_t)sav->sched_auth;
310*4f1223e8SApple OSS Distributions 
311*4f1223e8SApple OSS Distributions 	g_crypto_funcs->cchmac_init_fn(di, ctx,
312*4f1223e8SApple OSS Distributions 	    _KEYLEN(sav->key_auth), _KEYBUF(sav->key_auth));
313*4f1223e8SApple OSS Distributions 
314*4f1223e8SApple OSS Distributions 	return 0;
315*4f1223e8SApple OSS Distributions }
316*4f1223e8SApple OSS Distributions 
317*4f1223e8SApple OSS Distributions static void
ah_hmac_loop(struct ah_algorithm_state * state,caddr_t __sized_by (len)addr,size_t len)318*4f1223e8SApple OSS Distributions ah_hmac_loop(
319*4f1223e8SApple OSS Distributions 	struct ah_algorithm_state *state,
320*4f1223e8SApple OSS Distributions 	caddr_t __sized_by(len)addr, size_t len)
321*4f1223e8SApple OSS Distributions {
322*4f1223e8SApple OSS Distributions 	if (__improbable(state == NULL || state->digest == NULL)) {
323*4f1223e8SApple OSS Distributions 		panic("ah_hmac_loop: what?");
324*4f1223e8SApple OSS Distributions 	}
325*4f1223e8SApple OSS Distributions 
326*4f1223e8SApple OSS Distributions 	VERIFY(len <= UINT_MAX);
327*4f1223e8SApple OSS Distributions 	if (len > 0) {
328*4f1223e8SApple OSS Distributions 		g_crypto_funcs->cchmac_update_fn(state->digest, state->hmac_ctx, len, (void *)addr);
329*4f1223e8SApple OSS Distributions 	}
330*4f1223e8SApple OSS Distributions }
331*4f1223e8SApple OSS Distributions 
332*4f1223e8SApple OSS Distributions static void
ah_hmac_result(struct ah_algorithm_state * state,caddr_t __sized_by (len)addr,size_t len)333*4f1223e8SApple OSS Distributions ah_hmac_result(
334*4f1223e8SApple OSS Distributions 	struct ah_algorithm_state *state,
335*4f1223e8SApple OSS Distributions 	caddr_t __sized_by(len)addr, size_t len)
336*4f1223e8SApple OSS Distributions {
337*4f1223e8SApple OSS Distributions 	if (__improbable(state == NULL || state->digest == NULL)) {
338*4f1223e8SApple OSS Distributions 		panic("ah_hmac_result: what?");
339*4f1223e8SApple OSS Distributions 	}
340*4f1223e8SApple OSS Distributions 
341*4f1223e8SApple OSS Distributions 	const size_t output_size = state->digest->output_size;
342*4f1223e8SApple OSS Distributions 	u_char digest[output_size] __attribute__((aligned(4)));
343*4f1223e8SApple OSS Distributions 
344*4f1223e8SApple OSS Distributions 	g_crypto_funcs->cchmac_final_fn(state->digest, state->hmac_ctx, &digest[0]);
345*4f1223e8SApple OSS Distributions 	cchmac_di_clear(state->digest, state->hmac_ctx);
346*4f1223e8SApple OSS Distributions 	memcpy((void *)addr, &digest[0], sizeof(digest) > len ? len : sizeof(digest));
347*4f1223e8SApple OSS Distributions }
348*4f1223e8SApple OSS Distributions 
349*4f1223e8SApple OSS Distributions static int
ah_sumsiz_1216(struct secasvar * sav)350*4f1223e8SApple OSS Distributions ah_sumsiz_1216(struct secasvar *sav)
351*4f1223e8SApple OSS Distributions {
352*4f1223e8SApple OSS Distributions 	if (!sav) {
353*4f1223e8SApple OSS Distributions 		return -1;
354*4f1223e8SApple OSS Distributions 	}
355*4f1223e8SApple OSS Distributions 	if (sav->flags & SADB_X_EXT_OLD) {
356*4f1223e8SApple OSS Distributions 		return 16;
357*4f1223e8SApple OSS Distributions 	} else {
358*4f1223e8SApple OSS Distributions 		return 12;
359*4f1223e8SApple OSS Distributions 	}
360*4f1223e8SApple OSS Distributions }
361*4f1223e8SApple OSS Distributions 
362*4f1223e8SApple OSS Distributions static const struct ccdigest_info *
ah_digest_md5(void)363*4f1223e8SApple OSS Distributions ah_digest_md5(void)
364*4f1223e8SApple OSS Distributions {
365*4f1223e8SApple OSS Distributions 	return g_crypto_funcs->ccmd5_di;
366*4f1223e8SApple OSS Distributions }
367*4f1223e8SApple OSS Distributions 
368*4f1223e8SApple OSS Distributions static const struct ccdigest_info *
ah_digest_sha1(void)369*4f1223e8SApple OSS Distributions ah_digest_sha1(void)
370*4f1223e8SApple OSS Distributions {
371*4f1223e8SApple OSS Distributions 	return g_crypto_funcs->ccsha1_di;
372*4f1223e8SApple OSS Distributions }
373*4f1223e8SApple OSS Distributions 
374*4f1223e8SApple OSS Distributions #if AH_ALL_CRYPTO
375*4f1223e8SApple OSS Distributions static int
ah_sumsiz_sha2_256(struct secasvar * sav)376*4f1223e8SApple OSS Distributions ah_sumsiz_sha2_256(struct secasvar *sav)
377*4f1223e8SApple OSS Distributions {
378*4f1223e8SApple OSS Distributions 	if (!sav) {
379*4f1223e8SApple OSS Distributions 		return -1;
380*4f1223e8SApple OSS Distributions 	}
381*4f1223e8SApple OSS Distributions 	// return half the output size (in bytes), as per rfc 4868
382*4f1223e8SApple OSS Distributions 	return SHA256_DIGEST_LENGTH / 2;
383*4f1223e8SApple OSS Distributions }
384*4f1223e8SApple OSS Distributions 
385*4f1223e8SApple OSS Distributions static const struct ccdigest_info *
ah_digest_sha2_256(void)386*4f1223e8SApple OSS Distributions ah_digest_sha2_256(void)
387*4f1223e8SApple OSS Distributions {
388*4f1223e8SApple OSS Distributions 	return g_crypto_funcs->ccsha256_di;
389*4f1223e8SApple OSS Distributions }
390*4f1223e8SApple OSS Distributions 
391*4f1223e8SApple OSS Distributions static int
ah_sumsiz_sha2_384(struct secasvar * sav)392*4f1223e8SApple OSS Distributions ah_sumsiz_sha2_384(struct secasvar *sav)
393*4f1223e8SApple OSS Distributions {
394*4f1223e8SApple OSS Distributions 	if (!sav) {
395*4f1223e8SApple OSS Distributions 		return -1;
396*4f1223e8SApple OSS Distributions 	}
397*4f1223e8SApple OSS Distributions 	// return half the output size (in bytes), as per rfc 4868
398*4f1223e8SApple OSS Distributions 	return SHA384_DIGEST_LENGTH / 2;
399*4f1223e8SApple OSS Distributions }
400*4f1223e8SApple OSS Distributions 
401*4f1223e8SApple OSS Distributions static const struct ccdigest_info *
ah_digest_sha2_384(void)402*4f1223e8SApple OSS Distributions ah_digest_sha2_384(void)
403*4f1223e8SApple OSS Distributions {
404*4f1223e8SApple OSS Distributions 	return g_crypto_funcs->ccsha384_di;
405*4f1223e8SApple OSS Distributions }
406*4f1223e8SApple OSS Distributions 
407*4f1223e8SApple OSS Distributions static int
ah_sumsiz_sha2_512(struct secasvar * sav)408*4f1223e8SApple OSS Distributions ah_sumsiz_sha2_512(struct secasvar *sav)
409*4f1223e8SApple OSS Distributions {
410*4f1223e8SApple OSS Distributions 	if (!sav) {
411*4f1223e8SApple OSS Distributions 		return -1;
412*4f1223e8SApple OSS Distributions 	}
413*4f1223e8SApple OSS Distributions 	// return half the output size (in bytes), as per rfc 4868
414*4f1223e8SApple OSS Distributions 	return SHA512_DIGEST_LENGTH / 2;
415*4f1223e8SApple OSS Distributions }
416*4f1223e8SApple OSS Distributions 
417*4f1223e8SApple OSS Distributions static const struct ccdigest_info *
ah_digest_sha2_512(void)418*4f1223e8SApple OSS Distributions ah_digest_sha2_512(void)
419*4f1223e8SApple OSS Distributions {
420*4f1223e8SApple OSS Distributions 	return g_crypto_funcs->ccsha512_di;
421*4f1223e8SApple OSS Distributions }
422*4f1223e8SApple OSS Distributions #endif /* AH_ALL_CRYPTO */
423*4f1223e8SApple OSS Distributions 
424*4f1223e8SApple OSS Distributions static int
ah_sumsiz_zero(struct secasvar * sav)425*4f1223e8SApple OSS Distributions ah_sumsiz_zero(struct secasvar *sav)
426*4f1223e8SApple OSS Distributions {
427*4f1223e8SApple OSS Distributions 	if (!sav) {
428*4f1223e8SApple OSS Distributions 		return -1;
429*4f1223e8SApple OSS Distributions 	}
430*4f1223e8SApple OSS Distributions 	return 0;
431*4f1223e8SApple OSS Distributions }
432*4f1223e8SApple OSS Distributions 
433*4f1223e8SApple OSS Distributions static int
ah_none_mature(struct secasvar * sav)434*4f1223e8SApple OSS Distributions ah_none_mature(struct secasvar *sav)
435*4f1223e8SApple OSS Distributions {
436*4f1223e8SApple OSS Distributions 	if (sav->sah->saidx.proto == IPPROTO_AH) {
437*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR,
438*4f1223e8SApple OSS Distributions 		    "ah_none_mature: protocol and algorithm mismatch.\n"));
439*4f1223e8SApple OSS Distributions 		return 1;
440*4f1223e8SApple OSS Distributions 	}
441*4f1223e8SApple OSS Distributions 	return 0;
442*4f1223e8SApple OSS Distributions }
443*4f1223e8SApple OSS Distributions 
444*4f1223e8SApple OSS Distributions static int
ah_none_init(struct ah_algorithm_state * state,__unused struct secasvar * sav)445*4f1223e8SApple OSS Distributions ah_none_init(
446*4f1223e8SApple OSS Distributions 	struct ah_algorithm_state *state,
447*4f1223e8SApple OSS Distributions 	__unused struct secasvar *sav)
448*4f1223e8SApple OSS Distributions {
449*4f1223e8SApple OSS Distributions 	state->digest = NULL;
450*4f1223e8SApple OSS Distributions 	return 0;
451*4f1223e8SApple OSS Distributions }
452*4f1223e8SApple OSS Distributions 
453*4f1223e8SApple OSS Distributions static void
ah_none_loop(__unused struct ah_algorithm_state * state,__unused caddr_t __sized_by (len)addr,__unused size_t len)454*4f1223e8SApple OSS Distributions ah_none_loop(
455*4f1223e8SApple OSS Distributions 	__unused struct ah_algorithm_state *state,
456*4f1223e8SApple OSS Distributions 	__unused caddr_t __sized_by(len)addr,
457*4f1223e8SApple OSS Distributions 	__unused size_t len)
458*4f1223e8SApple OSS Distributions {
459*4f1223e8SApple OSS Distributions }
460*4f1223e8SApple OSS Distributions 
461*4f1223e8SApple OSS Distributions static void
ah_none_result(__unused struct ah_algorithm_state * state,__unused caddr_t __sized_by (len)addr,__unused size_t len)462*4f1223e8SApple OSS Distributions ah_none_result(
463*4f1223e8SApple OSS Distributions 	__unused struct ah_algorithm_state *state,
464*4f1223e8SApple OSS Distributions 	__unused caddr_t __sized_by(len)addr,
465*4f1223e8SApple OSS Distributions 	__unused size_t len)
466*4f1223e8SApple OSS Distributions {
467*4f1223e8SApple OSS Distributions }
468*4f1223e8SApple OSS Distributions 
469*4f1223e8SApple OSS Distributions /*------------------------------------------------------------*/
470*4f1223e8SApple OSS Distributions 
471*4f1223e8SApple OSS Distributions /*
472*4f1223e8SApple OSS Distributions  * go generate the checksum.
473*4f1223e8SApple OSS Distributions  */
474*4f1223e8SApple OSS Distributions static void
ah_update_mbuf(struct mbuf * m,int off,int len,const struct ah_algorithm * algo,struct ah_algorithm_state * algos)475*4f1223e8SApple OSS Distributions ah_update_mbuf(struct mbuf *m, int off, int len,
476*4f1223e8SApple OSS Distributions     const struct ah_algorithm *algo,
477*4f1223e8SApple OSS Distributions     struct ah_algorithm_state *algos)
478*4f1223e8SApple OSS Distributions {
479*4f1223e8SApple OSS Distributions 	struct mbuf *n;
480*4f1223e8SApple OSS Distributions 	int tlen;
481*4f1223e8SApple OSS Distributions 
482*4f1223e8SApple OSS Distributions 	/* easy case first */
483*4f1223e8SApple OSS Distributions 	if (off + len <= m->m_len) {
484*4f1223e8SApple OSS Distributions 		(algo->update)(algos, mtod(m, caddr_t) + off, len);
485*4f1223e8SApple OSS Distributions 		return;
486*4f1223e8SApple OSS Distributions 	}
487*4f1223e8SApple OSS Distributions 
488*4f1223e8SApple OSS Distributions 	for (n = m; n; n = n->m_next) {
489*4f1223e8SApple OSS Distributions 		if (off < n->m_len) {
490*4f1223e8SApple OSS Distributions 			break;
491*4f1223e8SApple OSS Distributions 		}
492*4f1223e8SApple OSS Distributions 
493*4f1223e8SApple OSS Distributions 		off -= n->m_len;
494*4f1223e8SApple OSS Distributions 	}
495*4f1223e8SApple OSS Distributions 
496*4f1223e8SApple OSS Distributions 	if (!n) {
497*4f1223e8SApple OSS Distributions 		panic("ah_update_mbuf: wrong offset specified");
498*4f1223e8SApple OSS Distributions 	}
499*4f1223e8SApple OSS Distributions 
500*4f1223e8SApple OSS Distributions 	for (/*nothing*/; n && len > 0; n = n->m_next) {
501*4f1223e8SApple OSS Distributions 		if (n->m_len == 0) {
502*4f1223e8SApple OSS Distributions 			continue;
503*4f1223e8SApple OSS Distributions 		}
504*4f1223e8SApple OSS Distributions 		if (n->m_len - off < len) {
505*4f1223e8SApple OSS Distributions 			tlen = n->m_len - off;
506*4f1223e8SApple OSS Distributions 		} else {
507*4f1223e8SApple OSS Distributions 			tlen = len;
508*4f1223e8SApple OSS Distributions 		}
509*4f1223e8SApple OSS Distributions 
510*4f1223e8SApple OSS Distributions 		(algo->update)(algos, mtod(n, caddr_t) + off, tlen);
511*4f1223e8SApple OSS Distributions 
512*4f1223e8SApple OSS Distributions 		len -= tlen;
513*4f1223e8SApple OSS Distributions 		off = 0;
514*4f1223e8SApple OSS Distributions 	}
515*4f1223e8SApple OSS Distributions }
516*4f1223e8SApple OSS Distributions 
517*4f1223e8SApple OSS Distributions #if INET
518*4f1223e8SApple OSS Distributions /*
519*4f1223e8SApple OSS Distributions  * Go generate the checksum. This function won't modify the mbuf chain
520*4f1223e8SApple OSS Distributions  * except AH itself.
521*4f1223e8SApple OSS Distributions  *
522*4f1223e8SApple OSS Distributions  * NOTE: the function does not free mbuf on failure.
523*4f1223e8SApple OSS Distributions  * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
524*4f1223e8SApple OSS Distributions  */
525*4f1223e8SApple OSS Distributions int
ah4_calccksum(struct mbuf * m,caddr_t __sized_by (len)ahdat,size_t len,const struct ah_algorithm * algo,struct secasvar * sav)526*4f1223e8SApple OSS Distributions ah4_calccksum(struct mbuf *m, caddr_t __sized_by(len)ahdat, size_t len,
527*4f1223e8SApple OSS Distributions     const struct ah_algorithm *algo, struct secasvar *sav)
528*4f1223e8SApple OSS Distributions {
529*4f1223e8SApple OSS Distributions 	int off;
530*4f1223e8SApple OSS Distributions 	int hdrtype;
531*4f1223e8SApple OSS Distributions 	size_t advancewidth;
532*4f1223e8SApple OSS Distributions 	struct ah_algorithm_state algos;
533*4f1223e8SApple OSS Distributions 	u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4)));
534*4f1223e8SApple OSS Distributions 	int error = 0;
535*4f1223e8SApple OSS Distributions 	int ahseen;
536*4f1223e8SApple OSS Distributions 	struct mbuf *n = NULL;
537*4f1223e8SApple OSS Distributions 
538*4f1223e8SApple OSS Distributions 	if ((m->m_flags & M_PKTHDR) == 0) {
539*4f1223e8SApple OSS Distributions 		return EINVAL;
540*4f1223e8SApple OSS Distributions 	}
541*4f1223e8SApple OSS Distributions 
542*4f1223e8SApple OSS Distributions 	ahseen = 0;
543*4f1223e8SApple OSS Distributions 	hdrtype = -1;   /*dummy, it is called IPPROTO_IP*/
544*4f1223e8SApple OSS Distributions 
545*4f1223e8SApple OSS Distributions 	off = 0;
546*4f1223e8SApple OSS Distributions 
547*4f1223e8SApple OSS Distributions 	/*
548*4f1223e8SApple OSS Distributions 	 * pre-compute and cache intermediate key
549*4f1223e8SApple OSS Distributions 	 */
550*4f1223e8SApple OSS Distributions 	if (__improbable((error = ah_schedule(algo, sav)) != 0)) {
551*4f1223e8SApple OSS Distributions 		return error;
552*4f1223e8SApple OSS Distributions 	}
553*4f1223e8SApple OSS Distributions 
554*4f1223e8SApple OSS Distributions 	error = (algo->init)(&algos, sav);
555*4f1223e8SApple OSS Distributions 	if (error) {
556*4f1223e8SApple OSS Distributions 		return error;
557*4f1223e8SApple OSS Distributions 	}
558*4f1223e8SApple OSS Distributions 
559*4f1223e8SApple OSS Distributions 	advancewidth = 0;       /*safety*/
560*4f1223e8SApple OSS Distributions 
561*4f1223e8SApple OSS Distributions again:
562*4f1223e8SApple OSS Distributions 	/* gory. */
563*4f1223e8SApple OSS Distributions 	switch (hdrtype) {
564*4f1223e8SApple OSS Distributions 	case -1:        /*first one only*/
565*4f1223e8SApple OSS Distributions 	{
566*4f1223e8SApple OSS Distributions 		/*
567*4f1223e8SApple OSS Distributions 		 * copy ip hdr, modify to fit the AH checksum rule,
568*4f1223e8SApple OSS Distributions 		 * then take a checksum.
569*4f1223e8SApple OSS Distributions 		 */
570*4f1223e8SApple OSS Distributions 		struct ip iphdr;
571*4f1223e8SApple OSS Distributions 		size_t hlen;
572*4f1223e8SApple OSS Distributions 
573*4f1223e8SApple OSS Distributions 		m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr);
574*4f1223e8SApple OSS Distributions #if _IP_VHL
575*4f1223e8SApple OSS Distributions 		hlen = IP_VHL_HL(iphdr.ip_vhl) << 2;
576*4f1223e8SApple OSS Distributions #else
577*4f1223e8SApple OSS Distributions 		hlen = iphdr.ip_hl << 2;
578*4f1223e8SApple OSS Distributions #endif
579*4f1223e8SApple OSS Distributions 		iphdr.ip_ttl = 0;
580*4f1223e8SApple OSS Distributions 		iphdr.ip_sum = htons(0);
581*4f1223e8SApple OSS Distributions 		if (ip4_ah_cleartos) {
582*4f1223e8SApple OSS Distributions 			iphdr.ip_tos = 0;
583*4f1223e8SApple OSS Distributions 		}
584*4f1223e8SApple OSS Distributions 		iphdr.ip_off = htons(ntohs(iphdr.ip_off) & ip4_ah_offsetmask);
585*4f1223e8SApple OSS Distributions 		(algo->update)(&algos, (caddr_t)&iphdr, sizeof(struct ip));
586*4f1223e8SApple OSS Distributions 
587*4f1223e8SApple OSS Distributions 		if (hlen != sizeof(struct ip)) {
588*4f1223e8SApple OSS Distributions 			u_char *p;
589*4f1223e8SApple OSS Distributions 			int i, l, skip;
590*4f1223e8SApple OSS Distributions 
591*4f1223e8SApple OSS Distributions 			if (hlen > MCLBYTES) {
592*4f1223e8SApple OSS Distributions 				error = EMSGSIZE;
593*4f1223e8SApple OSS Distributions 				goto fail;
594*4f1223e8SApple OSS Distributions 			}
595*4f1223e8SApple OSS Distributions 			MGET(n, M_DONTWAIT, MT_DATA);
596*4f1223e8SApple OSS Distributions 			if (n && hlen > MLEN) {
597*4f1223e8SApple OSS Distributions 				MCLGET(n, M_DONTWAIT);
598*4f1223e8SApple OSS Distributions 				if ((n->m_flags & M_EXT) == 0) {
599*4f1223e8SApple OSS Distributions 					m_free(n);
600*4f1223e8SApple OSS Distributions 					n = NULL;
601*4f1223e8SApple OSS Distributions 				}
602*4f1223e8SApple OSS Distributions 			}
603*4f1223e8SApple OSS Distributions 			if (n == NULL) {
604*4f1223e8SApple OSS Distributions 				error = ENOBUFS;
605*4f1223e8SApple OSS Distributions 				goto fail;
606*4f1223e8SApple OSS Distributions 			}
607*4f1223e8SApple OSS Distributions 			VERIFY(hlen <= INT_MAX);
608*4f1223e8SApple OSS Distributions 			m_copydata(m, off, (int)hlen, mtod(n, caddr_t));
609*4f1223e8SApple OSS Distributions 
610*4f1223e8SApple OSS Distributions 			/*
611*4f1223e8SApple OSS Distributions 			 * IP options processing.
612*4f1223e8SApple OSS Distributions 			 * See RFC2402 appendix A.
613*4f1223e8SApple OSS Distributions 			 */
614*4f1223e8SApple OSS Distributions 			p = mtod(n, u_char *);
615*4f1223e8SApple OSS Distributions 			i = sizeof(struct ip);
616*4f1223e8SApple OSS Distributions 			while (i < hlen) {
617*4f1223e8SApple OSS Distributions 				if (i + IPOPT_OPTVAL >= hlen) {
618*4f1223e8SApple OSS Distributions 					ipseclog((LOG_ERR, "ah4_calccksum: "
619*4f1223e8SApple OSS Distributions 					    "invalid IP option\n"));
620*4f1223e8SApple OSS Distributions 					error = EINVAL;
621*4f1223e8SApple OSS Distributions 					goto fail;
622*4f1223e8SApple OSS Distributions 				}
623*4f1223e8SApple OSS Distributions 				if (p[i + IPOPT_OPTVAL] == IPOPT_EOL ||
624*4f1223e8SApple OSS Distributions 				    p[i + IPOPT_OPTVAL] == IPOPT_NOP ||
625*4f1223e8SApple OSS Distributions 				    i + IPOPT_OLEN < hlen) {
626*4f1223e8SApple OSS Distributions 					;
627*4f1223e8SApple OSS Distributions 				} else {
628*4f1223e8SApple OSS Distributions 					ipseclog((LOG_ERR,
629*4f1223e8SApple OSS Distributions 					    "ah4_calccksum: invalid IP option "
630*4f1223e8SApple OSS Distributions 					    "(type=%02x)\n",
631*4f1223e8SApple OSS Distributions 					    p[i + IPOPT_OPTVAL]));
632*4f1223e8SApple OSS Distributions 					error = EINVAL;
633*4f1223e8SApple OSS Distributions 					goto fail;
634*4f1223e8SApple OSS Distributions 				}
635*4f1223e8SApple OSS Distributions 
636*4f1223e8SApple OSS Distributions 				skip = 1;
637*4f1223e8SApple OSS Distributions 				switch (p[i + IPOPT_OPTVAL]) {
638*4f1223e8SApple OSS Distributions 				case IPOPT_EOL:
639*4f1223e8SApple OSS Distributions 				case IPOPT_NOP:
640*4f1223e8SApple OSS Distributions 					l = 1;
641*4f1223e8SApple OSS Distributions 					skip = 0;
642*4f1223e8SApple OSS Distributions 					break;
643*4f1223e8SApple OSS Distributions 				case IPOPT_SECURITY:    /* 0x82 */
644*4f1223e8SApple OSS Distributions 				case 0x85:      /* Extended security */
645*4f1223e8SApple OSS Distributions 				case 0x86:      /* Commercial security */
646*4f1223e8SApple OSS Distributions 				case 0x94:      /* Router alert */
647*4f1223e8SApple OSS Distributions 				case 0x95:      /* RFC1770 */
648*4f1223e8SApple OSS Distributions 					l = p[i + IPOPT_OLEN];
649*4f1223e8SApple OSS Distributions 					if (l < 2) {
650*4f1223e8SApple OSS Distributions 						goto invalopt;
651*4f1223e8SApple OSS Distributions 					}
652*4f1223e8SApple OSS Distributions 					skip = 0;
653*4f1223e8SApple OSS Distributions 					break;
654*4f1223e8SApple OSS Distributions 				default:
655*4f1223e8SApple OSS Distributions 					l = p[i + IPOPT_OLEN];
656*4f1223e8SApple OSS Distributions 					if (l < 2) {
657*4f1223e8SApple OSS Distributions 						goto invalopt;
658*4f1223e8SApple OSS Distributions 					}
659*4f1223e8SApple OSS Distributions 					skip = 1;
660*4f1223e8SApple OSS Distributions 					break;
661*4f1223e8SApple OSS Distributions 				}
662*4f1223e8SApple OSS Distributions 				if (l < 1 || hlen - i < l) {
663*4f1223e8SApple OSS Distributions invalopt:
664*4f1223e8SApple OSS Distributions 					ipseclog((LOG_ERR,
665*4f1223e8SApple OSS Distributions 					    "ah4_calccksum: invalid IP option "
666*4f1223e8SApple OSS Distributions 					    "(type=%02x len=%02x)\n",
667*4f1223e8SApple OSS Distributions 					    p[i + IPOPT_OPTVAL],
668*4f1223e8SApple OSS Distributions 					    p[i + IPOPT_OLEN]));
669*4f1223e8SApple OSS Distributions 					error = EINVAL;
670*4f1223e8SApple OSS Distributions 					goto fail;
671*4f1223e8SApple OSS Distributions 				}
672*4f1223e8SApple OSS Distributions 				if (skip) {
673*4f1223e8SApple OSS Distributions 					bzero(p + i, l);
674*4f1223e8SApple OSS Distributions 				}
675*4f1223e8SApple OSS Distributions 				if (p[i + IPOPT_OPTVAL] == IPOPT_EOL) {
676*4f1223e8SApple OSS Distributions 					break;
677*4f1223e8SApple OSS Distributions 				}
678*4f1223e8SApple OSS Distributions 				i += l;
679*4f1223e8SApple OSS Distributions 			}
680*4f1223e8SApple OSS Distributions 
681*4f1223e8SApple OSS Distributions 			p = mtod(n, u_char *) + sizeof(struct ip);
682*4f1223e8SApple OSS Distributions 			(algo->update)(&algos, (caddr_t)p, hlen - sizeof(struct ip));
683*4f1223e8SApple OSS Distributions 
684*4f1223e8SApple OSS Distributions 			m_free(n);
685*4f1223e8SApple OSS Distributions 			n = NULL;
686*4f1223e8SApple OSS Distributions 		}
687*4f1223e8SApple OSS Distributions 
688*4f1223e8SApple OSS Distributions 		hdrtype = (iphdr.ip_p) & 0xff;
689*4f1223e8SApple OSS Distributions 		advancewidth = hlen;
690*4f1223e8SApple OSS Distributions 		break;
691*4f1223e8SApple OSS Distributions 	}
692*4f1223e8SApple OSS Distributions 
693*4f1223e8SApple OSS Distributions 	case IPPROTO_AH:
694*4f1223e8SApple OSS Distributions 	{
695*4f1223e8SApple OSS Distributions 		struct ah ah;
696*4f1223e8SApple OSS Distributions 		int siz;
697*4f1223e8SApple OSS Distributions 		int hdrsiz;
698*4f1223e8SApple OSS Distributions 		int totlen;
699*4f1223e8SApple OSS Distributions 
700*4f1223e8SApple OSS Distributions 		if (m->m_pkthdr.len - off < sizeof(ah)) {
701*4f1223e8SApple OSS Distributions 			error = EMSGSIZE;
702*4f1223e8SApple OSS Distributions 			goto fail;
703*4f1223e8SApple OSS Distributions 		}
704*4f1223e8SApple OSS Distributions 
705*4f1223e8SApple OSS Distributions 		m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
706*4f1223e8SApple OSS Distributions 		hdrsiz = (sav->flags & SADB_X_EXT_OLD)
707*4f1223e8SApple OSS Distributions 		    ? sizeof(struct ah)
708*4f1223e8SApple OSS Distributions 		    : sizeof(struct newah);
709*4f1223e8SApple OSS Distributions 		siz = (*algo->sumsiz)(sav);
710*4f1223e8SApple OSS Distributions 		totlen = (ah.ah_len + 2) << 2;
711*4f1223e8SApple OSS Distributions 
712*4f1223e8SApple OSS Distributions 		if (totlen > m->m_pkthdr.len - off) {
713*4f1223e8SApple OSS Distributions 			error = EMSGSIZE;
714*4f1223e8SApple OSS Distributions 			goto fail;
715*4f1223e8SApple OSS Distributions 		}
716*4f1223e8SApple OSS Distributions 
717*4f1223e8SApple OSS Distributions 		/*
718*4f1223e8SApple OSS Distributions 		 * special treatment is necessary for the first one, not others
719*4f1223e8SApple OSS Distributions 		 */
720*4f1223e8SApple OSS Distributions 		if (!ahseen) {
721*4f1223e8SApple OSS Distributions 			if (totlen > MCLBYTES) {
722*4f1223e8SApple OSS Distributions 				error = EMSGSIZE;
723*4f1223e8SApple OSS Distributions 				goto fail;
724*4f1223e8SApple OSS Distributions 			}
725*4f1223e8SApple OSS Distributions 			MGET(n, M_DONTWAIT, MT_DATA);
726*4f1223e8SApple OSS Distributions 			if (n && totlen > MLEN) {
727*4f1223e8SApple OSS Distributions 				MCLGET(n, M_DONTWAIT);
728*4f1223e8SApple OSS Distributions 				if ((n->m_flags & M_EXT) == 0) {
729*4f1223e8SApple OSS Distributions 					m_free(n);
730*4f1223e8SApple OSS Distributions 					n = NULL;
731*4f1223e8SApple OSS Distributions 				}
732*4f1223e8SApple OSS Distributions 			}
733*4f1223e8SApple OSS Distributions 			if (n == NULL) {
734*4f1223e8SApple OSS Distributions 				error = ENOBUFS;
735*4f1223e8SApple OSS Distributions 				goto fail;
736*4f1223e8SApple OSS Distributions 			}
737*4f1223e8SApple OSS Distributions 			m_copydata(m, off, totlen, mtod(n, caddr_t));
738*4f1223e8SApple OSS Distributions 			n->m_len = totlen;
739*4f1223e8SApple OSS Distributions 			bzero(mtod(n, caddr_t) + hdrsiz, siz);
740*4f1223e8SApple OSS Distributions 			(algo->update)(&algos, mtod(n, caddr_t), n->m_len);
741*4f1223e8SApple OSS Distributions 			m_free(n);
742*4f1223e8SApple OSS Distributions 			n = NULL;
743*4f1223e8SApple OSS Distributions 		} else {
744*4f1223e8SApple OSS Distributions 			ah_update_mbuf(m, off, totlen, algo, &algos);
745*4f1223e8SApple OSS Distributions 		}
746*4f1223e8SApple OSS Distributions 		ahseen++;
747*4f1223e8SApple OSS Distributions 
748*4f1223e8SApple OSS Distributions 		hdrtype = ah.ah_nxt;
749*4f1223e8SApple OSS Distributions 		advancewidth = totlen;
750*4f1223e8SApple OSS Distributions 		break;
751*4f1223e8SApple OSS Distributions 	}
752*4f1223e8SApple OSS Distributions 
753*4f1223e8SApple OSS Distributions 	default:
754*4f1223e8SApple OSS Distributions 		ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, &algos);
755*4f1223e8SApple OSS Distributions 		advancewidth = m->m_pkthdr.len - off;
756*4f1223e8SApple OSS Distributions 		break;
757*4f1223e8SApple OSS Distributions 	}
758*4f1223e8SApple OSS Distributions 
759*4f1223e8SApple OSS Distributions 	off += advancewidth;
760*4f1223e8SApple OSS Distributions 	if (off < m->m_pkthdr.len) {
761*4f1223e8SApple OSS Distributions 		goto again;
762*4f1223e8SApple OSS Distributions 	}
763*4f1223e8SApple OSS Distributions 
764*4f1223e8SApple OSS Distributions 	if (len < (*algo->sumsiz)(sav)) {
765*4f1223e8SApple OSS Distributions 		error = EINVAL;
766*4f1223e8SApple OSS Distributions 		goto fail;
767*4f1223e8SApple OSS Distributions 	}
768*4f1223e8SApple OSS Distributions 
769*4f1223e8SApple OSS Distributions 	(algo->result)(&algos, (caddr_t) &sumbuf[0], sizeof(sumbuf));
770*4f1223e8SApple OSS Distributions 	bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));
771*4f1223e8SApple OSS Distributions 
772*4f1223e8SApple OSS Distributions 	if (n) {
773*4f1223e8SApple OSS Distributions 		m_free(n);
774*4f1223e8SApple OSS Distributions 	}
775*4f1223e8SApple OSS Distributions 	return error;
776*4f1223e8SApple OSS Distributions 
777*4f1223e8SApple OSS Distributions fail:
778*4f1223e8SApple OSS Distributions 	if (n) {
779*4f1223e8SApple OSS Distributions 		m_free(n);
780*4f1223e8SApple OSS Distributions 	}
781*4f1223e8SApple OSS Distributions 	return error;
782*4f1223e8SApple OSS Distributions }
783*4f1223e8SApple OSS Distributions #endif
784*4f1223e8SApple OSS Distributions 
785*4f1223e8SApple OSS Distributions /*
786*4f1223e8SApple OSS Distributions  * Go generate the checksum. This function won't modify the mbuf chain
787*4f1223e8SApple OSS Distributions  * except AH itself.
788*4f1223e8SApple OSS Distributions  *
789*4f1223e8SApple OSS Distributions  * NOTE: the function does not free mbuf on failure.
790*4f1223e8SApple OSS Distributions  * Don't use m_copy(), it will try to share cluster mbuf by using refcnt.
791*4f1223e8SApple OSS Distributions  */
792*4f1223e8SApple OSS Distributions int
ah6_calccksum(struct mbuf * m,caddr_t __sized_by (len)ahdat,size_t len,const struct ah_algorithm * algo,struct secasvar * sav)793*4f1223e8SApple OSS Distributions ah6_calccksum(struct mbuf *m, caddr_t __sized_by(len)ahdat, size_t len,
794*4f1223e8SApple OSS Distributions     const struct ah_algorithm *algo, struct secasvar *sav)
795*4f1223e8SApple OSS Distributions {
796*4f1223e8SApple OSS Distributions 	int newoff, off;
797*4f1223e8SApple OSS Distributions 	int proto, nxt;
798*4f1223e8SApple OSS Distributions 	struct mbuf *n = NULL;
799*4f1223e8SApple OSS Distributions 	int error;
800*4f1223e8SApple OSS Distributions 	int ahseen;
801*4f1223e8SApple OSS Distributions 	struct ah_algorithm_state algos;
802*4f1223e8SApple OSS Distributions 	u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4)));
803*4f1223e8SApple OSS Distributions 
804*4f1223e8SApple OSS Distributions 	if ((m->m_flags & M_PKTHDR) == 0) {
805*4f1223e8SApple OSS Distributions 		return EINVAL;
806*4f1223e8SApple OSS Distributions 	}
807*4f1223e8SApple OSS Distributions 
808*4f1223e8SApple OSS Distributions 	/*
809*4f1223e8SApple OSS Distributions 	 * pre-compute and cache intermediate key
810*4f1223e8SApple OSS Distributions 	 */
811*4f1223e8SApple OSS Distributions 	if (__improbable((error = ah_schedule(algo, sav)) != 0)) {
812*4f1223e8SApple OSS Distributions 		return error;
813*4f1223e8SApple OSS Distributions 	}
814*4f1223e8SApple OSS Distributions 
815*4f1223e8SApple OSS Distributions 	error = (algo->init)(&algos, sav);
816*4f1223e8SApple OSS Distributions 	if (error) {
817*4f1223e8SApple OSS Distributions 		return error;
818*4f1223e8SApple OSS Distributions 	}
819*4f1223e8SApple OSS Distributions 
820*4f1223e8SApple OSS Distributions 	off = 0;
821*4f1223e8SApple OSS Distributions 	proto = IPPROTO_IPV6;
822*4f1223e8SApple OSS Distributions 	nxt = -1;
823*4f1223e8SApple OSS Distributions 	ahseen = 0;
824*4f1223e8SApple OSS Distributions 
825*4f1223e8SApple OSS Distributions again:
826*4f1223e8SApple OSS Distributions 	newoff = ip6_nexthdr(m, off, proto, &nxt);
827*4f1223e8SApple OSS Distributions 	if (newoff < 0) {
828*4f1223e8SApple OSS Distributions 		newoff = m->m_pkthdr.len;
829*4f1223e8SApple OSS Distributions 	} else if (newoff <= off) {
830*4f1223e8SApple OSS Distributions 		error = EINVAL;
831*4f1223e8SApple OSS Distributions 		goto fail;
832*4f1223e8SApple OSS Distributions 	} else if (m->m_pkthdr.len < newoff) {
833*4f1223e8SApple OSS Distributions 		error = EINVAL;
834*4f1223e8SApple OSS Distributions 		goto fail;
835*4f1223e8SApple OSS Distributions 	}
836*4f1223e8SApple OSS Distributions 
837*4f1223e8SApple OSS Distributions 	switch (proto) {
838*4f1223e8SApple OSS Distributions 	case IPPROTO_IPV6:
839*4f1223e8SApple OSS Distributions 		/*
840*4f1223e8SApple OSS Distributions 		 * special treatment is necessary for the first one, not others
841*4f1223e8SApple OSS Distributions 		 */
842*4f1223e8SApple OSS Distributions 		if (off == 0) {
843*4f1223e8SApple OSS Distributions 			struct ip6_hdr ip6copy;
844*4f1223e8SApple OSS Distributions 
845*4f1223e8SApple OSS Distributions 			if (newoff - off != sizeof(struct ip6_hdr)) {
846*4f1223e8SApple OSS Distributions 				error = EINVAL;
847*4f1223e8SApple OSS Distributions 				goto fail;
848*4f1223e8SApple OSS Distributions 			}
849*4f1223e8SApple OSS Distributions 
850*4f1223e8SApple OSS Distributions 			m_copydata(m, off, newoff - off, (caddr_t)&ip6copy);
851*4f1223e8SApple OSS Distributions 			/* RFC2402 */
852*4f1223e8SApple OSS Distributions 			ip6copy.ip6_flow = 0;
853*4f1223e8SApple OSS Distributions 			ip6copy.ip6_vfc &= ~IPV6_VERSION_MASK;
854*4f1223e8SApple OSS Distributions 			ip6copy.ip6_vfc |= IPV6_VERSION;
855*4f1223e8SApple OSS Distributions 			ip6copy.ip6_hlim = 0;
856*4f1223e8SApple OSS Distributions 			if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_src)) {
857*4f1223e8SApple OSS Distributions 				ip6copy.ip6_src.s6_addr16[1] = 0x0000;
858*4f1223e8SApple OSS Distributions 			}
859*4f1223e8SApple OSS Distributions 			if (IN6_IS_ADDR_LINKLOCAL(&ip6copy.ip6_dst)) {
860*4f1223e8SApple OSS Distributions 				ip6copy.ip6_dst.s6_addr16[1] = 0x0000;
861*4f1223e8SApple OSS Distributions 			}
862*4f1223e8SApple OSS Distributions 			(algo->update)(&algos, (caddr_t)&ip6copy,
863*4f1223e8SApple OSS Distributions 			    sizeof(struct ip6_hdr));
864*4f1223e8SApple OSS Distributions 		} else {
865*4f1223e8SApple OSS Distributions 			newoff = m->m_pkthdr.len;
866*4f1223e8SApple OSS Distributions 			ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo,
867*4f1223e8SApple OSS Distributions 			    &algos);
868*4f1223e8SApple OSS Distributions 		}
869*4f1223e8SApple OSS Distributions 		break;
870*4f1223e8SApple OSS Distributions 
871*4f1223e8SApple OSS Distributions 	case IPPROTO_AH:
872*4f1223e8SApple OSS Distributions 	{
873*4f1223e8SApple OSS Distributions 		int siz;
874*4f1223e8SApple OSS Distributions 		int hdrsiz;
875*4f1223e8SApple OSS Distributions 
876*4f1223e8SApple OSS Distributions 		hdrsiz = (sav->flags & SADB_X_EXT_OLD)
877*4f1223e8SApple OSS Distributions 		    ? sizeof(struct ah)
878*4f1223e8SApple OSS Distributions 		    : sizeof(struct newah);
879*4f1223e8SApple OSS Distributions 		siz = (*algo->sumsiz)(sav);
880*4f1223e8SApple OSS Distributions 
881*4f1223e8SApple OSS Distributions 		/*
882*4f1223e8SApple OSS Distributions 		 * special treatment is necessary for the first one, not others
883*4f1223e8SApple OSS Distributions 		 */
884*4f1223e8SApple OSS Distributions 		if (!ahseen) {
885*4f1223e8SApple OSS Distributions 			if (newoff - off > MCLBYTES) {
886*4f1223e8SApple OSS Distributions 				error = EMSGSIZE;
887*4f1223e8SApple OSS Distributions 				goto fail;
888*4f1223e8SApple OSS Distributions 			}
889*4f1223e8SApple OSS Distributions 			MGET(n, M_DONTWAIT, MT_DATA);
890*4f1223e8SApple OSS Distributions 			if (n && newoff - off > MLEN) {
891*4f1223e8SApple OSS Distributions 				MCLGET(n, M_DONTWAIT);
892*4f1223e8SApple OSS Distributions 				if ((n->m_flags & M_EXT) == 0) {
893*4f1223e8SApple OSS Distributions 					m_free(n);
894*4f1223e8SApple OSS Distributions 					n = NULL;
895*4f1223e8SApple OSS Distributions 				}
896*4f1223e8SApple OSS Distributions 			}
897*4f1223e8SApple OSS Distributions 			if (n == NULL) {
898*4f1223e8SApple OSS Distributions 				error = ENOBUFS;
899*4f1223e8SApple OSS Distributions 				goto fail;
900*4f1223e8SApple OSS Distributions 			}
901*4f1223e8SApple OSS Distributions 			m_copydata(m, off, newoff - off, mtod(n, caddr_t));
902*4f1223e8SApple OSS Distributions 			n->m_len = newoff - off;
903*4f1223e8SApple OSS Distributions 			bzero(mtod(n, caddr_t) + hdrsiz, siz);
904*4f1223e8SApple OSS Distributions 			(algo->update)(&algos, mtod(n, caddr_t), n->m_len);
905*4f1223e8SApple OSS Distributions 			m_free(n);
906*4f1223e8SApple OSS Distributions 			n = NULL;
907*4f1223e8SApple OSS Distributions 		} else {
908*4f1223e8SApple OSS Distributions 			ah_update_mbuf(m, off, newoff - off, algo, &algos);
909*4f1223e8SApple OSS Distributions 		}
910*4f1223e8SApple OSS Distributions 		ahseen++;
911*4f1223e8SApple OSS Distributions 		break;
912*4f1223e8SApple OSS Distributions 	}
913*4f1223e8SApple OSS Distributions 
914*4f1223e8SApple OSS Distributions 	case IPPROTO_HOPOPTS:
915*4f1223e8SApple OSS Distributions 	case IPPROTO_DSTOPTS:
916*4f1223e8SApple OSS Distributions 	{
917*4f1223e8SApple OSS Distributions 		struct ip6_ext *ip6e;
918*4f1223e8SApple OSS Distributions 		int hdrlen, optlen;
919*4f1223e8SApple OSS Distributions 		u_int8_t *p, *optend, *optp;
920*4f1223e8SApple OSS Distributions 
921*4f1223e8SApple OSS Distributions 		if (newoff - off > MCLBYTES) {
922*4f1223e8SApple OSS Distributions 			error = EMSGSIZE;
923*4f1223e8SApple OSS Distributions 			goto fail;
924*4f1223e8SApple OSS Distributions 		}
925*4f1223e8SApple OSS Distributions 		MGET(n, M_DONTWAIT, MT_DATA);
926*4f1223e8SApple OSS Distributions 		if (n && newoff - off > MLEN) {
927*4f1223e8SApple OSS Distributions 			MCLGET(n, M_DONTWAIT);
928*4f1223e8SApple OSS Distributions 			if ((n->m_flags & M_EXT) == 0) {
929*4f1223e8SApple OSS Distributions 				m_free(n);
930*4f1223e8SApple OSS Distributions 				n = NULL;
931*4f1223e8SApple OSS Distributions 			}
932*4f1223e8SApple OSS Distributions 		}
933*4f1223e8SApple OSS Distributions 		if (n == NULL) {
934*4f1223e8SApple OSS Distributions 			error = ENOBUFS;
935*4f1223e8SApple OSS Distributions 			goto fail;
936*4f1223e8SApple OSS Distributions 		}
937*4f1223e8SApple OSS Distributions 		m_copydata(m, off, newoff - off, mtod(n, caddr_t));
938*4f1223e8SApple OSS Distributions 		n->m_len = newoff - off;
939*4f1223e8SApple OSS Distributions 
940*4f1223e8SApple OSS Distributions 		ip6e = mtod(n, struct ip6_ext *);
941*4f1223e8SApple OSS Distributions 		hdrlen = (ip6e->ip6e_len + 1) << 3;
942*4f1223e8SApple OSS Distributions 		if (newoff - off < hdrlen) {
943*4f1223e8SApple OSS Distributions 			error = EINVAL;
944*4f1223e8SApple OSS Distributions 			m_free(n);
945*4f1223e8SApple OSS Distributions 			n = NULL;
946*4f1223e8SApple OSS Distributions 			goto fail;
947*4f1223e8SApple OSS Distributions 		}
948*4f1223e8SApple OSS Distributions 		p = mtod(n, u_int8_t *);
949*4f1223e8SApple OSS Distributions 		optend = p + hdrlen;
950*4f1223e8SApple OSS Distributions 
951*4f1223e8SApple OSS Distributions 		/*
952*4f1223e8SApple OSS Distributions 		 * ICV calculation for the options header including all
953*4f1223e8SApple OSS Distributions 		 * options.  This part is a little tricky since there are
954*4f1223e8SApple OSS Distributions 		 * two type of options; mutable and immutable.  We try to
955*4f1223e8SApple OSS Distributions 		 * null-out mutable ones here.
956*4f1223e8SApple OSS Distributions 		 */
957*4f1223e8SApple OSS Distributions 		optp = p + 2;
958*4f1223e8SApple OSS Distributions 		while (optp < optend) {
959*4f1223e8SApple OSS Distributions 			if (optp[0] == IP6OPT_PAD1) {
960*4f1223e8SApple OSS Distributions 				optlen = 1;
961*4f1223e8SApple OSS Distributions 			} else {
962*4f1223e8SApple OSS Distributions 				if (optp + 2 > optend) {
963*4f1223e8SApple OSS Distributions 					error = EINVAL;
964*4f1223e8SApple OSS Distributions 					m_free(n);
965*4f1223e8SApple OSS Distributions 					n = NULL;
966*4f1223e8SApple OSS Distributions 					goto fail;
967*4f1223e8SApple OSS Distributions 				}
968*4f1223e8SApple OSS Distributions 				optlen = optp[1] + 2;
969*4f1223e8SApple OSS Distributions 				if (optp + optlen > optend) {
970*4f1223e8SApple OSS Distributions 					error = EINVAL;
971*4f1223e8SApple OSS Distributions 					m_free(n);
972*4f1223e8SApple OSS Distributions 					n = NULL;
973*4f1223e8SApple OSS Distributions 					goto fail;
974*4f1223e8SApple OSS Distributions 				}
975*4f1223e8SApple OSS Distributions 
976*4f1223e8SApple OSS Distributions 				if (optp[0] & IP6OPT_MUTABLE) {
977*4f1223e8SApple OSS Distributions 					bzero(optp + 2, optlen - 2);
978*4f1223e8SApple OSS Distributions 				}
979*4f1223e8SApple OSS Distributions 			}
980*4f1223e8SApple OSS Distributions 
981*4f1223e8SApple OSS Distributions 			optp += optlen;
982*4f1223e8SApple OSS Distributions 		}
983*4f1223e8SApple OSS Distributions 
984*4f1223e8SApple OSS Distributions 		(algo->update)(&algos, mtod(n, caddr_t), n->m_len);
985*4f1223e8SApple OSS Distributions 		m_free(n);
986*4f1223e8SApple OSS Distributions 		n = NULL;
987*4f1223e8SApple OSS Distributions 		break;
988*4f1223e8SApple OSS Distributions 	}
989*4f1223e8SApple OSS Distributions 
990*4f1223e8SApple OSS Distributions 	case IPPROTO_ROUTING:
991*4f1223e8SApple OSS Distributions 	/*
992*4f1223e8SApple OSS Distributions 	 * For an input packet, we can just calculate `as is'.
993*4f1223e8SApple OSS Distributions 	 * For an output packet, we assume ip6_output have already
994*4f1223e8SApple OSS Distributions 	 * made packet how it will be received at the final
995*4f1223e8SApple OSS Distributions 	 * destination.
996*4f1223e8SApple OSS Distributions 	 */
997*4f1223e8SApple OSS Distributions 	/* FALLTHROUGH */
998*4f1223e8SApple OSS Distributions 
999*4f1223e8SApple OSS Distributions 	default:
1000*4f1223e8SApple OSS Distributions 		ah_update_mbuf(m, off, newoff - off, algo, &algos);
1001*4f1223e8SApple OSS Distributions 		break;
1002*4f1223e8SApple OSS Distributions 	}
1003*4f1223e8SApple OSS Distributions 
1004*4f1223e8SApple OSS Distributions 	if (newoff < m->m_pkthdr.len) {
1005*4f1223e8SApple OSS Distributions 		proto = nxt;
1006*4f1223e8SApple OSS Distributions 		off = newoff;
1007*4f1223e8SApple OSS Distributions 		goto again;
1008*4f1223e8SApple OSS Distributions 	}
1009*4f1223e8SApple OSS Distributions 
1010*4f1223e8SApple OSS Distributions 	if (len < (*algo->sumsiz)(sav)) {
1011*4f1223e8SApple OSS Distributions 		error = EINVAL;
1012*4f1223e8SApple OSS Distributions 		goto fail;
1013*4f1223e8SApple OSS Distributions 	}
1014*4f1223e8SApple OSS Distributions 
1015*4f1223e8SApple OSS Distributions 	(algo->result)(&algos, (caddr_t) &sumbuf[0], sizeof(sumbuf));
1016*4f1223e8SApple OSS Distributions 	bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav));
1017*4f1223e8SApple OSS Distributions 
1018*4f1223e8SApple OSS Distributions 	/* just in case */
1019*4f1223e8SApple OSS Distributions 	if (n) {
1020*4f1223e8SApple OSS Distributions 		m_free(n);
1021*4f1223e8SApple OSS Distributions 	}
1022*4f1223e8SApple OSS Distributions 	return 0;
1023*4f1223e8SApple OSS Distributions fail:
1024*4f1223e8SApple OSS Distributions 	/* just in case */
1025*4f1223e8SApple OSS Distributions 	if (n) {
1026*4f1223e8SApple OSS Distributions 		m_free(n);
1027*4f1223e8SApple OSS Distributions 	}
1028*4f1223e8SApple OSS Distributions 	return error;
1029*4f1223e8SApple OSS Distributions }
1030