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