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