]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ah_input.c
xnu-4903.241.1.tar.gz
[apple/xnu.git] / bsd / netinet6 / ah_input.c
CommitLineData
b0d623f7 1/*
39037602 2 * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39037602 5 *
b0d623f7
A
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.
39037602 14 *
b0d623f7
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39037602 17 *
b0d623f7
A
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.
39037602 25 *
b0d623f7
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
55e303ae
A
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 $ */
9bccf70c 31
1c79356b
A
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
1c79356b
A
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/malloc.h>
68#include <sys/mbuf.h>
316670eb 69#include <sys/mcache.h>
1c79356b
A
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>
fe8ab488 79#include <net/if_ipsec.h>
1c79356b 80#include <net/route.h>
1c79356b 81#include <kern/cpu_number.h>
91447636 82#include <kern/locks.h>
1c79356b
A
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>
9bccf70c
A
90#include <netinet/in_pcb.h>
91#if INET6
92#include <netinet6/ip6_ecn.h>
93#endif
1c79356b
A
94
95#if INET6
96#include <netinet/ip6.h>
97#include <netinet6/ip6_var.h>
9bccf70c 98#include <netinet6/in6_pcb.h>
1c79356b 99#include <netinet/icmp6.h>
9bccf70c 100#include <netinet6/ip6protosw.h>
1c79356b
A
101#endif
102
103#include <netinet6/ipsec.h>
9bccf70c
A
104#if INET6
105#include <netinet6/ipsec6.h>
106#endif
1c79356b 107#include <netinet6/ah.h>
9bccf70c
A
108#if INET6
109#include <netinet6/ah6.h>
110#endif
1c79356b
A
111#include <netkey/key.h>
112#include <netkey/keydb.h>
9bccf70c 113#if IPSEC_DEBUG
1c79356b 114#include <netkey/key_debug.h>
9bccf70c
A
115#else
116#define KEYDEBUG(lev,arg)
117#endif
1c79356b 118
2d21ac55
A
119#include <net/kpi_protocol.h>
120#include <netinet/kpi_ipfilter_var.h>
6d2010ae 121#include <mach/sdt.h>
1c79356b
A
122
123#include <net/net_osdep.h>
124
125#define IPLEN_FLIPPED
126
127#if INET
1c79356b
A
128void
129ah4_input(struct mbuf *m, int off)
130{
131 struct ip *ip;
132 struct ah *ah;
133 u_int32_t spi;
9bccf70c 134 const struct ah_algorithm *algo;
1c79356b
A
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;
9bccf70c 141 size_t stripsiz = 0;
2d21ac55 142 sa_family_t ifamily;
1c79356b 143
1c79356b
A
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"));
2d21ac55 149 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
150 goto fail;
151 }
152 }
153
316670eb
A
154 /* Expect 32-bit aligned data pointer on strict-align platforms */
155 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
156
1c79356b 157 ip = mtod(m, struct ip *);
316670eb 158 ah = (struct ah *)(void *)(((caddr_t)ip) + off);
1c79356b
A
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)));
2d21ac55 175 IPSEC_STAT_INCREMENT(ipsecstat.in_nosa);
1c79356b
A
176 goto fail;
177 }
178 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
179 printf("DP ah4_input called to allocate SA:0x%llx\n",
180 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
1c79356b
A
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)));
2d21ac55 186 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
1c79356b
A
187 goto fail;
188 }
9bccf70c
A
189
190 algo = ah_algorithm_lookup(sav->alg_auth);
191 if (!algo) {
1c79356b 192 ipseclog((LOG_DEBUG, "IPv4 AH input: "
9bccf70c 193 "unsupported authentication algorithm for spi %u\n",
1c79356b 194 (u_int32_t)ntohl(spi)));
2d21ac55 195 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
1c79356b
A
196 goto fail;
197 }
198
1c79356b
A
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
9bccf70c
A
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",
b0d623f7 234 (u_int32_t)siz1, (u_int32_t)siz,
9bccf70c 235 ipsec4_logpacketstr(ip, spi)));
2d21ac55 236 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
9bccf70c
A
237 goto fail;
238 }
1c79356b
A
239 if ((ah->ah_len << 2) - sizoff != siz1) {
240 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
9bccf70c 241 "(%d should be %lu): %s\n",
b0d623f7 242 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
9bccf70c 243 ipsec4_logpacketstr(ip, spi)));
2d21ac55 244 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
245 goto fail;
246 }
247
1c79356b
A
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"));
2d21ac55 252 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
253 goto fail;
254 }
316670eb
A
255 /* Expect 32-bit aligned data ptr on strict-align platforms */
256 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
1c79356b
A
257
258 ip = mtod(m, struct ip *);
316670eb 259 ah = (struct ah *)(void *)(((caddr_t)ip) + off);
1c79356b 260 }
1c79356b
A
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 {
2d21ac55 270 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
1c79356b
A
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"));
2d21ac55 286 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
287 goto fail;
288 }
289
1c79356b
A
290 /*
291 * some of IP header fields are flipped to the host endian.
292 * convert them back to network endian. VERY stupid.
293 */
1c79356b 294 ip->ip_len = htons(ip->ip_len + hlen);
1c79356b 295 ip->ip_off = htons(ip->ip_off);
9bccf70c
A
296 if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
297 FREE(cksum, M_TEMP);
2d21ac55 298 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
299 goto fail;
300 }
2d21ac55 301 IPSEC_STAT_INCREMENT(ipsecstat.in_ahhist[sav->alg_auth]);
1c79356b
A
302 /*
303 * flip them back.
304 */
1c79356b 305 ip->ip_len = ntohs(ip->ip_len) - hlen;
1c79356b 306 ip->ip_off = ntohs(ip->ip_off);
1c79356b
A
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)));
9bccf70c 323 FREE(cksum, M_TEMP);
2d21ac55 324 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
1c79356b
A
325 goto fail;
326 }
327 }
328
9bccf70c 329 FREE(cksum, M_TEMP);
1c79356b
A
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"));
2d21ac55 351 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
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
2d21ac55 377 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthsucc);
1c79356b
A
378 } else {
379 ipseclog((LOG_WARNING,
380 "authentication failed in IPv4 AH input: %s %s\n",
381 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
2d21ac55 382 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
1c79356b
A
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)) {
2d21ac55 391 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
1c79356b
A
392 goto fail;
393 }
394 }
395
396 /* was it transmitted over the IPsec tunnel SA? */
9bccf70c
A
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 }
2d21ac55 404 if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav, &ifamily)) {
6d2010ae
A
405 ifaddr_t ifa;
406 struct sockaddr_storage addr;
39037602 407 struct sockaddr_in *ipaddr;
6d2010ae 408
1c79356b
A
409 /*
410 * strip off all the headers that precedes AH.
411 * IP xx AH IP' payload -> IP' payload
412 *
413 * XXX more sanity checks
414 * XXX relationship with gif?
415 */
4bd07ac2
A
416 u_int8_t tos, otos;
417 int sum;
418
2d21ac55
A
419 if (ifamily == AF_INET6) {
420 ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch "
421 "in IPv4 AH input: %s\n", ipsec_logsastr(sav)));
422 goto fail;
423 }
1c79356b 424 tos = ip->ip_tos;
1c79356b
A
425 m_adj(m, off + stripsiz);
426 if (m->m_len < sizeof(*ip)) {
427 m = m_pullup(m, sizeof(*ip));
428 if (!m) {
2d21ac55 429 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
430 goto fail;
431 }
432 }
433 ip = mtod(m, struct ip *);
4bd07ac2 434 otos = ip->ip_tos;
1c79356b 435 /* ECN consideration. */
3e170ce0
A
436 if (ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos) == 0) {
437 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
438 goto fail;
439 }
4bd07ac2
A
440
441 if (otos != ip->ip_tos) {
442 sum = ~ntohs(ip->ip_sum) & 0xffff;
443 sum += (~otos & 0xffff) + ip->ip_tos;
444 sum = (sum >> 16) + (sum & 0xffff);
445 sum += (sum >> 16); /* add carry */
446 ip->ip_sum = htons(~sum & 0xffff);
447 }
448
1c79356b
A
449 if (!key_checktunnelsanity(sav, AF_INET,
450 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
451 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
452 "in IPv4 AH input: %s %s\n",
453 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
2d21ac55 454 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
455 goto fail;
456 }
457
1c79356b
A
458#if 1
459 /*
460 * Should the inner packet be considered authentic?
461 * My current answer is: NO.
462 *
463 * host1 -- gw1 === gw2 -- host2
464 * In this case, gw2 can trust the authenticity of the
465 * outer packet, but NOT inner. Packet may be altered
466 * between host1 and gw1.
467 *
468 * host1 -- gw1 === host2
469 * This case falls into the same scenario as above.
470 *
471 * host1 === host2
472 * This case is the only case when we may be able to leave
473 * M_AUTHIPHDR and M_AUTHIPDGM set.
474 * However, if host1 is wrongly configured, and allows
475 * attacker to inject some packet with src=host1 and
476 * dst=host2, you are in risk.
477 */
478 m->m_flags &= ~M_AUTHIPHDR;
479 m->m_flags &= ~M_AUTHIPDGM;
480#endif
481
482 key_sa_recordxfer(sav, m);
9bccf70c
A
483 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
484 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
2d21ac55 485 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
9bccf70c
A
486 goto fail;
487 }
6d2010ae 488
39037602
A
489 bzero(&addr, sizeof(addr));
490 ipaddr = (__typeof__(ipaddr))&addr;
491 ipaddr->sin_family = AF_INET;
492 ipaddr->sin_len = sizeof(*ipaddr);
493 ipaddr->sin_addr = ip->ip_dst;
494
495 // update the receiving interface address based on the inner address
496 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
497 if (ifa) {
498 m->m_pkthdr.rcvif = ifa->ifa_ifp;
499 IFA_REMREF(ifa);
6d2010ae 500 }
fe8ab488
A
501
502 // Input via IPSec interface
503 if (sav->sah->ipsec_if != NULL) {
504 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) {
505 m = NULL;
506 goto done;
507 } else {
508 goto fail;
509 }
510 }
511
6d2010ae
A
512 if (proto_input(PF_INET, m) != 0)
513 goto fail;
1c79356b
A
514 nxt = IPPROTO_DONE;
515 } else {
516 /*
517 * strip off AH.
1c79356b 518 */
1c79356b
A
519
520 ip = mtod(m, struct ip *);
9bccf70c
A
521 /*
522 * We do deep-copy since KAME requires that
523 * the packet is placed in a single external mbuf.
524 */
1c79356b
A
525 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
526 m->m_data += stripsiz;
527 m->m_len -= stripsiz;
528 m->m_pkthdr.len -= stripsiz;
1c79356b
A
529
530 if (m->m_len < sizeof(*ip)) {
531 m = m_pullup(m, sizeof(*ip));
532 if (m == NULL) {
2d21ac55 533 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
534 goto fail;
535 }
536 }
537 ip = mtod(m, struct ip *);
538#ifdef IPLEN_FLIPPED
539 ip->ip_len = ip->ip_len - stripsiz;
540#else
541 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
542#endif
543 ip->ip_p = nxt;
544 /* forget about IP hdr checksum, the check has already been passed */
545
546 key_sa_recordxfer(sav, m);
9bccf70c 547 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
2d21ac55 548 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
9bccf70c
A
549 goto fail;
550 }
1c79356b 551
6d2010ae
A
552 DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL,
553 struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif,
554 struct ip *, ip, struct ip6_hdr *, NULL);
555
9bccf70c 556 if (nxt != IPPROTO_DONE) {
fe8ab488
A
557 // Input via IPSec interface
558 if (sav->sah->ipsec_if != NULL) {
559 ip->ip_len = htons(ip->ip_len + hlen);
560 ip->ip_off = htons(ip->ip_off);
561 ip->ip_sum = 0;
562 ip->ip_sum = ip_cksum_hdr_in(m, hlen);
563 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) {
564 m = NULL;
565 goto done;
566 } else {
567 goto fail;
568 }
569 }
570
9bccf70c
A
571 if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 &&
572 ipsec4_in_reject(m, NULL)) {
2d21ac55 573 IPSEC_STAT_INCREMENT(ipsecstat.in_polvio);
9bccf70c
A
574 goto fail;
575 }
91447636 576 ip_proto_dispatch_in(m, off, nxt, 0);
9bccf70c 577 } else
1c79356b
A
578 m_freem(m);
579 m = NULL;
580 }
fe8ab488 581done:
1c79356b
A
582 if (sav) {
583 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
584 printf("DP ah4_input call free SA:0x%llx\n",
585 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 586 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 587 }
2d21ac55 588 IPSEC_STAT_INCREMENT(ipsecstat.in_success);
1c79356b
A
589 return;
590
591fail:
592 if (sav) {
593 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
594 printf("DP ah4_input call free SA:0x%llx\n",
595 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 596 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b
A
597 }
598 if (m)
599 m_freem(m);
600 return;
601}
602#endif /* INET */
603
604#if INET6
605int
6d2010ae 606ah6_input(struct mbuf **mp, int *offp, int proto)
1c79356b 607{
6d2010ae 608#pragma unused(proto)
1c79356b
A
609 struct mbuf *m = *mp;
610 int off = *offp;
611 struct ip6_hdr *ip6;
612 struct ah *ah;
613 u_int32_t spi;
9bccf70c 614 const struct ah_algorithm *algo;
1c79356b
A
615 size_t siz;
616 size_t siz1;
617 u_char *cksum;
618 struct secasvar *sav = NULL;
619 u_int16_t nxt;
9bccf70c 620 size_t stripsiz = 0;
3e170ce0 621 sa_family_t ifamily;
91447636 622
2d21ac55 623 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), {return IPPROTO_DONE;});
316670eb 624 ah = (struct ah *)(void *)(mtod(m, caddr_t) + off);
316670eb
A
625 /* Expect 32-bit aligned data pointer on strict-align platforms */
626 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
627
1c79356b
A
628 ip6 = mtod(m, struct ip6_hdr *);
629 nxt = ah->ah_nxt;
630
631 /* find the sassoc. */
632 spi = ah->ah_spi;
633
634 if (ntohs(ip6->ip6_plen) == 0) {
635 ipseclog((LOG_ERR, "IPv6 AH input: "
636 "AH with IPv6 jumbogram is not supported.\n"));
2d21ac55 637 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
638 goto fail;
639 }
640
641 if ((sav = key_allocsa(AF_INET6,
642 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
643 IPPROTO_AH, spi)) == 0) {
644 ipseclog((LOG_WARNING,
645 "IPv6 AH input: no key association found for spi %u\n",
646 (u_int32_t)ntohl(spi)));
2d21ac55 647 IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa);
1c79356b
A
648 goto fail;
649 }
650 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
651 printf("DP ah6_input called to allocate SA:0x%llx\n",
652 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
1c79356b
A
653 if (sav->state != SADB_SASTATE_MATURE
654 && sav->state != SADB_SASTATE_DYING) {
655 ipseclog((LOG_DEBUG,
656 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
657 (u_int32_t)ntohl(spi)));
2d21ac55 658 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
1c79356b
A
659 goto fail;
660 }
9bccf70c
A
661
662 algo = ah_algorithm_lookup(sav->alg_auth);
663 if (!algo) {
1c79356b 664 ipseclog((LOG_DEBUG, "IPv6 AH input: "
9bccf70c 665 "unsupported authentication algorithm for spi %u\n",
1c79356b 666 (u_int32_t)ntohl(spi)));
2d21ac55 667 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
1c79356b
A
668 goto fail;
669 }
670
1c79356b
A
671 siz = (*algo->sumsiz)(sav);
672 siz1 = ((siz + 3) & ~(4 - 1));
673
674 /*
675 * sanity checks for header, 1.
676 */
677 {
678 int sizoff;
679
680 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
681
9bccf70c
A
682 /*
683 * Here, we do not do "siz1 == siz". See ah4_input() for complete
684 * description.
685 */
686 if (siz1 < siz) {
687 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
688 "(%lu, should be at least %lu): %s\n",
b0d623f7 689 (u_int32_t)siz1, (u_int32_t)siz,
9bccf70c 690 ipsec6_logpacketstr(ip6, spi)));
2d21ac55 691 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
9bccf70c
A
692 goto fail;
693 }
1c79356b
A
694 if ((ah->ah_len << 2) - sizoff != siz1) {
695 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
9bccf70c 696 "(%d should be %lu): %s\n",
b0d623f7 697 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
9bccf70c 698 ipsec6_logpacketstr(ip6, spi)));
2d21ac55 699 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
700 goto fail;
701 }
91447636 702 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1,
2d21ac55 703 {return IPPROTO_DONE;});
1c79356b
A
704 }
705
706 /*
707 * check for sequence number.
708 */
709 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
710 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
711 ; /*okey*/
712 else {
2d21ac55 713 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
1c79356b
A
714 ipseclog((LOG_WARNING,
715 "replay packet in IPv6 AH input: %s %s\n",
716 ipsec6_logpacketstr(ip6, spi),
717 ipsec_logsastr(sav)));
718 goto fail;
719 }
720 }
721
722 /*
723 * alright, it seems sane. now we are going to check the
724 * cryptographic checksum.
725 */
726 cksum = _MALLOC(siz1, M_TEMP, M_NOWAIT);
727 if (!cksum) {
728 ipseclog((LOG_DEBUG, "IPv6 AH input: "
729 "couldn't alloc temporary region for cksum\n"));
2d21ac55 730 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
731 goto fail;
732 }
733
9bccf70c
A
734 if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
735 FREE(cksum, M_TEMP);
2d21ac55 736 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
737 goto fail;
738 }
2d21ac55 739 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahhist[sav->alg_auth]);
1c79356b
A
740
741 {
742 caddr_t sumpos = NULL;
743
744 if (sav->flags & SADB_X_EXT_OLD) {
745 /* RFC 1826 */
746 sumpos = (caddr_t)(ah + 1);
747 } else {
748 /* RFC 2402 */
749 sumpos = (caddr_t)(((struct newah *)ah) + 1);
750 }
751
752 if (bcmp(sumpos, cksum, siz) != 0) {
753 ipseclog((LOG_WARNING,
754 "checksum mismatch in IPv6 AH input: %s %s\n",
755 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
9bccf70c 756 FREE(cksum, M_TEMP);
2d21ac55 757 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
1c79356b
A
758 goto fail;
759 }
760 }
761
9bccf70c 762 FREE(cksum, M_TEMP);
1c79356b
A
763
764 m->m_flags |= M_AUTHIPHDR;
765 m->m_flags |= M_AUTHIPDGM;
766
767#if 0
768 /*
769 * looks okey, but we need more sanity check.
770 * XXX should elaborate.
771 */
772 if (ah->ah_nxt == IPPROTO_IPV6) {
773 struct ip6_hdr *nip6;
774 size_t sizoff;
775
776 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
777
778 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
91447636 779 + sizeof(struct ip6_hdr),
2d21ac55 780 {return IPPROTO_DONE;});
1c79356b
A
781
782 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
783 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
784 || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
785 m->m_flags &= ~M_AUTHIPHDR;
786 m->m_flags &= ~M_AUTHIPDGM;
787 }
788 } else if (ah->ah_nxt == IPPROTO_IPIP) {
789 m->m_flags &= ~M_AUTHIPHDR;
790 m->m_flags &= ~M_AUTHIPDGM;
791 } else if (ah->ah_nxt == IPPROTO_IP) {
792 m->m_flags &= ~M_AUTHIPHDR;
793 m->m_flags &= ~M_AUTHIPDGM;
794 }
795#endif
796
797 if (m->m_flags & M_AUTHIPHDR
798 && m->m_flags & M_AUTHIPDGM) {
799#if 0
800 ipseclog((LOG_DEBUG,
801 "IPv6 AH input: authentication succeess\n"));
802#endif
2d21ac55 803 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthsucc);
1c79356b
A
804 } else {
805 ipseclog((LOG_WARNING,
806 "authentication failed in IPv6 AH input: %s %s\n",
807 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
2d21ac55 808 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
1c79356b
A
809 goto fail;
810 }
811
812 /*
813 * update sequence number.
814 */
815 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
816 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
2d21ac55 817 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
1c79356b
A
818 goto fail;
819 }
820 }
821
822 /* was it transmitted over the IPsec tunnel SA? */
9bccf70c
A
823 if (sav->flags & SADB_X_EXT_OLD) {
824 /* RFC 1826 */
825 stripsiz = sizeof(struct ah) + siz1;
826 } else {
827 /* RFC 2402 */
828 stripsiz = sizeof(struct newah) + siz1;
829 }
3e170ce0 830 if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav, &ifamily)) {
6d2010ae
A
831 ifaddr_t ifa;
832 struct sockaddr_storage addr;
39037602 833 struct sockaddr_in6 *ip6addr;
1c79356b
A
834 /*
835 * strip off all the headers that precedes AH.
836 * IP6 xx AH IP6' payload -> IP6' payload
837 *
838 * XXX more sanity checks
839 * XXX relationship with gif?
840 */
1c79356b
A
841 u_int32_t flowinfo; /*net endian*/
842
3e170ce0
A
843 if (ifamily == AF_INET) {
844 ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch "
845 "in IPv6 AH input: %s\n", ipsec_logsastr(sav)));
846 goto fail;
847 }
848
1c79356b 849 flowinfo = ip6->ip6_flow;
1c79356b
A
850 m_adj(m, off + stripsiz);
851 if (m->m_len < sizeof(*ip6)) {
852 /*
853 * m_pullup is prohibited in KAME IPv6 input processing
854 * but there's no other way!
855 */
856 m = m_pullup(m, sizeof(*ip6));
857 if (!m) {
2d21ac55 858 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
859 goto fail;
860 }
861 }
862 ip6 = mtod(m, struct ip6_hdr *);
863 /* ECN consideration. */
3e170ce0
A
864 if (ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow) == 0) {
865 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
866 goto fail;
867 }
1c79356b
A
868 if (!key_checktunnelsanity(sav, AF_INET6,
869 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
870 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
871 "in IPv6 AH input: %s %s\n",
872 ipsec6_logpacketstr(ip6, spi),
873 ipsec_logsastr(sav)));
2d21ac55 874 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
875 goto fail;
876 }
877
1c79356b
A
878#if 1
879 /*
880 * should the inner packet be considered authentic?
881 * see comment in ah4_input().
882 */
883 m->m_flags &= ~M_AUTHIPHDR;
884 m->m_flags &= ~M_AUTHIPDGM;
885#endif
886
887 key_sa_recordxfer(sav, m);
9bccf70c
A
888 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
889 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
2d21ac55 890 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
9bccf70c
A
891 goto fail;
892 }
6d2010ae 893
39037602
A
894 bzero(&addr, sizeof(addr));
895 ip6addr = (__typeof__(ip6addr))&addr;
896 ip6addr->sin6_family = AF_INET6;
897 ip6addr->sin6_len = sizeof(*ip6addr);
898 ip6addr->sin6_addr = ip6->ip6_dst;
899
900 // update the receiving interface address based on the inner address
901 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
902 if (ifa) {
903 m->m_pkthdr.rcvif = ifa->ifa_ifp;
904 IFA_REMREF(ifa);
6d2010ae
A
905 }
906
fe8ab488
A
907 // Input via IPSec interface
908 if (sav->sah->ipsec_if != NULL) {
909 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) {
910 m = NULL;
911 nxt = IPPROTO_DONE;
912 goto done;
913 } else {
914 goto fail;
915 }
916 }
917
6d2010ae
A
918 if (proto_input(PF_INET6, m) != 0)
919 goto fail;
1c79356b
A
920 nxt = IPPROTO_DONE;
921 } else {
922 /*
923 * strip off AH.
1c79356b 924 */
1c79356b
A
925 char *prvnxtp;
926
927 /*
928 * Copy the value of the next header field of AH to the
929 * next header field of the previous header.
930 * This is necessary because AH will be stripped off below.
931 */
932 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
933 *prvnxtp = nxt;
934
1c79356b 935 ip6 = mtod(m, struct ip6_hdr *);
9bccf70c
A
936 /*
937 * We do deep-copy since KAME requires that
938 * the packet is placed in a single mbuf.
939 */
1c79356b
A
940 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
941 m->m_data += stripsiz;
942 m->m_len -= stripsiz;
943 m->m_pkthdr.len -= stripsiz;
1c79356b
A
944 ip6 = mtod(m, struct ip6_hdr *);
945 /* XXX jumbogram */
946 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
947
948 key_sa_recordxfer(sav, m);
9bccf70c 949 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
2d21ac55 950 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
9bccf70c
A
951 goto fail;
952 }
fe8ab488
A
953
954 // Input via IPSec interface
955 if (sav->sah->ipsec_if != NULL) {
956 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) {
957 m = NULL;
958 nxt = IPPROTO_DONE;
959 goto done;
960 } else {
961 goto fail;
962 }
963 }
1c79356b
A
964 }
965
fe8ab488 966done:
1c79356b
A
967 *offp = off;
968 *mp = m;
1c79356b
A
969 if (sav) {
970 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
971 printf("DP ah6_input call free SA:0x%llx\n",
972 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 973 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 974 }
2d21ac55 975 IPSEC_STAT_INCREMENT(ipsec6stat.in_success);
1c79356b
A
976 return nxt;
977
978fail:
979 if (sav) {
980 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
981 printf("DP ah6_input call free SA:0x%llx\n",
982 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 983 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b
A
984 }
985 if (m)
986 m_freem(m);
987 return IPPROTO_DONE;
988}
9bccf70c
A
989
990void
39037602 991ah6_ctlinput(int cmd, struct sockaddr *sa, void *d)
9bccf70c
A
992{
993 const struct newah *ahp;
994 struct newah ah;
995 struct secasvar *sav;
996 struct ip6_hdr *ip6;
997 struct mbuf *m;
998 struct ip6ctlparam *ip6cp = NULL;
5ba3f43e 999 int off = 0;
55e303ae 1000 struct sockaddr_in6 *sa6_src, *sa6_dst;
9bccf70c
A
1001
1002 if (sa->sa_family != AF_INET6 ||
1003 sa->sa_len != sizeof(struct sockaddr_in6))
1004 return;
1005 if ((unsigned)cmd >= PRC_NCMDS)
1006 return;
1007
1008 /* if the parameter is from icmp6, decode it. */
1009 if (d != NULL) {
1010 ip6cp = (struct ip6ctlparam *)d;
1011 m = ip6cp->ip6c_m;
1012 ip6 = ip6cp->ip6c_ip6;
1013 off = ip6cp->ip6c_off;
1014 } else {
1015 m = NULL;
1016 ip6 = NULL;
1017 }
1018
1019 if (ip6) {
1020 /*
1021 * XXX: We assume that when ip6 is non NULL,
1022 * M and OFF are valid.
1023 */
1024
1025 /* check if we can safely examine src and dst ports */
1026 if (m->m_pkthdr.len < off + sizeof(ah))
1027 return;
1028
1029 if (m->m_len < off + sizeof(ah)) {
1030 /*
1031 * this should be rare case,
1032 * so we compromise on this copy...
1033 */
1034 m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
1035 ahp = &ah;
1036 } else
316670eb 1037 ahp = (struct newah *)(void *)(mtod(m, caddr_t) + off);
9bccf70c
A
1038
1039 if (cmd == PRC_MSGSIZE) {
1040 int valid = 0;
1041
1042 /*
1043 * Check to see if we have a valid SA corresponding to
1044 * the address in the ICMP message payload.
1045 */
55e303ae 1046 sa6_src = ip6cp->ip6c_src;
316670eb 1047 sa6_dst = (struct sockaddr_in6 *)(void *)sa;
9bccf70c 1048 sav = key_allocsa(AF_INET6,
55e303ae
A
1049 (caddr_t)&sa6_src->sin6_addr,
1050 (caddr_t)&sa6_dst->sin6_addr,
9bccf70c
A
1051 IPPROTO_AH, ahp->ah_spi);
1052 if (sav) {
1053 if (sav->state == SADB_SASTATE_MATURE ||
1054 sav->state == SADB_SASTATE_DYING)
1055 valid++;
2d21ac55 1056 key_freesav(sav, KEY_SADB_UNLOCKED);
9bccf70c
A
1057 }
1058
1059 /* XXX Further validation? */
1060
1061 /*
1062 * Depending on the value of "valid" and routing table
1063 * size (mtudisc_{hi,lo}wat), we will:
1064 * - recalcurate the new MTU and create the
1065 * corresponding routing entry, or
1066 * - ignore the MTU change notification.
1067 */
1068 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1069 }
1070
1071 /* we normally notify single pcb here */
1072 } else {
1073 /* we normally notify any pcb here */
1074 }
1075}
1c79356b 1076#endif /* INET6 */