Initial import from FreeBSD RELENG_4:
[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 /*      $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 <netinet6/in6_pcb.h>
70 #include <netinet/icmp6.h>
71 #include <netinet6/ip6protosw.h>
72 #endif
73
74 #include <netinet6/ipsec.h>
75 #ifdef INET6
76 #include <netinet6/ipsec6.h>
77 #endif
78 #include <netinet6/ah.h>
79 #ifdef INET6
80 #include <netinet6/ah6.h>
81 #endif
82 #include <netkey/key.h>
83 #include <netkey/keydb.h>
84 #ifdef IPSEC_DEBUG
85 #include <netkey/key_debug.h>
86 #else
87 #define KEYDEBUG(lev,arg)
88 #endif
89
90 #include <machine/stdarg.h>
91
92 #include <net/net_osdep.h>
93
94 #define IPLEN_FLIPPED
95
96 #ifdef INET
97 #include <netinet/ipprotosw.h>
98 extern struct ipprotosw inetsw[];
99
100 void
101 #if __STDC__
102 ah4_input(struct mbuf *m, ...)
103 #else
104 ah4_input(m, va_alist)
105         struct mbuf *m;
106         va_dcl
107 #endif
108 {
109         struct ip *ip;
110         struct ah *ah;
111         u_int32_t spi;
112         const struct ah_algorithm *algo;
113         size_t siz;
114         size_t siz1;
115         u_char *cksum;
116         struct secasvar *sav = NULL;
117         u_int16_t nxt;
118         size_t hlen;
119         int s;
120         int off, proto;
121         va_list ap;
122         size_t stripsiz = 0;
123
124         va_start(ap, m);
125         off = va_arg(ap, int);
126         proto = va_arg(ap, int);
127         va_end(ap);
128
129 #ifndef PULLDOWN_TEST
130         if (m->m_len < off + sizeof(struct newah)) {
131                 m = m_pullup(m, off + sizeof(struct newah));
132                 if (!m) {
133                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
134                                 "dropping the packet for simplicity\n"));
135                         ipsecstat.in_inval++;
136                         goto fail;
137                 }
138         }
139
140         ip = mtod(m, struct ip *);
141         ah = (struct ah *)(((caddr_t)ip) + off);
142 #else
143         ip = mtod(m, struct ip *);
144         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
145         if (ah == NULL) {
146                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
147                         "dropping the packet for simplicity\n"));
148                 ipsecstat.in_inval++;
149                 goto fail;
150         }
151 #endif
152         nxt = ah->ah_nxt;
153 #ifdef _IP_VHL
154         hlen = IP_VHL_HL(ip->ip_vhl) << 2;
155 #else
156         hlen = ip->ip_hl << 2;
157 #endif
158
159         /* find the sassoc. */
160         spi = ah->ah_spi;
161
162         if ((sav = key_allocsa(AF_INET,
163                               (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
164                               IPPROTO_AH, spi)) == 0) {
165                 ipseclog((LOG_WARNING,
166                     "IPv4 AH input: no key association found for spi %u\n",
167                     (u_int32_t)ntohl(spi)));
168                 ipsecstat.in_nosa++;
169                 goto fail;
170         }
171         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
172                 printf("DP ah4_input called to allocate SA:%p\n", sav));
173         if (sav->state != SADB_SASTATE_MATURE
174          && sav->state != SADB_SASTATE_DYING) {
175                 ipseclog((LOG_DEBUG,
176                     "IPv4 AH input: non-mature/dying SA found for spi %u\n",
177                     (u_int32_t)ntohl(spi)));
178                 ipsecstat.in_badspi++;
179                 goto fail;
180         }
181
182         algo = ah_algorithm_lookup(sav->alg_auth);
183         if (!algo) {
184                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
185                     "unsupported authentication algorithm for spi %u\n",
186                     (u_int32_t)ntohl(spi)));
187                 ipsecstat.in_badspi++;
188                 goto fail;
189         }
190
191         siz = (*algo->sumsiz)(sav);
192         siz1 = ((siz + 3) & ~(4 - 1));
193
194         /*
195          * sanity checks for header, 1.
196          */
197     {
198         int sizoff;
199
200         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
201
202         /*
203          * Here, we do not do "siz1 == siz".  This is because the way
204          * RFC240[34] section 2 is written.  They do not require truncation
205          * to 96 bits.
206          * For example, Microsoft IPsec stack attaches 160 bits of
207          * authentication data for both hmac-md5 and hmac-sha1.  For hmac-sha1,
208          * 32 bits of padding is attached.
209          *
210          * There are two downsides to this specification.
211          * They have no real harm, however, they leave us fuzzy feeling.
212          * - if we attach more than 96 bits of authentication data onto AH,
213          *   we will never notice about possible modification by rogue
214          *   intermediate nodes.
215          *   Since extra bits in AH checksum is never used, this constitutes
216          *   no real issue, however, it is wacky.
217          * - even if the peer attaches big authentication data, we will never
218          *   notice the difference, since longer authentication data will just
219          *   work.
220          *
221          * We may need some clarification in the spec.
222          */
223         if (siz1 < siz) {
224                 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
225                     "(%lu, should be at least %lu): %s\n",
226                     (u_long)siz1, (u_long)siz,
227                     ipsec4_logpacketstr(ip, spi)));
228                 ipsecstat.in_inval++;
229                 goto fail;
230         }
231         if ((ah->ah_len << 2) - sizoff != siz1) {
232                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
233                     "(%d should be %lu): %s\n",
234                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
235                     ipsec4_logpacketstr(ip, spi)));
236                 ipsecstat.in_inval++;
237                 goto fail;
238         }
239
240 #ifndef PULLDOWN_TEST
241         if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
242                 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
243                 if (!m) {
244                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
245                         ipsecstat.in_inval++;
246                         goto fail;
247                 }
248
249                 ip = mtod(m, struct ip *);
250                 ah = (struct ah *)(((caddr_t)ip) + off);
251         }
252 #else
253         IP6_EXTHDR_GET(ah, struct ah *, m, off,
254                 sizeof(struct ah) + sizoff + siz1);
255         if (ah == NULL) {
256                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
257                 ipsecstat.in_inval++;
258                 goto fail;
259         }
260 #endif
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                         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                 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                 ipsecstat.in_inval++;
299                 goto fail;
300         }
301         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                 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                                 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 #ifdef 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                 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                 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                         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)) {
405                 /*
406                  * strip off all the headers that precedes AH.
407                  *      IP xx AH IP' payload -> IP' payload
408                  *
409                  * XXX more sanity checks
410                  * XXX relationship with gif?
411                  */
412                 u_int8_t tos;
413
414                 tos = ip->ip_tos;
415                 m_adj(m, off + stripsiz);
416                 if (m->m_len < sizeof(*ip)) {
417                         m = m_pullup(m, sizeof(*ip));
418                         if (!m) {
419                                 ipsecstat.in_inval++;
420                                 goto fail;
421                         }
422                 }
423                 ip = mtod(m, struct ip *);
424                 /* ECN consideration. */
425                 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
426                 if (!key_checktunnelsanity(sav, AF_INET,
427                             (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
428                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
429                             "in IPv4 AH input: %s %s\n",
430                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
431                         ipsecstat.in_inval++;
432                         goto fail;
433                 }
434
435 #if 1
436                 /*
437                  * Should the inner packet be considered authentic?
438                  * My current answer is: NO.
439                  *
440                  * host1 -- gw1 === gw2 -- host2
441                  *      In this case, gw2 can trust the authenticity of the
442                  *      outer packet, but NOT inner.  Packet may be altered
443                  *      between host1 and gw1.
444                  *
445                  * host1 -- gw1 === host2
446                  *      This case falls into the same scenario as above.
447                  *
448                  * host1 === host2
449                  *      This case is the only case when we may be able to leave
450                  *      M_AUTHIPHDR and M_AUTHIPDGM set.
451                  *      However, if host1 is wrongly configured, and allows
452                  *      attacker to inject some packet with src=host1 and
453                  *      dst=host2, you are in risk.
454                  */
455                 m->m_flags &= ~M_AUTHIPHDR;
456                 m->m_flags &= ~M_AUTHIPDGM;
457 #endif
458
459                 key_sa_recordxfer(sav, m);
460                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
461                     ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
462                         ipsecstat.in_nomem++;
463                         goto fail;
464                 }
465
466                 s = splimp();
467                 if (IF_QFULL(&ipintrq)) {
468                         ipsecstat.in_inval++;
469                         splx(s);
470                         goto fail;
471                 }
472                 IF_ENQUEUE(&ipintrq, m);
473                 m = NULL;
474                 schednetisr(NETISR_IP); /* can be skipped but to make sure */
475                 splx(s);
476                 nxt = IPPROTO_DONE;
477         } else {
478                 /*
479                  * strip off AH.
480                  */
481
482                 ip = mtod(m, struct ip *);
483 #ifndef PULLDOWN_TEST
484                 /*
485                  * We do deep-copy since KAME requires that
486                  * the packet is placed in a single external mbuf.
487                  */
488                 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
489                 m->m_data += stripsiz;
490                 m->m_len -= stripsiz;
491                 m->m_pkthdr.len -= stripsiz;
492 #else
493                 /*
494                  * even in m_pulldown case, we need to strip off AH so that
495                  * we can compute checksum for multiple AH correctly.
496                  */
497                 if (m->m_len >= stripsiz + off) {
498                         ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
499                         m->m_data += stripsiz;
500                         m->m_len -= stripsiz;
501                         m->m_pkthdr.len -= stripsiz;
502                 } else {
503                         /*
504                          * this comes with no copy if the boundary is on
505                          * cluster
506                          */
507                         struct mbuf *n;
508
509                         n = m_split(m, off, M_DONTWAIT);
510                         if (n == NULL) {
511                                 /* m is retained by m_split */
512                                 goto fail;
513                         }
514                         m_adj(n, stripsiz);
515                         m_cat(m, n);
516                         /* m_cat does not update m_pkthdr.len */
517                         m->m_pkthdr.len += n->m_pkthdr.len;
518                 }
519 #endif
520
521                 if (m->m_len < sizeof(*ip)) {
522                         m = m_pullup(m, sizeof(*ip));
523                         if (m == NULL) {
524                                 ipsecstat.in_inval++;
525                                 goto fail;
526                         }
527                 }
528                 ip = mtod(m, struct ip *);
529 #ifdef IPLEN_FLIPPED
530                 ip->ip_len = ip->ip_len - stripsiz;
531 #else
532                 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
533 #endif
534                 ip->ip_p = nxt;
535                 /* forget about IP hdr checksum, the check has already been passed */
536
537                 key_sa_recordxfer(sav, m);
538                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
539                         ipsecstat.in_nomem++;
540                         goto fail;
541                 }
542
543                 if (nxt != IPPROTO_DONE) {
544                         if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
545                             ipsec4_in_reject(m, NULL)) {
546                                 ipsecstat.in_polvio++;
547                                 goto fail;
548                         }
549                         (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
550                 } else
551                         m_freem(m);
552                 m = NULL;
553         }
554
555         if (sav) {
556                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
557                         printf("DP ah4_input call free SA:%p\n", sav));
558                 key_freesav(sav);
559         }
560         ipsecstat.in_success++;
561         return;
562
563 fail:
564         if (sav) {
565                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
566                         printf("DP ah4_input call free SA:%p\n", sav));
567                 key_freesav(sav);
568         }
569         if (m)
570                 m_freem(m);
571         return;
572 }
573 #endif /* INET */
574
575 #ifdef INET6
576 int
577 ah6_input(mp, offp, proto)
578         struct mbuf **mp;
579         int *offp, proto;
580 {
581         struct mbuf *m = *mp;
582         int off = *offp;
583         struct ip6_hdr *ip6;
584         struct ah *ah;
585         u_int32_t spi;
586         const struct ah_algorithm *algo;
587         size_t siz;
588         size_t siz1;
589         u_char *cksum;
590         struct secasvar *sav = NULL;
591         u_int16_t nxt;
592         int s;
593         size_t stripsiz = 0;
594
595 #ifndef PULLDOWN_TEST
596         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
597         ah = (struct ah *)(mtod(m, caddr_t) + off);
598 #else
599         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
600         if (ah == NULL) {
601                 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
602                 ipsec6stat.in_inval++;
603                 return IPPROTO_DONE;
604         }
605 #endif
606         ip6 = mtod(m, struct ip6_hdr *);
607         nxt = ah->ah_nxt;
608
609         /* find the sassoc. */
610         spi = ah->ah_spi;
611
612         if (ntohs(ip6->ip6_plen) == 0) {
613                 ipseclog((LOG_ERR, "IPv6 AH input: "
614                     "AH with IPv6 jumbogram is not supported.\n"));
615                 ipsec6stat.in_inval++;
616                 goto fail;
617         }
618
619         if ((sav = key_allocsa(AF_INET6,
620                               (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
621                               IPPROTO_AH, spi)) == 0) {
622                 ipseclog((LOG_WARNING,
623                     "IPv6 AH input: no key association found for spi %u\n",
624                     (u_int32_t)ntohl(spi)));
625                 ipsec6stat.in_nosa++;
626                 goto fail;
627         }
628         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
629                 printf("DP ah6_input called to allocate SA:%p\n", sav));
630         if (sav->state != SADB_SASTATE_MATURE
631          && sav->state != SADB_SASTATE_DYING) {
632                 ipseclog((LOG_DEBUG,
633                     "IPv6 AH input: non-mature/dying SA found for spi %u; ",
634                     (u_int32_t)ntohl(spi)));
635                 ipsec6stat.in_badspi++;
636                 goto fail;
637         }
638
639         algo = ah_algorithm_lookup(sav->alg_auth);
640         if (!algo) {
641                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
642                     "unsupported authentication algorithm for spi %u\n",
643                     (u_int32_t)ntohl(spi)));
644                 ipsec6stat.in_badspi++;
645                 goto fail;
646         }
647
648         siz = (*algo->sumsiz)(sav);
649         siz1 = ((siz + 3) & ~(4 - 1));
650
651         /*
652          * sanity checks for header, 1.
653          */
654     {
655         int sizoff;
656
657         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
658
659         /*
660          * Here, we do not do "siz1 == siz".  See ah4_input() for complete
661          * description.
662          */
663         if (siz1 < siz) {
664                 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
665                     "(%lu, should be at least %lu): %s\n",
666                     (u_long)siz1, (u_long)siz,
667                     ipsec6_logpacketstr(ip6, spi)));
668                 ipsec6stat.in_inval++;
669                 goto fail;
670         }
671         if ((ah->ah_len << 2) - sizoff != siz1) {
672                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
673                     "(%d should be %lu): %s\n",
674                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
675                     ipsec6_logpacketstr(ip6, spi)));
676                 ipsec6stat.in_inval++;
677                 goto fail;
678         }
679 #ifndef PULLDOWN_TEST
680         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
681 #else
682         IP6_EXTHDR_GET(ah, struct ah *, m, off,
683                 sizeof(struct ah) + sizoff + siz1);
684         if (ah == NULL) {
685                 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
686                 ipsec6stat.in_inval++;
687                 m = NULL;
688                 goto fail;
689         }
690 #endif
691     }
692
693         /*
694          * check for sequence number.
695          */
696         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
697                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
698                         ; /* okey */
699                 else {
700                         ipsec6stat.in_ahreplay++;
701                         ipseclog((LOG_WARNING,
702                             "replay packet in IPv6 AH input: %s %s\n",
703                             ipsec6_logpacketstr(ip6, spi),
704                             ipsec_logsastr(sav)));
705                         goto fail;
706                 }
707         }
708
709         /*
710          * alright, it seems sane.  now we are going to check the
711          * cryptographic checksum.
712          */
713         cksum = malloc(siz1, M_TEMP, M_NOWAIT);
714         if (!cksum) {
715                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
716                     "couldn't alloc temporary region for cksum\n"));
717                 ipsec6stat.in_inval++;
718                 goto fail;
719         }
720         
721         if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
722                 free(cksum, M_TEMP);
723                 ipsec6stat.in_inval++;
724                 goto fail;
725         }
726         ipsec6stat.in_ahhist[sav->alg_auth]++;
727
728     {
729         caddr_t sumpos = NULL;
730
731         if (sav->flags & SADB_X_EXT_OLD) {
732                 /* RFC 1826 */
733                 sumpos = (caddr_t)(ah + 1);
734         } else {
735                 /* RFC 2402 */
736                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
737         }
738
739         if (bcmp(sumpos, cksum, siz) != 0) {
740                 ipseclog((LOG_WARNING,
741                     "checksum mismatch in IPv6 AH input: %s %s\n",
742                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
743                 free(cksum, M_TEMP);
744                 ipsec6stat.in_ahauthfail++;
745                 goto fail;
746         }
747     }
748
749         free(cksum, M_TEMP);
750
751         m->m_flags |= M_AUTHIPHDR;
752         m->m_flags |= M_AUTHIPDGM;
753
754 #if 0
755         /*
756          * looks okey, but we need more sanity check.
757          * XXX should elaborate.
758          */
759         if (ah->ah_nxt == IPPROTO_IPV6) {
760                 struct ip6_hdr *nip6;
761                 size_t sizoff;
762
763                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
764
765                 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
766                                 + sizeof(struct ip6_hdr), IPPROTO_DONE);
767
768                 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
769                 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
770                  || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
771                         m->m_flags &= ~M_AUTHIPHDR;
772                         m->m_flags &= ~M_AUTHIPDGM;
773                 }
774         } else if (ah->ah_nxt == IPPROTO_IPIP) {
775                 m->m_flags &= ~M_AUTHIPHDR;
776                 m->m_flags &= ~M_AUTHIPDGM;
777         } else if (ah->ah_nxt == IPPROTO_IP) {
778                 m->m_flags &= ~M_AUTHIPHDR;
779                 m->m_flags &= ~M_AUTHIPDGM;
780         }
781 #endif
782
783         if (m->m_flags & M_AUTHIPHDR
784          && m->m_flags & M_AUTHIPDGM) {
785 #if 0
786                 ipseclog((LOG_DEBUG,
787                     "IPv6 AH input: authentication succeess\n"));
788 #endif
789                 ipsec6stat.in_ahauthsucc++;
790         } else {
791                 ipseclog((LOG_WARNING,
792                     "authentication failed in IPv6 AH input: %s %s\n",
793                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
794                 ipsec6stat.in_ahauthfail++;
795                 goto fail;
796         }
797
798         /*
799          * update sequence number.
800          */
801         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
802                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
803                         ipsec6stat.in_ahreplay++;
804                         goto fail;
805                 }
806         }
807
808         /* was it transmitted over the IPsec tunnel SA? */
809         if (sav->flags & SADB_X_EXT_OLD) {
810                 /* RFC 1826 */
811                 stripsiz = sizeof(struct ah) + siz1;
812         } else {
813                 /* RFC 2402 */
814                 stripsiz = sizeof(struct newah) + siz1;
815         }
816         if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
817                 /*
818                  * strip off all the headers that precedes AH.
819                  *      IP6 xx AH IP6' payload -> IP6' payload
820                  *
821                  * XXX more sanity checks
822                  * XXX relationship with gif?
823                  */
824                 u_int32_t flowinfo;     /* net endian */
825
826                 flowinfo = ip6->ip6_flow;
827                 m_adj(m, off + stripsiz);
828                 if (m->m_len < sizeof(*ip6)) {
829                         /*
830                          * m_pullup is prohibited in KAME IPv6 input processing
831                          * but there's no other way!
832                          */
833                         m = m_pullup(m, sizeof(*ip6));
834                         if (!m) {
835                                 ipsec6stat.in_inval++;
836                                 goto fail;
837                         }
838                 }
839                 ip6 = mtod(m, struct ip6_hdr *);
840                 /* ECN consideration. */
841                 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
842                 if (!key_checktunnelsanity(sav, AF_INET6,
843                             (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
844                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
845                             "in IPv6 AH input: %s %s\n",
846                             ipsec6_logpacketstr(ip6, spi),
847                             ipsec_logsastr(sav)));
848                         ipsec6stat.in_inval++;
849                         goto fail;
850                 }
851
852 #if 1
853                 /*
854                  * should the inner packet be considered authentic?
855                  * see comment in ah4_input().
856                  */
857                 m->m_flags &= ~M_AUTHIPHDR;
858                 m->m_flags &= ~M_AUTHIPDGM;
859 #endif
860
861                 key_sa_recordxfer(sav, m);
862                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
863                     ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
864                         ipsec6stat.in_nomem++;
865                         goto fail;
866                 }
867
868                 s = splimp();
869                 if (IF_QFULL(&ip6intrq)) {
870                         ipsec6stat.in_inval++;
871                         splx(s);
872                         goto fail;
873                 }
874                 IF_ENQUEUE(&ip6intrq, m);
875                 m = NULL;
876                 schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
877                 splx(s);
878                 nxt = IPPROTO_DONE;
879         } else {
880                 /*
881                  * strip off AH.
882                  */
883                 char *prvnxtp;
884
885                 /*
886                  * Copy the value of the next header field of AH to the
887                  * next header field of the previous header.
888                  * This is necessary because AH will be stripped off below.
889                  */
890                 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
891                 *prvnxtp = nxt;
892
893                 ip6 = mtod(m, struct ip6_hdr *);
894 #ifndef PULLDOWN_TEST
895                 /*
896                  * We do deep-copy since KAME requires that
897                  * the packet is placed in a single mbuf.
898                  */
899                 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
900                 m->m_data += stripsiz;
901                 m->m_len -= stripsiz;
902                 m->m_pkthdr.len -= stripsiz;
903 #else
904                 /*
905                  * even in m_pulldown case, we need to strip off AH so that
906                  * we can compute checksum for multiple AH correctly.
907                  */
908                 if (m->m_len >= stripsiz + off) {
909                         ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
910                         m->m_data += stripsiz;
911                         m->m_len -= stripsiz;
912                         m->m_pkthdr.len -= stripsiz;
913                 } else {
914                         /*
915                          * this comes with no copy if the boundary is on
916                          * cluster
917                          */
918                         struct mbuf *n;
919
920                         n = m_split(m, off, M_DONTWAIT);
921                         if (n == NULL) {
922                                 /* m is retained by m_split */
923                                 goto fail;
924                         }
925                         m_adj(n, stripsiz);
926                         m_cat(m, n);
927                         /* m_cat does not update m_pkthdr.len */
928                         m->m_pkthdr.len += n->m_pkthdr.len;
929                 }
930 #endif
931                 ip6 = mtod(m, struct ip6_hdr *);
932                 /* XXX jumbogram */
933                 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
934
935                 key_sa_recordxfer(sav, m);
936                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
937                         ipsec6stat.in_nomem++;
938                         goto fail;
939                 }
940         }
941
942         *offp = off;
943         *mp = m;
944
945         if (sav) {
946                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
947                         printf("DP ah6_input call free SA:%p\n", sav));
948                 key_freesav(sav);
949         }
950         ipsec6stat.in_success++;
951         return nxt;
952
953 fail:
954         if (sav) {
955                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
956                         printf("DP ah6_input call free SA:%p\n", sav));
957                 key_freesav(sav);
958         }
959         if (m)
960                 m_freem(m);
961         return IPPROTO_DONE;
962 }
963
964 void
965 ah6_ctlinput(cmd, sa, d)
966         int cmd;
967         struct sockaddr *sa;
968         void *d;
969 {
970         const struct newah *ahp;
971         struct newah ah;
972         struct secasvar *sav;
973         struct ip6_hdr *ip6;
974         struct mbuf *m;
975         struct ip6ctlparam *ip6cp = NULL;
976         int off;
977         struct sockaddr_in6 *sa6_src, *sa6_dst;
978
979         if (sa->sa_family != AF_INET6 ||
980             sa->sa_len != sizeof(struct sockaddr_in6))
981                 return;
982         if ((unsigned)cmd >= PRC_NCMDS)
983                 return;
984
985         /* if the parameter is from icmp6, decode it. */
986         if (d != NULL) {
987                 ip6cp = (struct ip6ctlparam *)d;
988                 m = ip6cp->ip6c_m;
989                 ip6 = ip6cp->ip6c_ip6;
990                 off = ip6cp->ip6c_off;
991         } else {
992                 m = NULL;
993                 ip6 = NULL;
994         }
995
996         if (ip6) {
997                 /*
998                  * XXX: We assume that when ip6 is non NULL,
999                  * M and OFF are valid.
1000                  */
1001
1002                 /* check if we can safely examine src and dst ports */
1003                 if (m->m_pkthdr.len < off + sizeof(ah))
1004                         return;
1005
1006                 if (m->m_len < off + sizeof(ah)) {
1007                         /*
1008                          * this should be rare case,
1009                          * so we compromise on this copy...
1010                          */
1011                         m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
1012                         ahp = &ah;
1013                 } else
1014                         ahp = (struct newah *)(mtod(m, caddr_t) + off);
1015
1016                 if (cmd == PRC_MSGSIZE) {
1017                         int valid = 0;
1018
1019                         /*
1020                          * Check to see if we have a valid SA corresponding to
1021                          * the address in the ICMP message payload.
1022                          */
1023                         sa6_src = ip6cp->ip6c_src;
1024                         sa6_dst = (struct sockaddr_in6 *)sa;
1025                         sav = key_allocsa(AF_INET6,
1026                                           (caddr_t)&sa6_src->sin6_addr,
1027                                           (caddr_t)&sa6_dst->sin6_addr,
1028                                           IPPROTO_AH, ahp->ah_spi);
1029                         if (sav) {
1030                                 if (sav->state == SADB_SASTATE_MATURE ||
1031                                     sav->state == SADB_SASTATE_DYING)
1032                                         valid++;
1033                                 key_freesav(sav);
1034                         }
1035
1036                         /* XXX Further validation? */
1037
1038                         /*
1039                          * Depending on the value of "valid" and routing table
1040                          * size (mtudisc_{hi,lo}wat), we will:
1041                          * - recalcurate the new MTU and create the
1042                          *   corresponding routing entry, or
1043                          * - ignore the MTU change notification.
1044                          */
1045                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1046                 }
1047
1048                 /* we normally notify single pcb here */
1049         } else {
1050                 /* we normally notify any pcb here */
1051         }
1052 }
1053 #endif /* INET6 */