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