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