xform_ah.c revision 252028
1105197Ssam/*	$FreeBSD: head/sys/netipsec/xform_ah.c 252028 2013-06-20 11:44:16Z ae $	*/
2105197Ssam/*	$OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */
3139823Simp/*-
4105197Ssam * The authors of this code are John Ioannidis (ji@tla.org),
5105197Ssam * Angelos D. Keromytis (kermit@csd.uch.gr) and
6105197Ssam * Niels Provos (provos@physnet.uni-hamburg.de).
7105197Ssam *
8105197Ssam * The original version of this code was written by John Ioannidis
9105197Ssam * for BSD/OS in Athens, Greece, in November 1995.
10105197Ssam *
11105197Ssam * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
12105197Ssam * by Angelos D. Keromytis.
13105197Ssam *
14105197Ssam * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
15105197Ssam * and Niels Provos.
16105197Ssam *
17105197Ssam * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist.
18105197Ssam *
19105197Ssam * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
20105197Ssam * Angelos D. Keromytis and Niels Provos.
21105197Ssam * Copyright (c) 1999 Niklas Hallqvist.
22105197Ssam * Copyright (c) 2001 Angelos D. Keromytis.
23105197Ssam *
24105197Ssam * Permission to use, copy, and modify this software with or without fee
25105197Ssam * is hereby granted, provided that this entire notice is included in
26105197Ssam * all copies of any software which is or includes a copy or
27105197Ssam * modification of this software.
28105197Ssam * You may use this code under the GNU public license if you so wish. Please
29105197Ssam * contribute changes back to the authors under this freer than GPL license
30105197Ssam * so that we may further the use of strong encryption without limitations to
31105197Ssam * all.
32105197Ssam *
33105197Ssam * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
34105197Ssam * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
35105197Ssam * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
36105197Ssam * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
37105197Ssam * PURPOSE.
38105197Ssam */
39105197Ssam#include "opt_inet.h"
40105197Ssam#include "opt_inet6.h"
41105197Ssam
42105197Ssam#include <sys/param.h>
43105197Ssam#include <sys/systm.h>
44105197Ssam#include <sys/mbuf.h>
45105197Ssam#include <sys/socket.h>
46105197Ssam#include <sys/syslog.h>
47105197Ssam#include <sys/kernel.h>
48105197Ssam#include <sys/sysctl.h>
49105197Ssam
50105197Ssam#include <net/if.h>
51195699Srwatson#include <net/vnet.h>
52105197Ssam
53105197Ssam#include <netinet/in.h>
54105197Ssam#include <netinet/in_systm.h>
55105197Ssam#include <netinet/ip.h>
56105197Ssam#include <netinet/ip_ecn.h>
57105197Ssam#include <netinet/ip6.h>
58105197Ssam
59105197Ssam#include <net/route.h>
60105197Ssam#include <netipsec/ipsec.h>
61105197Ssam#include <netipsec/ah.h>
62105197Ssam#include <netipsec/ah_var.h>
63105197Ssam#include <netipsec/xform.h>
64105197Ssam
65105197Ssam#ifdef INET6
66105197Ssam#include <netinet6/ip6_var.h>
67105197Ssam#include <netipsec/ipsec6.h>
68105197Ssam#include <netinet6/ip6_ecn.h>
69105197Ssam#endif
70105197Ssam
71105197Ssam#include <netipsec/key.h>
72105197Ssam#include <netipsec/key_debug.h>
73105197Ssam
74105197Ssam#include <opencrypto/cryptodev.h>
75105197Ssam
76105197Ssam/*
77105197Ssam * Return header size in bytes.  The old protocol did not support
78105197Ssam * the replay counter; the new protocol always includes the counter.
79105197Ssam */
80105197Ssam#define HDRSIZE(sav) \
81105197Ssam	(((sav)->flags & SADB_X_EXT_OLD) ? \
82105197Ssam		sizeof (struct ah) : sizeof (struct ah) + sizeof (u_int32_t))
83105197Ssam/*
84105197Ssam * Return authenticator size in bytes.  The old protocol is known
85158704Spjd * to use a fixed 16-byte authenticator.  The new algorithm use 12-byte
86158704Spjd * authenticator.
87105197Ssam */
88218794Svanhu#define	AUTHSIZE(sav)	ah_authsize(sav)
89105197Ssam
90195699SrwatsonVNET_DEFINE(int, ah_enable) = 1;	/* control flow of packets with AH */
91195699SrwatsonVNET_DEFINE(int, ah_cleartos) = 1;	/* clear ip_tos when doing AH calc */
92195699SrwatsonVNET_DEFINE(struct ahstat, ahstat);
93105197Ssam
94221129Sbz#ifdef INET
95105197SsamSYSCTL_DECL(_net_inet_ah);
96195699SrwatsonSYSCTL_VNET_INT(_net_inet_ah, OID_AUTO,
97195699Srwatson	ah_enable,	CTLFLAG_RW,	&VNET_NAME(ah_enable),	0, "");
98195699SrwatsonSYSCTL_VNET_INT(_net_inet_ah, OID_AUTO,
99195699Srwatson	ah_cleartos,	CTLFLAG_RW,	&VNET_NAME(ah_cleartos), 0, "");
100195699SrwatsonSYSCTL_VNET_STRUCT(_net_inet_ah, IPSECCTL_STATS,
101195699Srwatson	stats,		CTLFLAG_RD,	&VNET_NAME(ahstat), ahstat, "");
102221129Sbz#endif
103105197Ssam
104105197Ssamstatic unsigned char ipseczeroes[256];	/* larger than an ip6 extension hdr */
105105197Ssam
106105197Ssamstatic int ah_input_cb(struct cryptop*);
107105197Ssamstatic int ah_output_cb(struct cryptop*);
108105197Ssam
109218794Svanhustatic int
110218794Svanhuah_authsize(struct secasvar *sav)
111218794Svanhu{
112218794Svanhu
113218794Svanhu	IPSEC_ASSERT(sav != NULL, ("%s: sav == NULL", __func__));
114218794Svanhu
115218794Svanhu	if (sav->flags & SADB_X_EXT_OLD)
116218794Svanhu		return 16;
117218794Svanhu
118218794Svanhu	switch (sav->alg_auth) {
119218794Svanhu	case SADB_X_AALG_SHA2_256:
120218794Svanhu		return 16;
121218794Svanhu	case SADB_X_AALG_SHA2_384:
122218794Svanhu		return 24;
123218794Svanhu	case SADB_X_AALG_SHA2_512:
124218794Svanhu		return 32;
125218794Svanhu	default:
126218794Svanhu		return AH_HMAC_HASHLEN;
127218794Svanhu	}
128218794Svanhu	/* NOTREACHED */
129218794Svanhu}
130105197Ssam/*
131105197Ssam * NB: this is public for use by the PF_KEY support.
132105197Ssam */
133105197Ssamstruct auth_hash *
134105197Ssamah_algorithm_lookup(int alg)
135105197Ssam{
136171133Sgnn	if (alg > SADB_AALG_MAX)
137105197Ssam		return NULL;
138105197Ssam	switch (alg) {
139105197Ssam	case SADB_X_AALG_NULL:
140105197Ssam		return &auth_hash_null;
141105197Ssam	case SADB_AALG_MD5HMAC:
142158704Spjd		return &auth_hash_hmac_md5;
143105197Ssam	case SADB_AALG_SHA1HMAC:
144158704Spjd		return &auth_hash_hmac_sha1;
145105197Ssam	case SADB_X_AALG_RIPEMD160HMAC:
146158704Spjd		return &auth_hash_hmac_ripemd_160;
147105197Ssam	case SADB_X_AALG_MD5:
148105197Ssam		return &auth_hash_key_md5;
149105197Ssam	case SADB_X_AALG_SHA:
150105197Ssam		return &auth_hash_key_sha1;
151105197Ssam	case SADB_X_AALG_SHA2_256:
152105197Ssam		return &auth_hash_hmac_sha2_256;
153105197Ssam	case SADB_X_AALG_SHA2_384:
154105197Ssam		return &auth_hash_hmac_sha2_384;
155105197Ssam	case SADB_X_AALG_SHA2_512:
156105197Ssam		return &auth_hash_hmac_sha2_512;
157105197Ssam	}
158105197Ssam	return NULL;
159105197Ssam}
160105197Ssam
161105197Ssamsize_t
162105197Ssamah_hdrsiz(struct secasvar *sav)
163105197Ssam{
164105197Ssam	size_t size;
165105197Ssam
166105197Ssam	if (sav != NULL) {
167105197Ssam		int authsize;
168120585Ssam		IPSEC_ASSERT(sav->tdb_authalgxform != NULL, ("null xform"));
169105197Ssam		/*XXX not right for null algorithm--does it matter??*/
170105197Ssam		authsize = AUTHSIZE(sav);
171105197Ssam		size = roundup(authsize, sizeof (u_int32_t)) + HDRSIZE(sav);
172105197Ssam	} else {
173105197Ssam		/* default guess */
174105197Ssam		size = sizeof (struct ah) + sizeof (u_int32_t) + 16;
175105197Ssam	}
176105197Ssam	return size;
177105197Ssam}
178105197Ssam
179105197Ssam/*
180105197Ssam * NB: public for use by esp_init.
181105197Ssam */
182105197Ssamint
183105197Ssamah_init0(struct secasvar *sav, struct xformsw *xsp, struct cryptoini *cria)
184105197Ssam{
185105197Ssam	struct auth_hash *thash;
186105197Ssam	int keylen;
187105197Ssam
188105197Ssam	thash = ah_algorithm_lookup(sav->alg_auth);
189105197Ssam	if (thash == NULL) {
190120585Ssam		DPRINTF(("%s: unsupported authentication algorithm %u\n",
191120585Ssam			__func__, sav->alg_auth));
192105197Ssam		return EINVAL;
193105197Ssam	}
194105197Ssam	/*
195105197Ssam	 * Verify the replay state block allocation is consistent with
196105197Ssam	 * the protocol type.  We check here so we can make assumptions
197105197Ssam	 * later during protocol processing.
198105197Ssam	 */
199105197Ssam	/* NB: replay state is setup elsewhere (sigh) */
200105197Ssam	if (((sav->flags&SADB_X_EXT_OLD) == 0) ^ (sav->replay != NULL)) {
201120585Ssam		DPRINTF(("%s: replay state block inconsistency, "
202120585Ssam			"%s algorithm %s replay state\n", __func__,
203105197Ssam			(sav->flags & SADB_X_EXT_OLD) ? "old" : "new",
204105197Ssam			sav->replay == NULL ? "without" : "with"));
205105197Ssam		return EINVAL;
206105197Ssam	}
207105197Ssam	if (sav->key_auth == NULL) {
208120585Ssam		DPRINTF(("%s: no authentication key for %s algorithm\n",
209120585Ssam			__func__, thash->name));
210105197Ssam		return EINVAL;
211105197Ssam	}
212105197Ssam	keylen = _KEYLEN(sav->key_auth);
213105197Ssam	if (keylen != thash->keysize && thash->keysize != 0) {
214120585Ssam		DPRINTF(("%s: invalid keylength %d, algorithm %s requires "
215120585Ssam			"keysize %d\n", __func__,
216105197Ssam			 keylen, thash->name, thash->keysize));
217105197Ssam		return EINVAL;
218105197Ssam	}
219105197Ssam
220105197Ssam	sav->tdb_xform = xsp;
221105197Ssam	sav->tdb_authalgxform = thash;
222105197Ssam
223105197Ssam	/* Initialize crypto session. */
224105197Ssam	bzero(cria, sizeof (*cria));
225105197Ssam	cria->cri_alg = sav->tdb_authalgxform->type;
226105197Ssam	cria->cri_klen = _KEYBITS(sav->key_auth);
227157123Sgnn	cria->cri_key = sav->key_auth->key_data;
228158704Spjd	cria->cri_mlen = AUTHSIZE(sav);
229105197Ssam
230105197Ssam	return 0;
231105197Ssam}
232105197Ssam
233105197Ssam/*
234105197Ssam * ah_init() is called when an SPI is being set up.
235105197Ssam */
236105197Ssamstatic int
237105197Ssamah_init(struct secasvar *sav, struct xformsw *xsp)
238105197Ssam{
239105197Ssam	struct cryptoini cria;
240105197Ssam	int error;
241105197Ssam
242105197Ssam	error = ah_init0(sav, xsp, &cria);
243105197Ssam	return error ? error :
244181803Sbz		 crypto_newsession(&sav->tdb_cryptoid, &cria, V_crypto_support);
245105197Ssam}
246105197Ssam
247105197Ssam/*
248105197Ssam * Paranoia.
249105197Ssam *
250105197Ssam * NB: public for use by esp_zeroize (XXX).
251105197Ssam */
252105197Ssamint
253105197Ssamah_zeroize(struct secasvar *sav)
254105197Ssam{
255105197Ssam	int err;
256105197Ssam
257105197Ssam	if (sav->key_auth)
258157123Sgnn		bzero(sav->key_auth->key_data, _KEYLEN(sav->key_auth));
259105197Ssam
260105197Ssam	err = crypto_freesession(sav->tdb_cryptoid);
261105197Ssam	sav->tdb_cryptoid = 0;
262105197Ssam	sav->tdb_authalgxform = NULL;
263105197Ssam	sav->tdb_xform = NULL;
264105197Ssam	return err;
265105197Ssam}
266105197Ssam
267105197Ssam/*
268105197Ssam * Massage IPv4/IPv6 headers for AH processing.
269105197Ssam */
270105197Ssamstatic int
271105197Ssamah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
272105197Ssam{
273105197Ssam	struct mbuf *m = *m0;
274105197Ssam	unsigned char *ptr;
275105197Ssam	int off, count;
276105197Ssam
277105197Ssam#ifdef INET
278105197Ssam	struct ip *ip;
279105197Ssam#endif /* INET */
280105197Ssam
281105197Ssam#ifdef INET6
282105197Ssam	struct ip6_ext *ip6e;
283105197Ssam	struct ip6_hdr ip6;
284105197Ssam	int alloc, len, ad;
285105197Ssam#endif /* INET6 */
286105197Ssam
287105197Ssam	switch (proto) {
288105197Ssam#ifdef INET
289105197Ssam	case AF_INET:
290105197Ssam		/*
291105197Ssam		 * This is the least painful way of dealing with IPv4 header
292105197Ssam		 * and option processing -- just make sure they're in
293105197Ssam		 * contiguous memory.
294105197Ssam		 */
295105197Ssam		*m0 = m = m_pullup(m, skip);
296105197Ssam		if (m == NULL) {
297120585Ssam			DPRINTF(("%s: m_pullup failed\n", __func__));
298105197Ssam			return ENOBUFS;
299105197Ssam		}
300105197Ssam
301105197Ssam		/* Fix the IP header */
302105197Ssam		ip = mtod(m, struct ip *);
303181803Sbz		if (V_ah_cleartos)
304105197Ssam			ip->ip_tos = 0;
305105197Ssam		ip->ip_ttl = 0;
306105197Ssam		ip->ip_sum = 0;
307105197Ssam
308241919Sglebius		if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK)
309241919Sglebius			ip->ip_off &= htons(IP_DF);
310241919Sglebius		else
311241919Sglebius			ip->ip_off = htons(0);
312105197Ssam
313105197Ssam		ptr = mtod(m, unsigned char *) + sizeof(struct ip);
314105197Ssam
315105197Ssam		/* IPv4 option processing */
316105197Ssam		for (off = sizeof(struct ip); off < skip;) {
317105197Ssam			if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP ||
318105197Ssam			    off + 1 < skip)
319105197Ssam				;
320105197Ssam			else {
321120585Ssam				DPRINTF(("%s: illegal IPv4 option length for "
322120585Ssam					"option %d\n", __func__, ptr[off]));
323105197Ssam
324105197Ssam				m_freem(m);
325105197Ssam				return EINVAL;
326105197Ssam			}
327105197Ssam
328105197Ssam			switch (ptr[off]) {
329105197Ssam			case IPOPT_EOL:
330105197Ssam				off = skip;  /* End the loop. */
331105197Ssam				break;
332105197Ssam
333105197Ssam			case IPOPT_NOP:
334105197Ssam				off++;
335105197Ssam				break;
336105197Ssam
337105197Ssam			case IPOPT_SECURITY:	/* 0x82 */
338105197Ssam			case 0x85:	/* Extended security. */
339105197Ssam			case 0x86:	/* Commercial security. */
340105197Ssam			case 0x94:	/* Router alert */
341105197Ssam			case 0x95:	/* RFC1770 */
342105197Ssam				/* Sanity check for option length. */
343105197Ssam				if (ptr[off + 1] < 2) {
344120585Ssam					DPRINTF(("%s: illegal IPv4 option "
345120585Ssam						"length for option %d\n",
346120585Ssam						__func__, ptr[off]));
347105197Ssam
348105197Ssam					m_freem(m);
349105197Ssam					return EINVAL;
350105197Ssam				}
351105197Ssam
352105197Ssam				off += ptr[off + 1];
353105197Ssam				break;
354105197Ssam
355105197Ssam			case IPOPT_LSRR:
356105197Ssam			case IPOPT_SSRR:
357105197Ssam				/* Sanity check for option length. */
358105197Ssam				if (ptr[off + 1] < 2) {
359120585Ssam					DPRINTF(("%s: illegal IPv4 option "
360120585Ssam						"length for option %d\n",
361120585Ssam						__func__, ptr[off]));
362105197Ssam
363105197Ssam					m_freem(m);
364105197Ssam					return EINVAL;
365105197Ssam				}
366105197Ssam
367105197Ssam				/*
368105197Ssam				 * On output, if we have either of the
369105197Ssam				 * source routing options, we should
370105197Ssam				 * swap the destination address of the
371105197Ssam				 * IP header with the last address
372105197Ssam				 * specified in the option, as that is
373105197Ssam				 * what the destination's IP header
374105197Ssam				 * will look like.
375105197Ssam				 */
376105197Ssam				if (out)
377105197Ssam					bcopy(ptr + off + ptr[off + 1] -
378105197Ssam					    sizeof(struct in_addr),
379105197Ssam					    &(ip->ip_dst), sizeof(struct in_addr));
380105197Ssam
381105197Ssam				/* Fall through */
382105197Ssam			default:
383105197Ssam				/* Sanity check for option length. */
384105197Ssam				if (ptr[off + 1] < 2) {
385120585Ssam					DPRINTF(("%s: illegal IPv4 option "
386120585Ssam						"length for option %d\n",
387120585Ssam						__func__, ptr[off]));
388105197Ssam					m_freem(m);
389105197Ssam					return EINVAL;
390105197Ssam				}
391105197Ssam
392105197Ssam				/* Zeroize all other options. */
393105197Ssam				count = ptr[off + 1];
394105197Ssam				bcopy(ipseczeroes, ptr, count);
395105197Ssam				off += count;
396105197Ssam				break;
397105197Ssam			}
398105197Ssam
399105197Ssam			/* Sanity check. */
400105197Ssam			if (off > skip)	{
401120585Ssam				DPRINTF(("%s: malformed IPv4 options header\n",
402120585Ssam					__func__));
403105197Ssam
404105197Ssam				m_freem(m);
405105197Ssam				return EINVAL;
406105197Ssam			}
407105197Ssam		}
408105197Ssam
409105197Ssam		break;
410105197Ssam#endif /* INET */
411105197Ssam
412105197Ssam#ifdef INET6
413105197Ssam	case AF_INET6:  /* Ugly... */
414105197Ssam		/* Copy and "cook" the IPv6 header. */
415105197Ssam		m_copydata(m, 0, sizeof(ip6), (caddr_t) &ip6);
416105197Ssam
417105197Ssam		/* We don't do IPv6 Jumbograms. */
418105197Ssam		if (ip6.ip6_plen == 0) {
419120585Ssam			DPRINTF(("%s: unsupported IPv6 jumbogram\n", __func__));
420105197Ssam			m_freem(m);
421105197Ssam			return EMSGSIZE;
422105197Ssam		}
423105197Ssam
424105197Ssam		ip6.ip6_flow = 0;
425105197Ssam		ip6.ip6_hlim = 0;
426105197Ssam		ip6.ip6_vfc &= ~IPV6_VERSION_MASK;
427105197Ssam		ip6.ip6_vfc |= IPV6_VERSION;
428105197Ssam
429105197Ssam		/* Scoped address handling. */
430105197Ssam		if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_src))
431105197Ssam			ip6.ip6_src.s6_addr16[1] = 0;
432105197Ssam		if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_dst))
433105197Ssam			ip6.ip6_dst.s6_addr16[1] = 0;
434105197Ssam
435105197Ssam		/* Done with IPv6 header. */
436105197Ssam		m_copyback(m, 0, sizeof(struct ip6_hdr), (caddr_t) &ip6);
437105197Ssam
438105197Ssam		/* Let's deal with the remaining headers (if any). */
439105197Ssam		if (skip - sizeof(struct ip6_hdr) > 0) {
440105197Ssam			if (m->m_len <= skip) {
441105197Ssam				ptr = (unsigned char *) malloc(
442105197Ssam				    skip - sizeof(struct ip6_hdr),
443105197Ssam				    M_XDATA, M_NOWAIT);
444105197Ssam				if (ptr == NULL) {
445120585Ssam					DPRINTF(("%s: failed to allocate memory"
446120585Ssam						"for IPv6 headers\n",__func__));
447105197Ssam					m_freem(m);
448105197Ssam					return ENOBUFS;
449105197Ssam				}
450105197Ssam
451105197Ssam				/*
452105197Ssam				 * Copy all the protocol headers after
453105197Ssam				 * the IPv6 header.
454105197Ssam				 */
455105197Ssam				m_copydata(m, sizeof(struct ip6_hdr),
456105197Ssam				    skip - sizeof(struct ip6_hdr), ptr);
457105197Ssam				alloc = 1;
458105197Ssam			} else {
459105197Ssam				/* No need to allocate memory. */
460105197Ssam				ptr = mtod(m, unsigned char *) +
461105197Ssam				    sizeof(struct ip6_hdr);
462105197Ssam				alloc = 0;
463105197Ssam			}
464105197Ssam		} else
465105197Ssam			break;
466105197Ssam
467105197Ssam		off = ip6.ip6_nxt & 0xff; /* Next header type. */
468105197Ssam
469105197Ssam		for (len = 0; len < skip - sizeof(struct ip6_hdr);)
470105197Ssam			switch (off) {
471105197Ssam			case IPPROTO_HOPOPTS:
472105197Ssam			case IPPROTO_DSTOPTS:
473105197Ssam				ip6e = (struct ip6_ext *) (ptr + len);
474105197Ssam
475105197Ssam				/*
476105197Ssam				 * Process the mutable/immutable
477105197Ssam				 * options -- borrows heavily from the
478105197Ssam				 * KAME code.
479105197Ssam				 */
480105197Ssam				for (count = len + sizeof(struct ip6_ext);
481105197Ssam				     count < len + ((ip6e->ip6e_len + 1) << 3);) {
482105197Ssam					if (ptr[count] == IP6OPT_PAD1) {
483105197Ssam						count++;
484105197Ssam						continue; /* Skip padding. */
485105197Ssam					}
486105197Ssam
487105197Ssam					/* Sanity check. */
488105197Ssam					if (count > len +
489105197Ssam					    ((ip6e->ip6e_len + 1) << 3)) {
490105197Ssam						m_freem(m);
491105197Ssam
492105197Ssam						/* Free, if we allocated. */
493105197Ssam						if (alloc)
494184205Sdes							free(ptr, M_XDATA);
495105197Ssam						return EINVAL;
496105197Ssam					}
497105197Ssam
498105197Ssam					ad = ptr[count + 1];
499105197Ssam
500105197Ssam					/* If mutable option, zeroize. */
501105197Ssam					if (ptr[count] & IP6OPT_MUTABLE)
502105197Ssam						bcopy(ipseczeroes, ptr + count,
503105197Ssam						    ptr[count + 1]);
504105197Ssam
505105197Ssam					count += ad;
506105197Ssam
507105197Ssam					/* Sanity check. */
508105197Ssam					if (count >
509105197Ssam					    skip - sizeof(struct ip6_hdr)) {
510105197Ssam						m_freem(m);
511105197Ssam
512105197Ssam						/* Free, if we allocated. */
513105197Ssam						if (alloc)
514184205Sdes							free(ptr, M_XDATA);
515105197Ssam						return EINVAL;
516105197Ssam					}
517105197Ssam				}
518105197Ssam
519105197Ssam				/* Advance. */
520105197Ssam				len += ((ip6e->ip6e_len + 1) << 3);
521105197Ssam				off = ip6e->ip6e_nxt;
522105197Ssam				break;
523105197Ssam
524105197Ssam			case IPPROTO_ROUTING:
525105197Ssam				/*
526105197Ssam				 * Always include routing headers in
527105197Ssam				 * computation.
528105197Ssam				 */
529105197Ssam				ip6e = (struct ip6_ext *) (ptr + len);
530105197Ssam				len += ((ip6e->ip6e_len + 1) << 3);
531105197Ssam				off = ip6e->ip6e_nxt;
532105197Ssam				break;
533105197Ssam
534105197Ssam			default:
535120585Ssam				DPRINTF(("%s: unexpected IPv6 header type %d",
536120585Ssam					__func__, off));
537105197Ssam				if (alloc)
538184205Sdes					free(ptr, M_XDATA);
539105197Ssam				m_freem(m);
540105197Ssam				return EINVAL;
541105197Ssam			}
542105197Ssam
543105197Ssam		/* Copyback and free, if we allocated. */
544105197Ssam		if (alloc) {
545105197Ssam			m_copyback(m, sizeof(struct ip6_hdr),
546105197Ssam			    skip - sizeof(struct ip6_hdr), ptr);
547105197Ssam			free(ptr, M_XDATA);
548105197Ssam		}
549105197Ssam
550105197Ssam		break;
551105197Ssam#endif /* INET6 */
552105197Ssam	}
553105197Ssam
554105197Ssam	return 0;
555105197Ssam}
556105197Ssam
557105197Ssam/*
558105197Ssam * ah_input() gets called to verify that an input packet
559105197Ssam * passes authentication.
560105197Ssam */
561105197Ssamstatic int
562105197Ssamah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
563105197Ssam{
564105197Ssam	struct auth_hash *ahx;
565105197Ssam	struct tdb_ident *tdbi;
566105197Ssam	struct tdb_crypto *tc;
567105197Ssam	struct m_tag *mtag;
568105197Ssam	struct newah *ah;
569105197Ssam	int hl, rplen, authsize;
570105197Ssam
571105197Ssam	struct cryptodesc *crda;
572105197Ssam	struct cryptop *crp;
573105197Ssam
574120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
575120585Ssam	IPSEC_ASSERT(sav->key_auth != NULL, ("null authentication key"));
576120585Ssam	IPSEC_ASSERT(sav->tdb_authalgxform != NULL,
577120585Ssam		("null authentication xform"));
578105197Ssam
579105197Ssam	/* Figure out header size. */
580105197Ssam	rplen = HDRSIZE(sav);
581105197Ssam
582105197Ssam	/* XXX don't pullup, just copy header */
583105197Ssam	IP6_EXTHDR_GET(ah, struct newah *, m, skip, rplen);
584105197Ssam	if (ah == NULL) {
585105197Ssam		DPRINTF(("ah_input: cannot pullup header\n"));
586252028Sae		AHSTAT_INC(ahs_hdrops);		/*XXX*/
587105197Ssam		m_freem(m);
588105197Ssam		return ENOBUFS;
589105197Ssam	}
590105197Ssam
591105197Ssam	/* Check replay window, if applicable. */
592105197Ssam	if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) {
593252028Sae		AHSTAT_INC(ahs_replay);
594120585Ssam		DPRINTF(("%s: packet replay failure: %s\n", __func__,
595105197Ssam			  ipsec_logsastr(sav)));
596105197Ssam		m_freem(m);
597105197Ssam		return ENOBUFS;
598105197Ssam	}
599105197Ssam
600105197Ssam	/* Verify AH header length. */
601105197Ssam	hl = ah->ah_len * sizeof (u_int32_t);
602105197Ssam	ahx = sav->tdb_authalgxform;
603105197Ssam	authsize = AUTHSIZE(sav);
604105197Ssam	if (hl != authsize + rplen - sizeof (struct ah)) {
605120585Ssam		DPRINTF(("%s: bad authenticator length %u (expecting %lu)"
606120585Ssam			" for packet in SA %s/%08lx\n", __func__,
607105197Ssam			hl, (u_long) (authsize + rplen - sizeof (struct ah)),
608105197Ssam			ipsec_address(&sav->sah->saidx.dst),
609105197Ssam			(u_long) ntohl(sav->spi)));
610252028Sae		AHSTAT_INC(ahs_badauthl);
611105197Ssam		m_freem(m);
612105197Ssam		return EACCES;
613105197Ssam	}
614252028Sae	AHSTAT_ADD(ahs_ibytes, m->m_pkthdr.len - skip - hl);
615105197Ssam
616105197Ssam	/* Get crypto descriptors. */
617105197Ssam	crp = crypto_getreq(1);
618105197Ssam	if (crp == NULL) {
619120585Ssam		DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
620252028Sae		AHSTAT_INC(ahs_crypto);
621105197Ssam		m_freem(m);
622105197Ssam		return ENOBUFS;
623105197Ssam	}
624105197Ssam
625105197Ssam	crda = crp->crp_desc;
626120585Ssam	IPSEC_ASSERT(crda != NULL, ("null crypto descriptor"));
627105197Ssam
628105197Ssam	crda->crd_skip = 0;
629105197Ssam	crda->crd_len = m->m_pkthdr.len;
630105197Ssam	crda->crd_inject = skip + rplen;
631105197Ssam
632105197Ssam	/* Authentication operation. */
633105197Ssam	crda->crd_alg = ahx->type;
634105197Ssam	crda->crd_klen = _KEYBITS(sav->key_auth);
635157123Sgnn	crda->crd_key = sav->key_auth->key_data;
636105197Ssam
637105197Ssam	/* Find out if we've already done crypto. */
638105197Ssam	for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
639105197Ssam	     mtag != NULL;
640105197Ssam	     mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) {
641105197Ssam		tdbi = (struct tdb_ident *) (mtag + 1);
642105197Ssam		if (tdbi->proto == sav->sah->saidx.proto &&
643105197Ssam		    tdbi->spi == sav->spi &&
644105197Ssam		    !bcmp(&tdbi->dst, &sav->sah->saidx.dst,
645105197Ssam			  sizeof (union sockaddr_union)))
646105197Ssam			break;
647105197Ssam	}
648105197Ssam
649105197Ssam	/* Allocate IPsec-specific opaque crypto info. */
650105197Ssam	if (mtag == NULL) {
651105197Ssam		tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto) +
652105197Ssam			skip + rplen + authsize, M_XDATA, M_NOWAIT|M_ZERO);
653105197Ssam	} else {
654105197Ssam		/* Hash verification has already been done successfully. */
655105197Ssam		tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto),
656105197Ssam						    M_XDATA, M_NOWAIT|M_ZERO);
657105197Ssam	}
658105197Ssam	if (tc == NULL) {
659120585Ssam		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
660252028Sae		AHSTAT_INC(ahs_crypto);
661105197Ssam		crypto_freereq(crp);
662105197Ssam		m_freem(m);
663105197Ssam		return ENOBUFS;
664105197Ssam	}
665105197Ssam
666105197Ssam	/* Only save information if crypto processing is needed. */
667105197Ssam	if (mtag == NULL) {
668105197Ssam		int error;
669105197Ssam
670105197Ssam		/*
671105197Ssam		 * Save the authenticator, the skipped portion of the packet,
672105197Ssam		 * and the AH header.
673105197Ssam		 */
674105197Ssam		m_copydata(m, 0, skip + rplen + authsize, (caddr_t)(tc+1));
675105197Ssam
676105197Ssam		/* Zeroize the authenticator on the packet. */
677105197Ssam		m_copyback(m, skip + rplen, authsize, ipseczeroes);
678105197Ssam
679105197Ssam		/* "Massage" the packet headers for crypto processing. */
680105197Ssam		error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family,
681105197Ssam		    skip, ahx->type, 0);
682105197Ssam		if (error != 0) {
683105197Ssam			/* NB: mbuf is free'd by ah_massage_headers */
684252028Sae			AHSTAT_INC(ahs_hdrops);
685105197Ssam			free(tc, M_XDATA);
686105197Ssam			crypto_freereq(crp);
687105197Ssam			return error;
688105197Ssam		}
689105197Ssam	}
690105197Ssam
691105197Ssam	/* Crypto operation descriptor. */
692105197Ssam	crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
693117058Ssam	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
694105197Ssam	crp->crp_buf = (caddr_t) m;
695105197Ssam	crp->crp_callback = ah_input_cb;
696105197Ssam	crp->crp_sid = sav->tdb_cryptoid;
697105197Ssam	crp->crp_opaque = (caddr_t) tc;
698105197Ssam
699105197Ssam	/* These are passed as-is to the callback. */
700105197Ssam	tc->tc_spi = sav->spi;
701105197Ssam	tc->tc_dst = sav->sah->saidx.dst;
702105197Ssam	tc->tc_proto = sav->sah->saidx.proto;
703105197Ssam	tc->tc_nxt = ah->ah_nxt;
704105197Ssam	tc->tc_protoff = protoff;
705105197Ssam	tc->tc_skip = skip;
706105197Ssam	tc->tc_ptr = (caddr_t) mtag; /* Save the mtag we've identified. */
707220206Sfabient	KEY_ADDREFSA(sav);
708220206Sfabient	tc->tc_sav = sav;
709105197Ssam
710105197Ssam	if (mtag == NULL)
711105197Ssam		return crypto_dispatch(crp);
712105197Ssam	else
713105197Ssam		return ah_input_cb(crp);
714105197Ssam}
715105197Ssam
716105197Ssam/*
717105197Ssam * AH input callback from the crypto driver.
718105197Ssam */
719105197Ssamstatic int
720105197Ssamah_input_cb(struct cryptop *crp)
721105197Ssam{
722105197Ssam	int rplen, error, skip, protoff;
723105197Ssam	unsigned char calc[AH_ALEN_MAX];
724105197Ssam	struct mbuf *m;
725105197Ssam	struct cryptodesc *crd;
726105197Ssam	struct auth_hash *ahx;
727105197Ssam	struct tdb_crypto *tc;
728105197Ssam	struct m_tag *mtag;
729105197Ssam	struct secasvar *sav;
730105197Ssam	struct secasindex *saidx;
731105197Ssam	u_int8_t nxt;
732105197Ssam	caddr_t ptr;
733119643Ssam	int authsize;
734105197Ssam
735105197Ssam	crd = crp->crp_desc;
736105197Ssam
737105197Ssam	tc = (struct tdb_crypto *) crp->crp_opaque;
738120585Ssam	IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!"));
739105197Ssam	skip = tc->tc_skip;
740105197Ssam	nxt = tc->tc_nxt;
741105197Ssam	protoff = tc->tc_protoff;
742105197Ssam	mtag = (struct m_tag *) tc->tc_ptr;
743105197Ssam	m = (struct mbuf *) crp->crp_buf;
744105197Ssam
745220206Sfabient	sav = tc->tc_sav;
746220206Sfabient	IPSEC_ASSERT(sav != NULL, ("null SA!"));
747105197Ssam
748105197Ssam	saidx = &sav->sah->saidx;
749120585Ssam	IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
750105197Ssam		saidx->dst.sa.sa_family == AF_INET6,
751120585Ssam		("unexpected protocol family %u", saidx->dst.sa.sa_family));
752105197Ssam
753105197Ssam	ahx = (struct auth_hash *) sav->tdb_authalgxform;
754105197Ssam
755105197Ssam	/* Check for crypto errors. */
756105197Ssam	if (crp->crp_etype) {
757105197Ssam		if (sav->tdb_cryptoid != 0)
758105197Ssam			sav->tdb_cryptoid = crp->crp_sid;
759105197Ssam
760228009Spjd		if (crp->crp_etype == EAGAIN)
761228009Spjd			return (crypto_dispatch(crp));
762105197Ssam
763252028Sae		AHSTAT_INC(ahs_noxform);
764120585Ssam		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
765105197Ssam		error = crp->crp_etype;
766105197Ssam		goto bad;
767105197Ssam	} else {
768252028Sae		AHSTAT_INC(ahs_hist[sav->alg_auth]);
769105197Ssam		crypto_freereq(crp);		/* No longer needed. */
770105197Ssam		crp = NULL;
771105197Ssam	}
772105197Ssam
773105197Ssam	/* Shouldn't happen... */
774105197Ssam	if (m == NULL) {
775252028Sae		AHSTAT_INC(ahs_crypto);
776120585Ssam		DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
777105197Ssam		error = EINVAL;
778105197Ssam		goto bad;
779105197Ssam	}
780105197Ssam
781105197Ssam	/* Figure out header size. */
782105197Ssam	rplen = HDRSIZE(sav);
783105197Ssam	authsize = AUTHSIZE(sav);
784105197Ssam
785105197Ssam	/* Copy authenticator off the packet. */
786105197Ssam	m_copydata(m, skip + rplen, authsize, calc);
787105197Ssam
788105197Ssam	/*
789105197Ssam	 * If we have an mtag, we don't need to verify the authenticator --
790105197Ssam	 * it has been verified by an IPsec-aware NIC.
791105197Ssam	 */
792105197Ssam	if (mtag == NULL) {
793105197Ssam		ptr = (caddr_t) (tc + 1);
794105197Ssam
795105197Ssam		/* Verify authenticator. */
796105197Ssam		if (bcmp(ptr + skip + rplen, calc, authsize)) {
797120585Ssam			DPRINTF(("%s: authentication hash mismatch for packet "
798120585Ssam			    "in SA %s/%08lx\n", __func__,
799105197Ssam			    ipsec_address(&saidx->dst),
800105197Ssam			    (u_long) ntohl(sav->spi)));
801252028Sae			AHSTAT_INC(ahs_badauth);
802105197Ssam			error = EACCES;
803105197Ssam			goto bad;
804105197Ssam		}
805105197Ssam
806105197Ssam		/* Fix the Next Protocol field. */
807105197Ssam		((u_int8_t *) ptr)[protoff] = nxt;
808105197Ssam
809105197Ssam		/* Copyback the saved (uncooked) network headers. */
810105197Ssam		m_copyback(m, 0, skip, ptr);
811105197Ssam	} else {
812105197Ssam		/* Fix the Next Protocol field. */
813105197Ssam		m_copyback(m, protoff, sizeof(u_int8_t), &nxt);
814105197Ssam	}
815105197Ssam
816105197Ssam	free(tc, M_XDATA), tc = NULL;			/* No longer needed */
817105197Ssam
818105197Ssam	/*
819105197Ssam	 * Header is now authenticated.
820105197Ssam	 */
821105197Ssam	m->m_flags |= M_AUTHIPHDR|M_AUTHIPDGM;
822105197Ssam
823105197Ssam	/*
824105197Ssam	 * Update replay sequence number, if appropriate.
825105197Ssam	 */
826105197Ssam	if (sav->replay) {
827105197Ssam		u_int32_t seq;
828105197Ssam
829105197Ssam		m_copydata(m, skip + offsetof(struct newah, ah_seq),
830105197Ssam			   sizeof (seq), (caddr_t) &seq);
831105197Ssam		if (ipsec_updatereplay(ntohl(seq), sav)) {
832252028Sae			AHSTAT_INC(ahs_replay);
833105197Ssam			error = ENOBUFS;			/*XXX as above*/
834105197Ssam			goto bad;
835105197Ssam		}
836105197Ssam	}
837105197Ssam
838105197Ssam	/*
839105197Ssam	 * Remove the AH header and authenticator from the mbuf.
840105197Ssam	 */
841105197Ssam	error = m_striphdr(m, skip, rplen + authsize);
842105197Ssam	if (error) {
843120585Ssam		DPRINTF(("%s: mangled mbuf chain for SA %s/%08lx\n", __func__,
844105197Ssam		    ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi)));
845105197Ssam
846252028Sae		AHSTAT_INC(ahs_hdrops);
847105197Ssam		goto bad;
848105197Ssam	}
849105197Ssam
850221129Sbz	switch (saidx->dst.sa.sa_family) {
851221129Sbz#ifdef INET6
852221129Sbz	case AF_INET6:
853221129Sbz		error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag);
854221129Sbz		break;
855221129Sbz#endif
856221129Sbz#ifdef INET
857221129Sbz	case AF_INET:
858221129Sbz		error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag);
859221129Sbz		break;
860221129Sbz#endif
861221129Sbz	default:
862221129Sbz		panic("%s: Unexpected address family: %d saidx=%p", __func__,
863221129Sbz		    saidx->dst.sa.sa_family, saidx);
864221129Sbz	}
865105197Ssam
866105197Ssam	KEY_FREESAV(&sav);
867105197Ssam	return error;
868105197Ssambad:
869105197Ssam	if (sav)
870105197Ssam		KEY_FREESAV(&sav);
871105197Ssam	if (m != NULL)
872105197Ssam		m_freem(m);
873105197Ssam	if (tc != NULL)
874105197Ssam		free(tc, M_XDATA);
875105197Ssam	if (crp != NULL)
876105197Ssam		crypto_freereq(crp);
877105197Ssam	return error;
878105197Ssam}
879105197Ssam
880105197Ssam/*
881105197Ssam * AH output routine, called by ipsec[46]_process_packet().
882105197Ssam */
883105197Ssamstatic int
884105197Ssamah_output(
885105197Ssam	struct mbuf *m,
886105197Ssam	struct ipsecrequest *isr,
887105197Ssam	struct mbuf **mp,
888105197Ssam	int skip,
889105197Ssam	int protoff)
890105197Ssam{
891105197Ssam	struct secasvar *sav;
892105197Ssam	struct auth_hash *ahx;
893105197Ssam	struct cryptodesc *crda;
894105197Ssam	struct tdb_crypto *tc;
895105197Ssam	struct mbuf *mi;
896105197Ssam	struct cryptop *crp;
897105197Ssam	u_int16_t iplen;
898105197Ssam	int error, rplen, authsize, maxpacketsize, roff;
899105197Ssam	u_int8_t prot;
900105197Ssam	struct newah *ah;
901105197Ssam
902105197Ssam	sav = isr->sav;
903120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
904105197Ssam	ahx = sav->tdb_authalgxform;
905120585Ssam	IPSEC_ASSERT(ahx != NULL, ("null authentication xform"));
906105197Ssam
907252028Sae	AHSTAT_INC(ahs_output);
908105197Ssam
909105197Ssam	/* Figure out header size. */
910105197Ssam	rplen = HDRSIZE(sav);
911105197Ssam
912105197Ssam	/* Check for maximum packet size violations. */
913105197Ssam	switch (sav->sah->saidx.dst.sa.sa_family) {
914105197Ssam#ifdef INET
915105197Ssam	case AF_INET:
916105197Ssam		maxpacketsize = IP_MAXPACKET;
917105197Ssam		break;
918105197Ssam#endif /* INET */
919105197Ssam#ifdef INET6
920105197Ssam	case AF_INET6:
921105197Ssam		maxpacketsize = IPV6_MAXPACKET;
922105197Ssam		break;
923105197Ssam#endif /* INET6 */
924105197Ssam	default:
925120585Ssam		DPRINTF(("%s: unknown/unsupported protocol family %u, "
926120585Ssam		    "SA %s/%08lx\n", __func__,
927105197Ssam		    sav->sah->saidx.dst.sa.sa_family,
928105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
929105197Ssam		    (u_long) ntohl(sav->spi)));
930252028Sae		AHSTAT_INC(ahs_nopf);
931105197Ssam		error = EPFNOSUPPORT;
932105197Ssam		goto bad;
933105197Ssam	}
934105197Ssam	authsize = AUTHSIZE(sav);
935105197Ssam	if (rplen + authsize + m->m_pkthdr.len > maxpacketsize) {
936120585Ssam		DPRINTF(("%s: packet in SA %s/%08lx got too big "
937120585Ssam		    "(len %u, max len %u)\n", __func__,
938105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
939105197Ssam		    (u_long) ntohl(sav->spi),
940105197Ssam		    rplen + authsize + m->m_pkthdr.len, maxpacketsize));
941252028Sae		AHSTAT_INC(ahs_toobig);
942105197Ssam		error = EMSGSIZE;
943105197Ssam		goto bad;
944105197Ssam	}
945105197Ssam
946105197Ssam	/* Update the counters. */
947252028Sae	AHSTAT_ADD(ahs_obytes, m->m_pkthdr.len - skip);
948105197Ssam
949156756Ssam	m = m_unshare(m, M_NOWAIT);
950105197Ssam	if (m == NULL) {
951120585Ssam		DPRINTF(("%s: cannot clone mbuf chain, SA %s/%08lx\n", __func__,
952105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
953105197Ssam		    (u_long) ntohl(sav->spi)));
954252028Sae		AHSTAT_INC(ahs_hdrops);
955105197Ssam		error = ENOBUFS;
956105197Ssam		goto bad;
957105197Ssam	}
958105197Ssam
959105197Ssam	/* Inject AH header. */
960105197Ssam	mi = m_makespace(m, skip, rplen + authsize, &roff);
961105197Ssam	if (mi == NULL) {
962120585Ssam		DPRINTF(("%s: failed to inject %u byte AH header for SA "
963120585Ssam		    "%s/%08lx\n", __func__,
964105197Ssam		    rplen + authsize,
965105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
966105197Ssam		    (u_long) ntohl(sav->spi)));
967252028Sae		AHSTAT_INC(ahs_hdrops);		/*XXX differs from openbsd */
968105197Ssam		error = ENOBUFS;
969105197Ssam		goto bad;
970105197Ssam	}
971105197Ssam
972105197Ssam	/*
973105197Ssam	 * The AH header is guaranteed by m_makespace() to be in
974105197Ssam	 * contiguous memory, at roff bytes offset into the returned mbuf.
975105197Ssam	 */
976105197Ssam	ah = (struct newah *)(mtod(mi, caddr_t) + roff);
977105197Ssam
978105197Ssam	/* Initialize the AH header. */
979105197Ssam	m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &ah->ah_nxt);
980105197Ssam	ah->ah_len = (rplen + authsize - sizeof(struct ah)) / sizeof(u_int32_t);
981105197Ssam	ah->ah_reserve = 0;
982105197Ssam	ah->ah_spi = sav->spi;
983105197Ssam
984105197Ssam	/* Zeroize authenticator. */
985105197Ssam	m_copyback(m, skip + rplen, authsize, ipseczeroes);
986105197Ssam
987105197Ssam	/* Insert packet replay counter, as requested.  */
988105197Ssam	if (sav->replay) {
989105197Ssam		if (sav->replay->count == ~0 &&
990105197Ssam		    (sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
991120585Ssam			DPRINTF(("%s: replay counter wrapped for SA %s/%08lx\n",
992120585Ssam				__func__,
993105197Ssam				ipsec_address(&sav->sah->saidx.dst),
994105197Ssam				(u_long) ntohl(sav->spi)));
995252028Sae			AHSTAT_INC(ahs_wrap);
996105197Ssam			error = EINVAL;
997105197Ssam			goto bad;
998105197Ssam		}
999157634Spjd#ifdef REGRESSION
1000157613Spjd		/* Emulate replay attack when ipsec_replay is TRUE. */
1001181803Sbz		if (!V_ipsec_replay)
1002157634Spjd#endif
1003157613Spjd			sav->replay->count++;
1004105197Ssam		ah->ah_seq = htonl(sav->replay->count);
1005105197Ssam	}
1006105197Ssam
1007105197Ssam	/* Get crypto descriptors. */
1008105197Ssam	crp = crypto_getreq(1);
1009105197Ssam	if (crp == NULL) {
1010120585Ssam		DPRINTF(("%s: failed to acquire crypto descriptors\n",
1011120585Ssam			__func__));
1012252028Sae		AHSTAT_INC(ahs_crypto);
1013105197Ssam		error = ENOBUFS;
1014105197Ssam		goto bad;
1015105197Ssam	}
1016105197Ssam
1017105197Ssam	crda = crp->crp_desc;
1018105197Ssam
1019105197Ssam	crda->crd_skip = 0;
1020105197Ssam	crda->crd_inject = skip + rplen;
1021105197Ssam	crda->crd_len = m->m_pkthdr.len;
1022105197Ssam
1023105197Ssam	/* Authentication operation. */
1024105197Ssam	crda->crd_alg = ahx->type;
1025157123Sgnn	crda->crd_key = sav->key_auth->key_data;
1026105197Ssam	crda->crd_klen = _KEYBITS(sav->key_auth);
1027105197Ssam
1028105197Ssam	/* Allocate IPsec-specific opaque crypto info. */
1029105197Ssam	tc = (struct tdb_crypto *) malloc(
1030105197Ssam		sizeof(struct tdb_crypto) + skip, M_XDATA, M_NOWAIT|M_ZERO);
1031105197Ssam	if (tc == NULL) {
1032105197Ssam		crypto_freereq(crp);
1033120585Ssam		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
1034252028Sae		AHSTAT_INC(ahs_crypto);
1035105197Ssam		error = ENOBUFS;
1036105197Ssam		goto bad;
1037105197Ssam	}
1038105197Ssam
1039105197Ssam	/* Save the skipped portion of the packet. */
1040105197Ssam	m_copydata(m, 0, skip, (caddr_t) (tc + 1));
1041105197Ssam
1042105197Ssam	/*
1043105197Ssam	 * Fix IP header length on the header used for
1044105197Ssam	 * authentication. We don't need to fix the original
1045105197Ssam	 * header length as it will be fixed by our caller.
1046105197Ssam	 */
1047105197Ssam	switch (sav->sah->saidx.dst.sa.sa_family) {
1048105197Ssam#ifdef INET
1049105197Ssam	case AF_INET:
1050105197Ssam		bcopy(((caddr_t)(tc + 1)) +
1051105197Ssam		    offsetof(struct ip, ip_len),
1052105197Ssam		    (caddr_t) &iplen, sizeof(u_int16_t));
1053105197Ssam		iplen = htons(ntohs(iplen) + rplen + authsize);
1054105197Ssam		m_copyback(m, offsetof(struct ip, ip_len),
1055105197Ssam		    sizeof(u_int16_t), (caddr_t) &iplen);
1056105197Ssam		break;
1057105197Ssam#endif /* INET */
1058105197Ssam
1059105197Ssam#ifdef INET6
1060105197Ssam	case AF_INET6:
1061105197Ssam		bcopy(((caddr_t)(tc + 1)) +
1062105197Ssam		    offsetof(struct ip6_hdr, ip6_plen),
1063105197Ssam		    (caddr_t) &iplen, sizeof(u_int16_t));
1064105197Ssam		iplen = htons(ntohs(iplen) + rplen + authsize);
1065105197Ssam		m_copyback(m, offsetof(struct ip6_hdr, ip6_plen),
1066105197Ssam		    sizeof(u_int16_t), (caddr_t) &iplen);
1067105197Ssam		break;
1068105197Ssam#endif /* INET6 */
1069105197Ssam	}
1070105197Ssam
1071105197Ssam	/* Fix the Next Header field in saved header. */
1072105197Ssam	((u_int8_t *) (tc + 1))[protoff] = IPPROTO_AH;
1073105197Ssam
1074105197Ssam	/* Update the Next Protocol field in the IP header. */
1075105197Ssam	prot = IPPROTO_AH;
1076105197Ssam	m_copyback(m, protoff, sizeof(u_int8_t), (caddr_t) &prot);
1077105197Ssam
1078105197Ssam	/* "Massage" the packet headers for crypto processing. */
1079105197Ssam	error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family,
1080105197Ssam			skip, ahx->type, 1);
1081105197Ssam	if (error != 0) {
1082105197Ssam		m = NULL;	/* mbuf was free'd by ah_massage_headers. */
1083105197Ssam		free(tc, M_XDATA);
1084105197Ssam		crypto_freereq(crp);
1085105197Ssam		goto bad;
1086105197Ssam	}
1087105197Ssam
1088105197Ssam	/* Crypto operation descriptor. */
1089105197Ssam	crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
1090117058Ssam	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
1091105197Ssam	crp->crp_buf = (caddr_t) m;
1092105197Ssam	crp->crp_callback = ah_output_cb;
1093105197Ssam	crp->crp_sid = sav->tdb_cryptoid;
1094105197Ssam	crp->crp_opaque = (caddr_t) tc;
1095105197Ssam
1096105197Ssam	/* These are passed as-is to the callback. */
1097105197Ssam	tc->tc_isr = isr;
1098220206Sfabient	KEY_ADDREFSA(sav);
1099220206Sfabient	tc->tc_sav = sav;
1100105197Ssam	tc->tc_spi = sav->spi;
1101105197Ssam	tc->tc_dst = sav->sah->saidx.dst;
1102105197Ssam	tc->tc_proto = sav->sah->saidx.proto;
1103105197Ssam	tc->tc_skip = skip;
1104105197Ssam	tc->tc_protoff = protoff;
1105105197Ssam
1106105197Ssam	return crypto_dispatch(crp);
1107105197Ssambad:
1108105197Ssam	if (m)
1109105197Ssam		m_freem(m);
1110105197Ssam	return (error);
1111105197Ssam}
1112105197Ssam
1113105197Ssam/*
1114105197Ssam * AH output callback from the crypto driver.
1115105197Ssam */
1116105197Ssamstatic int
1117105197Ssamah_output_cb(struct cryptop *crp)
1118105197Ssam{
1119105197Ssam	int skip, protoff, error;
1120105197Ssam	struct tdb_crypto *tc;
1121105197Ssam	struct ipsecrequest *isr;
1122105197Ssam	struct secasvar *sav;
1123105197Ssam	struct mbuf *m;
1124105197Ssam	caddr_t ptr;
1125105197Ssam
1126105197Ssam	tc = (struct tdb_crypto *) crp->crp_opaque;
1127120585Ssam	IPSEC_ASSERT(tc != NULL, ("null opaque data area!"));
1128105197Ssam	skip = tc->tc_skip;
1129105197Ssam	protoff = tc->tc_protoff;
1130105197Ssam	ptr = (caddr_t) (tc + 1);
1131105197Ssam	m = (struct mbuf *) crp->crp_buf;
1132105197Ssam
1133105197Ssam	isr = tc->tc_isr;
1134120585Ssam	IPSECREQUEST_LOCK(isr);
1135220206Sfabient	sav = tc->tc_sav;
1136220206Sfabient	/* With the isr lock released SA pointer can be updated. */
1137220206Sfabient	if (sav != isr->sav) {
1138252028Sae		AHSTAT_INC(ahs_notdb);
1139120585Ssam		DPRINTF(("%s: SA expired while in crypto\n", __func__));
1140105197Ssam		error = ENOBUFS;		/*XXX*/
1141105197Ssam		goto bad;
1142105197Ssam	}
1143105197Ssam
1144105197Ssam	/* Check for crypto errors. */
1145105197Ssam	if (crp->crp_etype) {
1146105197Ssam		if (sav->tdb_cryptoid != 0)
1147105197Ssam			sav->tdb_cryptoid = crp->crp_sid;
1148105197Ssam
1149105197Ssam		if (crp->crp_etype == EAGAIN) {
1150120585Ssam			IPSECREQUEST_UNLOCK(isr);
1151228009Spjd			return (crypto_dispatch(crp));
1152105197Ssam		}
1153105197Ssam
1154252028Sae		AHSTAT_INC(ahs_noxform);
1155120585Ssam		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
1156105197Ssam		error = crp->crp_etype;
1157105197Ssam		goto bad;
1158105197Ssam	}
1159105197Ssam
1160105197Ssam	/* Shouldn't happen... */
1161105197Ssam	if (m == NULL) {
1162252028Sae		AHSTAT_INC(ahs_crypto);
1163120585Ssam		DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
1164105197Ssam		error = EINVAL;
1165105197Ssam		goto bad;
1166105197Ssam	}
1167252028Sae	AHSTAT_INC(ahs_hist[sav->alg_auth]);
1168105197Ssam
1169105197Ssam	/*
1170105197Ssam	 * Copy original headers (with the new protocol number) back
1171105197Ssam	 * in place.
1172105197Ssam	 */
1173105197Ssam	m_copyback(m, 0, skip, ptr);
1174105197Ssam
1175105197Ssam	/* No longer needed. */
1176105197Ssam	free(tc, M_XDATA);
1177105197Ssam	crypto_freereq(crp);
1178105197Ssam
1179157634Spjd#ifdef REGRESSION
1180157613Spjd	/* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */
1181181803Sbz	if (V_ipsec_integrity) {
1182157613Spjd		int alen;
1183157613Spjd
1184157613Spjd		/*
1185157613Spjd		 * Corrupt HMAC if we want to test integrity verification of
1186157613Spjd		 * the other side.
1187157613Spjd		 */
1188157613Spjd		alen = AUTHSIZE(sav);
1189157613Spjd		m_copyback(m, m->m_pkthdr.len - alen, alen, ipseczeroes);
1190157613Spjd	}
1191157634Spjd#endif
1192157613Spjd
1193105197Ssam	/* NB: m is reclaimed by ipsec_process_done. */
1194228010Spjd	error = ipsec_process_done(m, isr);
1195105197Ssam	KEY_FREESAV(&sav);
1196120585Ssam	IPSECREQUEST_UNLOCK(isr);
1197228010Spjd	return error;
1198105197Ssambad:
1199105197Ssam	if (sav)
1200105197Ssam		KEY_FREESAV(&sav);
1201120585Ssam	IPSECREQUEST_UNLOCK(isr);
1202105197Ssam	if (m)
1203105197Ssam		m_freem(m);
1204105197Ssam	free(tc, M_XDATA);
1205105197Ssam	crypto_freereq(crp);
1206105197Ssam	return error;
1207105197Ssam}
1208105197Ssam
1209105197Ssamstatic struct xformsw ah_xformsw = {
1210105197Ssam	XF_AH,		XFT_AUTH,	"IPsec AH",
1211105197Ssam	ah_init,	ah_zeroize,	ah_input,	ah_output,
1212105197Ssam};
1213105197Ssam
1214105197Ssamstatic void
1215105197Ssamah_attach(void)
1216105197Ssam{
1217185088Szec
1218190787Szec	xform_register(&ah_xformsw);
1219190787Szec}
1220190787Szec
1221105197SsamSYSINIT(ah_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ah_attach, NULL);
1222