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