The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_ah.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: ip_ah.c,v 1.174 2022/05/03 09:18:11 claudio Exp $ */
    2 /*
    3  * The authors of this code are John Ioannidis (ji@tla.org),
    4  * Angelos D. Keromytis (kermit@csd.uch.gr) and
    5  * Niels Provos (provos@physnet.uni-hamburg.de).
    6  *
    7  * The original version of this code was written by John Ioannidis
    8  * for BSD/OS in Athens, Greece, in November 1995.
    9  *
   10  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
   11  * by Angelos D. Keromytis.
   12  *
   13  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
   14  * and Niels Provos.
   15  *
   16  * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist.
   17  *
   18  * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
   19  * Angelos D. Keromytis and Niels Provos.
   20  * Copyright (c) 1999 Niklas Hallqvist.
   21  * Copyright (c) 2001 Angelos D. Keromytis.
   22  *
   23  * Permission to use, copy, and modify this software with or without fee
   24  * is hereby granted, provided that this entire notice is included in
   25  * all copies of any software which is or includes a copy or
   26  * modification of this software.
   27  * You may use this code under the GNU public license if you so wish. Please
   28  * contribute changes back to the authors under this freer than GPL license
   29  * so that we may further the use of strong encryption without limitations to
   30  * all.
   31  *
   32  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
   33  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
   34  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
   35  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
   36  * PURPOSE.
   37  */
   38 
   39 #include "pfsync.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/socket.h>
   45 
   46 #include <net/if.h>
   47 #include <net/if_var.h>
   48 #include <net/bpf.h>
   49 
   50 #include <netinet/in.h>
   51 #include <netinet/ip.h>
   52 #include <netinet/ip_var.h>
   53 
   54 #ifdef INET6
   55 #include <netinet/ip6.h>
   56 #endif /* INET6 */
   57 
   58 #include <netinet/ip_ipsp.h>
   59 #include <netinet/ip_ah.h>
   60 #include <net/pfkeyv2.h>
   61 #include <net/if_enc.h>
   62 
   63 #if NPFSYNC > 0
   64 #include <net/pfvar.h>
   65 #include <net/if_pfsync.h>
   66 #endif /* NPFSYNC > 0 */
   67 
   68 #include <crypto/cryptodev.h>
   69 #include <crypto/xform.h>
   70 
   71 #include "bpfilter.h"
   72 
   73 #ifdef ENCDEBUG
   74 #define DPRINTF(fmt, args...)                                           \
   75         do {                                                            \
   76                 if (encdebug)                                           \
   77                         printf("%s: " fmt "\n", __func__, ## args);     \
   78         } while (0)
   79 #else
   80 #define DPRINTF(fmt, args...)                                           \
   81         do { } while (0)
   82 #endif
   83 
   84 int     ah_massage_headers(struct mbuf **, int, int, int, int);
   85 
   86 const unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
   87 
   88 
   89 /*
   90  * ah_attach() is called from the transformation initialization code.
   91  */
   92 int
   93 ah_attach(void)
   94 {
   95         return 0;
   96 }
   97 
   98 /*
   99  * ah_init() is called when an SPI is being set up.
  100  */
  101 int
  102 ah_init(struct tdb *tdbp, const struct xformsw *xsp, struct ipsecinit *ii)
  103 {
  104         const struct auth_hash *thash = NULL;
  105         struct cryptoini cria, crin;
  106         int error;
  107 
  108         /* Authentication operation. */
  109         switch (ii->ii_authalg) {
  110         case SADB_AALG_MD5HMAC:
  111                 thash = &auth_hash_hmac_md5_96;
  112                 break;
  113 
  114         case SADB_AALG_SHA1HMAC:
  115                 thash = &auth_hash_hmac_sha1_96;
  116                 break;
  117 
  118         case SADB_X_AALG_RIPEMD160HMAC:
  119                 thash = &auth_hash_hmac_ripemd_160_96;
  120                 break;
  121 
  122         case SADB_X_AALG_SHA2_256:
  123                 thash = &auth_hash_hmac_sha2_256_128;
  124                 break;
  125 
  126         case SADB_X_AALG_SHA2_384:
  127                 thash = &auth_hash_hmac_sha2_384_192;
  128                 break;
  129 
  130         case SADB_X_AALG_SHA2_512:
  131                 thash = &auth_hash_hmac_sha2_512_256;
  132                 break;
  133 
  134         default:
  135                 DPRINTF("unsupported authentication algorithm %d specified",
  136                     ii->ii_authalg);
  137                 return EINVAL;
  138         }
  139 
  140         if (ii->ii_authkeylen != thash->keysize && thash->keysize != 0) {
  141                 DPRINTF("keylength %d doesn't match algorithm %s keysize (%d)",
  142                     ii->ii_authkeylen, thash->name, thash->keysize);
  143                 return EINVAL;
  144         }
  145 
  146         tdbp->tdb_xform = xsp;
  147         tdbp->tdb_authalgxform = thash;
  148         tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL;
  149 
  150         DPRINTF("initialized TDB with hash algorithm %s", thash->name);
  151 
  152         tdbp->tdb_amxkeylen = ii->ii_authkeylen;
  153         tdbp->tdb_amxkey = malloc(tdbp->tdb_amxkeylen, M_XDATA, M_WAITOK);
  154 
  155         memcpy(tdbp->tdb_amxkey, ii->ii_authkey, tdbp->tdb_amxkeylen);
  156 
  157         /* Initialize crypto session. */
  158         memset(&cria, 0, sizeof(cria));
  159         cria.cri_alg = tdbp->tdb_authalgxform->type;
  160         cria.cri_klen = ii->ii_authkeylen * 8;
  161         cria.cri_key = ii->ii_authkey;
  162 
  163         if ((tdbp->tdb_wnd > 0) && (tdbp->tdb_flags & TDBF_ESN)) {
  164                 memset(&crin, 0, sizeof(crin));
  165                 crin.cri_alg = CRYPTO_ESN;
  166                 cria.cri_next = &crin;
  167         }
  168 
  169         KERNEL_LOCK();
  170         error = crypto_newsession(&tdbp->tdb_cryptoid, &cria, 0);
  171         KERNEL_UNLOCK();
  172         return error;
  173 }
  174 
  175 /*
  176  * Paranoia.
  177  */
  178 int
  179 ah_zeroize(struct tdb *tdbp)
  180 {
  181         int error;
  182 
  183         if (tdbp->tdb_amxkey) {
  184                 explicit_bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
  185                 free(tdbp->tdb_amxkey, M_XDATA, tdbp->tdb_amxkeylen);
  186                 tdbp->tdb_amxkey = NULL;
  187         }
  188 
  189         KERNEL_LOCK();
  190         error = crypto_freesession(tdbp->tdb_cryptoid);
  191         KERNEL_UNLOCK();
  192         tdbp->tdb_cryptoid = 0;
  193         return error;
  194 }
  195 
  196 /*
  197  * Massage IPv4/IPv6 headers for AH processing.
  198  */
  199 int
  200 ah_massage_headers(struct mbuf **mp, int af, int skip, int alg, int out)
  201 {
  202         struct mbuf *m = *mp;
  203         unsigned char *ptr;
  204         int off, count, error;
  205         struct ip *ip;
  206 #ifdef INET6
  207         struct ip6_ext *ip6e;
  208         struct ip6_hdr ip6;
  209         int ad, alloc, nxt, noff;
  210 #endif /* INET6 */
  211 
  212         switch (af) {
  213         case AF_INET:
  214                 /*
  215                  * This is the least painful way of dealing with IPv4 header
  216                  * and option processing -- just make sure they're in
  217                  * contiguous memory.
  218                  */
  219                 m = *mp = m_pullup(m, skip);
  220                 if (m == NULL) {
  221                         DPRINTF("m_pullup() failed");
  222                         ahstat_inc(ahs_hdrops);
  223                         error = ENOBUFS;
  224                         goto drop;
  225                 }
  226 
  227                 /* Fix the IP header */
  228                 ip = mtod(m, struct ip *);
  229                 ip->ip_tos = 0;
  230                 ip->ip_ttl = 0;
  231                 ip->ip_sum = 0;
  232                 ip->ip_off = 0;
  233 
  234                 ptr = mtod(m, unsigned char *);
  235 
  236                 /* IPv4 option processing */
  237                 for (off = sizeof(struct ip); off < skip;) {
  238                         if (ptr[off] != IPOPT_EOL && ptr[off] != IPOPT_NOP &&
  239                             off + 1 >= skip) {
  240                                 DPRINTF("illegal IPv4 option length "
  241                                     "for option %d",
  242                                     ptr[off]);
  243                                 ahstat_inc(ahs_hdrops);
  244                                 error = EINVAL;
  245                                 goto drop;
  246                         }
  247 
  248                         switch (ptr[off]) {
  249                         case IPOPT_EOL:
  250                                 off = skip;  /* End the loop. */
  251                                 break;
  252 
  253                         case IPOPT_NOP:
  254                                 off++;
  255                                 break;
  256 
  257                         case IPOPT_SECURITY:    /* 0x82 */
  258                         case 0x85:      /* Extended security. */
  259                         case 0x86:      /* Commercial security. */
  260                         case 0x94:      /* Router alert */
  261                         case 0x95:      /* RFC1770 */
  262                                 /* Sanity check for option length. */
  263                                 if (ptr[off + 1] < 2) {
  264                                         DPRINTF("illegal IPv4 option length "
  265                                             "for option %d",
  266                                             ptr[off]);
  267                                         ahstat_inc(ahs_hdrops);
  268                                         error = EINVAL;
  269                                         goto drop;
  270                                 }
  271 
  272                                 off += ptr[off + 1];
  273                                 break;
  274 
  275                         case IPOPT_LSRR:
  276                         case IPOPT_SSRR:
  277                                 /* Sanity check for option length. */
  278                                 if (ptr[off + 1] < 2) {
  279                                         DPRINTF("illegal IPv4 option length "
  280                                             "for option %d",
  281                                             ptr[off]);
  282                                         ahstat_inc(ahs_hdrops);
  283                                         error = EINVAL;
  284                                         goto drop;
  285                                 }
  286 
  287                                 /*
  288                                  * On output, if we have either of the
  289                                  * source routing options, we should
  290                                  * swap the destination address of the
  291                                  * IP header with the last address
  292                                  * specified in the option, as that is
  293                                  * what the destination's IP header
  294                                  * will look like.
  295                                  */
  296                                 if (out &&
  297                                     ptr[off + 1] >= 2 + sizeof(struct in_addr))
  298                                         memcpy(&ip->ip_dst,
  299                                             ptr + off + ptr[off + 1] -
  300                                             sizeof(struct in_addr),
  301                                             sizeof(struct in_addr));
  302 
  303                                 /* FALLTHROUGH */
  304                         default:
  305                                 /* Sanity check for option length. */
  306                                 if (ptr[off + 1] < 2) {
  307                                         DPRINTF("illegal IPv4 option length "
  308                                             "for option %d",
  309                                             ptr[off]);
  310                                         ahstat_inc(ahs_hdrops);
  311                                         error = EINVAL;
  312                                         goto drop;
  313                                 }
  314 
  315                                 /* Zeroize all other options. */
  316                                 count = ptr[off + 1];
  317                                 memset(ptr + off, 0, count);
  318                                 off += count;
  319                                 break;
  320                         }
  321 
  322                         /* Sanity check. */
  323                         if (off > skip) {
  324                                 DPRINTF("malformed IPv4 options header");
  325                                 ahstat_inc(ahs_hdrops);
  326                                 error = EINVAL;
  327                                 goto drop;
  328                         }
  329                 }
  330 
  331                 break;
  332 
  333 #ifdef INET6
  334         case AF_INET6:  /* Ugly... */
  335                 /* Copy and "cook" the IPv6 header. */
  336                 m_copydata(m, 0, sizeof(ip6), &ip6);
  337 
  338                 /* We don't do IPv6 Jumbograms. */
  339                 if (ip6.ip6_plen == 0) {
  340                         DPRINTF("unsupported IPv6 jumbogram");
  341                         ahstat_inc(ahs_hdrops);
  342                         error = EMSGSIZE;
  343                         goto drop;
  344                 }
  345 
  346                 ip6.ip6_flow = 0;
  347                 ip6.ip6_hlim = 0;
  348                 ip6.ip6_vfc &= ~IPV6_VERSION_MASK;
  349                 ip6.ip6_vfc |= IPV6_VERSION;
  350 
  351                 /* Scoped address handling. */
  352                 if (IN6_IS_SCOPE_EMBED(&ip6.ip6_src))
  353                         ip6.ip6_src.s6_addr16[1] = 0;
  354                 if (IN6_IS_SCOPE_EMBED(&ip6.ip6_dst))
  355                         ip6.ip6_dst.s6_addr16[1] = 0;
  356 
  357                 /* Done with IPv6 header. */
  358                 error = m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6,
  359                     M_NOWAIT);
  360                 if (error) {
  361                         DPRINTF("m_copyback no memory");
  362                         ahstat_inc(ahs_hdrops);
  363                         goto drop;
  364                 }
  365 
  366                 /* Let's deal with the remaining headers (if any). */
  367                 if (skip - sizeof(struct ip6_hdr) > 0) {
  368                         if (m->m_len <= skip) {
  369                                 ptr = malloc(skip - sizeof(struct ip6_hdr),
  370                                     M_XDATA, M_NOWAIT);
  371                                 if (ptr == NULL) {
  372                                         DPRINTF("failed to allocate "
  373                                             "memory for IPv6 headers");
  374                                         ahstat_inc(ahs_hdrops);
  375                                         error = ENOBUFS;
  376                                         goto drop;
  377                                 }
  378 
  379                                 /*
  380                                  * Copy all the protocol headers after
  381                                  * the IPv6 header.
  382                                  */
  383                                 m_copydata(m, sizeof(struct ip6_hdr),
  384                                     skip - sizeof(struct ip6_hdr), ptr);
  385                                 alloc = 1;
  386                         } else {
  387                                 /* No need to allocate memory. */
  388                                 ptr = mtod(m, unsigned char *) +
  389                                     sizeof(struct ip6_hdr);
  390                                 alloc = 0;
  391                         }
  392                 } else
  393                         break;
  394 
  395                 nxt = ip6.ip6_nxt;  /* Next header type. */
  396 
  397                 for (off = 0; off < skip - sizeof(struct ip6_hdr);) {
  398                         if (off + sizeof(struct ip6_ext) >
  399                             skip - sizeof(struct ip6_hdr))
  400                                 goto error6;
  401                         ip6e = (struct ip6_ext *)(ptr + off);
  402 
  403                         switch (nxt) {
  404                         case IPPROTO_HOPOPTS:
  405                         case IPPROTO_DSTOPTS:
  406                                 noff = off + ((ip6e->ip6e_len + 1) << 3);
  407 
  408                                 /* Sanity check. */
  409                                 if (noff > skip - sizeof(struct ip6_hdr))
  410                                         goto error6;
  411 
  412                                 /*
  413                                  * Zero out mutable options.
  414                                  */
  415                                 for (count = off + sizeof(struct ip6_ext);
  416                                      count < noff;) {
  417                                         if (ptr[count] == IP6OPT_PAD1) {
  418                                                 count++;
  419                                                 continue; /* Skip padding. */
  420                                         }
  421 
  422                                         if (count + 2 > noff)
  423                                                 goto error6;
  424                                         ad = ptr[count + 1] + 2;
  425                                         if (count + ad > noff)
  426                                                 goto error6;
  427 
  428                                         /* If mutable option, zeroize. */
  429                                         if (ptr[count] & IP6OPT_MUTABLE)
  430                                                 memset(ptr + count, 0, ad);
  431 
  432                                         count += ad;
  433                                 }
  434 
  435                                 if (count != noff)
  436                                         goto error6;
  437                                 break;
  438 
  439                         case IPPROTO_ROUTING:
  440                                 /*
  441                                  * Always include routing headers in
  442                                  * computation.
  443                                  */
  444                             {
  445                                 struct ip6_rthdr *rh;
  446 
  447                                 rh = (struct ip6_rthdr *)(ptr + off);
  448                                 /*
  449                                  * must adjust content to make it look like
  450                                  * its final form (as seen at the final
  451                                  * destination).
  452                                  * we only know how to massage type 0 routing
  453                                  * header.
  454                                  */
  455                                 if (out && rh->ip6r_type == IPV6_RTHDR_TYPE_0) {
  456                                         struct ip6_rthdr0 *rh0;
  457                                         struct in6_addr *addr, finaldst;
  458                                         int i;
  459 
  460                                         rh0 = (struct ip6_rthdr0 *)rh;
  461                                         addr = (struct in6_addr *)(rh0 + 1);
  462 
  463                                         for (i = 0; i < rh0->ip6r0_segleft; i++)
  464                                                 if (IN6_IS_SCOPE_EMBED(&addr[i]))
  465                                                         addr[i].s6_addr16[1] = 0;
  466 
  467                                         finaldst = addr[rh0->ip6r0_segleft - 1];
  468                                         memmove(&addr[1], &addr[0],
  469                                             sizeof(struct in6_addr) *
  470                                             (rh0->ip6r0_segleft - 1));
  471 
  472                                         m_copydata(m, 0, sizeof(ip6), &ip6);
  473                                         addr[0] = ip6.ip6_dst;
  474                                         ip6.ip6_dst = finaldst;
  475                                         error = m_copyback(m, 0, sizeof(ip6),
  476                                             &ip6, M_NOWAIT);
  477                                         if (error) {
  478                                                 if (alloc)
  479                                                         free(ptr, M_XDATA, 0);
  480                                                 ahstat_inc(ahs_hdrops);
  481                                                 goto drop;
  482                                         }
  483                                         rh0->ip6r0_segleft = 0;
  484                                 }
  485                                 break;
  486                             }
  487 
  488                         default:
  489                                 DPRINTF("unexpected IPv6 header type %d", off);
  490 error6:
  491                                 if (alloc)
  492                                         free(ptr, M_XDATA, 0);
  493                                 ahstat_inc(ahs_hdrops);
  494                                 error = EINVAL;
  495                                 goto drop;
  496                         }
  497 
  498                         /* Advance. */
  499                         off += ((ip6e->ip6e_len + 1) << 3);
  500                         nxt = ip6e->ip6e_nxt;
  501                 }
  502 
  503                 /* Copyback and free, if we allocated. */
  504                 if (alloc) {
  505                         error = m_copyback(m, sizeof(struct ip6_hdr),
  506                             skip - sizeof(struct ip6_hdr), ptr, M_NOWAIT);
  507                         free(ptr, M_XDATA, 0);
  508                         if (error) {
  509                                 ahstat_inc(ahs_hdrops);
  510                                 goto drop;
  511                         }
  512                 }
  513 
  514                 break;
  515 #endif /* INET6 */
  516         }
  517 
  518         return 0;
  519 
  520  drop:
  521         m_freemp(mp);
  522         return error;
  523 }
  524 
  525 /*
  526  * ah_input() gets called to verify that an input packet
  527  * passes authentication.
  528  */
  529 int
  530 ah_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff)
  531 {
  532         const struct auth_hash *ahx = tdb->tdb_authalgxform;
  533         struct mbuf *m = *mp, *m1, *m0;
  534         struct cryptodesc *crda = NULL;
  535         struct cryptop *crp = NULL;
  536         int roff;
  537         uint32_t btsx, esn;
  538         uint8_t *ptr = NULL;
  539         uint8_t hl;
  540         int error, rplen;
  541         uint64_t ibytes;
  542 #ifdef ENCDEBUG
  543         char buf[INET6_ADDRSTRLEN];
  544 #endif
  545         uint8_t calc[AH_ALEN_MAX];
  546 
  547         rplen = AH_FLENGTH + sizeof(u_int32_t);
  548 
  549         /* Save the AH header, we use it throughout. */
  550         m_copydata(m, skip + offsetof(struct ah, ah_hl), sizeof(u_int8_t), &hl);
  551 
  552         /* Replay window checking, if applicable. */
  553         if (tdb->tdb_wnd > 0) {
  554                 m_copydata(m, skip + offsetof(struct ah, ah_rpl),
  555                     sizeof(u_int32_t), &btsx);
  556                 btsx = ntohl(btsx);
  557 
  558                 switch (checkreplaywindow(tdb, tdb->tdb_rpl, btsx, &esn, 0)) {
  559                 case 0: /* All's well. */
  560                         break;
  561                 case 1:
  562                         DPRINTF("replay counter wrapped for SA %s/%08x",
  563                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  564                             ntohl(tdb->tdb_spi));
  565                         ahstat_inc(ahs_wrap);
  566                         goto drop;
  567                 case 2:
  568                         DPRINTF("old packet received in SA %s/%08x",
  569                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  570                             ntohl(tdb->tdb_spi));
  571                         ahstat_inc(ahs_replay);
  572                         goto drop;
  573                 case 3:
  574                         DPRINTF("duplicate packet received in SA %s/%08x",
  575                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  576                             ntohl(tdb->tdb_spi));
  577                         ahstat_inc(ahs_replay);
  578                         goto drop;
  579                 default:
  580                         DPRINTF("bogus value from checkreplaywindow() "
  581                             "in SA %s/%08x",
  582                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  583                             ntohl(tdb->tdb_spi));
  584                         ahstat_inc(ahs_replay);
  585                         goto drop;
  586                 }
  587         }
  588 
  589         /* Verify AH header length. */
  590         if (hl * sizeof(u_int32_t) != ahx->authsize + rplen - AH_FLENGTH) {
  591                 DPRINTF("bad authenticator length %ld for packet in SA %s/%08x",
  592                     hl * sizeof(u_int32_t),
  593                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  594                     ntohl(tdb->tdb_spi));
  595                 ahstat_inc(ahs_badauthl);
  596                 goto drop;
  597         }
  598         if (skip + ahx->authsize + rplen > m->m_pkthdr.len) {
  599                 DPRINTF("bad mbuf length %d (expecting %d) for packet "
  600                     "in SA %s/%08x",
  601                     m->m_pkthdr.len, skip + ahx->authsize + rplen,
  602                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  603                     ntohl(tdb->tdb_spi));
  604                 ahstat_inc(ahs_badauthl);
  605                 goto drop;
  606         }
  607 
  608         /* Update the counters. */
  609         ibytes = (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t));
  610         tdb->tdb_cur_bytes += ibytes;
  611         tdbstat_add(tdb, tdb_ibytes, ibytes);
  612         ahstat_add(ahs_ibytes, ibytes);
  613 
  614         /* Hard expiration. */
  615         if ((tdb->tdb_flags & TDBF_BYTES) &&
  616             (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
  617                 ipsecstat_inc(ipsec_exctdb);
  618                 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
  619                 tdb_delete(tdb);
  620                 goto drop;
  621         }
  622 
  623         /* Notify on expiration. */
  624         mtx_enter(&tdb->tdb_mtx);
  625         if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
  626             (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
  627                 tdb->tdb_flags &= ~TDBF_SOFT_BYTES;  /* Turn off checking */
  628                 mtx_leave(&tdb->tdb_mtx);
  629                 /* may sleep in solock() for the pfkey socket */
  630                 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
  631         } else
  632                 mtx_leave(&tdb->tdb_mtx);
  633 
  634         /* Get crypto descriptors. */
  635         crp = crypto_getreq(1);
  636         if (crp == NULL) {
  637                 DPRINTF("failed to acquire crypto descriptors");
  638                 ahstat_inc(ahs_crypto);
  639                 goto drop;
  640         }
  641 
  642         crda = &crp->crp_desc[0];
  643 
  644         crda->crd_skip = 0;
  645         crda->crd_len = m->m_pkthdr.len;
  646         crda->crd_inject = skip + rplen;
  647 
  648         /* Authentication operation. */
  649         crda->crd_alg = ahx->type;
  650         crda->crd_key = tdb->tdb_amxkey;
  651         crda->crd_klen = tdb->tdb_amxkeylen * 8;
  652 
  653         if ((tdb->tdb_wnd > 0) && (tdb->tdb_flags & TDBF_ESN)) {
  654                 esn = htonl(esn);
  655                 memcpy(crda->crd_esn, &esn, 4);
  656                 crda->crd_flags |= CRD_F_ESN;
  657         }
  658 
  659         /* Allocate IPsec-specific opaque crypto info. */
  660         ptr = malloc(skip + rplen + ahx->authsize, M_XDATA, M_NOWAIT | M_ZERO);
  661         if (ptr == NULL) {
  662                 DPRINTF("failed to allocate buffer");
  663                 ahstat_inc(ahs_crypto);
  664                 goto drop;
  665         }
  666 
  667         /*
  668          * Save the authenticator, the skipped portion of the packet,
  669          * and the AH header.
  670          */
  671         m_copydata(m, 0, skip + rplen + ahx->authsize, ptr);
  672 
  673         /* Zeroize the authenticator on the packet. */
  674         m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes, M_NOWAIT);
  675 
  676         /* "Massage" the packet headers for crypto processing. */
  677         error = ah_massage_headers(mp, tdb->tdb_dst.sa.sa_family, skip,
  678             ahx->type, 0);
  679         /* callee may change or free mbuf */
  680         m = *mp;
  681         if (error)
  682                 goto drop;
  683 
  684         /* Crypto operation descriptor. */
  685         crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
  686         crp->crp_flags = CRYPTO_F_IMBUF;
  687         crp->crp_buf = (caddr_t)m;
  688         crp->crp_sid = tdb->tdb_cryptoid;
  689 
  690         while ((error = crypto_invoke(crp)) == EAGAIN) {
  691                 /* Reset the session ID */
  692                 if (tdb->tdb_cryptoid != 0)
  693                         tdb->tdb_cryptoid = crp->crp_sid;
  694         }
  695         if (error) {
  696                 DPRINTF("crypto error %d", error);
  697                 ipsecstat_inc(ipsec_noxform);
  698                 goto drop;
  699         }
  700 
  701         /* Release the crypto descriptors */
  702         crypto_freereq(crp);
  703         crp = NULL;
  704 
  705         /* Copy authenticator off the packet. */
  706         m_copydata(m, skip + rplen, ahx->authsize, calc);
  707 
  708         /* Verify authenticator. */
  709         if (timingsafe_bcmp(ptr + skip + rplen, calc, ahx->authsize)) {
  710                 DPRINTF("authentication failed for packet in SA %s/%08x",
  711                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  712                     ntohl(tdb->tdb_spi));
  713                 ahstat_inc(ahs_badauth);
  714                 goto drop;
  715         }
  716 
  717         /* Fix the Next Protocol field. */
  718         ptr[protoff] = ptr[skip];
  719 
  720         /* Copyback the saved (uncooked) network headers. */
  721         m_copyback(m, 0, skip, ptr, M_NOWAIT);
  722 
  723         free(ptr, M_XDATA, 0);
  724         ptr = NULL;
  725 
  726         /* Replay window checking, if applicable. */
  727         if (tdb->tdb_wnd > 0) {
  728                 m_copydata(m, skip + offsetof(struct ah, ah_rpl),
  729                     sizeof(u_int32_t), &btsx);
  730                 btsx = ntohl(btsx);
  731 
  732                 switch (checkreplaywindow(tdb, tdb->tdb_rpl, btsx, &esn, 1)) {
  733                 case 0: /* All's well. */
  734 #if NPFSYNC > 0
  735                         pfsync_update_tdb(tdb,0);
  736 #endif
  737                         break;
  738                 case 1:
  739                         DPRINTF("replay counter wrapped for SA %s/%08x",
  740                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  741                             ntohl(tdb->tdb_spi));
  742                         ahstat_inc(ahs_wrap);
  743                         goto drop;
  744                 case 2:
  745                         DPRINTF("old packet received in SA %s/%08x",
  746                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  747                             ntohl(tdb->tdb_spi));
  748                         ahstat_inc(ahs_replay);
  749                         goto drop;
  750                 case 3:
  751                         DPRINTF("duplicate packet received in SA %s/%08x",
  752                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  753                             ntohl(tdb->tdb_spi));
  754                         ahstat_inc(ahs_replay);
  755                         goto drop;
  756                 default:
  757                         DPRINTF("bogus value from checkreplaywindow() "
  758                             "in SA %s/%08x",
  759                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  760                             ntohl(tdb->tdb_spi));
  761                         ahstat_inc(ahs_replay);
  762                         goto drop;
  763                 }
  764         }
  765 
  766         /* Record the beginning of the AH header. */
  767         m1 = m_getptr(m, skip, &roff);
  768         if (m1 == NULL) {
  769                 DPRINTF("bad mbuf chain for packet in SA %s/%08x",
  770                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  771                     ntohl(tdb->tdb_spi));
  772                 ahstat_inc(ahs_hdrops);
  773                 goto drop;
  774         }
  775 
  776         /* Remove the AH header from the mbuf. */
  777         if (roff == 0) {
  778                 /*
  779                  * The AH header was conveniently at the beginning of
  780                  * the mbuf.
  781                  */
  782                 m_adj(m1, rplen + ahx->authsize);
  783                 /*
  784                  * If m1 is the first mbuf, it has set M_PKTHDR and m_adj()
  785                  * has already adjusted the packet header length for us.
  786                  */
  787                 if (m1 != m)
  788                         m->m_pkthdr.len -= rplen + ahx->authsize;
  789         } else
  790                 if (roff + rplen + ahx->authsize >= m1->m_len) {
  791                         int adjlen;
  792 
  793                         /*
  794                          * Part or all of the AH header is at the end
  795                          * of this mbuf, so first let's remove the
  796                          * remainder of the AH header from the
  797                          * beginning of the remainder of the mbuf
  798                          * chain, if any.
  799                          */
  800                         if (roff + rplen + ahx->authsize > m1->m_len) {
  801                                 adjlen = roff + rplen + ahx->authsize -
  802                                     m1->m_len;
  803                                 /* Adjust the next mbuf by the remainder. */
  804                                 m_adj(m1->m_next, adjlen);
  805 
  806                                 /*
  807                                  * The second mbuf is guaranteed not
  808                                  * to have a pkthdr...
  809                                  */
  810                                 m->m_pkthdr.len -= adjlen;
  811                         }
  812 
  813                         /* Now, let's unlink the mbuf chain for a second... */
  814                         m0 = m1->m_next;
  815                         m1->m_next = NULL;
  816 
  817                         /*
  818                          * ...and trim the end of the first part of
  819                          * the chain...sick
  820                          */
  821                         adjlen = m1->m_len - roff;
  822                         m_adj(m1, -adjlen);
  823                         /*
  824                          * If m1 is the first mbuf, it has set M_PKTHDR and
  825                          * m_adj() has already adjusted the packet header len.
  826                          */
  827                         if (m1 != m)
  828                                 m->m_pkthdr.len -= adjlen;
  829 
  830                         /* Finally, let's relink. */
  831                         m1->m_next = m0;
  832                 } else {
  833                         /*
  834                          * The AH header lies in the "middle" of the
  835                          * mbuf...do an overlapping copy of the
  836                          * remainder of the mbuf over the ESP header.
  837                          */
  838                         bcopy(mtod(m1, u_char *) + roff + rplen +
  839                             ahx->authsize, mtod(m1, u_char *) + roff,
  840                             m1->m_len - (roff + rplen + ahx->authsize));
  841                         m1->m_len -= rplen + ahx->authsize;
  842                         m->m_pkthdr.len -= rplen + ahx->authsize;
  843                 }
  844 
  845         return ipsec_common_input_cb(mp, tdb, skip, protoff);
  846 
  847  drop:
  848         free(ptr, M_XDATA, 0);
  849         m_freemp(mp);
  850         crypto_freereq(crp);
  851         return IPPROTO_DONE;
  852 }
  853 
  854 /*
  855  * AH output routine, called by ipsp_process_packet().
  856  */
  857 int
  858 ah_output(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
  859 {
  860         const struct auth_hash *ahx = tdb->tdb_authalgxform;
  861         struct cryptodesc *crda;
  862         struct mbuf *mi;
  863         struct cryptop *crp = NULL;
  864         uint64_t replay64;
  865         uint16_t iplen;
  866         int error, rplen, roff;
  867         uint8_t *ptr = NULL;
  868         uint8_t prot;
  869         struct ah *ah;
  870 #if NBPFILTER > 0
  871         struct ifnet *encif;
  872 #ifdef ENCDEBUG
  873         char buf[INET6_ADDRSTRLEN];
  874 #endif
  875 
  876         if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) != NULL) {
  877                 encif->if_opackets++;
  878                 encif->if_obytes += m->m_pkthdr.len;
  879 
  880                 if (encif->if_bpf) {
  881                         struct enchdr hdr;
  882 
  883                         memset(&hdr, 0, sizeof(hdr));
  884 
  885                         hdr.af = tdb->tdb_dst.sa.sa_family;
  886                         hdr.spi = tdb->tdb_spi;
  887                         hdr.flags |= M_AUTH;
  888 
  889                         bpf_mtap_hdr(encif->if_bpf, (char *)&hdr,
  890                             ENC_HDRLEN, m, BPF_DIRECTION_OUT);
  891                 }
  892         }
  893 #endif
  894 
  895         ahstat_inc(ahs_output);
  896 
  897         /*
  898          * Check for replay counter wrap-around in automatic (not
  899          * manual) keying.
  900          */
  901         if ((tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0)) {
  902                 DPRINTF("SA %s/%08x should have expired",
  903                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  904                     ntohl(tdb->tdb_spi));
  905                 ahstat_inc(ahs_wrap);
  906                 error = EINVAL;
  907                 goto drop;
  908         }
  909 
  910         rplen = AH_FLENGTH + sizeof(u_int32_t);
  911 
  912         switch (tdb->tdb_dst.sa.sa_family) {
  913         case AF_INET:
  914                 /* Check for IP maximum packet size violations. */
  915                 if (rplen + ahx->authsize + m->m_pkthdr.len > IP_MAXPACKET) {
  916                         DPRINTF("packet in SA %s/%08x got too big",
  917                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  918                             ntohl(tdb->tdb_spi));
  919                         ahstat_inc(ahs_toobig);
  920                         error = EMSGSIZE;
  921                         goto drop;
  922                 }
  923                 break;
  924 
  925 #ifdef INET6
  926         case AF_INET6:
  927                 /* Check for IPv6 maximum packet size violations. */
  928                 if (rplen + ahx->authsize + m->m_pkthdr.len > IPV6_MAXPACKET) {
  929                         DPRINTF("packet in SA %s/%08x got too big",
  930                             ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  931                             ntohl(tdb->tdb_spi));
  932                         ahstat_inc(ahs_toobig);
  933                         error = EMSGSIZE;
  934                         goto drop;
  935                 }
  936                 break;
  937 #endif /* INET6 */
  938 
  939         default:
  940                 DPRINTF("unknown/unsupported protocol family %d, SA %s/%08x",
  941                     tdb->tdb_dst.sa.sa_family,
  942                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
  943                     ntohl(tdb->tdb_spi));
  944                 ahstat_inc(ahs_nopf);
  945                 error = EPFNOSUPPORT;
  946                 goto drop;
  947         }
  948 
  949         /* Update the counters. */
  950         tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
  951         ahstat_add(ahs_obytes, m->m_pkthdr.len - skip);
  952 
  953         /* Hard expiration. */
  954         if ((tdb->tdb_flags & TDBF_BYTES) &&
  955             (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
  956                 ipsecstat_inc(ipsec_exctdb);
  957                 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
  958                 tdb_delete(tdb);
  959                 error = EINVAL;
  960                 goto drop;
  961         }
  962 
  963         /* Notify on expiration. */
  964         mtx_enter(&tdb->tdb_mtx);
  965         if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
  966             (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
  967                 tdb->tdb_flags &= ~TDBF_SOFT_BYTES;  /* Turn off checking */
  968                 mtx_leave(&tdb->tdb_mtx);
  969                 /* may sleep in solock() for the pfkey socket */
  970                 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
  971         } else
  972                 mtx_leave(&tdb->tdb_mtx);
  973 
  974         /*
  975          * Loop through mbuf chain; if we find a readonly mbuf,
  976          * copy the packet.
  977          */
  978         mi = m;
  979         while (mi != NULL && !M_READONLY(mi))
  980                 mi = mi->m_next;
  981 
  982         if (mi != NULL) {
  983                 struct mbuf *n = m_dup_pkt(m, 0, M_DONTWAIT);
  984 
  985                 if (n == NULL) {
  986                         ahstat_inc(ahs_hdrops);
  987                         error = ENOBUFS;
  988                         goto drop;
  989                 }
  990 
  991                 m_freem(m);
  992                 m = n;
  993         }
  994 
  995         /* Inject AH header. */
  996         mi = m_makespace(m, skip, rplen + ahx->authsize, &roff);
  997         if (mi == NULL) {
  998                 DPRINTF("failed to inject AH header for SA %s/%08x",
  999                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
 1000                     ntohl(tdb->tdb_spi));
 1001                 ahstat_inc(ahs_hdrops);
 1002                 error = ENOBUFS;
 1003                 goto drop;
 1004         }
 1005 
 1006         /*
 1007          * The AH header is guaranteed by m_makespace() to be in
 1008          * contiguous memory, at 'roff' of the returned mbuf.
 1009          */
 1010         ah = (struct ah *)(mtod(mi, caddr_t) + roff);
 1011 
 1012         /* Initialize the AH header. */
 1013         m_copydata(m, protoff, sizeof(u_int8_t), &ah->ah_nh);
 1014         ah->ah_hl = (rplen + ahx->authsize - AH_FLENGTH) / sizeof(u_int32_t);
 1015         ah->ah_rv = 0;
 1016         ah->ah_spi = tdb->tdb_spi;
 1017 
 1018         /* Zeroize authenticator. */
 1019         m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes, M_NOWAIT);
 1020 
 1021         replay64 = tdb->tdb_rpl++;
 1022         ah->ah_rpl = htonl((u_int32_t)replay64);
 1023 #if NPFSYNC > 0
 1024         pfsync_update_tdb(tdb,1);
 1025 #endif
 1026 
 1027         /* Get crypto descriptors. */
 1028         crp = crypto_getreq(1);
 1029         if (crp == NULL) {
 1030                 DPRINTF("failed to acquire crypto descriptors");
 1031                 ahstat_inc(ahs_crypto);
 1032                 error = ENOBUFS;
 1033                 goto drop;
 1034         }
 1035 
 1036         crda = &crp->crp_desc[0];
 1037 
 1038         crda->crd_skip = 0;
 1039         crda->crd_inject = skip + rplen;
 1040         crda->crd_len = m->m_pkthdr.len;
 1041 
 1042         /* Authentication operation. */
 1043         crda->crd_alg = ahx->type;
 1044         crda->crd_key = tdb->tdb_amxkey;
 1045         crda->crd_klen = tdb->tdb_amxkeylen * 8;
 1046 
 1047         if ((tdb->tdb_wnd > 0) && (tdb->tdb_flags & TDBF_ESN)) {
 1048                 u_int32_t esn;
 1049 
 1050                 esn = htonl((u_int32_t)(replay64 >> 32));
 1051                 memcpy(crda->crd_esn, &esn, 4);
 1052                 crda->crd_flags |= CRD_F_ESN;
 1053         }
 1054 
 1055         ptr = malloc(skip, M_XDATA, M_NOWAIT | M_ZERO);
 1056         if (ptr == NULL) {
 1057                 DPRINTF("failed to allocate buffer");
 1058                 ahstat_inc(ahs_crypto);
 1059                 error = ENOBUFS;
 1060                 goto drop;
 1061         }
 1062 
 1063         /* Save the skipped portion of the packet. */
 1064         m_copydata(m, 0, skip, ptr);
 1065 
 1066         /*
 1067          * Fix IP header length on the header used for
 1068          * authentication. We don't need to fix the original
 1069          * header length as it will be fixed by our caller.
 1070          */
 1071         switch (tdb->tdb_dst.sa.sa_family) {
 1072         case AF_INET:
 1073                 memcpy((caddr_t) &iplen, ((caddr_t)ptr) +
 1074                     offsetof(struct ip, ip_len), sizeof(u_int16_t));
 1075                 iplen = htons(ntohs(iplen) + rplen + ahx->authsize);
 1076                 m_copyback(m, offsetof(struct ip, ip_len),
 1077                     sizeof(u_int16_t), &iplen, M_NOWAIT);
 1078                 break;
 1079 
 1080 #ifdef INET6
 1081         case AF_INET6:
 1082                 memcpy((caddr_t) &iplen, ((caddr_t)ptr) +
 1083                     offsetof(struct ip6_hdr, ip6_plen), sizeof(u_int16_t));
 1084                 iplen = htons(ntohs(iplen) + rplen + ahx->authsize);
 1085                 m_copyback(m, offsetof(struct ip6_hdr, ip6_plen),
 1086                     sizeof(u_int16_t), &iplen, M_NOWAIT);
 1087                 break;
 1088 #endif /* INET6 */
 1089         }
 1090 
 1091         /* Fix the Next Header field in saved header. */
 1092         ptr[protoff] = IPPROTO_AH;
 1093 
 1094         /* Update the Next Protocol field in the IP header. */
 1095         prot = IPPROTO_AH;
 1096         m_copyback(m, protoff, sizeof(u_int8_t), &prot, M_NOWAIT);
 1097 
 1098         /* "Massage" the packet headers for crypto processing. */
 1099         error = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, skip,
 1100             ahx->type, 1);
 1101         if (error) {
 1102                 /* mbuf was freed by callee. */
 1103                 m = NULL;
 1104                 goto drop;
 1105         }
 1106 
 1107         /* Crypto operation descriptor. */
 1108         crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
 1109         crp->crp_flags = CRYPTO_F_IMBUF;
 1110         crp->crp_buf = (caddr_t)m;
 1111         crp->crp_sid = tdb->tdb_cryptoid;
 1112 
 1113         while ((error = crypto_invoke(crp)) == EAGAIN) {
 1114                 /* Reset the session ID */
 1115                 if (tdb->tdb_cryptoid != 0)
 1116                         tdb->tdb_cryptoid = crp->crp_sid;
 1117         }
 1118         if (error) {
 1119                 DPRINTF("crypto error %d", error);
 1120                 ipsecstat_inc(ipsec_noxform);
 1121                 goto drop;
 1122         }
 1123 
 1124         /* Release the crypto descriptors */
 1125         crypto_freereq(crp);
 1126         crp = NULL;
 1127 
 1128         /*
 1129          * Copy original headers (with the new protocol number) back
 1130          * in place.
 1131          */
 1132         m_copyback(m, 0, skip, ptr, M_NOWAIT);
 1133         free(ptr, M_XDATA, 0);
 1134         ptr = NULL;
 1135 
 1136         /* Call the IPsec input callback. */
 1137         error = ipsp_process_done(m, tdb);
 1138         if (error)
 1139                 ahstat_inc(ahs_outfail);
 1140         return error;
 1141 
 1142  drop:
 1143         free(ptr, M_XDATA, 0);
 1144         m_freem(m);
 1145         crypto_freereq(crp);
 1146         return error;
 1147 }

Cache object: b8cff7194f2123aef9e766e335ec1a2c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.