xref: /xnu-11417.121.6/bsd/netinet6/ah_input.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
1 /*
2  * Copyright (c) 2008-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_input.c,v 1.1.2.6 2002/04/28 05:40:26 suz Exp $	*/
30 /*	$KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc 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 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/malloc.h>
68 #include <sys/mbuf.h>
69 #include <sys/mcache.h>
70 #include <sys/domain.h>
71 #include <sys/protosw.h>
72 #include <sys/socket.h>
73 #include <sys/errno.h>
74 #include <sys/time.h>
75 #include <sys/kernel.h>
76 #include <sys/syslog.h>
77 
78 #include <net/if.h>
79 #include <net/if_ipsec.h>
80 #include <net/route.h>
81 #include <kern/cpu_number.h>
82 #include <kern/locks.h>
83 
84 #include <netinet/in.h>
85 #include <netinet/in_systm.h>
86 #include <netinet/in_var.h>
87 #include <netinet/ip.h>
88 #include <netinet/ip_var.h>
89 #include <netinet/ip_ecn.h>
90 #include <netinet/in_pcb.h>
91 #include <netinet6/ip6_ecn.h>
92 
93 #include <netinet/ip6.h>
94 #include <netinet6/ip6_var.h>
95 #include <netinet6/in6_pcb.h>
96 #include <netinet/icmp6.h>
97 #include <netinet6/ip6protosw.h>
98 
99 #include <netinet6/ipsec.h>
100 #include <netinet6/ipsec6.h>
101 #include <netinet6/ah.h>
102 #include <netinet6/ah6.h>
103 #include <netkey/key.h>
104 #include <netkey/keydb.h>
105 #if IPSEC_DEBUG
106 #include <netkey/key_debug.h>
107 #else
108 #define KEYDEBUG(lev, arg)
109 #endif
110 
111 #include <net/kpi_protocol.h>
112 #include <netinet/kpi_ipfilter_var.h>
113 #include <mach/sdt.h>
114 
115 #include <net/net_osdep.h>
116 
117 #define IPLEN_FLIPPED
118 
119 #if INET
120 void
ah4_input(struct mbuf * m,int off)121 ah4_input(struct mbuf *m, int off)
122 {
123 	union sockaddr_in_4_6 src = {};
124 	union sockaddr_in_4_6 dst = {};
125 	struct ip *ip;
126 	struct ah *ah;
127 	u_int32_t spi;
128 	const struct ah_algorithm *algo;
129 	size_t siz;
130 	size_t siz1;
131 	u_char *__bidi_indexable cksum = NULL;
132 	struct secasvar *sav = NULL;
133 	u_int16_t nxt;
134 	u_int8_t hlen;
135 	size_t stripsiz = 0;
136 	sa_family_t ifamily;
137 
138 	if (m->m_len < off + sizeof(struct newah)) {
139 		m = m_pullup(m, off + sizeof(struct newah));
140 		if (!m) {
141 			ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
142 			    "dropping the packet for simplicity\n"));
143 			IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
144 			goto fail;
145 		}
146 	}
147 
148 	/* Expect 32-bit aligned data pointer on strict-align platforms */
149 	MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
150 
151 	ip = mtod(m, struct ip *);
152 	ah = (struct ah *)(void *)(((caddr_t)ip) + off);
153 	nxt = ah->ah_nxt;
154 #ifdef _IP_VHL
155 	hlen = (u_int8_t)(IP_VHL_HL(ip->ip_vhl) << 2);
156 #else
157 	hlen = (u_int8_t)(ip->ip_hl << 2);
158 #endif
159 
160 	/* find the sassoc. */
161 	spi = ah->ah_spi;
162 
163 	ipsec_fill_ip_sockaddr_4_6(&src, ip->ip_src, 0);
164 	ipsec_fill_ip_sockaddr_4_6(&dst, ip->ip_dst, 0);
165 
166 	if ((sav = key_allocsa(&src, &dst, IPPROTO_AH, spi, NULL)) == 0) {
167 		ipseclog((LOG_WARNING,
168 		    "IPv4 AH input: no key association found for spi %u\n",
169 		    (u_int32_t)ntohl(spi)));
170 		IPSEC_STAT_INCREMENT(ipsecstat.in_nosa);
171 		goto fail;
172 	}
173 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
174 	    printf("DP ah4_input called to allocate SA:0x%llx\n",
175 	    (uint64_t)VM_KERNEL_ADDRPERM(sav)));
176 	if (sav->state != SADB_SASTATE_MATURE
177 	    && sav->state != SADB_SASTATE_DYING) {
178 		ipseclog((LOG_DEBUG,
179 		    "IPv4 AH input: non-mature/dying SA found for spi %u\n",
180 		    (u_int32_t)ntohl(spi)));
181 		IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
182 		goto fail;
183 	}
184 
185 	algo = ah_algorithm_lookup(sav->alg_auth);
186 	if (!algo) {
187 		ipseclog((LOG_DEBUG, "IPv4 AH input: "
188 		    "unsupported authentication algorithm for spi %u\n",
189 		    (u_int32_t)ntohl(spi)));
190 		IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
191 		goto fail;
192 	}
193 
194 	siz = (*algo->sumsiz)(sav);
195 	siz1 = ((siz + 3) & ~(4 - 1));
196 
197 	/*
198 	 * sanity checks for header, 1.
199 	 */
200 	{
201 		int sizoff;
202 
203 		sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
204 
205 		/*
206 		 * Here, we do not do "siz1 == siz".  This is because the way
207 		 * RFC240[34] section 2 is written.  They do not require truncation
208 		 * to 96 bits.
209 		 * For example, Microsoft IPsec stack attaches 160 bits of
210 		 * authentication data for both hmac-md5 and hmac-sha1.  For hmac-sha1,
211 		 * 32 bits of padding is attached.
212 		 *
213 		 * There are two downsides to this specification.
214 		 * They have no real harm, however, they leave us fuzzy feeling.
215 		 * - if we attach more than 96 bits of authentication data onto AH,
216 		 *   we will never notice about possible modification by rogue
217 		 *   intermediate nodes.
218 		 *   Since extra bits in AH checksum is never used, this constitutes
219 		 *   no real issue, however, it is wacky.
220 		 * - even if the peer attaches big authentication data, we will never
221 		 *   notice the difference, since longer authentication data will just
222 		 *   work.
223 		 *
224 		 * We may need some clarification in the spec.
225 		 */
226 		if (siz1 < siz) {
227 			ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
228 			    "(%u, should be at least %u): %s\n",
229 			    (u_int32_t)siz1, (u_int32_t)siz,
230 			    ipsec4_logpacketstr(ip, spi)));
231 			IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
232 			goto fail;
233 		}
234 		if ((ah->ah_len << 2) - sizoff != siz1) {
235 			ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
236 			    "(%d should be %u): %s\n",
237 			    (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
238 			    ipsec4_logpacketstr(ip, spi)));
239 			IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
240 			goto fail;
241 		}
242 
243 		if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
244 			VERIFY((off + sizeof(struct ah) + sizoff + siz1) <= INT_MAX);
245 			m = m_pullup(m, (int)(off + sizeof(struct ah) + sizoff + siz1));
246 			if (!m) {
247 				ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
248 				IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
249 				goto fail;
250 			}
251 			/* Expect 32-bit aligned data ptr on strict-align platforms */
252 			MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
253 
254 			ip = mtod(m, struct ip *);
255 			ah = (struct ah *)(void *)(((caddr_t)ip) + off);
256 		}
257 	}
258 
259 	/*
260 	 * check for sequence number.
261 	 */
262 	if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
263 		if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
264 			; /*okey*/
265 		} else {
266 			IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
267 			ipseclog((LOG_WARNING,
268 			    "replay packet in IPv4 AH input: %s %s\n",
269 			    ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
270 			goto fail;
271 		}
272 	}
273 
274 	/*
275 	 * alright, it seems sane.  now we are going to check the
276 	 * cryptographic checksum.
277 	 */
278 	cksum = (u_char *)kalloc_data(siz1, Z_NOWAIT);
279 	if (!cksum) {
280 		ipseclog((LOG_DEBUG, "IPv4 AH input: "
281 		    "couldn't alloc temporary region for cksum\n"));
282 		IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
283 		goto fail;
284 	}
285 
286 	/*
287 	 * some of IP header fields are flipped to the host endian.
288 	 * convert them back to network endian.  VERY stupid.
289 	 */
290 	if ((ip->ip_len + hlen) > UINT16_MAX) {
291 		ipseclog((LOG_DEBUG, "IPv4 AH input: "
292 		    "bad length ip header len %u, total len %u\n",
293 		    ip->ip_len, hlen));
294 		IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
295 		goto fail;
296 	}
297 
298 	ip->ip_len = htons((u_int16_t)(ip->ip_len + hlen));
299 	ip->ip_off = htons(ip->ip_off);
300 	if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
301 		kfree_data(cksum, siz1);
302 		IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
303 		goto fail;
304 	}
305 	IPSEC_STAT_INCREMENT(ipsecstat.in_ahhist[sav->alg_auth]);
306 	/*
307 	 * flip them back.
308 	 */
309 	ip->ip_len = ntohs(ip->ip_len) - hlen;
310 	ip->ip_off = ntohs(ip->ip_off);
311 
312 	{
313 		caddr_t sumpos = NULL;
314 
315 		if (sav->flags & SADB_X_EXT_OLD) {
316 			/* RFC 1826 */
317 			sumpos = (caddr_t)(ah + 1);
318 		} else {
319 			/* RFC 2402 */
320 			sumpos = (caddr_t)(((struct newah *)ah) + 1);
321 		}
322 
323 		if (bcmp(sumpos, cksum, siz) != 0) {
324 			ipseclog((LOG_WARNING,
325 			    "checksum mismatch in IPv4 AH input: %s %s\n",
326 			    ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
327 			kfree_data(cksum, siz1);
328 			IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
329 			goto fail;
330 		}
331 	}
332 
333 	kfree_data(cksum, siz1);
334 
335 	m->m_flags |= M_AUTHIPHDR;
336 	m->m_flags |= M_AUTHIPDGM;
337 
338 	if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) {
339 		IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthsucc);
340 	} else {
341 		ipseclog((LOG_WARNING,
342 		    "authentication failed in IPv4 AH input: %s %s\n",
343 		    ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
344 		IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
345 		goto fail;
346 	}
347 
348 	/*
349 	 * update sequence number.
350 	 */
351 	if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
352 		if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
353 			IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
354 			goto fail;
355 		}
356 	}
357 
358 	/* was it transmitted over the IPsec tunnel SA? */
359 	if (sav->flags & SADB_X_EXT_OLD) {
360 		/* RFC 1826 */
361 		stripsiz = sizeof(struct ah) + siz1;
362 	} else {
363 		/* RFC 2402 */
364 		stripsiz = sizeof(struct newah) + siz1;
365 	}
366 	if (ipsec4_tunnel_validate(m, (int)(off + stripsiz), nxt, sav, &ifamily)) {
367 		ifaddr_t ifa;
368 		struct sockaddr_storage addr;
369 		struct sockaddr_in *ipaddr;
370 
371 		/*
372 		 * strip off all the headers that precedes AH.
373 		 *	IP xx AH IP' payload -> IP' payload
374 		 *
375 		 * XXX more sanity checks
376 		 * XXX relationship with gif?
377 		 */
378 		u_int8_t tos, otos;
379 		int sum;
380 
381 		if (ifamily == AF_INET6) {
382 			ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch "
383 			    "in IPv4 AH input: %s\n", ipsec_logsastr(sav)));
384 			goto fail;
385 		}
386 		tos = ip->ip_tos;
387 		m_adj(m, (int)(off + stripsiz));
388 		if (m->m_len < sizeof(*ip)) {
389 			m = m_pullup(m, sizeof(*ip));
390 			if (!m) {
391 				IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
392 				goto fail;
393 			}
394 		}
395 		ip = mtod(m, struct ip *);
396 		otos = ip->ip_tos;
397 		/* ECN consideration. */
398 		if (ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos) == 0) {
399 			IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
400 			goto fail;
401 		}
402 
403 		if (otos != ip->ip_tos) {
404 			sum = ~ntohs(ip->ip_sum) & 0xffff;
405 			sum += (~otos & 0xffff) + ip->ip_tos;
406 			sum = (sum >> 16) + (sum & 0xffff);
407 			sum += (sum >> 16); /* add carry */
408 			ip->ip_sum = htons(~sum & 0xffff);
409 		}
410 
411 		if (!key_checktunnelsanity(sav, AF_INET,
412 		    (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
413 			ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
414 			    "in IPv4 AH input: %s %s\n",
415 			    ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
416 			IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
417 			goto fail;
418 		}
419 
420 #if 1
421 		/*
422 		 * Should the inner packet be considered authentic?
423 		 * My current answer is: NO.
424 		 *
425 		 * host1 -- gw1 === gw2 -- host2
426 		 *	In this case, gw2 can trust the	authenticity of the
427 		 *	outer packet, but NOT inner.  Packet may be altered
428 		 *	between host1 and gw1.
429 		 *
430 		 * host1 -- gw1 === host2
431 		 *	This case falls into the same scenario as above.
432 		 *
433 		 * host1 === host2
434 		 *	This case is the only case when we may be able to leave
435 		 *	M_AUTHIPHDR and M_AUTHIPDGM set.
436 		 *	However, if host1 is wrongly configured, and allows
437 		 *	attacker to inject some packet with src=host1 and
438 		 *	dst=host2, you are in risk.
439 		 */
440 		m->m_flags &= ~M_AUTHIPHDR;
441 		m->m_flags &= ~M_AUTHIPDGM;
442 #endif
443 
444 		key_sa_recordxfer(sav, m->m_pkthdr.len);
445 		if (ipsec_incr_history_count(m, IPPROTO_AH, spi) != 0 ||
446 		    ipsec_incr_history_count(m, IPPROTO_IPV4, 0) != 0) {
447 			IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
448 			goto fail;
449 		}
450 
451 		bzero(&addr, sizeof(addr));
452 		ipaddr = (__typeof__(ipaddr)) & addr;
453 		ipaddr->sin_family = AF_INET;
454 		ipaddr->sin_len = sizeof(*ipaddr);
455 		ipaddr->sin_addr = ip->ip_dst;
456 
457 		// update the receiving interface address based on the inner address
458 		ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
459 		if (ifa) {
460 			m->m_pkthdr.rcvif = ifa->ifa_ifp;
461 			ifa_remref(ifa);
462 		}
463 
464 		// Input via IPsec interface
465 		lck_mtx_lock(sadb_mutex);
466 		ifnet_t ipsec_if = sav->sah->ipsec_if;
467 		if (ipsec_if != NULL) {
468 			// If an interface is found, add a reference count before dropping the lock
469 			ifnet_reference(ipsec_if);
470 		}
471 		lck_mtx_unlock(sadb_mutex);
472 		if (ipsec_if != NULL) {
473 			errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
474 			ifnet_release(ipsec_if);
475 			if (inject_error == 0) {
476 				m = NULL;
477 				goto done;
478 			} else {
479 				goto fail;
480 			}
481 		}
482 
483 		if (proto_input(PF_INET, m) != 0) {
484 			goto fail;
485 		}
486 		nxt = IPPROTO_DONE;
487 	} else {
488 		/*
489 		 * strip off AH.
490 		 */
491 
492 		ip = mtod(m, struct ip *);
493 		/*
494 		 * We do deep-copy since KAME requires that
495 		 * the packet is placed in a single external mbuf.
496 		 */
497 		ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
498 		m->m_data += stripsiz;
499 		m->m_len -= stripsiz;
500 		m->m_pkthdr.len -= stripsiz;
501 
502 		if (m->m_len < sizeof(*ip)) {
503 			m = m_pullup(m, sizeof(*ip));
504 			if (m == NULL) {
505 				IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
506 				goto fail;
507 			}
508 		}
509 		ip = mtod(m, struct ip *);
510 #ifdef IPLEN_FLIPPED
511 		ip->ip_len = (u_short)(ip->ip_len - stripsiz);
512 #else
513 		ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
514 #endif
515 		ip->ip_p = (u_char)nxt;
516 		/* forget about IP hdr checksum, the check has already been passed */
517 
518 		key_sa_recordxfer(sav, m->m_pkthdr.len);
519 		if (ipsec_incr_history_count(m, IPPROTO_AH, spi) != 0) {
520 			IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
521 			goto fail;
522 		}
523 
524 		DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL,
525 		    struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif,
526 		    struct ip *, ip, struct ip6_hdr *, NULL);
527 
528 		if (nxt != IPPROTO_DONE) {
529 			// Input via IPsec interface
530 			lck_mtx_lock(sadb_mutex);
531 			ifnet_t ipsec_if = sav->sah->ipsec_if;
532 			if (ipsec_if != NULL) {
533 				// If an interface is found, add a reference count before dropping the lock
534 				ifnet_reference(ipsec_if);
535 			}
536 			lck_mtx_unlock(sadb_mutex);
537 			if (ipsec_if != NULL) {
538 				ip->ip_len = htons(ip->ip_len + hlen);
539 				ip->ip_off = htons(ip->ip_off);
540 				ip->ip_sum = 0;
541 				ip->ip_sum = ip_cksum_hdr_in(m, hlen);
542 				errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
543 				ifnet_release(ipsec_if);
544 				if (inject_error == 0) {
545 					m = NULL;
546 					goto done;
547 				} else {
548 					goto fail;
549 				}
550 			}
551 
552 			if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 &&
553 			    ipsec4_in_reject(m, NULL)) {
554 				IPSEC_STAT_INCREMENT(ipsecstat.in_polvio);
555 				goto fail;
556 			}
557 			ip_proto_dispatch_in(m, off, (u_int8_t)nxt, 0);
558 		} else {
559 			m_freem(m);
560 		}
561 		m = NULL;
562 	}
563 done:
564 	if (sav) {
565 		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
566 		    printf("DP ah4_input call free SA:0x%llx\n",
567 		    (uint64_t)VM_KERNEL_ADDRPERM(sav)));
568 		key_freesav(sav, KEY_SADB_UNLOCKED);
569 	}
570 	IPSEC_STAT_INCREMENT(ipsecstat.in_success);
571 	return;
572 
573 fail:
574 	if (sav) {
575 		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
576 		    printf("DP ah4_input call free SA:0x%llx\n",
577 		    (uint64_t)VM_KERNEL_ADDRPERM(sav)));
578 		key_freesav(sav, KEY_SADB_UNLOCKED);
579 	}
580 	if (m) {
581 		m_freem(m);
582 	}
583 	return;
584 }
585 #endif /* INET */
586 
587 int
ah6_input(struct mbuf ** mp,int * offp,int proto)588 ah6_input(struct mbuf **mp, int *offp, int proto)
589 {
590 #pragma unused(proto)
591 	union sockaddr_in_4_6 src = {};
592 	union sockaddr_in_4_6 dst = {};
593 	struct mbuf *m = *mp;
594 	int off = *offp;
595 	struct ip6_hdr *ip6 = NULL;
596 	struct ah *ah = NULL;
597 	u_int32_t spi = 0;
598 	const struct ah_algorithm *algo = NULL;
599 	size_t siz = 0;
600 	size_t siz1 = 0;
601 	u_char *__bidi_indexable cksum = NULL;
602 	struct secasvar *sav = NULL;
603 	u_int16_t nxt = IPPROTO_DONE;
604 	size_t stripsiz = 0;
605 	sa_family_t ifamily = AF_UNSPEC;
606 
607 	IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), {return IPPROTO_DONE;});
608 	ah = (struct ah *)(void *)(mtod(m, caddr_t) + off);
609 	/* Expect 32-bit aligned data pointer on strict-align platforms */
610 	MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
611 
612 	ip6 = mtod(m, struct ip6_hdr *);
613 	nxt = ah->ah_nxt;
614 
615 	/* find the sassoc.  */
616 	spi = ah->ah_spi;
617 
618 	if (ntohs(ip6->ip6_plen) == 0) {
619 		ipseclog((LOG_ERR, "IPv6 AH input: "
620 		    "AH with IPv6 jumbogram is not supported.\n"));
621 		IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
622 		goto fail;
623 	}
624 
625 	ipsec_fill_ip6_sockaddr_4_6(&src, &ip6->ip6_src, 0);
626 	ipsec_fill_ip6_sockaddr_4_6_with_ifscope(&dst, &ip6->ip6_dst, 0,
627 	    ip6_input_getsrcifscope(m));
628 
629 	if ((sav = key_allocsa(&src, &dst, IPPROTO_AH, spi, NULL)) == 0) {
630 		ipseclog((LOG_WARNING,
631 		    "IPv6 AH input: no key association found for spi %u\n",
632 		    (u_int32_t)ntohl(spi)));
633 		IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa);
634 		goto fail;
635 	}
636 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
637 	    printf("DP ah6_input called to allocate SA:0x%llx\n",
638 	    (uint64_t)VM_KERNEL_ADDRPERM(sav)));
639 	if (sav->state != SADB_SASTATE_MATURE
640 	    && sav->state != SADB_SASTATE_DYING) {
641 		ipseclog((LOG_DEBUG,
642 		    "IPv6 AH input: non-mature/dying SA found for spi %u; ",
643 		    (u_int32_t)ntohl(spi)));
644 		IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
645 		goto fail;
646 	}
647 
648 	algo = ah_algorithm_lookup(sav->alg_auth);
649 	if (!algo) {
650 		ipseclog((LOG_DEBUG, "IPv6 AH input: "
651 		    "unsupported authentication algorithm for spi %u\n",
652 		    (u_int32_t)ntohl(spi)));
653 		IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
654 		goto fail;
655 	}
656 
657 	siz = (*algo->sumsiz)(sav);
658 	siz1 = ((siz + 3) & ~(4 - 1));
659 
660 	/*
661 	 * sanity checks for header, 1.
662 	 */
663 	{
664 		int sizoff;
665 
666 		sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
667 
668 		/*
669 		 * Here, we do not do "siz1 == siz".  See ah4_input() for complete
670 		 * description.
671 		 */
672 		if (siz1 < siz) {
673 			ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
674 			    "(%u, should be at least %u): %s\n",
675 			    (u_int32_t)siz1, (u_int32_t)siz,
676 			    ipsec6_logpacketstr(ip6, spi)));
677 			IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
678 			goto fail;
679 		}
680 		if ((ah->ah_len << 2) - sizoff != siz1) {
681 			ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
682 			    "(%d should be %u): %s\n",
683 			    (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
684 			    ipsec6_logpacketstr(ip6, spi)));
685 			IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
686 			goto fail;
687 		}
688 		VERIFY((sizeof(struct ah) + sizoff + siz1) <= INT_MAX);
689 		IP6_EXTHDR_CHECK(m, off, (int)(sizeof(struct ah) + sizoff + siz1),
690 		    {goto fail;});
691 		ip6 = mtod(m, struct ip6_hdr *);
692 		ah = (struct ah *)(void *)(mtod(m, caddr_t) + off);
693 	}
694 
695 	/*
696 	 * check for sequence number.
697 	 */
698 	if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
699 		if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
700 			; /*okey*/
701 		} else {
702 			IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
703 			ipseclog((LOG_WARNING,
704 			    "replay packet in IPv6 AH input: %s %s\n",
705 			    ipsec6_logpacketstr(ip6, spi),
706 			    ipsec_logsastr(sav)));
707 			goto fail;
708 		}
709 	}
710 
711 	/*
712 	 * alright, it seems sane.  now we are going to check the
713 	 * cryptographic checksum.
714 	 */
715 	cksum = (u_char *)kalloc_data(siz1, Z_NOWAIT);
716 	if (!cksum) {
717 		ipseclog((LOG_DEBUG, "IPv6 AH input: "
718 		    "couldn't alloc temporary region for cksum\n"));
719 		IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
720 		goto fail;
721 	}
722 
723 	if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
724 		kfree_data(cksum, siz1);
725 		IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
726 		goto fail;
727 	}
728 	IPSEC_STAT_INCREMENT(ipsec6stat.in_ahhist[sav->alg_auth]);
729 
730 	{
731 		caddr_t sumpos = NULL;
732 
733 		if (sav->flags & SADB_X_EXT_OLD) {
734 			/* RFC 1826 */
735 			sumpos = (caddr_t)(ah + 1);
736 		} else {
737 			/* RFC 2402 */
738 			sumpos = (caddr_t)(((struct newah *)ah) + 1);
739 		}
740 
741 		if (bcmp(sumpos, cksum, siz) != 0) {
742 			ipseclog((LOG_WARNING,
743 			    "checksum mismatch in IPv6 AH input: %s %s\n",
744 			    ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
745 			kfree_data(cksum, siz1);
746 			IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
747 			goto fail;
748 		}
749 	}
750 
751 	kfree_data(cksum, siz1);
752 
753 	m->m_flags |= M_AUTHIPHDR;
754 	m->m_flags |= M_AUTHIPDGM;
755 
756 	if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) {
757 		IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthsucc);
758 	} else {
759 		ipseclog((LOG_WARNING,
760 		    "authentication failed in IPv6 AH input: %s %s\n",
761 		    ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
762 		IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
763 		goto fail;
764 	}
765 
766 	/*
767 	 * update sequence number.
768 	 */
769 	if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
770 		if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
771 			IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
772 			goto fail;
773 		}
774 	}
775 
776 	/* was it transmitted over the IPsec tunnel SA? */
777 	if (sav->flags & SADB_X_EXT_OLD) {
778 		/* RFC 1826 */
779 		stripsiz = sizeof(struct ah) + siz1;
780 	} else {
781 		/* RFC 2402 */
782 		stripsiz = sizeof(struct newah) + siz1;
783 	}
784 	if (ipsec6_tunnel_validate(m, (int)(off + stripsiz), nxt, sav, &ifamily)) {
785 		ifaddr_t ifa;
786 		struct sockaddr_storage addr;
787 		struct sockaddr_in6 *ip6addr;
788 		/*
789 		 * strip off all the headers that precedes AH.
790 		 *	IP6 xx AH IP6' payload -> IP6' payload
791 		 *
792 		 * XXX more sanity checks
793 		 * XXX relationship with gif?
794 		 */
795 		u_int32_t flowinfo;     /*net endian*/
796 
797 		if (ifamily == AF_INET) {
798 			ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch "
799 			    "in IPv6 AH input: %s\n", ipsec_logsastr(sav)));
800 			goto fail;
801 		}
802 
803 		flowinfo = ip6->ip6_flow;
804 		m_adj(m, (int)(off + stripsiz));
805 		if (m->m_len < sizeof(*ip6)) {
806 			/*
807 			 * m_pullup is prohibited in KAME IPv6 input processing
808 			 * but there's no other way!
809 			 */
810 			m = m_pullup(m, sizeof(*ip6));
811 			if (!m) {
812 				IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
813 				goto fail;
814 			}
815 		}
816 		ip6 = mtod(m, struct ip6_hdr *);
817 		/* ECN consideration. */
818 		if (ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow) == 0) {
819 			IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
820 			goto fail;
821 		}
822 		if (!key_checktunnelsanity(sav, AF_INET6,
823 		    (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
824 			ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
825 			    "in IPv6 AH input: %s %s\n",
826 			    ipsec6_logpacketstr(ip6, spi),
827 			    ipsec_logsastr(sav)));
828 			IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
829 			goto fail;
830 		}
831 
832 		/*
833 		 * should the inner packet be considered authentic?
834 		 * see comment in ah4_input().
835 		 */
836 		m->m_flags &= ~M_AUTHIPHDR;
837 		m->m_flags &= ~M_AUTHIPDGM;
838 
839 		key_sa_recordxfer(sav, m->m_pkthdr.len);
840 		if (ipsec_incr_history_count(m, IPPROTO_AH, spi) != 0 ||
841 		    ipsec_incr_history_count(m, IPPROTO_IPV6, 0) != 0) {
842 			IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
843 			goto fail;
844 		}
845 
846 		bzero(&addr, sizeof(addr));
847 		ip6addr = (__typeof__(ip6addr)) & addr;
848 		ip6addr->sin6_family = AF_INET6;
849 		ip6addr->sin6_len = sizeof(*ip6addr);
850 		ip6addr->sin6_addr = ip6->ip6_dst;
851 
852 		// update the receiving interface address based on the inner address
853 		ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
854 		if (ifa) {
855 			m->m_pkthdr.rcvif = ifa->ifa_ifp;
856 			ifa_remref(ifa);
857 		}
858 
859 		// Input via IPsec interface
860 		lck_mtx_lock(sadb_mutex);
861 		ifnet_t ipsec_if = sav->sah->ipsec_if;
862 		if (ipsec_if != NULL) {
863 			// If an interface is found, add a reference count before dropping the lock
864 			ifnet_reference(ipsec_if);
865 		}
866 		lck_mtx_unlock(sadb_mutex);
867 		if (ipsec_if != NULL) {
868 			errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
869 			ifnet_release(ipsec_if);
870 			if (inject_error == 0) {
871 				m = NULL;
872 				nxt = IPPROTO_DONE;
873 				goto done;
874 			} else {
875 				goto fail;
876 			}
877 		}
878 
879 		if (proto_input(PF_INET6, m) != 0) {
880 			goto fail;
881 		}
882 		nxt = IPPROTO_DONE;
883 	} else {
884 		/*
885 		 * strip off AH.
886 		 */
887 		char *prvnxtp;
888 
889 		/*
890 		 * Copy the value of the next header field of AH to the
891 		 * next header field of the previous header.
892 		 * This is necessary because AH will be stripped off below.
893 		 */
894 		prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
895 		*prvnxtp = (u_int8_t)nxt;
896 
897 		ip6 = mtod(m, struct ip6_hdr *);
898 		/*
899 		 * We do deep-copy since KAME requires that
900 		 * the packet is placed in a single mbuf.
901 		 */
902 		ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
903 		m->m_data += stripsiz;
904 		m->m_len -= stripsiz;
905 		m->m_pkthdr.len -= stripsiz;
906 		ip6 = mtod(m, struct ip6_hdr *);
907 		/* XXX jumbogram */
908 		ip6->ip6_plen = htons((u_int16_t)(ntohs(ip6->ip6_plen) - stripsiz));
909 
910 		key_sa_recordxfer(sav, m->m_pkthdr.len);
911 		if (ipsec_incr_history_count(m, IPPROTO_AH, spi) != 0) {
912 			IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
913 			goto fail;
914 		}
915 
916 		// Input via IPsec interface
917 		lck_mtx_lock(sadb_mutex);
918 		ifnet_t ipsec_if = sav->sah->ipsec_if;
919 		if (ipsec_if != NULL) {
920 			// If an interface is found, add a reference count before dropping the lock
921 			ifnet_reference(ipsec_if);
922 		}
923 		lck_mtx_unlock(sadb_mutex);
924 		if (ipsec_if != NULL) {
925 			errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
926 			ifnet_release(ipsec_if);
927 			if (inject_error == 0) {
928 				m = NULL;
929 				nxt = IPPROTO_DONE;
930 				goto done;
931 			} else {
932 				goto fail;
933 			}
934 		}
935 	}
936 
937 done:
938 	*offp = off;
939 	*mp = m;
940 	if (sav) {
941 		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
942 		    printf("DP ah6_input call free SA:0x%llx\n",
943 		    (uint64_t)VM_KERNEL_ADDRPERM(sav)));
944 		key_freesav(sav, KEY_SADB_UNLOCKED);
945 	}
946 	IPSEC_STAT_INCREMENT(ipsec6stat.in_success);
947 	return nxt;
948 
949 fail:
950 	if (sav) {
951 		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
952 		    printf("DP ah6_input call free SA:0x%llx\n",
953 		    (uint64_t)VM_KERNEL_ADDRPERM(sav)));
954 		key_freesav(sav, KEY_SADB_UNLOCKED);
955 	}
956 	if (m) {
957 		m_freem(m);
958 		*mp = NULL;
959 	}
960 	return IPPROTO_DONE;
961 }
962 
963 void
ah6_ctlinput(int cmd,struct sockaddr * sa,void * d)964 ah6_ctlinput(int cmd, struct sockaddr *sa, void *d)
965 {
966 	union sockaddr_in_4_6 src = {};
967 	union sockaddr_in_4_6 dst = {};
968 	const struct newah *ahp;
969 	struct newah ah;
970 	struct secasvar *sav;
971 	struct ip6_hdr *ip6;
972 	struct mbuf *m;
973 	struct ip6ctlparam *ip6cp = NULL;
974 	struct sockaddr_in6 *sa6_src, *sa6_dst;
975 	int off = 0;
976 
977 	if (sa->sa_family != AF_INET6 ||
978 	    sa->sa_len != sizeof(struct sockaddr_in6)) {
979 		return;
980 	}
981 	if ((unsigned)cmd >= PRC_NCMDS) {
982 		return;
983 	}
984 
985 	/* if the parameter is from icmp6, decode it. */
986 	if (d != NULL) {
987 		ip6cp = (struct ip6ctlparam *)d;
988 		m = ip6cp->ip6c_m;
989 		ip6 = ip6cp->ip6c_ip6;
990 		off = ip6cp->ip6c_off;
991 	} else {
992 		m = NULL;
993 		ip6 = NULL;
994 	}
995 
996 	if (ip6) {
997 		/*
998 		 * XXX: We assume that when ip6 is non NULL,
999 		 * M and OFF are valid.
1000 		 */
1001 
1002 		/* check if we can safely examine src and dst ports */
1003 		if (m->m_pkthdr.len < off + sizeof(ah)) {
1004 			return;
1005 		}
1006 
1007 		if (m->m_len < off + sizeof(ah)) {
1008 			/*
1009 			 * this should be rare case,
1010 			 * so we compromise on this copy...
1011 			 */
1012 			m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
1013 			ahp = &ah;
1014 		} else {
1015 			ahp = (struct newah *)(void *)(mtod(m, caddr_t) + off);
1016 		}
1017 
1018 		if (cmd == PRC_MSGSIZE) {
1019 			int valid = 0;
1020 
1021 			/*
1022 			 * Check to see if we have a valid SA corresponding to
1023 			 * the address in the ICMP message payload.
1024 			 */
1025 			sa6_src = ip6cp->ip6c_src;
1026 			sa6_dst = SIN6(sa);
1027 			ipsec_fill_ip6_sockaddr_4_6(&src, &sa6_src->sin6_addr, 0);
1028 			ipsec_fill_ip6_sockaddr_4_6_with_ifscope(&dst,
1029 			    &sa6_dst->sin6_addr, 0, sa6_dst->sin6_scope_id);
1030 
1031 			sav = key_allocsa(&src, &dst, IPPROTO_AH, ahp->ah_spi, NULL);
1032 			if (sav) {
1033 				if (sav->state == SADB_SASTATE_MATURE ||
1034 				    sav->state == SADB_SASTATE_DYING) {
1035 					valid++;
1036 				}
1037 				key_freesav(sav, KEY_SADB_UNLOCKED);
1038 			}
1039 
1040 			/* XXX Further validation? */
1041 
1042 			/*
1043 			 * Depending on the value of "valid" and routing table
1044 			 * size (mtudisc_{hi,lo}wat), we will:
1045 			 * - recalcurate the new MTU and create the
1046 			 *   corresponding routing entry, or
1047 			 * - ignore the MTU change notification.
1048 			 */
1049 			icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1050 		}
1051 
1052 		/* we normally notify single pcb here */
1053 	} else {
1054 		/* we normally notify any pcb here */
1055 	}
1056 }
1057