188768458SSam Leffler /* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */ 2c398230bSWarner Losh /*- 388768458SSam Leffler * The authors of this code are John Ioannidis (ji@tla.org), 488768458SSam Leffler * Angelos D. Keromytis (kermit@csd.uch.gr) and 588768458SSam Leffler * Niels Provos (provos@physnet.uni-hamburg.de). 688768458SSam Leffler * 788768458SSam Leffler * The original version of this code was written by John Ioannidis 888768458SSam Leffler * for BSD/OS in Athens, Greece, in November 1995. 988768458SSam Leffler * 1088768458SSam Leffler * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 1188768458SSam Leffler * by Angelos D. Keromytis. 1288768458SSam Leffler * 1388768458SSam Leffler * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 1488768458SSam Leffler * and Niels Provos. 1588768458SSam Leffler * 1688768458SSam Leffler * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist. 1788768458SSam Leffler * 1888768458SSam Leffler * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, 1988768458SSam Leffler * Angelos D. Keromytis and Niels Provos. 2088768458SSam Leffler * Copyright (c) 1999 Niklas Hallqvist. 2188768458SSam Leffler * Copyright (c) 2001 Angelos D. Keromytis. 2288768458SSam Leffler * 2388768458SSam Leffler * Permission to use, copy, and modify this software with or without fee 2488768458SSam Leffler * is hereby granted, provided that this entire notice is included in 2588768458SSam Leffler * all copies of any software which is or includes a copy or 2688768458SSam Leffler * modification of this software. 2788768458SSam Leffler * You may use this code under the GNU public license if you so wish. Please 2888768458SSam Leffler * contribute changes back to the authors under this freer than GPL license 2988768458SSam Leffler * so that we may further the use of strong encryption without limitations to 3088768458SSam Leffler * all. 3188768458SSam Leffler * 3288768458SSam Leffler * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 3388768458SSam Leffler * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 3488768458SSam Leffler * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 3588768458SSam Leffler * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 3688768458SSam Leffler * PURPOSE. 3788768458SSam Leffler */ 3888768458SSam Leffler #include "opt_inet.h" 3988768458SSam Leffler #include "opt_inet6.h" 4028d2a72bSJohn Baldwin #include "opt_ipsec.h" 4188768458SSam Leffler 4288768458SSam Leffler #include <sys/param.h> 4388768458SSam Leffler #include <sys/systm.h> 4435d9e00dSJohn Baldwin #include <sys/malloc.h> 4588768458SSam Leffler #include <sys/mbuf.h> 4688768458SSam Leffler #include <sys/socket.h> 4788768458SSam Leffler #include <sys/syslog.h> 4888768458SSam Leffler #include <sys/kernel.h> 49eedc7fd9SGleb Smirnoff #include <sys/lock.h> 50fcf59617SAndrey V. Elsukov #include <sys/mutex.h> 5188768458SSam Leffler #include <sys/sysctl.h> 5288768458SSam Leffler 5388768458SSam Leffler #include <net/if.h> 54eddfbb76SRobert Watson #include <net/vnet.h> 5588768458SSam Leffler 5688768458SSam Leffler #include <netinet/in.h> 5788768458SSam Leffler #include <netinet/in_systm.h> 5888768458SSam Leffler #include <netinet/ip.h> 5988768458SSam Leffler #include <netinet/ip_ecn.h> 6088768458SSam Leffler #include <netinet/ip6.h> 6188768458SSam Leffler 6288768458SSam Leffler #include <netipsec/ipsec.h> 6388768458SSam Leffler #include <netipsec/ah.h> 6488768458SSam Leffler #include <netipsec/ah_var.h> 6588768458SSam Leffler #include <netipsec/xform.h> 6688768458SSam Leffler 6788768458SSam Leffler #ifdef INET6 6888768458SSam Leffler #include <netinet6/ip6_var.h> 6988768458SSam Leffler #include <netipsec/ipsec6.h> 7088768458SSam Leffler #include <netinet6/ip6_ecn.h> 7188768458SSam Leffler #endif 7288768458SSam Leffler 7388768458SSam Leffler #include <netipsec/key.h> 7488768458SSam Leffler #include <netipsec/key_debug.h> 7588768458SSam Leffler 7688768458SSam Leffler #include <opencrypto/cryptodev.h> 7788768458SSam Leffler 7888768458SSam Leffler /* 7988768458SSam Leffler * Return header size in bytes. The old protocol did not support 8088768458SSam Leffler * the replay counter; the new protocol always includes the counter. 8188768458SSam Leffler */ 8288768458SSam Leffler #define HDRSIZE(sav) \ 8388768458SSam Leffler (((sav)->flags & SADB_X_EXT_OLD) ? \ 8488768458SSam Leffler sizeof (struct ah) : sizeof (struct ah) + sizeof (u_int32_t)) 8588768458SSam Leffler /* 8616de9ac1SGeorge V. Neville-Neil * Return authenticator size in bytes, based on a field in the 8716de9ac1SGeorge V. Neville-Neil * algorithm descriptor. 8888768458SSam Leffler */ 89a09a7146SJohn-Mark Gurney #define AUTHSIZE(sav) ((sav->flags & SADB_X_EXT_OLD) ? 16 : \ 90a09a7146SJohn-Mark Gurney xform_ah_authsize((sav)->tdb_authalgxform)) 9188768458SSam Leffler 92eddfbb76SRobert Watson VNET_DEFINE(int, ah_enable) = 1; /* control flow of packets with AH */ 93eddfbb76SRobert Watson VNET_DEFINE(int, ah_cleartos) = 1; /* clear ip_tos when doing AH calc */ 94db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ahstat, ahstat); 95db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ahstat); 96db8c0879SAndrey V. Elsukov 97db8c0879SAndrey V. Elsukov #ifdef VIMAGE 98db8c0879SAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ahstat); 99db8c0879SAndrey V. Elsukov #endif /* VIMAGE */ 10088768458SSam Leffler 101db178eb8SBjoern A. Zeeb #ifdef INET 10288768458SSam Leffler SYSCTL_DECL(_net_inet_ah); 1036df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ah, OID_AUTO, ah_enable, 1046df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_enable), 0, ""); 1056df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ah, OID_AUTO, ah_cleartos, 1066df8a710SGleb Smirnoff CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, ""); 107db8c0879SAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet_ah, IPSECCTL_STATS, stats, struct ahstat, 108db8c0879SAndrey V. Elsukov ahstat, "AH statistics (struct ahstat, netipsec/ah_var.h)"); 109db178eb8SBjoern A. Zeeb #endif 11088768458SSam Leffler 11135d9e00dSJohn Baldwin static MALLOC_DEFINE(M_AH, "ah", "IPsec AH"); 11235d9e00dSJohn Baldwin 11388768458SSam Leffler static unsigned char ipseczeroes[256]; /* larger than an ip6 extension hdr */ 11488768458SSam Leffler 11588768458SSam Leffler static int ah_input_cb(struct cryptop*); 11688768458SSam Leffler static int ah_output_cb(struct cryptop*); 11788768458SSam Leffler 118a09a7146SJohn-Mark Gurney int 119fcf59617SAndrey V. Elsukov xform_ah_authsize(const struct auth_hash *esph) 120a09a7146SJohn-Mark Gurney { 121a09a7146SJohn-Mark Gurney int alen; 122a09a7146SJohn-Mark Gurney 123a09a7146SJohn-Mark Gurney if (esph == NULL) 124a09a7146SJohn-Mark Gurney return 0; 125a09a7146SJohn-Mark Gurney 126a09a7146SJohn-Mark Gurney switch (esph->type) { 127a09a7146SJohn-Mark Gurney case CRYPTO_SHA2_256_HMAC: 128a09a7146SJohn-Mark Gurney case CRYPTO_SHA2_384_HMAC: 129a09a7146SJohn-Mark Gurney case CRYPTO_SHA2_512_HMAC: 130a09a7146SJohn-Mark Gurney alen = esph->hashsize / 2; /* RFC4868 2.3 */ 131a09a7146SJohn-Mark Gurney break; 132a09a7146SJohn-Mark Gurney 1339f8f3a8eSKristof Provost case CRYPTO_POLY1305: 134c0341432SJohn Baldwin case CRYPTO_AES_NIST_GMAC: 135a09a7146SJohn-Mark Gurney alen = esph->hashsize; 136a09a7146SJohn-Mark Gurney break; 137a09a7146SJohn-Mark Gurney 138a09a7146SJohn-Mark Gurney default: 139a09a7146SJohn-Mark Gurney alen = AH_HMAC_HASHLEN; 140a09a7146SJohn-Mark Gurney break; 141a09a7146SJohn-Mark Gurney } 142a09a7146SJohn-Mark Gurney 143a09a7146SJohn-Mark Gurney return alen; 144a09a7146SJohn-Mark Gurney } 145a09a7146SJohn-Mark Gurney 14688768458SSam Leffler size_t 14788768458SSam Leffler ah_hdrsiz(struct secasvar *sav) 14888768458SSam Leffler { 14988768458SSam Leffler size_t size; 15088768458SSam Leffler 15188768458SSam Leffler if (sav != NULL) { 152ede2f773SConrad Meyer int authsize, rplen, align; 153ede2f773SConrad Meyer 1549ffa9677SSam Leffler IPSEC_ASSERT(sav->tdb_authalgxform != NULL, ("null xform")); 15588768458SSam Leffler /*XXX not right for null algorithm--does it matter??*/ 156ede2f773SConrad Meyer 157ede2f773SConrad Meyer /* RFC4302: use the correct alignment. */ 158ede2f773SConrad Meyer align = sizeof(uint32_t); 159ede2f773SConrad Meyer #ifdef INET6 160ede2f773SConrad Meyer if (sav->sah->saidx.dst.sa.sa_family == AF_INET6) { 161ede2f773SConrad Meyer align = sizeof(uint64_t); 162ede2f773SConrad Meyer } 163ede2f773SConrad Meyer #endif 164ede2f773SConrad Meyer rplen = HDRSIZE(sav); 16588768458SSam Leffler authsize = AUTHSIZE(sav); 166ede2f773SConrad Meyer size = roundup(rplen + authsize, align); 16788768458SSam Leffler } else { 16888768458SSam Leffler /* default guess */ 16988768458SSam Leffler size = sizeof (struct ah) + sizeof (u_int32_t) + 16; 17088768458SSam Leffler } 17188768458SSam Leffler return size; 17288768458SSam Leffler } 17388768458SSam Leffler 17488768458SSam Leffler /* 17588768458SSam Leffler * NB: public for use by esp_init. 17688768458SSam Leffler */ 17788768458SSam Leffler int 178c0341432SJohn Baldwin ah_init0(struct secasvar *sav, struct xformsw *xsp, 179c0341432SJohn Baldwin struct crypto_session_params *csp) 18088768458SSam Leffler { 181fcf59617SAndrey V. Elsukov const struct auth_hash *thash; 18288768458SSam Leffler int keylen; 18388768458SSam Leffler 184fcf59617SAndrey V. Elsukov thash = auth_algorithm_lookup(sav->alg_auth); 18588768458SSam Leffler if (thash == NULL) { 1869ffa9677SSam Leffler DPRINTF(("%s: unsupported authentication algorithm %u\n", 1879ffa9677SSam Leffler __func__, sav->alg_auth)); 18888768458SSam Leffler return EINVAL; 18988768458SSam Leffler } 190c2fd516fSJohn Baldwin 19188768458SSam Leffler /* 19288768458SSam Leffler * Verify the replay state block allocation is consistent with 19388768458SSam Leffler * the protocol type. We check here so we can make assumptions 19488768458SSam Leffler * later during protocol processing. 19588768458SSam Leffler */ 19688768458SSam Leffler /* NB: replay state is setup elsewhere (sigh) */ 19788768458SSam Leffler if (((sav->flags&SADB_X_EXT_OLD) == 0) ^ (sav->replay != NULL)) { 1989ffa9677SSam Leffler DPRINTF(("%s: replay state block inconsistency, " 1999ffa9677SSam Leffler "%s algorithm %s replay state\n", __func__, 20088768458SSam Leffler (sav->flags & SADB_X_EXT_OLD) ? "old" : "new", 20188768458SSam Leffler sav->replay == NULL ? "without" : "with")); 20288768458SSam Leffler return EINVAL; 20388768458SSam Leffler } 20488768458SSam Leffler if (sav->key_auth == NULL) { 2059ffa9677SSam Leffler DPRINTF(("%s: no authentication key for %s algorithm\n", 2069ffa9677SSam Leffler __func__, thash->name)); 20788768458SSam Leffler return EINVAL; 20888768458SSam Leffler } 20988768458SSam Leffler keylen = _KEYLEN(sav->key_auth); 2103693b188SConrad Meyer if (keylen > thash->keysize && thash->keysize != 0) { 2119ffa9677SSam Leffler DPRINTF(("%s: invalid keylength %d, algorithm %s requires " 2123693b188SConrad Meyer "keysize less than %d\n", __func__, 21388768458SSam Leffler keylen, thash->name, thash->keysize)); 21488768458SSam Leffler return EINVAL; 21588768458SSam Leffler } 21688768458SSam Leffler 21788768458SSam Leffler sav->tdb_xform = xsp; 21888768458SSam Leffler sav->tdb_authalgxform = thash; 21988768458SSam Leffler 22088768458SSam Leffler /* Initialize crypto session. */ 221c0341432SJohn Baldwin csp->csp_auth_alg = sav->tdb_authalgxform->type; 222897e4312SJohn Baldwin if (csp->csp_auth_alg != CRYPTO_NULL_HMAC) { 223c0341432SJohn Baldwin csp->csp_auth_klen = _KEYBITS(sav->key_auth) / 8; 224c0341432SJohn Baldwin csp->csp_auth_key = sav->key_auth->key_data; 225897e4312SJohn Baldwin }; 226c0341432SJohn Baldwin csp->csp_auth_mlen = AUTHSIZE(sav); 22788768458SSam Leffler 22888768458SSam Leffler return 0; 22988768458SSam Leffler } 23088768458SSam Leffler 23188768458SSam Leffler /* 23288768458SSam Leffler * ah_init() is called when an SPI is being set up. 23388768458SSam Leffler */ 23488768458SSam Leffler static int 23588768458SSam Leffler ah_init(struct secasvar *sav, struct xformsw *xsp) 23688768458SSam Leffler { 237c0341432SJohn Baldwin struct crypto_session_params csp; 23888768458SSam Leffler int error; 23988768458SSam Leffler 240c0341432SJohn Baldwin memset(&csp, 0, sizeof(csp)); 241c0341432SJohn Baldwin csp.csp_mode = CSP_MODE_DIGEST; 2424d36d1fdSMarcin Wojtas 2434d36d1fdSMarcin Wojtas if (sav->flags & SADB_X_SAFLAGS_ESN) 2444d36d1fdSMarcin Wojtas csp.csp_flags |= CSP_F_ESN; 2454d36d1fdSMarcin Wojtas 246c0341432SJohn Baldwin error = ah_init0(sav, xsp, &csp); 24788768458SSam Leffler return error ? error : 248c0341432SJohn Baldwin crypto_newsession(&sav->tdb_cryptoid, &csp, V_crypto_support); 24988768458SSam Leffler } 25088768458SSam Leffler 251dae61c9dSJohn Baldwin static void 252dae61c9dSJohn Baldwin ah_cleanup(struct secasvar *sav) 25388768458SSam Leffler { 25488768458SSam Leffler 2551b0909d5SConrad Meyer crypto_freesession(sav->tdb_cryptoid); 2561b0909d5SConrad Meyer sav->tdb_cryptoid = NULL; 25788768458SSam Leffler sav->tdb_authalgxform = NULL; 25888768458SSam Leffler } 25988768458SSam Leffler 26088768458SSam Leffler /* 26188768458SSam Leffler * Massage IPv4/IPv6 headers for AH processing. 26288768458SSam Leffler */ 26388768458SSam Leffler static int 26488768458SSam Leffler ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out) 26588768458SSam Leffler { 26688768458SSam Leffler struct mbuf *m = *m0; 26788768458SSam Leffler unsigned char *ptr; 26888768458SSam Leffler int off, count; 26988768458SSam Leffler 27088768458SSam Leffler #ifdef INET 27188768458SSam Leffler struct ip *ip; 27288768458SSam Leffler #endif /* INET */ 27388768458SSam Leffler 27488768458SSam Leffler #ifdef INET6 27588768458SSam Leffler struct ip6_ext *ip6e; 27688768458SSam Leffler struct ip6_hdr ip6; 277055679e6SAndrey V. Elsukov int ad, alloc, nxt, noff; 27888768458SSam Leffler #endif /* INET6 */ 27988768458SSam Leffler 28088768458SSam Leffler switch (proto) { 28188768458SSam Leffler #ifdef INET 28288768458SSam Leffler case AF_INET: 28388768458SSam Leffler /* 28488768458SSam Leffler * This is the least painful way of dealing with IPv4 header 28588768458SSam Leffler * and option processing -- just make sure they're in 28688768458SSam Leffler * contiguous memory. 28788768458SSam Leffler */ 28888768458SSam Leffler *m0 = m = m_pullup(m, skip); 28988768458SSam Leffler if (m == NULL) { 2909ffa9677SSam Leffler DPRINTF(("%s: m_pullup failed\n", __func__)); 29188768458SSam Leffler return ENOBUFS; 29288768458SSam Leffler } 29388768458SSam Leffler 29488768458SSam Leffler /* Fix the IP header */ 29588768458SSam Leffler ip = mtod(m, struct ip *); 296603724d3SBjoern A. Zeeb if (V_ah_cleartos) 29788768458SSam Leffler ip->ip_tos = 0; 29888768458SSam Leffler ip->ip_ttl = 0; 29988768458SSam Leffler ip->ip_sum = 0; 30020472bceSGleb Smirnoff ip->ip_off = htons(0); 30188768458SSam Leffler 302b12a7532SAndrey V. Elsukov ptr = mtod(m, unsigned char *); 30388768458SSam Leffler 30488768458SSam Leffler /* IPv4 option processing */ 30588768458SSam Leffler for (off = sizeof(struct ip); off < skip;) { 30688768458SSam Leffler if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP || 30788768458SSam Leffler off + 1 < skip) 30888768458SSam Leffler ; 30988768458SSam Leffler else { 3109ffa9677SSam Leffler DPRINTF(("%s: illegal IPv4 option length for " 3119ffa9677SSam Leffler "option %d\n", __func__, ptr[off])); 31288768458SSam Leffler 31388768458SSam Leffler m_freem(m); 31488768458SSam Leffler return EINVAL; 31588768458SSam Leffler } 31688768458SSam Leffler 31788768458SSam Leffler switch (ptr[off]) { 31888768458SSam Leffler case IPOPT_EOL: 31988768458SSam Leffler off = skip; /* End the loop. */ 32088768458SSam Leffler break; 32188768458SSam Leffler 32288768458SSam Leffler case IPOPT_NOP: 32388768458SSam Leffler off++; 32488768458SSam Leffler break; 32588768458SSam Leffler 32688768458SSam Leffler case IPOPT_SECURITY: /* 0x82 */ 32788768458SSam Leffler case 0x85: /* Extended security. */ 32888768458SSam Leffler case 0x86: /* Commercial security. */ 32988768458SSam Leffler case 0x94: /* Router alert */ 33088768458SSam Leffler case 0x95: /* RFC1770 */ 33188768458SSam Leffler /* Sanity check for option length. */ 33288768458SSam Leffler if (ptr[off + 1] < 2) { 3339ffa9677SSam Leffler DPRINTF(("%s: illegal IPv4 option " 3349ffa9677SSam Leffler "length for option %d\n", 3359ffa9677SSam Leffler __func__, ptr[off])); 33688768458SSam Leffler 33788768458SSam Leffler m_freem(m); 33888768458SSam Leffler return EINVAL; 33988768458SSam Leffler } 34088768458SSam Leffler 34188768458SSam Leffler off += ptr[off + 1]; 34288768458SSam Leffler break; 34388768458SSam Leffler 34488768458SSam Leffler case IPOPT_LSRR: 34588768458SSam Leffler case IPOPT_SSRR: 34688768458SSam Leffler /* Sanity check for option length. */ 34788768458SSam Leffler if (ptr[off + 1] < 2) { 3489ffa9677SSam Leffler DPRINTF(("%s: illegal IPv4 option " 3499ffa9677SSam Leffler "length for option %d\n", 3509ffa9677SSam Leffler __func__, ptr[off])); 35188768458SSam Leffler 35288768458SSam Leffler m_freem(m); 35388768458SSam Leffler return EINVAL; 35488768458SSam Leffler } 35588768458SSam Leffler 35688768458SSam Leffler /* 35788768458SSam Leffler * On output, if we have either of the 35888768458SSam Leffler * source routing options, we should 35988768458SSam Leffler * swap the destination address of the 36088768458SSam Leffler * IP header with the last address 36188768458SSam Leffler * specified in the option, as that is 36288768458SSam Leffler * what the destination's IP header 36388768458SSam Leffler * will look like. 36488768458SSam Leffler */ 36588768458SSam Leffler if (out) 36688768458SSam Leffler bcopy(ptr + off + ptr[off + 1] - 36788768458SSam Leffler sizeof(struct in_addr), 36888768458SSam Leffler &(ip->ip_dst), sizeof(struct in_addr)); 36988768458SSam Leffler 37088768458SSam Leffler /* Fall through */ 37188768458SSam Leffler default: 37288768458SSam Leffler /* Sanity check for option length. */ 37388768458SSam Leffler if (ptr[off + 1] < 2) { 3749ffa9677SSam Leffler DPRINTF(("%s: illegal IPv4 option " 3759ffa9677SSam Leffler "length for option %d\n", 3769ffa9677SSam Leffler __func__, ptr[off])); 37788768458SSam Leffler m_freem(m); 37888768458SSam Leffler return EINVAL; 37988768458SSam Leffler } 38088768458SSam Leffler 38188768458SSam Leffler /* Zeroize all other options. */ 38288768458SSam Leffler count = ptr[off + 1]; 383b12a7532SAndrey V. Elsukov bcopy(ipseczeroes, ptr + off, count); 38488768458SSam Leffler off += count; 38588768458SSam Leffler break; 38688768458SSam Leffler } 38788768458SSam Leffler 38888768458SSam Leffler /* Sanity check. */ 38988768458SSam Leffler if (off > skip) { 3909ffa9677SSam Leffler DPRINTF(("%s: malformed IPv4 options header\n", 3919ffa9677SSam Leffler __func__)); 39288768458SSam Leffler 39388768458SSam Leffler m_freem(m); 39488768458SSam Leffler return EINVAL; 39588768458SSam Leffler } 39688768458SSam Leffler } 39788768458SSam Leffler 39888768458SSam Leffler break; 39988768458SSam Leffler #endif /* INET */ 40088768458SSam Leffler 40188768458SSam Leffler #ifdef INET6 40288768458SSam Leffler case AF_INET6: /* Ugly... */ 40388768458SSam Leffler /* Copy and "cook" the IPv6 header. */ 40488768458SSam Leffler m_copydata(m, 0, sizeof(ip6), (caddr_t) &ip6); 40588768458SSam Leffler 40688768458SSam Leffler /* We don't do IPv6 Jumbograms. */ 40788768458SSam Leffler if (ip6.ip6_plen == 0) { 4089ffa9677SSam Leffler DPRINTF(("%s: unsupported IPv6 jumbogram\n", __func__)); 40988768458SSam Leffler m_freem(m); 41088768458SSam Leffler return EMSGSIZE; 41188768458SSam Leffler } 41288768458SSam Leffler 41388768458SSam Leffler ip6.ip6_flow = 0; 41488768458SSam Leffler ip6.ip6_hlim = 0; 41588768458SSam Leffler ip6.ip6_vfc &= ~IPV6_VERSION_MASK; 41688768458SSam Leffler ip6.ip6_vfc |= IPV6_VERSION; 41788768458SSam Leffler 41888768458SSam Leffler /* Scoped address handling. */ 41988768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_src)) 42088768458SSam Leffler ip6.ip6_src.s6_addr16[1] = 0; 42188768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_dst)) 42288768458SSam Leffler ip6.ip6_dst.s6_addr16[1] = 0; 42388768458SSam Leffler 42488768458SSam Leffler /* Done with IPv6 header. */ 42588768458SSam Leffler m_copyback(m, 0, sizeof(struct ip6_hdr), (caddr_t) &ip6); 42688768458SSam Leffler 42788768458SSam Leffler /* Let's deal with the remaining headers (if any). */ 42888768458SSam Leffler if (skip - sizeof(struct ip6_hdr) > 0) { 42988768458SSam Leffler if (m->m_len <= skip) { 43088768458SSam Leffler ptr = (unsigned char *) malloc( 43188768458SSam Leffler skip - sizeof(struct ip6_hdr), 43235d9e00dSJohn Baldwin M_AH, M_NOWAIT); 43388768458SSam Leffler if (ptr == NULL) { 4349ffa9677SSam Leffler DPRINTF(("%s: failed to allocate memory" 4359ffa9677SSam Leffler "for IPv6 headers\n",__func__)); 43688768458SSam Leffler m_freem(m); 43788768458SSam Leffler return ENOBUFS; 43888768458SSam Leffler } 43988768458SSam Leffler 44088768458SSam Leffler /* 44188768458SSam Leffler * Copy all the protocol headers after 44288768458SSam Leffler * the IPv6 header. 44388768458SSam Leffler */ 44488768458SSam Leffler m_copydata(m, sizeof(struct ip6_hdr), 44588768458SSam Leffler skip - sizeof(struct ip6_hdr), ptr); 44688768458SSam Leffler alloc = 1; 44788768458SSam Leffler } else { 44888768458SSam Leffler /* No need to allocate memory. */ 44988768458SSam Leffler ptr = mtod(m, unsigned char *) + 45088768458SSam Leffler sizeof(struct ip6_hdr); 45188768458SSam Leffler alloc = 0; 45288768458SSam Leffler } 45388768458SSam Leffler } else 45488768458SSam Leffler break; 45588768458SSam Leffler 456055679e6SAndrey V. Elsukov nxt = ip6.ip6_nxt & 0xff; /* Next header type. */ 45788768458SSam Leffler 458055679e6SAndrey V. Elsukov for (off = 0; off < skip - sizeof(struct ip6_hdr);) 459055679e6SAndrey V. Elsukov switch (nxt) { 46088768458SSam Leffler case IPPROTO_HOPOPTS: 46188768458SSam Leffler case IPPROTO_DSTOPTS: 462055679e6SAndrey V. Elsukov ip6e = (struct ip6_ext *)(ptr + off); 463055679e6SAndrey V. Elsukov noff = off + ((ip6e->ip6e_len + 1) << 3); 464055679e6SAndrey V. Elsukov 465055679e6SAndrey V. Elsukov /* Sanity check. */ 466055679e6SAndrey V. Elsukov if (noff > skip - sizeof(struct ip6_hdr)) 467055679e6SAndrey V. Elsukov goto error6; 46888768458SSam Leffler 46988768458SSam Leffler /* 470055679e6SAndrey V. Elsukov * Zero out mutable options. 47188768458SSam Leffler */ 472055679e6SAndrey V. Elsukov for (count = off + sizeof(struct ip6_ext); 473055679e6SAndrey V. Elsukov count < noff;) { 47488768458SSam Leffler if (ptr[count] == IP6OPT_PAD1) { 47588768458SSam Leffler count++; 47688768458SSam Leffler continue; /* Skip padding. */ 47788768458SSam Leffler } 47888768458SSam Leffler 479055679e6SAndrey V. Elsukov ad = ptr[count + 1] + 2; 480055679e6SAndrey V. Elsukov if (count + ad > noff) 481055679e6SAndrey V. Elsukov goto error6; 48288768458SSam Leffler 48388768458SSam Leffler if (ptr[count] & IP6OPT_MUTABLE) 484055679e6SAndrey V. Elsukov memset(ptr + count, 0, ad); 48588768458SSam Leffler count += ad; 48688768458SSam Leffler } 487055679e6SAndrey V. Elsukov 488055679e6SAndrey V. Elsukov if (count != noff) 489055679e6SAndrey V. Elsukov goto error6; 49088768458SSam Leffler 49188768458SSam Leffler /* Advance. */ 492055679e6SAndrey V. Elsukov off += ((ip6e->ip6e_len + 1) << 3); 493055679e6SAndrey V. Elsukov nxt = ip6e->ip6e_nxt; 49488768458SSam Leffler break; 49588768458SSam Leffler 49688768458SSam Leffler case IPPROTO_ROUTING: 49788768458SSam Leffler /* 49888768458SSam Leffler * Always include routing headers in 49988768458SSam Leffler * computation. 50088768458SSam Leffler */ 501055679e6SAndrey V. Elsukov ip6e = (struct ip6_ext *) (ptr + off); 502055679e6SAndrey V. Elsukov off += ((ip6e->ip6e_len + 1) << 3); 503055679e6SAndrey V. Elsukov nxt = ip6e->ip6e_nxt; 50488768458SSam Leffler break; 50588768458SSam Leffler 50688768458SSam Leffler default: 5079ffa9677SSam Leffler DPRINTF(("%s: unexpected IPv6 header type %d", 5089ffa9677SSam Leffler __func__, off)); 509055679e6SAndrey V. Elsukov error6: 51088768458SSam Leffler if (alloc) 51135d9e00dSJohn Baldwin free(ptr, M_AH); 51288768458SSam Leffler m_freem(m); 51388768458SSam Leffler return EINVAL; 51488768458SSam Leffler } 51588768458SSam Leffler 51688768458SSam Leffler /* Copyback and free, if we allocated. */ 51788768458SSam Leffler if (alloc) { 51888768458SSam Leffler m_copyback(m, sizeof(struct ip6_hdr), 51988768458SSam Leffler skip - sizeof(struct ip6_hdr), ptr); 52035d9e00dSJohn Baldwin free(ptr, M_AH); 52188768458SSam Leffler } 52288768458SSam Leffler 52388768458SSam Leffler break; 52488768458SSam Leffler #endif /* INET6 */ 52588768458SSam Leffler } 52688768458SSam Leffler 52788768458SSam Leffler return 0; 52888768458SSam Leffler } 52988768458SSam Leffler 53088768458SSam Leffler /* 53188768458SSam Leffler * ah_input() gets called to verify that an input packet 53288768458SSam Leffler * passes authentication. 53388768458SSam Leffler */ 53488768458SSam Leffler static int 53588768458SSam Leffler ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) 53688768458SSam Leffler { 5377f1f6591SAndrey V. Elsukov IPSEC_DEBUG_DECLARE(char buf[128]); 538fcf59617SAndrey V. Elsukov const struct auth_hash *ahx; 53988768458SSam Leffler struct cryptop *crp; 540fcf59617SAndrey V. Elsukov struct xform_data *xd; 541fcf59617SAndrey V. Elsukov struct newah *ah; 5422e08e39fSConrad Meyer crypto_session_t cryptoid; 543ede2f773SConrad Meyer int hl, rplen, authsize, ahsize, error; 5448b7f3994SMarcin Wojtas uint32_t seqh; 54588768458SSam Leffler 5460361f165SKristof Provost SECASVAR_RLOCK_TRACKER; 5470361f165SKristof Provost 5489ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("null SA")); 5499ffa9677SSam Leffler IPSEC_ASSERT(sav->key_auth != NULL, ("null authentication key")); 5509ffa9677SSam Leffler IPSEC_ASSERT(sav->tdb_authalgxform != NULL, 5519ffa9677SSam Leffler ("null authentication xform")); 55288768458SSam Leffler 55388768458SSam Leffler /* Figure out header size. */ 55488768458SSam Leffler rplen = HDRSIZE(sav); 55588768458SSam Leffler 556a4adf6ccSBjoern A. Zeeb if (m->m_len < skip + rplen) { 55763abacc2SBjoern A. Zeeb m = m_pullup(m, skip + rplen); 55863abacc2SBjoern A. Zeeb if (m == NULL) { 55988768458SSam Leffler DPRINTF(("ah_input: cannot pullup header\n")); 560a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_hdrops); /*XXX*/ 5615f7c516fSAndrey V. Elsukov error = ENOBUFS; 5625f7c516fSAndrey V. Elsukov goto bad; 56388768458SSam Leffler } 564a4adf6ccSBjoern A. Zeeb } 56563abacc2SBjoern A. Zeeb ah = (struct newah *)(mtod(m, caddr_t) + skip); 56688768458SSam Leffler 56788768458SSam Leffler /* Check replay window, if applicable. */ 5680361f165SKristof Provost SECASVAR_RLOCK(sav); 569fcf59617SAndrey V. Elsukov if (sav->replay != NULL && sav->replay->wsize != 0 && 5708b7f3994SMarcin Wojtas ipsec_chkreplay(ntohl(ah->ah_seq), &seqh, sav) == 0) { 5710361f165SKristof Provost SECASVAR_RUNLOCK(sav); 572a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_replay); 5739ffa9677SSam Leffler DPRINTF(("%s: packet replay failure: %s\n", __func__, 574fcf59617SAndrey V. Elsukov ipsec_sa2str(sav, buf, sizeof(buf)))); 5755f7c516fSAndrey V. Elsukov error = EACCES; 5765f7c516fSAndrey V. Elsukov goto bad; 57788768458SSam Leffler } 578fcf59617SAndrey V. Elsukov cryptoid = sav->tdb_cryptoid; 5790361f165SKristof Provost SECASVAR_RUNLOCK(sav); 58088768458SSam Leffler 58188768458SSam Leffler /* Verify AH header length. */ 582ede2f773SConrad Meyer hl = sizeof(struct ah) + (ah->ah_len * sizeof (u_int32_t)); 58388768458SSam Leffler ahx = sav->tdb_authalgxform; 58488768458SSam Leffler authsize = AUTHSIZE(sav); 585ede2f773SConrad Meyer ahsize = ah_hdrsiz(sav); 586ede2f773SConrad Meyer if (hl != ahsize) { 5879ffa9677SSam Leffler DPRINTF(("%s: bad authenticator length %u (expecting %lu)" 588962ac6c7SAndrey V. Elsukov " for packet in SA %s/%08lx\n", __func__, hl, 589ede2f773SConrad Meyer (u_long)ahsize, 590962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), 59188768458SSam Leffler (u_long) ntohl(sav->spi))); 592a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_badauthl); 5935f7c516fSAndrey V. Elsukov error = EACCES; 5945f7c516fSAndrey V. Elsukov goto bad; 59588768458SSam Leffler } 596ede2f773SConrad Meyer if (skip + ahsize > m->m_pkthdr.len) { 5976ca39da3SAndrey V. Elsukov DPRINTF(("%s: bad mbuf length %u (expecting %lu)" 5986ca39da3SAndrey V. Elsukov " for packet in SA %s/%08lx\n", __func__, 599ede2f773SConrad Meyer m->m_pkthdr.len, (u_long)(skip + ahsize), 6006ca39da3SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), 6016ca39da3SAndrey V. Elsukov (u_long) ntohl(sav->spi))); 6026ca39da3SAndrey V. Elsukov AHSTAT_INC(ahs_badauthl); 6036ca39da3SAndrey V. Elsukov error = EACCES; 6046ca39da3SAndrey V. Elsukov goto bad; 6056ca39da3SAndrey V. Elsukov } 606a04d64d8SAndrey V. Elsukov AHSTAT_ADD(ahs_ibytes, m->m_pkthdr.len - skip - hl); 60788768458SSam Leffler 60888768458SSam Leffler /* Get crypto descriptors. */ 609c0341432SJohn Baldwin crp = crypto_getreq(cryptoid, M_NOWAIT); 61088768458SSam Leffler if (crp == NULL) { 611fcf59617SAndrey V. Elsukov DPRINTF(("%s: failed to acquire crypto descriptor\n", 612fcf59617SAndrey V. Elsukov __func__)); 613a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_crypto); 6145f7c516fSAndrey V. Elsukov error = ENOBUFS; 6155f7c516fSAndrey V. Elsukov goto bad; 61688768458SSam Leffler } 61788768458SSam Leffler 618c0341432SJohn Baldwin crp->crp_payload_start = 0; 619c0341432SJohn Baldwin crp->crp_payload_length = m->m_pkthdr.len; 620c0341432SJohn Baldwin crp->crp_digest_start = skip + rplen; 62188768458SSam Leffler 62288768458SSam Leffler /* Allocate IPsec-specific opaque crypto info. */ 62335d9e00dSJohn Baldwin xd = malloc(sizeof(*xd) + skip + rplen + authsize, M_AH, 624fcf59617SAndrey V. Elsukov M_NOWAIT | M_ZERO); 625fcf59617SAndrey V. Elsukov if (xd == NULL) { 626fcf59617SAndrey V. Elsukov DPRINTF(("%s: failed to allocate xform_data\n", __func__)); 627a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_crypto); 62888768458SSam Leffler crypto_freereq(crp); 6295f7c516fSAndrey V. Elsukov error = ENOBUFS; 6305f7c516fSAndrey V. Elsukov goto bad; 63188768458SSam Leffler } 63288768458SSam Leffler 63388768458SSam Leffler /* 63488768458SSam Leffler * Save the authenticator, the skipped portion of the packet, 63588768458SSam Leffler * and the AH header. 63688768458SSam Leffler */ 637fcf59617SAndrey V. Elsukov m_copydata(m, 0, skip + rplen + authsize, (caddr_t)(xd + 1)); 63888768458SSam Leffler 63988768458SSam Leffler /* Zeroize the authenticator on the packet. */ 64088768458SSam Leffler m_copyback(m, skip + rplen, authsize, ipseczeroes); 64188768458SSam Leffler 6426ca39da3SAndrey V. Elsukov /* Save ah_nxt, since ah pointer can become invalid after "massage" */ 6436ca39da3SAndrey V. Elsukov hl = ah->ah_nxt; 6446ca39da3SAndrey V. Elsukov 64588768458SSam Leffler /* "Massage" the packet headers for crypto processing. */ 64688768458SSam Leffler error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, 64788768458SSam Leffler skip, ahx->type, 0); 64888768458SSam Leffler if (error != 0) { 64988768458SSam Leffler /* NB: mbuf is free'd by ah_massage_headers */ 650a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_hdrops); 65135d9e00dSJohn Baldwin free(xd, M_AH); 65288768458SSam Leffler crypto_freereq(crp); 6535f7c516fSAndrey V. Elsukov key_freesav(&sav); 65408537f45SAndrey V. Elsukov return (error); 65588768458SSam Leffler } 65688768458SSam Leffler 65788768458SSam Leffler /* Crypto operation descriptor. */ 658c0341432SJohn Baldwin crp->crp_op = CRYPTO_OP_COMPUTE_DIGEST; 659c0341432SJohn Baldwin crp->crp_flags = CRYPTO_F_CBIFSYNC; 6609c0e3d3aSJohn Baldwin crypto_use_mbuf(crp, m); 66188768458SSam Leffler crp->crp_callback = ah_input_cb; 662c0341432SJohn Baldwin crp->crp_opaque = xd; 66388768458SSam Leffler 6644d36d1fdSMarcin Wojtas if (sav->flags & SADB_X_SAFLAGS_ESN && 6654d36d1fdSMarcin Wojtas sav->replay != NULL && sav->replay->wsize != 0) { 6664d36d1fdSMarcin Wojtas seqh = htonl(seqh); 6674d36d1fdSMarcin Wojtas memcpy(crp->crp_esn, &seqh, sizeof(seqh)); 6684d36d1fdSMarcin Wojtas } 6694d36d1fdSMarcin Wojtas 67088768458SSam Leffler /* These are passed as-is to the callback. */ 671fcf59617SAndrey V. Elsukov xd->sav = sav; 6726ca39da3SAndrey V. Elsukov xd->nxt = hl; 673fcf59617SAndrey V. Elsukov xd->protoff = protoff; 674fcf59617SAndrey V. Elsukov xd->skip = skip; 675fcf59617SAndrey V. Elsukov xd->cryptoid = cryptoid; 676fd40ecf3SJohn Baldwin xd->vnet = curvnet; 67768f6800cSMark Johnston if (V_async_crypto) 67868f6800cSMark Johnston return (crypto_dispatch_async(crp, CRYPTO_ASYNC_ORDERED)); 67968f6800cSMark Johnston else 68008537f45SAndrey V. Elsukov return (crypto_dispatch(crp)); 6815f7c516fSAndrey V. Elsukov bad: 6825f7c516fSAndrey V. Elsukov m_freem(m); 6835f7c516fSAndrey V. Elsukov key_freesav(&sav); 6845f7c516fSAndrey V. Elsukov return (error); 68588768458SSam Leffler } 68688768458SSam Leffler 68788768458SSam Leffler /* 68888768458SSam Leffler * AH input callback from the crypto driver. 68988768458SSam Leffler */ 69088768458SSam Leffler static int 69188768458SSam Leffler ah_input_cb(struct cryptop *crp) 69288768458SSam Leffler { 6937f1f6591SAndrey V. Elsukov IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); 69488768458SSam Leffler unsigned char calc[AH_ALEN_MAX]; 69588768458SSam Leffler struct mbuf *m; 696fcf59617SAndrey V. Elsukov struct xform_data *xd; 69788768458SSam Leffler struct secasvar *sav; 69888768458SSam Leffler struct secasindex *saidx; 69988768458SSam Leffler caddr_t ptr; 7002e08e39fSConrad Meyer crypto_session_t cryptoid; 701ede2f773SConrad Meyer int authsize, rplen, ahsize, error, skip, protoff; 702fcf59617SAndrey V. Elsukov uint8_t nxt; 70388768458SSam Leffler 7040361f165SKristof Provost SECASVAR_RLOCK_TRACKER; 7050361f165SKristof Provost 7069c0e3d3aSJohn Baldwin m = crp->crp_buf.cb_mbuf; 707c0341432SJohn Baldwin xd = crp->crp_opaque; 708fd40ecf3SJohn Baldwin CURVNET_SET(xd->vnet); 709fcf59617SAndrey V. Elsukov sav = xd->sav; 710fcf59617SAndrey V. Elsukov skip = xd->skip; 711fcf59617SAndrey V. Elsukov nxt = xd->nxt; 712fcf59617SAndrey V. Elsukov protoff = xd->protoff; 713fcf59617SAndrey V. Elsukov cryptoid = xd->cryptoid; 71488768458SSam Leffler saidx = &sav->sah->saidx; 7159ffa9677SSam Leffler IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET || 71688768458SSam Leffler saidx->dst.sa.sa_family == AF_INET6, 7179ffa9677SSam Leffler ("unexpected protocol family %u", saidx->dst.sa.sa_family)); 71888768458SSam Leffler 71988768458SSam Leffler /* Check for crypto errors. */ 72088768458SSam Leffler if (crp->crp_etype) { 721fcf59617SAndrey V. Elsukov if (crp->crp_etype == EAGAIN) { 722fcf59617SAndrey V. Elsukov /* Reset the session ID */ 7231b0909d5SConrad Meyer if (ipsec_updateid(sav, &crp->crp_session, &cryptoid) != 0) 724fcf59617SAndrey V. Elsukov crypto_freesession(cryptoid); 7251b0909d5SConrad Meyer xd->cryptoid = crp->crp_session; 726fd40ecf3SJohn Baldwin CURVNET_RESTORE(); 7270a95a08eSPawel Jakub Dawidek return (crypto_dispatch(crp)); 728fcf59617SAndrey V. Elsukov } 729a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_noxform); 7309ffa9677SSam Leffler DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype)); 73188768458SSam Leffler error = crp->crp_etype; 73288768458SSam Leffler goto bad; 73388768458SSam Leffler } else { 734*b1c3a4d7SKristof Provost AHSTAT_INC2(ahs_hist, sav->alg_auth); 73588768458SSam Leffler crypto_freereq(crp); /* No longer needed. */ 73688768458SSam Leffler crp = NULL; 73788768458SSam Leffler } 73888768458SSam Leffler 73988768458SSam Leffler /* Shouldn't happen... */ 74088768458SSam Leffler if (m == NULL) { 741a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_crypto); 7429ffa9677SSam Leffler DPRINTF(("%s: bogus returned buffer from crypto\n", __func__)); 74388768458SSam Leffler error = EINVAL; 74488768458SSam Leffler goto bad; 74588768458SSam Leffler } 74688768458SSam Leffler 74788768458SSam Leffler /* Figure out header size. */ 74888768458SSam Leffler rplen = HDRSIZE(sav); 74988768458SSam Leffler authsize = AUTHSIZE(sav); 750ede2f773SConrad Meyer ahsize = ah_hdrsiz(sav); 75188768458SSam Leffler 75288768458SSam Leffler /* Copy authenticator off the packet. */ 75388768458SSam Leffler m_copydata(m, skip + rplen, authsize, calc); 75488768458SSam Leffler 75588768458SSam Leffler /* Verify authenticator. */ 756fcf59617SAndrey V. Elsukov ptr = (caddr_t) (xd + 1); 75742e5fcbfSJohn-Mark Gurney if (timingsafe_bcmp(ptr + skip + rplen, calc, authsize)) { 7589ffa9677SSam Leffler DPRINTF(("%s: authentication hash mismatch for packet " 7599ffa9677SSam Leffler "in SA %s/%08lx\n", __func__, 760962ac6c7SAndrey V. Elsukov ipsec_address(&saidx->dst, buf, sizeof(buf)), 76188768458SSam Leffler (u_long) ntohl(sav->spi))); 762a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_badauth); 76388768458SSam Leffler error = EACCES; 76488768458SSam Leffler goto bad; 76588768458SSam Leffler } 76688768458SSam Leffler /* Fix the Next Protocol field. */ 767fcf59617SAndrey V. Elsukov ((uint8_t *) ptr)[protoff] = nxt; 76888768458SSam Leffler 76988768458SSam Leffler /* Copyback the saved (uncooked) network headers. */ 77088768458SSam Leffler m_copyback(m, 0, skip, ptr); 77135d9e00dSJohn Baldwin free(xd, M_AH), xd = NULL; /* No longer needed */ 77288768458SSam Leffler 77388768458SSam Leffler /* 77488768458SSam Leffler * Header is now authenticated. 77588768458SSam Leffler */ 77688768458SSam Leffler m->m_flags |= M_AUTHIPHDR|M_AUTHIPDGM; 77788768458SSam Leffler 77888768458SSam Leffler /* 77988768458SSam Leffler * Update replay sequence number, if appropriate. 78088768458SSam Leffler */ 78188768458SSam Leffler if (sav->replay) { 78288768458SSam Leffler u_int32_t seq; 78388768458SSam Leffler 78488768458SSam Leffler m_copydata(m, skip + offsetof(struct newah, ah_seq), 78588768458SSam Leffler sizeof (seq), (caddr_t) &seq); 7860361f165SKristof Provost SECASVAR_RLOCK(sav); 78788768458SSam Leffler if (ipsec_updatereplay(ntohl(seq), sav)) { 7880361f165SKristof Provost SECASVAR_RUNLOCK(sav); 789a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_replay); 790fcf59617SAndrey V. Elsukov error = EACCES; 79188768458SSam Leffler goto bad; 79288768458SSam Leffler } 7930361f165SKristof Provost SECASVAR_RUNLOCK(sav); 79488768458SSam Leffler } 79588768458SSam Leffler 79688768458SSam Leffler /* 79788768458SSam Leffler * Remove the AH header and authenticator from the mbuf. 79888768458SSam Leffler */ 799ede2f773SConrad Meyer error = m_striphdr(m, skip, ahsize); 80088768458SSam Leffler if (error) { 8019ffa9677SSam Leffler DPRINTF(("%s: mangled mbuf chain for SA %s/%08lx\n", __func__, 802962ac6c7SAndrey V. Elsukov ipsec_address(&saidx->dst, buf, sizeof(buf)), 803962ac6c7SAndrey V. Elsukov (u_long) ntohl(sav->spi))); 804a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_hdrops); 80588768458SSam Leffler goto bad; 80688768458SSam Leffler } 80788768458SSam Leffler 808db178eb8SBjoern A. Zeeb switch (saidx->dst.sa.sa_family) { 809db178eb8SBjoern A. Zeeb #ifdef INET6 810db178eb8SBjoern A. Zeeb case AF_INET6: 811f0514a8bSAndrey V. Elsukov error = ipsec6_common_input_cb(m, sav, skip, protoff); 812db178eb8SBjoern A. Zeeb break; 813db178eb8SBjoern A. Zeeb #endif 814db178eb8SBjoern A. Zeeb #ifdef INET 815db178eb8SBjoern A. Zeeb case AF_INET: 816f0514a8bSAndrey V. Elsukov error = ipsec4_common_input_cb(m, sav, skip, protoff); 817db178eb8SBjoern A. Zeeb break; 818db178eb8SBjoern A. Zeeb #endif 819db178eb8SBjoern A. Zeeb default: 820db178eb8SBjoern A. Zeeb panic("%s: Unexpected address family: %d saidx=%p", __func__, 821db178eb8SBjoern A. Zeeb saidx->dst.sa.sa_family, saidx); 822db178eb8SBjoern A. Zeeb } 823fd40ecf3SJohn Baldwin CURVNET_RESTORE(); 82488768458SSam Leffler return error; 82588768458SSam Leffler bad: 826fd40ecf3SJohn Baldwin CURVNET_RESTORE(); 82788768458SSam Leffler if (sav) 828fcf59617SAndrey V. Elsukov key_freesav(&sav); 82988768458SSam Leffler if (m != NULL) 83088768458SSam Leffler m_freem(m); 831fcf59617SAndrey V. Elsukov if (xd != NULL) 83235d9e00dSJohn Baldwin free(xd, M_AH); 83388768458SSam Leffler if (crp != NULL) 83488768458SSam Leffler crypto_freereq(crp); 83588768458SSam Leffler return error; 83688768458SSam Leffler } 83788768458SSam Leffler 83888768458SSam Leffler /* 839fcf59617SAndrey V. Elsukov * AH output routine, called by ipsec[46]_perform_request(). 84088768458SSam Leffler */ 84188768458SSam Leffler static int 842fcf59617SAndrey V. Elsukov ah_output(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav, 843fcf59617SAndrey V. Elsukov u_int idx, int skip, int protoff) 84488768458SSam Leffler { 8457f1f6591SAndrey V. Elsukov IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); 846fcf59617SAndrey V. Elsukov const struct auth_hash *ahx; 847fcf59617SAndrey V. Elsukov struct xform_data *xd; 84888768458SSam Leffler struct mbuf *mi; 84988768458SSam Leffler struct cryptop *crp; 85088768458SSam Leffler struct newah *ah; 8512e08e39fSConrad Meyer crypto_session_t cryptoid; 852fcf59617SAndrey V. Elsukov uint16_t iplen; 853ede2f773SConrad Meyer int error, rplen, authsize, ahsize, maxpacketsize, roff; 854fcf59617SAndrey V. Elsukov uint8_t prot; 8554d36d1fdSMarcin Wojtas uint32_t seqh; 85688768458SSam Leffler 8570361f165SKristof Provost SECASVAR_RLOCK_TRACKER; 8580361f165SKristof Provost 8599ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("null SA")); 86088768458SSam Leffler ahx = sav->tdb_authalgxform; 8619ffa9677SSam Leffler IPSEC_ASSERT(ahx != NULL, ("null authentication xform")); 86288768458SSam Leffler 863a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_output); 86488768458SSam Leffler 86588768458SSam Leffler /* Figure out header size. */ 86688768458SSam Leffler rplen = HDRSIZE(sav); 867ede2f773SConrad Meyer authsize = AUTHSIZE(sav); 868ede2f773SConrad Meyer ahsize = ah_hdrsiz(sav); 86988768458SSam Leffler 87088768458SSam Leffler /* Check for maximum packet size violations. */ 87188768458SSam Leffler switch (sav->sah->saidx.dst.sa.sa_family) { 87288768458SSam Leffler #ifdef INET 87388768458SSam Leffler case AF_INET: 87488768458SSam Leffler maxpacketsize = IP_MAXPACKET; 87588768458SSam Leffler break; 87688768458SSam Leffler #endif /* INET */ 87788768458SSam Leffler #ifdef INET6 87888768458SSam Leffler case AF_INET6: 87988768458SSam Leffler maxpacketsize = IPV6_MAXPACKET; 88088768458SSam Leffler break; 88188768458SSam Leffler #endif /* INET6 */ 88288768458SSam Leffler default: 8839ffa9677SSam Leffler DPRINTF(("%s: unknown/unsupported protocol family %u, " 8849ffa9677SSam Leffler "SA %s/%08lx\n", __func__, 88588768458SSam Leffler sav->sah->saidx.dst.sa.sa_family, 886962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), 88788768458SSam Leffler (u_long) ntohl(sav->spi))); 888a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_nopf); 88988768458SSam Leffler error = EPFNOSUPPORT; 89088768458SSam Leffler goto bad; 89188768458SSam Leffler } 892ede2f773SConrad Meyer if (ahsize + m->m_pkthdr.len > maxpacketsize) { 8939ffa9677SSam Leffler DPRINTF(("%s: packet in SA %s/%08lx got too big " 8949ffa9677SSam Leffler "(len %u, max len %u)\n", __func__, 895962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), 89688768458SSam Leffler (u_long) ntohl(sav->spi), 897ede2f773SConrad Meyer ahsize + m->m_pkthdr.len, maxpacketsize)); 898a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_toobig); 89988768458SSam Leffler error = EMSGSIZE; 90088768458SSam Leffler goto bad; 90188768458SSam Leffler } 90288768458SSam Leffler 90388768458SSam Leffler /* Update the counters. */ 904a04d64d8SAndrey V. Elsukov AHSTAT_ADD(ahs_obytes, m->m_pkthdr.len - skip); 90588768458SSam Leffler 90647e2996eSSam Leffler m = m_unshare(m, M_NOWAIT); 90788768458SSam Leffler if (m == NULL) { 9089ffa9677SSam Leffler DPRINTF(("%s: cannot clone mbuf chain, SA %s/%08lx\n", __func__, 909962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), 91088768458SSam Leffler (u_long) ntohl(sav->spi))); 911a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_hdrops); 91288768458SSam Leffler error = ENOBUFS; 91388768458SSam Leffler goto bad; 91488768458SSam Leffler } 91588768458SSam Leffler 91688768458SSam Leffler /* Inject AH header. */ 917ede2f773SConrad Meyer mi = m_makespace(m, skip, ahsize, &roff); 91888768458SSam Leffler if (mi == NULL) { 9199ffa9677SSam Leffler DPRINTF(("%s: failed to inject %u byte AH header for SA " 920ede2f773SConrad Meyer "%s/%08lx\n", __func__, ahsize, 921962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)), 92288768458SSam Leffler (u_long) ntohl(sav->spi))); 923a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_hdrops); /*XXX differs from openbsd */ 92488768458SSam Leffler error = ENOBUFS; 92588768458SSam Leffler goto bad; 92688768458SSam Leffler } 92788768458SSam Leffler 92888768458SSam Leffler /* 92988768458SSam Leffler * The AH header is guaranteed by m_makespace() to be in 93088768458SSam Leffler * contiguous memory, at roff bytes offset into the returned mbuf. 93188768458SSam Leffler */ 93288768458SSam Leffler ah = (struct newah *)(mtod(mi, caddr_t) + roff); 93388768458SSam Leffler 93488768458SSam Leffler /* Initialize the AH header. */ 93588768458SSam Leffler m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &ah->ah_nxt); 936ede2f773SConrad Meyer ah->ah_len = (ahsize - sizeof(struct ah)) / sizeof(u_int32_t); 93788768458SSam Leffler ah->ah_reserve = 0; 93888768458SSam Leffler ah->ah_spi = sav->spi; 93988768458SSam Leffler 94088768458SSam Leffler /* Zeroize authenticator. */ 94188768458SSam Leffler m_copyback(m, skip + rplen, authsize, ipseczeroes); 94288768458SSam Leffler 943ede2f773SConrad Meyer /* Zeroize padding */ 944ede2f773SConrad Meyer m_copyback(m, skip + rplen + authsize, ahsize - (rplen + authsize), 945ede2f773SConrad Meyer ipseczeroes); 946ede2f773SConrad Meyer 94788768458SSam Leffler /* Insert packet replay counter, as requested. */ 9480361f165SKristof Provost SECASVAR_RLOCK(sav); 949fcf59617SAndrey V. Elsukov if (sav->replay) { 9500361f165SKristof Provost SECREPLAY_LOCK(sav->replay); 9518b7f3994SMarcin Wojtas if ((sav->replay->count == ~0 || 9528b7f3994SMarcin Wojtas (!(sav->flags & SADB_X_SAFLAGS_ESN) && 9538b7f3994SMarcin Wojtas ((uint32_t)sav->replay->count) == ~0)) && 95488768458SSam Leffler (sav->flags & SADB_X_EXT_CYCSEQ) == 0) { 9550361f165SKristof Provost SECREPLAY_UNLOCK(sav->replay); 9560361f165SKristof Provost SECASVAR_RUNLOCK(sav); 9579ffa9677SSam Leffler DPRINTF(("%s: replay counter wrapped for SA %s/%08lx\n", 958962ac6c7SAndrey V. Elsukov __func__, ipsec_address(&sav->sah->saidx.dst, buf, 959962ac6c7SAndrey V. Elsukov sizeof(buf)), (u_long) ntohl(sav->spi))); 960a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_wrap); 961fcf59617SAndrey V. Elsukov error = EACCES; 96288768458SSam Leffler goto bad; 96388768458SSam Leffler } 9646131838bSPawel Jakub Dawidek #ifdef REGRESSION 965dfa9422bSPawel Jakub Dawidek /* Emulate replay attack when ipsec_replay is TRUE. */ 966603724d3SBjoern A. Zeeb if (!V_ipsec_replay) 9676131838bSPawel Jakub Dawidek #endif 96888768458SSam Leffler sav->replay->count++; 9698b7f3994SMarcin Wojtas ah->ah_seq = htonl((uint32_t)sav->replay->count); 9700361f165SKristof Provost SECREPLAY_UNLOCK(sav->replay); 97188768458SSam Leffler } 972fcf59617SAndrey V. Elsukov cryptoid = sav->tdb_cryptoid; 9730361f165SKristof Provost SECASVAR_RUNLOCK(sav); 97488768458SSam Leffler 97588768458SSam Leffler /* Get crypto descriptors. */ 976c0341432SJohn Baldwin crp = crypto_getreq(cryptoid, M_NOWAIT); 97788768458SSam Leffler if (crp == NULL) { 9789ffa9677SSam Leffler DPRINTF(("%s: failed to acquire crypto descriptors\n", 9799ffa9677SSam Leffler __func__)); 980a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_crypto); 98188768458SSam Leffler error = ENOBUFS; 98288768458SSam Leffler goto bad; 98388768458SSam Leffler } 98488768458SSam Leffler 985c0341432SJohn Baldwin crp->crp_payload_start = 0; 986c0341432SJohn Baldwin crp->crp_payload_length = m->m_pkthdr.len; 987c0341432SJohn Baldwin crp->crp_digest_start = skip + rplen; 98888768458SSam Leffler 98988768458SSam Leffler /* Allocate IPsec-specific opaque crypto info. */ 99035d9e00dSJohn Baldwin xd = malloc(sizeof(struct xform_data) + skip, M_AH, 991fcf59617SAndrey V. Elsukov M_NOWAIT | M_ZERO); 992fcf59617SAndrey V. Elsukov if (xd == NULL) { 99388768458SSam Leffler crypto_freereq(crp); 994fcf59617SAndrey V. Elsukov DPRINTF(("%s: failed to allocate xform_data\n", __func__)); 995a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_crypto); 99688768458SSam Leffler error = ENOBUFS; 99788768458SSam Leffler goto bad; 99888768458SSam Leffler } 99988768458SSam Leffler 100088768458SSam Leffler /* Save the skipped portion of the packet. */ 1001fcf59617SAndrey V. Elsukov m_copydata(m, 0, skip, (caddr_t) (xd + 1)); 100288768458SSam Leffler 100388768458SSam Leffler /* 100488768458SSam Leffler * Fix IP header length on the header used for 100588768458SSam Leffler * authentication. We don't need to fix the original 100688768458SSam Leffler * header length as it will be fixed by our caller. 100788768458SSam Leffler */ 100888768458SSam Leffler switch (sav->sah->saidx.dst.sa.sa_family) { 100988768458SSam Leffler #ifdef INET 101088768458SSam Leffler case AF_INET: 1011fcf59617SAndrey V. Elsukov bcopy(((caddr_t)(xd + 1)) + 101288768458SSam Leffler offsetof(struct ip, ip_len), 101388768458SSam Leffler (caddr_t) &iplen, sizeof(u_int16_t)); 1014ede2f773SConrad Meyer iplen = htons(ntohs(iplen) + ahsize); 101588768458SSam Leffler m_copyback(m, offsetof(struct ip, ip_len), 101688768458SSam Leffler sizeof(u_int16_t), (caddr_t) &iplen); 101788768458SSam Leffler break; 101888768458SSam Leffler #endif /* INET */ 101988768458SSam Leffler 102088768458SSam Leffler #ifdef INET6 102188768458SSam Leffler case AF_INET6: 1022fcf59617SAndrey V. Elsukov bcopy(((caddr_t)(xd + 1)) + 102388768458SSam Leffler offsetof(struct ip6_hdr, ip6_plen), 1024fcf59617SAndrey V. Elsukov (caddr_t) &iplen, sizeof(uint16_t)); 1025ede2f773SConrad Meyer iplen = htons(ntohs(iplen) + ahsize); 102688768458SSam Leffler m_copyback(m, offsetof(struct ip6_hdr, ip6_plen), 1027fcf59617SAndrey V. Elsukov sizeof(uint16_t), (caddr_t) &iplen); 102888768458SSam Leffler break; 102988768458SSam Leffler #endif /* INET6 */ 103088768458SSam Leffler } 103188768458SSam Leffler 103288768458SSam Leffler /* Fix the Next Header field in saved header. */ 1033fcf59617SAndrey V. Elsukov ((uint8_t *) (xd + 1))[protoff] = IPPROTO_AH; 103488768458SSam Leffler 103588768458SSam Leffler /* Update the Next Protocol field in the IP header. */ 103688768458SSam Leffler prot = IPPROTO_AH; 1037fcf59617SAndrey V. Elsukov m_copyback(m, protoff, sizeof(uint8_t), (caddr_t) &prot); 103888768458SSam Leffler 103988768458SSam Leffler /* "Massage" the packet headers for crypto processing. */ 104088768458SSam Leffler error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family, 104188768458SSam Leffler skip, ahx->type, 1); 104288768458SSam Leffler if (error != 0) { 104388768458SSam Leffler m = NULL; /* mbuf was free'd by ah_massage_headers. */ 104435d9e00dSJohn Baldwin free(xd, M_AH); 104588768458SSam Leffler crypto_freereq(crp); 104688768458SSam Leffler goto bad; 104788768458SSam Leffler } 104888768458SSam Leffler 104988768458SSam Leffler /* Crypto operation descriptor. */ 1050c0341432SJohn Baldwin crp->crp_op = CRYPTO_OP_COMPUTE_DIGEST; 1051c0341432SJohn Baldwin crp->crp_flags = CRYPTO_F_CBIFSYNC; 10529c0e3d3aSJohn Baldwin crypto_use_mbuf(crp, m); 105388768458SSam Leffler crp->crp_callback = ah_output_cb; 1054c0341432SJohn Baldwin crp->crp_opaque = xd; 105588768458SSam Leffler 10564d36d1fdSMarcin Wojtas if (sav->flags & SADB_X_SAFLAGS_ESN && sav->replay != NULL) { 10570361f165SKristof Provost SECREPLAY_LOCK(sav->replay); 10584d36d1fdSMarcin Wojtas seqh = htonl((uint32_t)(sav->replay->count >> IPSEC_SEQH_SHIFT)); 10594d36d1fdSMarcin Wojtas memcpy(crp->crp_esn, &seqh, sizeof(seqh)); 10600361f165SKristof Provost SECREPLAY_UNLOCK(sav->replay); 10614d36d1fdSMarcin Wojtas } 10624d36d1fdSMarcin Wojtas 106388768458SSam Leffler /* These are passed as-is to the callback. */ 1064fcf59617SAndrey V. Elsukov xd->sp = sp; 1065fcf59617SAndrey V. Elsukov xd->sav = sav; 1066fcf59617SAndrey V. Elsukov xd->skip = skip; 1067fcf59617SAndrey V. Elsukov xd->idx = idx; 1068fcf59617SAndrey V. Elsukov xd->cryptoid = cryptoid; 1069fd40ecf3SJohn Baldwin xd->vnet = curvnet; 107088768458SSam Leffler 107168f6800cSMark Johnston if (V_async_crypto) 107268f6800cSMark Johnston return (crypto_dispatch_async(crp, CRYPTO_ASYNC_ORDERED)); 107368f6800cSMark Johnston else 107468f6800cSMark Johnston return (crypto_dispatch(crp)); 107588768458SSam Leffler bad: 107688768458SSam Leffler if (m) 107788768458SSam Leffler m_freem(m); 10783aee7099SAndrey V. Elsukov key_freesav(&sav); 10793aee7099SAndrey V. Elsukov key_freesp(&sp); 108088768458SSam Leffler return (error); 108188768458SSam Leffler } 108288768458SSam Leffler 108388768458SSam Leffler /* 108488768458SSam Leffler * AH output callback from the crypto driver. 108588768458SSam Leffler */ 108688768458SSam Leffler static int 108788768458SSam Leffler ah_output_cb(struct cryptop *crp) 108888768458SSam Leffler { 1089fcf59617SAndrey V. Elsukov struct xform_data *xd; 1090fcf59617SAndrey V. Elsukov struct secpolicy *sp; 109188768458SSam Leffler struct secasvar *sav; 109288768458SSam Leffler struct mbuf *m; 10932e08e39fSConrad Meyer crypto_session_t cryptoid; 109488768458SSam Leffler caddr_t ptr; 1095fcf59617SAndrey V. Elsukov u_int idx; 1096fcf59617SAndrey V. Elsukov int skip, error; 109788768458SSam Leffler 10989c0e3d3aSJohn Baldwin m = crp->crp_buf.cb_mbuf; 1099fcf59617SAndrey V. Elsukov xd = (struct xform_data *) crp->crp_opaque; 1100fd40ecf3SJohn Baldwin CURVNET_SET(xd->vnet); 1101fcf59617SAndrey V. Elsukov sp = xd->sp; 1102fcf59617SAndrey V. Elsukov sav = xd->sav; 1103fcf59617SAndrey V. Elsukov skip = xd->skip; 1104fcf59617SAndrey V. Elsukov idx = xd->idx; 1105fcf59617SAndrey V. Elsukov cryptoid = xd->cryptoid; 1106fcf59617SAndrey V. Elsukov ptr = (caddr_t) (xd + 1); 110788768458SSam Leffler 110888768458SSam Leffler /* Check for crypto errors. */ 110988768458SSam Leffler if (crp->crp_etype) { 111088768458SSam Leffler if (crp->crp_etype == EAGAIN) { 1111fcf59617SAndrey V. Elsukov /* Reset the session ID */ 11121b0909d5SConrad Meyer if (ipsec_updateid(sav, &crp->crp_session, &cryptoid) != 0) 1113fcf59617SAndrey V. Elsukov crypto_freesession(cryptoid); 11141b0909d5SConrad Meyer xd->cryptoid = crp->crp_session; 1115fd40ecf3SJohn Baldwin CURVNET_RESTORE(); 11160a95a08eSPawel Jakub Dawidek return (crypto_dispatch(crp)); 111788768458SSam Leffler } 1118a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_noxform); 11199ffa9677SSam Leffler DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype)); 112088768458SSam Leffler error = crp->crp_etype; 1121fcf59617SAndrey V. Elsukov m_freem(m); 112288768458SSam Leffler goto bad; 112388768458SSam Leffler } 112488768458SSam Leffler 112588768458SSam Leffler /* Shouldn't happen... */ 112688768458SSam Leffler if (m == NULL) { 1127a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_crypto); 11289ffa9677SSam Leffler DPRINTF(("%s: bogus returned buffer from crypto\n", __func__)); 112988768458SSam Leffler error = EINVAL; 113088768458SSam Leffler goto bad; 113188768458SSam Leffler } 113288768458SSam Leffler /* 113388768458SSam Leffler * Copy original headers (with the new protocol number) back 113488768458SSam Leffler * in place. 113588768458SSam Leffler */ 113688768458SSam Leffler m_copyback(m, 0, skip, ptr); 113788768458SSam Leffler 113835d9e00dSJohn Baldwin free(xd, M_AH); 113988768458SSam Leffler crypto_freereq(crp); 1140*b1c3a4d7SKristof Provost AHSTAT_INC2(ahs_hist, sav->alg_auth); 11416131838bSPawel Jakub Dawidek #ifdef REGRESSION 1142dfa9422bSPawel Jakub Dawidek /* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */ 1143603724d3SBjoern A. Zeeb if (V_ipsec_integrity) { 1144dfa9422bSPawel Jakub Dawidek int alen; 1145dfa9422bSPawel Jakub Dawidek 1146dfa9422bSPawel Jakub Dawidek /* 1147dfa9422bSPawel Jakub Dawidek * Corrupt HMAC if we want to test integrity verification of 1148dfa9422bSPawel Jakub Dawidek * the other side. 1149dfa9422bSPawel Jakub Dawidek */ 1150dfa9422bSPawel Jakub Dawidek alen = AUTHSIZE(sav); 1151dfa9422bSPawel Jakub Dawidek m_copyback(m, m->m_pkthdr.len - alen, alen, ipseczeroes); 1152dfa9422bSPawel Jakub Dawidek } 11536131838bSPawel Jakub Dawidek #endif 1154dfa9422bSPawel Jakub Dawidek 115588768458SSam Leffler /* NB: m is reclaimed by ipsec_process_done. */ 1156fcf59617SAndrey V. Elsukov error = ipsec_process_done(m, sp, sav, idx); 1157fd40ecf3SJohn Baldwin CURVNET_RESTORE(); 11583d80e82dSAndrey V. Elsukov return (error); 115988768458SSam Leffler bad: 1160fd40ecf3SJohn Baldwin CURVNET_RESTORE(); 116135d9e00dSJohn Baldwin free(xd, M_AH); 116288768458SSam Leffler crypto_freereq(crp); 1163fcf59617SAndrey V. Elsukov key_freesav(&sav); 1164fcf59617SAndrey V. Elsukov key_freesp(&sp); 11653d80e82dSAndrey V. Elsukov return (error); 116688768458SSam Leffler } 116788768458SSam Leffler 116888768458SSam Leffler static struct xformsw ah_xformsw = { 1169fcf59617SAndrey V. Elsukov .xf_type = XF_AH, 1170fcf59617SAndrey V. Elsukov .xf_name = "IPsec AH", 1171fcf59617SAndrey V. Elsukov .xf_init = ah_init, 1172dae61c9dSJohn Baldwin .xf_cleanup = ah_cleanup, 1173fcf59617SAndrey V. Elsukov .xf_input = ah_input, 1174fcf59617SAndrey V. Elsukov .xf_output = ah_output, 117588768458SSam Leffler }; 117688768458SSam Leffler 1177fcf59617SAndrey V. Elsukov SYSINIT(ah_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, 1178fcf59617SAndrey V. Elsukov xform_attach, &ah_xformsw); 1179fcf59617SAndrey V. Elsukov SYSUNINIT(ah_xform_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, 1180fcf59617SAndrey V. Elsukov xform_detach, &ah_xformsw); 1181