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