xref: /freebsd-src/sys/netipsec/xform_ah.c (revision b1c3a4d75f4ff74218434a11cdd4e56632e13711)
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