Update files for OpenSSL-1.0.0g import.
[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 #include <machine/stdarg.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 <netproto/key/key.h>
84 #include <netproto/key/keydb.h>
85 #ifdef IPSEC_DEBUG
86 #include <netproto/key/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 int
101 ah4_input(struct mbuf **mp, int *offp, int proto)
102 {
103         int off;
104         struct mbuf *m;
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         size_t stripsiz = 0;
116
117         off = *offp;
118         m = *mp;
119         *mp = NULL;
120
121 #ifndef PULLDOWN_TEST
122         if (m->m_len < off + sizeof(struct newah)) {
123                 m = m_pullup(m, off + sizeof(struct newah));
124                 if (!m) {
125                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
126                                 "dropping the packet for simplicity\n"));
127                         ipsecstat.in_inval++;
128                         goto fail;
129                 }
130         }
131
132         ip = mtod(m, struct ip *);
133         ah = (struct ah *)(((caddr_t)ip) + off);
134 #else
135         ip = mtod(m, struct ip *);
136         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
137         if (ah == NULL) {
138                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
139                         "dropping the packet for simplicity\n"));
140                 ipsecstat.in_inval++;
141                 goto fail;
142         }
143 #endif
144         nxt = ah->ah_nxt;
145 #ifdef _IP_VHL
146         hlen = IP_VHL_HL(ip->ip_vhl) << 2;
147 #else
148         hlen = ip->ip_hl << 2;
149 #endif
150
151         /* find the sassoc. */
152         spi = ah->ah_spi;
153
154         if ((sav = key_allocsa(AF_INET,
155                               (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
156                               IPPROTO_AH, spi)) == NULL) {
157                 ipseclog((LOG_WARNING,
158                     "IPv4 AH input: no key association found for spi %u\n",
159                     (u_int32_t)ntohl(spi)));
160                 ipsecstat.in_nosa++;
161                 goto fail;
162         }
163         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
164                 kprintf("DP ah4_input called to allocate SA:%p\n", sav));
165         if (sav->state != SADB_SASTATE_MATURE
166          && sav->state != SADB_SASTATE_DYING) {
167                 ipseclog((LOG_DEBUG,
168                     "IPv4 AH input: non-mature/dying SA found for spi %u\n",
169                     (u_int32_t)ntohl(spi)));
170                 ipsecstat.in_badspi++;
171                 goto fail;
172         }
173
174         algo = ah_algorithm_lookup(sav->alg_auth);
175         if (!algo) {
176                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
177                     "unsupported authentication algorithm for spi %u\n",
178                     (u_int32_t)ntohl(spi)));
179                 ipsecstat.in_badspi++;
180                 goto fail;
181         }
182
183         siz = (*algo->sumsiz)(sav);
184         siz1 = ((siz + 3) & ~(4 - 1));
185
186         /*
187          * sanity checks for header, 1.
188          */
189     {
190         int sizoff;
191
192         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
193
194         /*
195          * Here, we do not do "siz1 == siz".  This is because the way
196          * RFC240[34] section 2 is written.  They do not require truncation
197          * to 96 bits.
198          * For example, Microsoft IPsec stack attaches 160 bits of
199          * authentication data for both hmac-md5 and hmac-sha1.  For hmac-sha1,
200          * 32 bits of padding is attached.
201          *
202          * There are two downsides to this specification.
203          * They have no real harm, however, they leave us fuzzy feeling.
204          * - if we attach more than 96 bits of authentication data onto AH,
205          *   we will never notice about possible modification by rogue
206          *   intermediate nodes.
207          *   Since extra bits in AH checksum is never used, this constitutes
208          *   no real issue, however, it is wacky.
209          * - even if the peer attaches big authentication data, we will never
210          *   notice the difference, since longer authentication data will just
211          *   work.
212          *
213          * We may need some clarification in the spec.
214          */
215         if (siz1 < siz) {
216                 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
217                     "(%lu, should be at least %lu): %s\n",
218                     (u_long)siz1, (u_long)siz,
219                     ipsec4_logpacketstr(ip, spi)));
220                 ipsecstat.in_inval++;
221                 goto fail;
222         }
223         if ((ah->ah_len << 2) - sizoff != siz1) {
224                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
225                     "(%d should be %lu): %s\n",
226                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
227                     ipsec4_logpacketstr(ip, spi)));
228                 ipsecstat.in_inval++;
229                 goto fail;
230         }
231
232 #ifndef PULLDOWN_TEST
233         if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
234                 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
235                 if (!m) {
236                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
237                         ipsecstat.in_inval++;
238                         goto fail;
239                 }
240
241                 ip = mtod(m, struct ip *);
242                 ah = (struct ah *)(((caddr_t)ip) + off);
243         }
244 #else
245         IP6_EXTHDR_GET(ah, struct ah *, m, off,
246                 sizeof(struct ah) + sizoff + siz1);
247         if (ah == NULL) {
248                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
249                 ipsecstat.in_inval++;
250                 goto fail;
251         }
252 #endif
253     }
254
255         /*
256          * check for sequence number.
257          */
258         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
259                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
260                         ; /* okey */
261                 else {
262                         ipsecstat.in_ahreplay++;
263                         ipseclog((LOG_WARNING,
264                             "replay packet in IPv4 AH input: %s %s\n",
265                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
266                         goto fail;
267                 }
268         }
269
270         /*
271          * alright, it seems sane.  now we are going to check the
272          * cryptographic checksum.
273          */
274         cksum = kmalloc(siz1, M_TEMP, M_NOWAIT);
275         if (!cksum) {
276                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
277                     "couldn't alloc temporary region for cksum\n"));
278                 ipsecstat.in_inval++;
279                 goto fail;
280         }
281         
282         /*
283          * some of IP header fields are flipped to the host endian.
284          * convert them back to network endian.  VERY stupid.
285          */
286         ip->ip_len = htons(ip->ip_len + hlen);
287         ip->ip_off = htons(ip->ip_off);
288         if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
289                 kfree(cksum, M_TEMP);
290                 ipsecstat.in_inval++;
291                 goto fail;
292         }
293         ipsecstat.in_ahhist[sav->alg_auth]++;
294         /*
295          * flip them back.
296          */
297         ip->ip_len = ntohs(ip->ip_len) - hlen;
298         ip->ip_off = ntohs(ip->ip_off);
299
300     {
301         caddr_t sumpos = NULL;
302
303         if (sav->flags & SADB_X_EXT_OLD) {
304                 /* RFC 1826 */
305                 sumpos = (caddr_t)(ah + 1);
306         } else {
307                 /* RFC 2402 */
308                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
309         }
310
311         if (bcmp(sumpos, cksum, siz) != 0) {
312                 ipseclog((LOG_WARNING,
313                     "checksum mismatch in IPv4 AH input: %s %s\n",
314                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
315                 kfree(cksum, M_TEMP);
316                 ipsecstat.in_ahauthfail++;
317                 goto fail;
318         }
319     }
320
321         kfree(cksum, M_TEMP);
322
323         m->m_flags |= M_AUTHIPHDR;
324         m->m_flags |= M_AUTHIPDGM;
325
326 #if 0
327         /*
328          * looks okey, but we need more sanity check.
329          * XXX should elaborate.
330          */
331         if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
332                 struct ip *nip;
333                 size_t sizoff;
334
335                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
336
337                 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
338                         m = m_pullup(m, off + sizeof(struct ah)
339                                         + sizoff + siz1 + hlen);
340                         if (!m) {
341                                 ipseclog((LOG_DEBUG,
342                                     "IPv4 AH input: can't pullup\n"));
343                                 ipsecstat.in_inval++;
344                                 goto fail;
345                         }
346                 }
347
348                 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
349                 if (nip->ip_src.s_addr != ip->ip_src.s_addr
350                  || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
351                         m->m_flags &= ~M_AUTHIPHDR;
352                         m->m_flags &= ~M_AUTHIPDGM;
353                 }
354         }
355 #ifdef INET6
356         else if (ah->ah_nxt == IPPROTO_IPV6) {
357                 m->m_flags &= ~M_AUTHIPHDR;
358                 m->m_flags &= ~M_AUTHIPDGM;
359         }
360 #endif /* INET6 */
361 #endif /* 0 */
362
363         if (m->m_flags & M_AUTHIPHDR
364          && m->m_flags & M_AUTHIPDGM) {
365 #if 0
366                 ipseclog((LOG_DEBUG,
367                     "IPv4 AH input: authentication succeess\n"));
368 #endif
369                 ipsecstat.in_ahauthsucc++;
370         } else {
371                 ipseclog((LOG_WARNING,
372                     "authentication failed in IPv4 AH input: %s %s\n",
373                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
374                 ipsecstat.in_ahauthfail++;
375                 goto fail;
376         }
377
378         /*
379          * update sequence number.
380          */
381         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
382                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
383                         ipsecstat.in_ahreplay++;
384                         goto fail;
385                 }
386         }
387
388         /* was it transmitted over the IPsec tunnel SA? */
389         if (sav->flags & SADB_X_EXT_OLD) {
390                 /* RFC 1826 */
391                 stripsiz = sizeof(struct ah) + siz1;
392         } else {
393                 /* RFC 2402 */
394                 stripsiz = sizeof(struct newah) + siz1;
395         }
396         if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) {
397                 /*
398                  * strip off all the headers that precedes AH.
399                  *      IP xx AH IP' payload -> IP' payload
400                  *
401                  * XXX more sanity checks
402                  * XXX relationship with gif?
403                  */
404                 u_int8_t tos;
405
406                 tos = ip->ip_tos;
407                 m_adj(m, off + stripsiz);
408                 if (m->m_len < sizeof(*ip)) {
409                         m = m_pullup(m, sizeof(*ip));
410                         if (!m) {
411                                 ipsecstat.in_inval++;
412                                 goto fail;
413                         }
414                 }
415                 ip = mtod(m, struct ip *);
416                 /* ECN consideration. */
417                 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
418                 if (!key_checktunnelsanity(sav, AF_INET,
419                             (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
420                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
421                             "in IPv4 AH input: %s %s\n",
422                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
423                         ipsecstat.in_inval++;
424                         goto fail;
425                 }
426
427 #if 1
428                 /*
429                  * Should the inner packet be considered authentic?
430                  * My current answer is: NO.
431                  *
432                  * host1 -- gw1 === gw2 -- host2
433                  *      In this case, gw2 can trust the authenticity of the
434                  *      outer packet, but NOT inner.  Packet may be altered
435                  *      between host1 and gw1.
436                  *
437                  * host1 -- gw1 === host2
438                  *      This case falls into the same scenario as above.
439                  *
440                  * host1 === host2
441                  *      This case is the only case when we may be able to leave
442                  *      M_AUTHIPHDR and M_AUTHIPDGM set.
443                  *      However, if host1 is wrongly configured, and allows
444                  *      attacker to inject some packet with src=host1 and
445                  *      dst=host2, you are in risk.
446                  */
447                 m->m_flags &= ~M_AUTHIPHDR;
448                 m->m_flags &= ~M_AUTHIPDGM;
449 #endif
450
451                 key_sa_recordxfer(sav, m);
452                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
453                     ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
454                         ipsecstat.in_nomem++;
455                         goto fail;
456                 }
457
458                 if (netisr_queue(NETISR_IP, m)) {
459                         ipsecstat.in_inval++;
460                         m = NULL;
461                         goto fail;
462                 }
463
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, MB_DONTWAIT);
498                         if (n == NULL) {
499                                 /* m is retained by m_split */
500                                 goto fail;
501                         }
502                         m_adj(n, stripsiz);
503                         /* m_cat does not update m_pkthdr.len */
504                         m->m_pkthdr.len += n->m_pkthdr.len;
505                         m_cat(m, n);
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) &&
533                             ipsec4_in_reject(m, NULL)) {
534                                 ipsecstat.in_polvio++;
535                                 goto fail;
536                         }
537                         if (!ip_lengthcheck(&m, 0)) {
538                                 /* freed in ip_lengthcheck() */
539                                 goto fail;
540                         }
541                         *mp = m;
542                         *offp = off;
543                         (*inetsw[ip_protox[nxt]].pr_input)(mp, offp, nxt);
544                 } else {
545                         m_freem(m);
546                 }
547                 m = NULL;
548         }
549
550         if (sav) {
551                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
552                         kprintf("DP ah4_input call free SA:%p\n", sav));
553                 key_freesav(sav);
554         }
555         ipsecstat.in_success++;
556         return(IPPROTO_DONE);
557
558 fail:
559         if (sav) {
560                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
561                         kprintf("DP ah4_input call free SA:%p\n", sav));
562                 key_freesav(sav);
563         }
564         if (m)
565                 m_freem(m);
566         return(IPPROTO_DONE);
567 }
568 #endif /* INET */
569
570 #ifdef INET6
571 int
572 ah6_input(struct mbuf **mp, int *offp, int proto)
573 {
574         struct mbuf *m = *mp;
575         int off = *offp;
576         struct ip6_hdr *ip6;
577         struct ah *ah;
578         u_int32_t spi;
579         const struct ah_algorithm *algo;
580         size_t siz;
581         size_t siz1;
582         u_char *cksum;
583         struct secasvar *sav = NULL;
584         u_int16_t nxt;
585         size_t stripsiz = 0;
586
587 #ifndef PULLDOWN_TEST
588         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
589         ah = (struct ah *)(mtod(m, caddr_t) + off);
590 #else
591         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
592         if (ah == NULL) {
593                 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
594                 ipsec6stat.in_inval++;
595                 return IPPROTO_DONE;
596         }
597 #endif
598         ip6 = mtod(m, struct ip6_hdr *);
599         nxt = ah->ah_nxt;
600
601         /* find the sassoc. */
602         spi = ah->ah_spi;
603
604         if (ntohs(ip6->ip6_plen) == 0) {
605                 ipseclog((LOG_ERR, "IPv6 AH input: "
606                     "AH with IPv6 jumbogram is not supported.\n"));
607                 ipsec6stat.in_inval++;
608                 goto fail;
609         }
610
611         if ((sav = key_allocsa(AF_INET6,
612                               (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
613                               IPPROTO_AH, spi)) == NULL) {
614                 ipseclog((LOG_WARNING,
615                     "IPv6 AH input: no key association found for spi %u\n",
616                     (u_int32_t)ntohl(spi)));
617                 ipsec6stat.in_nosa++;
618                 goto fail;
619         }
620         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
621                 kprintf("DP ah6_input called to allocate SA:%p\n", sav));
622         if (sav->state != SADB_SASTATE_MATURE
623          && sav->state != SADB_SASTATE_DYING) {
624                 ipseclog((LOG_DEBUG,
625                     "IPv6 AH input: non-mature/dying SA found for spi %u; ",
626                     (u_int32_t)ntohl(spi)));
627                 ipsec6stat.in_badspi++;
628                 goto fail;
629         }
630
631         algo = ah_algorithm_lookup(sav->alg_auth);
632         if (!algo) {
633                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
634                     "unsupported authentication algorithm for spi %u\n",
635                     (u_int32_t)ntohl(spi)));
636                 ipsec6stat.in_badspi++;
637                 goto fail;
638         }
639
640         siz = (*algo->sumsiz)(sav);
641         siz1 = ((siz + 3) & ~(4 - 1));
642
643         /*
644          * sanity checks for header, 1.
645          */
646     {
647         int sizoff;
648
649         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
650
651         /*
652          * Here, we do not do "siz1 == siz".  See ah4_input() for complete
653          * description.
654          */
655         if (siz1 < siz) {
656                 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
657                     "(%lu, should be at least %lu): %s\n",
658                     (u_long)siz1, (u_long)siz,
659                     ipsec6_logpacketstr(ip6, spi)));
660                 ipsec6stat.in_inval++;
661                 goto fail;
662         }
663         if ((ah->ah_len << 2) - sizoff != siz1) {
664                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
665                     "(%d should be %lu): %s\n",
666                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
667                     ipsec6_logpacketstr(ip6, spi)));
668                 ipsec6stat.in_inval++;
669                 goto fail;
670         }
671 #ifndef PULLDOWN_TEST
672         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
673 #else
674         IP6_EXTHDR_GET(ah, struct ah *, m, off,
675                 sizeof(struct ah) + sizoff + siz1);
676         if (ah == NULL) {
677                 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
678                 ipsec6stat.in_inval++;
679                 m = NULL;
680                 goto fail;
681         }
682 #endif
683     }
684
685         /*
686          * check for sequence number.
687          */
688         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
689                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
690                         ; /* okey */
691                 else {
692                         ipsec6stat.in_ahreplay++;
693                         ipseclog((LOG_WARNING,
694                             "replay packet in IPv6 AH input: %s %s\n",
695                             ipsec6_logpacketstr(ip6, spi),
696                             ipsec_logsastr(sav)));
697                         goto fail;
698                 }
699         }
700
701         /*
702          * alright, it seems sane.  now we are going to check the
703          * cryptographic checksum.
704          */
705         cksum = kmalloc(siz1, M_TEMP, M_NOWAIT);
706         if (!cksum) {
707                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
708                     "couldn't alloc temporary region for cksum\n"));
709                 ipsec6stat.in_inval++;
710                 goto fail;
711         }
712         
713         if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
714                 kfree(cksum, M_TEMP);
715                 ipsec6stat.in_inval++;
716                 goto fail;
717         }
718         ipsec6stat.in_ahhist[sav->alg_auth]++;
719
720     {
721         caddr_t sumpos = NULL;
722
723         if (sav->flags & SADB_X_EXT_OLD) {
724                 /* RFC 1826 */
725                 sumpos = (caddr_t)(ah + 1);
726         } else {
727                 /* RFC 2402 */
728                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
729         }
730
731         if (bcmp(sumpos, cksum, siz) != 0) {
732                 ipseclog((LOG_WARNING,
733                     "checksum mismatch in IPv6 AH input: %s %s\n",
734                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
735                 kfree(cksum, M_TEMP);
736                 ipsec6stat.in_ahauthfail++;
737                 goto fail;
738         }
739     }
740
741         kfree(cksum, M_TEMP);
742
743         m->m_flags |= M_AUTHIPHDR;
744         m->m_flags |= M_AUTHIPDGM;
745
746 #if 0
747         /*
748          * looks okey, but we need more sanity check.
749          * XXX should elaborate.
750          */
751         if (ah->ah_nxt == IPPROTO_IPV6) {
752                 struct ip6_hdr *nip6;
753                 size_t sizoff;
754
755                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
756
757                 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
758                                 + sizeof(struct ip6_hdr), IPPROTO_DONE);
759
760                 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
761                 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
762                  || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
763                         m->m_flags &= ~M_AUTHIPHDR;
764                         m->m_flags &= ~M_AUTHIPDGM;
765                 }
766         } else if (ah->ah_nxt == IPPROTO_IPIP) {
767                 m->m_flags &= ~M_AUTHIPHDR;
768                 m->m_flags &= ~M_AUTHIPDGM;
769         } else if (ah->ah_nxt == IPPROTO_IP) {
770                 m->m_flags &= ~M_AUTHIPHDR;
771                 m->m_flags &= ~M_AUTHIPDGM;
772         }
773 #endif
774
775         if (m->m_flags & M_AUTHIPHDR
776          && m->m_flags & M_AUTHIPDGM) {
777 #if 0
778                 ipseclog((LOG_DEBUG,
779                     "IPv6 AH input: authentication succeess\n"));
780 #endif
781                 ipsec6stat.in_ahauthsucc++;
782         } else {
783                 ipseclog((LOG_WARNING,
784                     "authentication failed in IPv6 AH input: %s %s\n",
785                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
786                 ipsec6stat.in_ahauthfail++;
787                 goto fail;
788         }
789
790         /*
791          * update sequence number.
792          */
793         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
794                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
795                         ipsec6stat.in_ahreplay++;
796                         goto fail;
797                 }
798         }
799
800         /* was it transmitted over the IPsec tunnel SA? */
801         if (sav->flags & SADB_X_EXT_OLD) {
802                 /* RFC 1826 */
803                 stripsiz = sizeof(struct ah) + siz1;
804         } else {
805                 /* RFC 2402 */
806                 stripsiz = sizeof(struct newah) + siz1;
807         }
808         if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
809                 /*
810                  * strip off all the headers that precedes AH.
811                  *      IP6 xx AH IP6' payload -> IP6' payload
812                  *
813                  * XXX more sanity checks
814                  * XXX relationship with gif?
815                  */
816                 u_int32_t flowinfo;     /* net endian */
817
818                 flowinfo = ip6->ip6_flow;
819                 m_adj(m, off + stripsiz);
820                 if (m->m_len < sizeof(*ip6)) {
821                         /*
822                          * m_pullup is prohibited in KAME IPv6 input processing
823                          * but there's no other way!
824                          */
825                         m = m_pullup(m, sizeof(*ip6));
826                         if (!m) {
827                                 ipsec6stat.in_inval++;
828                                 goto fail;
829                         }
830                 }
831                 ip6 = mtod(m, struct ip6_hdr *);
832                 /* ECN consideration. */
833                 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
834                 if (!key_checktunnelsanity(sav, AF_INET6,
835                             (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
836                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
837                             "in IPv6 AH input: %s %s\n",
838                             ipsec6_logpacketstr(ip6, spi),
839                             ipsec_logsastr(sav)));
840                         ipsec6stat.in_inval++;
841                         goto fail;
842                 }
843
844 #if 1
845                 /*
846                  * should the inner packet be considered authentic?
847                  * see comment in ah4_input().
848                  */
849                 m->m_flags &= ~M_AUTHIPHDR;
850                 m->m_flags &= ~M_AUTHIPDGM;
851 #endif
852
853                 key_sa_recordxfer(sav, m);
854                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
855                     ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
856                         ipsec6stat.in_nomem++;
857                         goto fail;
858                 }
859
860                 if (netisr_queue(NETISR_IPV6, m)) {
861                         ipsec6stat.in_inval++;
862                         m = NULL;
863                         goto fail;
864                 }
865
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, MB_DONTWAIT);
909                         if (n == NULL) {
910                                 /* m is retained by m_split */
911                                 goto fail;
912                         }
913                         m_adj(n, stripsiz);
914                         /* m_cat does not update m_pkthdr.len */
915                         m->m_pkthdr.len += n->m_pkthdr.len;
916                         m_cat(m, n);
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                         kprintf("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                         kprintf("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(int cmd, struct sockaddr *sa, void *d)
954 {
955         const struct newah *ahp;
956         struct newah ah;
957         struct secasvar *sav;
958         struct ip6_hdr *ip6;
959         struct mbuf *m;
960         struct ip6ctlparam *ip6cp = NULL;
961         int off;
962         struct sockaddr_in6 *sa6_src, *sa6_dst;
963
964         if (sa->sa_family != AF_INET6 ||
965             sa->sa_len != sizeof(struct sockaddr_in6))
966                 return;
967         if ((unsigned)cmd >= PRC_NCMDS)
968                 return;
969
970         /* if the parameter is from icmp6, decode it. */
971         if (d != NULL) {
972                 ip6cp = (struct ip6ctlparam *)d;
973                 m = ip6cp->ip6c_m;
974                 ip6 = ip6cp->ip6c_ip6;
975                 off = ip6cp->ip6c_off;
976         } else {
977                 m = NULL;
978                 ip6 = NULL;
979                 off = 0; /* fix warning */
980         }
981
982         if (ip6) {
983                 /*
984                  * XXX: We assume that when ip6 is non NULL,
985                  * M and OFF are valid.
986                  */
987
988                 /* check if we can safely examine src and dst ports */
989                 if (m->m_pkthdr.len < off + sizeof(ah))
990                         return;
991
992                 if (m->m_len < off + sizeof(ah)) {
993                         /*
994                          * this should be rare case,
995                          * so we compromise on this copy...
996                          */
997                         m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
998                         ahp = &ah;
999                 } else
1000                         ahp = (struct newah *)(mtod(m, caddr_t) + off);
1001
1002                 if (cmd == PRC_MSGSIZE) {
1003                         int valid = 0;
1004
1005                         /*
1006                          * Check to see if we have a valid SA corresponding to
1007                          * the address in the ICMP message payload.
1008                          */
1009                         sa6_src = ip6cp->ip6c_src;
1010                         sa6_dst = (struct sockaddr_in6 *)sa;
1011                         sav = key_allocsa(AF_INET6,
1012                                           (caddr_t)&sa6_src->sin6_addr,
1013                                           (caddr_t)&sa6_dst->sin6_addr,
1014                                           IPPROTO_AH, ahp->ah_spi);
1015                         if (sav) {
1016                                 if (sav->state == SADB_SASTATE_MATURE ||
1017                                     sav->state == SADB_SASTATE_DYING)
1018                                         valid++;
1019                                 key_freesav(sav);
1020                         }
1021
1022                         /* XXX Further validation? */
1023
1024                         /*
1025                          * Depending on the value of "valid" and routing table
1026                          * size (mtudisc_{hi,lo}wat), we will:
1027                          * - recalcurate the new MTU and create the
1028                          *   corresponding routing entry, or
1029                          * - ignore the MTU change notification.
1030                          */
1031                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1032                 }
1033
1034                 /* we normally notify single pcb here */
1035         } else {
1036                 /* we normally notify any pcb here */
1037         }
1038 }
1039 #endif /* INET6 */