1105197Ssam/*	$FreeBSD: stable/10/sys/netipsec/xform_ah.c 330609 2018-03-07 16:55:15Z gordon $	*/
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 <netipsec/ipsec.h>
60105197Ssam#include <netipsec/ah.h>
61105197Ssam#include <netipsec/ah_var.h>
62105197Ssam#include <netipsec/xform.h>
63105197Ssam
64105197Ssam#ifdef INET6
65105197Ssam#include <netinet6/ip6_var.h>
66105197Ssam#include <netipsec/ipsec6.h>
67105197Ssam#include <netinet6/ip6_ecn.h>
68105197Ssam#endif
69105197Ssam
70105197Ssam#include <netipsec/key.h>
71105197Ssam#include <netipsec/key_debug.h>
72105197Ssam
73105197Ssam#include <opencrypto/cryptodev.h>
74105197Ssam
75105197Ssam/*
76105197Ssam * Return header size in bytes.  The old protocol did not support
77105197Ssam * the replay counter; the new protocol always includes the counter.
78105197Ssam */
79105197Ssam#define HDRSIZE(sav) \
80105197Ssam	(((sav)->flags & SADB_X_EXT_OLD) ? \
81105197Ssam		sizeof (struct ah) : sizeof (struct ah) + sizeof (u_int32_t))
82105197Ssam/*
83105197Ssam * Return authenticator size in bytes.  The old protocol is known
84158704Spjd * to use a fixed 16-byte authenticator.  The new algorithm use 12-byte
85158704Spjd * authenticator.
86105197Ssam */
87218794Svanhu#define	AUTHSIZE(sav)	ah_authsize(sav)
88105197Ssam
89195699SrwatsonVNET_DEFINE(int, ah_enable) = 1;	/* control flow of packets with AH */
90195699SrwatsonVNET_DEFINE(int, ah_cleartos) = 1;	/* clear ip_tos when doing AH calc */
91253088SaeVNET_PCPUSTAT_DEFINE(struct ahstat, ahstat);
92253088SaeVNET_PCPUSTAT_SYSINIT(ahstat);
93105197Ssam
94253088Sae#ifdef VIMAGE
95253088SaeVNET_PCPUSTAT_SYSUNINIT(ahstat);
96253088Sae#endif /* VIMAGE */
97253088Sae
98221129Sbz#ifdef INET
99105197SsamSYSCTL_DECL(_net_inet_ah);
100195699SrwatsonSYSCTL_VNET_INT(_net_inet_ah, OID_AUTO,
101195699Srwatson	ah_enable,	CTLFLAG_RW,	&VNET_NAME(ah_enable),	0, "");
102195699SrwatsonSYSCTL_VNET_INT(_net_inet_ah, OID_AUTO,
103195699Srwatson	ah_cleartos,	CTLFLAG_RW,	&VNET_NAME(ah_cleartos), 0, "");
104253088SaeSYSCTL_VNET_PCPUSTAT(_net_inet_ah, IPSECCTL_STATS, stats, struct ahstat,
105253088Sae    ahstat, "AH statistics (struct ahstat, netipsec/ah_var.h)");
106221129Sbz#endif
107105197Ssam
108105197Ssamstatic unsigned char ipseczeroes[256];	/* larger than an ip6 extension hdr */
109105197Ssam
110105197Ssamstatic int ah_input_cb(struct cryptop*);
111105197Ssamstatic int ah_output_cb(struct cryptop*);
112105197Ssam
113218794Svanhustatic int
114218794Svanhuah_authsize(struct secasvar *sav)
115218794Svanhu{
116218794Svanhu
117218794Svanhu	IPSEC_ASSERT(sav != NULL, ("%s: sav == NULL", __func__));
118218794Svanhu
119218794Svanhu	if (sav->flags & SADB_X_EXT_OLD)
120218794Svanhu		return 16;
121218794Svanhu
122218794Svanhu	switch (sav->alg_auth) {
123218794Svanhu	case SADB_X_AALG_SHA2_256:
124218794Svanhu		return 16;
125218794Svanhu	case SADB_X_AALG_SHA2_384:
126218794Svanhu		return 24;
127218794Svanhu	case SADB_X_AALG_SHA2_512:
128218794Svanhu		return 32;
129218794Svanhu	default:
130218794Svanhu		return AH_HMAC_HASHLEN;
131218794Svanhu	}
132218794Svanhu	/* NOTREACHED */
133218794Svanhu}
134105197Ssam/*
135105197Ssam * NB: this is public for use by the PF_KEY support.
136105197Ssam */
137105197Ssamstruct auth_hash *
138105197Ssamah_algorithm_lookup(int alg)
139105197Ssam{
140171133Sgnn	if (alg > SADB_AALG_MAX)
141105197Ssam		return NULL;
142105197Ssam	switch (alg) {
143105197Ssam	case SADB_X_AALG_NULL:
144105197Ssam		return &auth_hash_null;
145105197Ssam	case SADB_AALG_MD5HMAC:
146158704Spjd		return &auth_hash_hmac_md5;
147105197Ssam	case SADB_AALG_SHA1HMAC:
148158704Spjd		return &auth_hash_hmac_sha1;
149105197Ssam	case SADB_X_AALG_RIPEMD160HMAC:
150158704Spjd		return &auth_hash_hmac_ripemd_160;
151105197Ssam	case SADB_X_AALG_MD5:
152105197Ssam		return &auth_hash_key_md5;
153105197Ssam	case SADB_X_AALG_SHA:
154105197Ssam		return &auth_hash_key_sha1;
155105197Ssam	case SADB_X_AALG_SHA2_256:
156105197Ssam		return &auth_hash_hmac_sha2_256;
157105197Ssam	case SADB_X_AALG_SHA2_384:
158105197Ssam		return &auth_hash_hmac_sha2_384;
159105197Ssam	case SADB_X_AALG_SHA2_512:
160105197Ssam		return &auth_hash_hmac_sha2_512;
161105197Ssam	}
162105197Ssam	return NULL;
163105197Ssam}
164105197Ssam
165105197Ssamsize_t
166105197Ssamah_hdrsiz(struct secasvar *sav)
167105197Ssam{
168105197Ssam	size_t size;
169105197Ssam
170105197Ssam	if (sav != NULL) {
171105197Ssam		int authsize;
172120585Ssam		IPSEC_ASSERT(sav->tdb_authalgxform != NULL, ("null xform"));
173105197Ssam		/*XXX not right for null algorithm--does it matter??*/
174105197Ssam		authsize = AUTHSIZE(sav);
175105197Ssam		size = roundup(authsize, sizeof (u_int32_t)) + HDRSIZE(sav);
176105197Ssam	} else {
177105197Ssam		/* default guess */
178105197Ssam		size = sizeof (struct ah) + sizeof (u_int32_t) + 16;
179105197Ssam	}
180105197Ssam	return size;
181105197Ssam}
182105197Ssam
183105197Ssam/*
184105197Ssam * NB: public for use by esp_init.
185105197Ssam */
186105197Ssamint
187105197Ssamah_init0(struct secasvar *sav, struct xformsw *xsp, struct cryptoini *cria)
188105197Ssam{
189105197Ssam	struct auth_hash *thash;
190105197Ssam	int keylen;
191105197Ssam
192105197Ssam	thash = ah_algorithm_lookup(sav->alg_auth);
193105197Ssam	if (thash == NULL) {
194120585Ssam		DPRINTF(("%s: unsupported authentication algorithm %u\n",
195120585Ssam			__func__, sav->alg_auth));
196105197Ssam		return EINVAL;
197105197Ssam	}
198105197Ssam	/*
199105197Ssam	 * Verify the replay state block allocation is consistent with
200105197Ssam	 * the protocol type.  We check here so we can make assumptions
201105197Ssam	 * later during protocol processing.
202105197Ssam	 */
203105197Ssam	/* NB: replay state is setup elsewhere (sigh) */
204105197Ssam	if (((sav->flags&SADB_X_EXT_OLD) == 0) ^ (sav->replay != NULL)) {
205120585Ssam		DPRINTF(("%s: replay state block inconsistency, "
206120585Ssam			"%s algorithm %s replay state\n", __func__,
207105197Ssam			(sav->flags & SADB_X_EXT_OLD) ? "old" : "new",
208105197Ssam			sav->replay == NULL ? "without" : "with"));
209105197Ssam		return EINVAL;
210105197Ssam	}
211105197Ssam	if (sav->key_auth == NULL) {
212120585Ssam		DPRINTF(("%s: no authentication key for %s algorithm\n",
213120585Ssam			__func__, thash->name));
214105197Ssam		return EINVAL;
215105197Ssam	}
216105197Ssam	keylen = _KEYLEN(sav->key_auth);
217105197Ssam	if (keylen != thash->keysize && thash->keysize != 0) {
218120585Ssam		DPRINTF(("%s: invalid keylength %d, algorithm %s requires "
219120585Ssam			"keysize %d\n", __func__,
220105197Ssam			 keylen, thash->name, thash->keysize));
221105197Ssam		return EINVAL;
222105197Ssam	}
223105197Ssam
224105197Ssam	sav->tdb_xform = xsp;
225105197Ssam	sav->tdb_authalgxform = thash;
226105197Ssam
227105197Ssam	/* Initialize crypto session. */
228105197Ssam	bzero(cria, sizeof (*cria));
229105197Ssam	cria->cri_alg = sav->tdb_authalgxform->type;
230105197Ssam	cria->cri_klen = _KEYBITS(sav->key_auth);
231157123Sgnn	cria->cri_key = sav->key_auth->key_data;
232158704Spjd	cria->cri_mlen = AUTHSIZE(sav);
233105197Ssam
234105197Ssam	return 0;
235105197Ssam}
236105197Ssam
237105197Ssam/*
238105197Ssam * ah_init() is called when an SPI is being set up.
239105197Ssam */
240105197Ssamstatic int
241105197Ssamah_init(struct secasvar *sav, struct xformsw *xsp)
242105197Ssam{
243105197Ssam	struct cryptoini cria;
244105197Ssam	int error;
245105197Ssam
246105197Ssam	error = ah_init0(sav, xsp, &cria);
247105197Ssam	return error ? error :
248181803Sbz		 crypto_newsession(&sav->tdb_cryptoid, &cria, V_crypto_support);
249105197Ssam}
250105197Ssam
251105197Ssam/*
252105197Ssam * Paranoia.
253105197Ssam *
254105197Ssam * NB: public for use by esp_zeroize (XXX).
255105197Ssam */
256105197Ssamint
257105197Ssamah_zeroize(struct secasvar *sav)
258105197Ssam{
259105197Ssam	int err;
260105197Ssam
261105197Ssam	if (sav->key_auth)
262157123Sgnn		bzero(sav->key_auth->key_data, _KEYLEN(sav->key_auth));
263105197Ssam
264105197Ssam	err = crypto_freesession(sav->tdb_cryptoid);
265105197Ssam	sav->tdb_cryptoid = 0;
266105197Ssam	sav->tdb_authalgxform = NULL;
267105197Ssam	sav->tdb_xform = NULL;
268105197Ssam	return err;
269105197Ssam}
270105197Ssam
271105197Ssam/*
272105197Ssam * Massage IPv4/IPv6 headers for AH processing.
273105197Ssam */
274105197Ssamstatic int
275105197Ssamah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
276105197Ssam{
277105197Ssam	struct mbuf *m = *m0;
278105197Ssam	unsigned char *ptr;
279105197Ssam	int off, count;
280105197Ssam
281105197Ssam#ifdef INET
282105197Ssam	struct ip *ip;
283105197Ssam#endif /* INET */
284105197Ssam
285105197Ssam#ifdef INET6
286105197Ssam	struct ip6_ext *ip6e;
287105197Ssam	struct ip6_hdr ip6;
288328621Sae	int ad, alloc, nxt, noff;
289105197Ssam#endif /* INET6 */
290105197Ssam
291105197Ssam	switch (proto) {
292105197Ssam#ifdef INET
293105197Ssam	case AF_INET:
294105197Ssam		/*
295105197Ssam		 * This is the least painful way of dealing with IPv4 header
296105197Ssam		 * and option processing -- just make sure they're in
297105197Ssam		 * contiguous memory.
298105197Ssam		 */
299105197Ssam		*m0 = m = m_pullup(m, skip);
300105197Ssam		if (m == NULL) {
301120585Ssam			DPRINTF(("%s: m_pullup failed\n", __func__));
302105197Ssam			return ENOBUFS;
303105197Ssam		}
304105197Ssam
305105197Ssam		/* Fix the IP header */
306105197Ssam		ip = mtod(m, struct ip *);
307181803Sbz		if (V_ah_cleartos)
308105197Ssam			ip->ip_tos = 0;
309105197Ssam		ip->ip_ttl = 0;
310105197Ssam		ip->ip_sum = 0;
311105197Ssam
312241919Sglebius		if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK)
313241919Sglebius			ip->ip_off &= htons(IP_DF);
314241919Sglebius		else
315241919Sglebius			ip->ip_off = htons(0);
316105197Ssam
317328621Sae		ptr = mtod(m, unsigned char *);
318105197Ssam
319105197Ssam		/* IPv4 option processing */
320105197Ssam		for (off = sizeof(struct ip); off < skip;) {
321105197Ssam			if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP ||
322105197Ssam			    off + 1 < skip)
323105197Ssam				;
324105197Ssam			else {
325120585Ssam				DPRINTF(("%s: illegal IPv4 option length for "
326120585Ssam					"option %d\n", __func__, ptr[off]));
327105197Ssam
328105197Ssam				m_freem(m);
329105197Ssam				return EINVAL;
330105197Ssam			}
331105197Ssam
332105197Ssam			switch (ptr[off]) {
333105197Ssam			case IPOPT_EOL:
334105197Ssam				off = skip;  /* End the loop. */
335105197Ssam				break;
336105197Ssam
337105197Ssam			case IPOPT_NOP:
338105197Ssam				off++;
339105197Ssam				break;
340105197Ssam
341105197Ssam			case IPOPT_SECURITY:	/* 0x82 */
342105197Ssam			case 0x85:	/* Extended security. */
343105197Ssam			case 0x86:	/* Commercial security. */
344105197Ssam			case 0x94:	/* Router alert */
345105197Ssam			case 0x95:	/* RFC1770 */
346105197Ssam				/* Sanity check for option length. */
347105197Ssam				if (ptr[off + 1] < 2) {
348120585Ssam					DPRINTF(("%s: illegal IPv4 option "
349120585Ssam						"length for option %d\n",
350120585Ssam						__func__, ptr[off]));
351105197Ssam
352105197Ssam					m_freem(m);
353105197Ssam					return EINVAL;
354105197Ssam				}
355105197Ssam
356105197Ssam				off += ptr[off + 1];
357105197Ssam				break;
358105197Ssam
359105197Ssam			case IPOPT_LSRR:
360105197Ssam			case IPOPT_SSRR:
361105197Ssam				/* Sanity check for option length. */
362105197Ssam				if (ptr[off + 1] < 2) {
363120585Ssam					DPRINTF(("%s: illegal IPv4 option "
364120585Ssam						"length for option %d\n",
365120585Ssam						__func__, ptr[off]));
366105197Ssam
367105197Ssam					m_freem(m);
368105197Ssam					return EINVAL;
369105197Ssam				}
370105197Ssam
371105197Ssam				/*
372105197Ssam				 * On output, if we have either of the
373105197Ssam				 * source routing options, we should
374105197Ssam				 * swap the destination address of the
375105197Ssam				 * IP header with the last address
376105197Ssam				 * specified in the option, as that is
377105197Ssam				 * what the destination's IP header
378105197Ssam				 * will look like.
379105197Ssam				 */
380105197Ssam				if (out)
381105197Ssam					bcopy(ptr + off + ptr[off + 1] -
382105197Ssam					    sizeof(struct in_addr),
383105197Ssam					    &(ip->ip_dst), sizeof(struct in_addr));
384105197Ssam
385105197Ssam				/* Fall through */
386105197Ssam			default:
387105197Ssam				/* Sanity check for option length. */
388105197Ssam				if (ptr[off + 1] < 2) {
389120585Ssam					DPRINTF(("%s: illegal IPv4 option "
390120585Ssam						"length for option %d\n",
391120585Ssam						__func__, ptr[off]));
392105197Ssam					m_freem(m);
393105197Ssam					return EINVAL;
394105197Ssam				}
395105197Ssam
396105197Ssam				/* Zeroize all other options. */
397105197Ssam				count = ptr[off + 1];
398328621Sae				bcopy(ipseczeroes, ptr + off, count);
399105197Ssam				off += count;
400105197Ssam				break;
401105197Ssam			}
402105197Ssam
403105197Ssam			/* Sanity check. */
404105197Ssam			if (off > skip)	{
405120585Ssam				DPRINTF(("%s: malformed IPv4 options header\n",
406120585Ssam					__func__));
407105197Ssam
408105197Ssam				m_freem(m);
409105197Ssam				return EINVAL;
410105197Ssam			}
411105197Ssam		}
412105197Ssam
413105197Ssam		break;
414105197Ssam#endif /* INET */
415105197Ssam
416105197Ssam#ifdef INET6
417105197Ssam	case AF_INET6:  /* Ugly... */
418105197Ssam		/* Copy and "cook" the IPv6 header. */
419105197Ssam		m_copydata(m, 0, sizeof(ip6), (caddr_t) &ip6);
420105197Ssam
421105197Ssam		/* We don't do IPv6 Jumbograms. */
422105197Ssam		if (ip6.ip6_plen == 0) {
423120585Ssam			DPRINTF(("%s: unsupported IPv6 jumbogram\n", __func__));
424105197Ssam			m_freem(m);
425105197Ssam			return EMSGSIZE;
426105197Ssam		}
427105197Ssam
428105197Ssam		ip6.ip6_flow = 0;
429105197Ssam		ip6.ip6_hlim = 0;
430105197Ssam		ip6.ip6_vfc &= ~IPV6_VERSION_MASK;
431105197Ssam		ip6.ip6_vfc |= IPV6_VERSION;
432105197Ssam
433105197Ssam		/* Scoped address handling. */
434105197Ssam		if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_src))
435105197Ssam			ip6.ip6_src.s6_addr16[1] = 0;
436105197Ssam		if (IN6_IS_SCOPE_LINKLOCAL(&ip6.ip6_dst))
437105197Ssam			ip6.ip6_dst.s6_addr16[1] = 0;
438105197Ssam
439105197Ssam		/* Done with IPv6 header. */
440105197Ssam		m_copyback(m, 0, sizeof(struct ip6_hdr), (caddr_t) &ip6);
441105197Ssam
442105197Ssam		/* Let's deal with the remaining headers (if any). */
443105197Ssam		if (skip - sizeof(struct ip6_hdr) > 0) {
444105197Ssam			if (m->m_len <= skip) {
445105197Ssam				ptr = (unsigned char *) malloc(
446105197Ssam				    skip - sizeof(struct ip6_hdr),
447105197Ssam				    M_XDATA, M_NOWAIT);
448105197Ssam				if (ptr == NULL) {
449120585Ssam					DPRINTF(("%s: failed to allocate memory"
450120585Ssam						"for IPv6 headers\n",__func__));
451105197Ssam					m_freem(m);
452105197Ssam					return ENOBUFS;
453105197Ssam				}
454105197Ssam
455105197Ssam				/*
456105197Ssam				 * Copy all the protocol headers after
457105197Ssam				 * the IPv6 header.
458105197Ssam				 */
459105197Ssam				m_copydata(m, sizeof(struct ip6_hdr),
460105197Ssam				    skip - sizeof(struct ip6_hdr), ptr);
461105197Ssam				alloc = 1;
462105197Ssam			} else {
463105197Ssam				/* No need to allocate memory. */
464105197Ssam				ptr = mtod(m, unsigned char *) +
465105197Ssam				    sizeof(struct ip6_hdr);
466105197Ssam				alloc = 0;
467105197Ssam			}
468105197Ssam		} else
469105197Ssam			break;
470105197Ssam
471328621Sae		nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
472105197Ssam
473328621Sae		for (off = 0; off < skip - sizeof(struct ip6_hdr);)
474328621Sae			switch (nxt) {
475105197Ssam			case IPPROTO_HOPOPTS:
476105197Ssam			case IPPROTO_DSTOPTS:
477328621Sae				ip6e = (struct ip6_ext *)(ptr + off);
478328621Sae				noff = off + ((ip6e->ip6e_len + 1) << 3);
479105197Ssam
480328621Sae				/* Sanity check. */
481328621Sae				if (noff > skip - sizeof(struct ip6_hdr))
482328621Sae					goto error6;
483328621Sae
484105197Ssam				/*
485328621Sae				 * Zero out mutable options.
486105197Ssam				 */
487328621Sae				for (count = off + sizeof(struct ip6_ext);
488328621Sae				     count < noff;) {
489105197Ssam					if (ptr[count] == IP6OPT_PAD1) {
490105197Ssam						count++;
491105197Ssam						continue; /* Skip padding. */
492105197Ssam					}
493105197Ssam
494328621Sae					ad = ptr[count + 1] + 2;
495328621Sae					if (count + ad > noff)
496328621Sae						goto error6;
497105197Ssam
498105197Ssam					if (ptr[count] & IP6OPT_MUTABLE)
499328621Sae						memset(ptr + count, 0, ad);
500105197Ssam					count += ad;
501328621Sae				}
502105197Ssam
503328621Sae				if (count != noff)
504328621Sae					goto error6;
505105197Ssam
506105197Ssam				/* Advance. */
507328621Sae				off += ((ip6e->ip6e_len + 1) << 3);
508328621Sae				nxt = ip6e->ip6e_nxt;
509105197Ssam				break;
510105197Ssam
511105197Ssam			case IPPROTO_ROUTING:
512105197Ssam				/*
513105197Ssam				 * Always include routing headers in
514105197Ssam				 * computation.
515105197Ssam				 */
516328621Sae				ip6e = (struct ip6_ext *) (ptr + off);
517328621Sae				off += ((ip6e->ip6e_len + 1) << 3);
518328621Sae				nxt = ip6e->ip6e_nxt;
519105197Ssam				break;
520105197Ssam
521105197Ssam			default:
522120585Ssam				DPRINTF(("%s: unexpected IPv6 header type %d",
523120585Ssam					__func__, off));
524328621Saeerror6:
525105197Ssam				if (alloc)
526184205Sdes					free(ptr, M_XDATA);
527105197Ssam				m_freem(m);
528105197Ssam				return EINVAL;
529105197Ssam			}
530105197Ssam
531105197Ssam		/* Copyback and free, if we allocated. */
532105197Ssam		if (alloc) {
533105197Ssam			m_copyback(m, sizeof(struct ip6_hdr),
534105197Ssam			    skip - sizeof(struct ip6_hdr), ptr);
535105197Ssam			free(ptr, M_XDATA);
536105197Ssam		}
537105197Ssam
538105197Ssam		break;
539105197Ssam#endif /* INET6 */
540105197Ssam	}
541105197Ssam
542105197Ssam	return 0;
543105197Ssam}
544105197Ssam
545105197Ssam/*
546105197Ssam * ah_input() gets called to verify that an input packet
547105197Ssam * passes authentication.
548105197Ssam */
549105197Ssamstatic int
550105197Ssamah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
551105197Ssam{
552105197Ssam	struct auth_hash *ahx;
553105197Ssam	struct tdb_ident *tdbi;
554105197Ssam	struct tdb_crypto *tc;
555105197Ssam	struct m_tag *mtag;
556105197Ssam	struct newah *ah;
557105197Ssam	int hl, rplen, authsize;
558105197Ssam
559105197Ssam	struct cryptodesc *crda;
560105197Ssam	struct cryptop *crp;
561105197Ssam
562120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
563120585Ssam	IPSEC_ASSERT(sav->key_auth != NULL, ("null authentication key"));
564120585Ssam	IPSEC_ASSERT(sav->tdb_authalgxform != NULL,
565120585Ssam		("null authentication xform"));
566105197Ssam
567105197Ssam	/* Figure out header size. */
568105197Ssam	rplen = HDRSIZE(sav);
569105197Ssam
570105197Ssam	/* XXX don't pullup, just copy header */
571105197Ssam	IP6_EXTHDR_GET(ah, struct newah *, m, skip, rplen);
572105197Ssam	if (ah == NULL) {
573105197Ssam		DPRINTF(("ah_input: cannot pullup header\n"));
574252028Sae		AHSTAT_INC(ahs_hdrops);		/*XXX*/
575105197Ssam		m_freem(m);
576105197Ssam		return ENOBUFS;
577105197Ssam	}
578105197Ssam
579105197Ssam	/* Check replay window, if applicable. */
580105197Ssam	if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) {
581252028Sae		AHSTAT_INC(ahs_replay);
582120585Ssam		DPRINTF(("%s: packet replay failure: %s\n", __func__,
583105197Ssam			  ipsec_logsastr(sav)));
584105197Ssam		m_freem(m);
585105197Ssam		return ENOBUFS;
586105197Ssam	}
587105197Ssam
588105197Ssam	/* Verify AH header length. */
589105197Ssam	hl = ah->ah_len * sizeof (u_int32_t);
590105197Ssam	ahx = sav->tdb_authalgxform;
591105197Ssam	authsize = AUTHSIZE(sav);
592105197Ssam	if (hl != authsize + rplen - sizeof (struct ah)) {
593120585Ssam		DPRINTF(("%s: bad authenticator length %u (expecting %lu)"
594120585Ssam			" for packet in SA %s/%08lx\n", __func__,
595105197Ssam			hl, (u_long) (authsize + rplen - sizeof (struct ah)),
596105197Ssam			ipsec_address(&sav->sah->saidx.dst),
597105197Ssam			(u_long) ntohl(sav->spi)));
598252028Sae		AHSTAT_INC(ahs_badauthl);
599105197Ssam		m_freem(m);
600105197Ssam		return EACCES;
601105197Ssam	}
602330565Sgordon	if (skip + authsize + rplen > m->m_pkthdr.len) {
603330565Sgordon		DPRINTF(("%s: bad mbuf length %u (expecting %lu)"
604330565Sgordon		    " for packet in SA %s/%08lx\n", __func__,
605330565Sgordon		    m->m_pkthdr.len, (u_long) (skip + authsize + rplen),
606330609Sgordon		    ipsec_address(&sav->sah->saidx.dst),
607330565Sgordon		    (u_long) ntohl(sav->spi)));
608330565Sgordon		AHSTAT_INC(ahs_badauthl);
609330609Sgordon		m_freem(m);
610330609Sgordon		return EACCES;
611330565Sgordon	}
612252028Sae	AHSTAT_ADD(ahs_ibytes, m->m_pkthdr.len - skip - hl);
613105197Ssam
614105197Ssam	/* Get crypto descriptors. */
615105197Ssam	crp = crypto_getreq(1);
616105197Ssam	if (crp == NULL) {
617120585Ssam		DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
618252028Sae		AHSTAT_INC(ahs_crypto);
619105197Ssam		m_freem(m);
620105197Ssam		return ENOBUFS;
621105197Ssam	}
622105197Ssam
623105197Ssam	crda = crp->crp_desc;
624120585Ssam	IPSEC_ASSERT(crda != NULL, ("null crypto descriptor"));
625105197Ssam
626105197Ssam	crda->crd_skip = 0;
627105197Ssam	crda->crd_len = m->m_pkthdr.len;
628105197Ssam	crda->crd_inject = skip + rplen;
629105197Ssam
630105197Ssam	/* Authentication operation. */
631105197Ssam	crda->crd_alg = ahx->type;
632105197Ssam	crda->crd_klen = _KEYBITS(sav->key_auth);
633157123Sgnn	crda->crd_key = sav->key_auth->key_data;
634105197Ssam
635105197Ssam	/* Find out if we've already done crypto. */
636105197Ssam	for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
637105197Ssam	     mtag != NULL;
638105197Ssam	     mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) {
639105197Ssam		tdbi = (struct tdb_ident *) (mtag + 1);
640105197Ssam		if (tdbi->proto == sav->sah->saidx.proto &&
641105197Ssam		    tdbi->spi == sav->spi &&
642105197Ssam		    !bcmp(&tdbi->dst, &sav->sah->saidx.dst,
643105197Ssam			  sizeof (union sockaddr_union)))
644105197Ssam			break;
645105197Ssam	}
646105197Ssam
647105197Ssam	/* Allocate IPsec-specific opaque crypto info. */
648105197Ssam	if (mtag == NULL) {
649105197Ssam		tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto) +
650105197Ssam			skip + rplen + authsize, M_XDATA, M_NOWAIT|M_ZERO);
651105197Ssam	} else {
652105197Ssam		/* Hash verification has already been done successfully. */
653105197Ssam		tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto),
654105197Ssam						    M_XDATA, M_NOWAIT|M_ZERO);
655105197Ssam	}
656105197Ssam	if (tc == NULL) {
657120585Ssam		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
658252028Sae		AHSTAT_INC(ahs_crypto);
659105197Ssam		crypto_freereq(crp);
660105197Ssam		m_freem(m);
661105197Ssam		return ENOBUFS;
662105197Ssam	}
663105197Ssam
664105197Ssam	/* Only save information if crypto processing is needed. */
665105197Ssam	if (mtag == NULL) {
666105197Ssam		int error;
667105197Ssam
668105197Ssam		/*
669105197Ssam		 * Save the authenticator, the skipped portion of the packet,
670105197Ssam		 * and the AH header.
671105197Ssam		 */
672105197Ssam		m_copydata(m, 0, skip + rplen + authsize, (caddr_t)(tc+1));
673105197Ssam
674105197Ssam		/* Zeroize the authenticator on the packet. */
675105197Ssam		m_copyback(m, skip + rplen, authsize, ipseczeroes);
676105197Ssam
677330565Sgordon		/* Save ah_nxt, since ah pointer can become invalid after "massage" */
678330565Sgordon		hl = ah->ah_nxt;
679330565Sgordon
680105197Ssam		/* "Massage" the packet headers for crypto processing. */
681105197Ssam		error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family,
682105197Ssam		    skip, ahx->type, 0);
683105197Ssam		if (error != 0) {
684105197Ssam			/* NB: mbuf is free'd by ah_massage_headers */
685252028Sae			AHSTAT_INC(ahs_hdrops);
686105197Ssam			free(tc, M_XDATA);
687105197Ssam			crypto_freereq(crp);
688105197Ssam			return error;
689105197Ssam		}
690105197Ssam	}
691105197Ssam
692105197Ssam	/* Crypto operation descriptor. */
693105197Ssam	crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
694117058Ssam	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
695105197Ssam	crp->crp_buf = (caddr_t) m;
696105197Ssam	crp->crp_callback = ah_input_cb;
697105197Ssam	crp->crp_sid = sav->tdb_cryptoid;
698105197Ssam	crp->crp_opaque = (caddr_t) tc;
699105197Ssam
700105197Ssam	/* These are passed as-is to the callback. */
701105197Ssam	tc->tc_spi = sav->spi;
702105197Ssam	tc->tc_dst = sav->sah->saidx.dst;
703105197Ssam	tc->tc_proto = sav->sah->saidx.proto;
704330565Sgordon	tc->tc_nxt = hl;
705105197Ssam	tc->tc_protoff = protoff;
706105197Ssam	tc->tc_skip = skip;
707105197Ssam	tc->tc_ptr = (caddr_t) mtag; /* Save the mtag we've identified. */
708220206Sfabient	KEY_ADDREFSA(sav);
709220206Sfabient	tc->tc_sav = sav;
710105197Ssam
711105197Ssam	if (mtag == NULL)
712105197Ssam		return crypto_dispatch(crp);
713105197Ssam	else
714105197Ssam		return ah_input_cb(crp);
715105197Ssam}
716105197Ssam
717105197Ssam/*
718105197Ssam * AH input callback from the crypto driver.
719105197Ssam */
720105197Ssamstatic int
721105197Ssamah_input_cb(struct cryptop *crp)
722105197Ssam{
723105197Ssam	int rplen, error, skip, protoff;
724105197Ssam	unsigned char calc[AH_ALEN_MAX];
725105197Ssam	struct mbuf *m;
726105197Ssam	struct cryptodesc *crd;
727105197Ssam	struct auth_hash *ahx;
728105197Ssam	struct tdb_crypto *tc;
729105197Ssam	struct m_tag *mtag;
730105197Ssam	struct secasvar *sav;
731105197Ssam	struct secasindex *saidx;
732105197Ssam	u_int8_t nxt;
733105197Ssam	caddr_t ptr;
734119643Ssam	int authsize;
735105197Ssam
736105197Ssam	crd = crp->crp_desc;
737105197Ssam
738105197Ssam	tc = (struct tdb_crypto *) crp->crp_opaque;
739120585Ssam	IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!"));
740105197Ssam	skip = tc->tc_skip;
741105197Ssam	nxt = tc->tc_nxt;
742105197Ssam	protoff = tc->tc_protoff;
743105197Ssam	mtag = (struct m_tag *) tc->tc_ptr;
744105197Ssam	m = (struct mbuf *) crp->crp_buf;
745105197Ssam
746220206Sfabient	sav = tc->tc_sav;
747220206Sfabient	IPSEC_ASSERT(sav != NULL, ("null SA!"));
748105197Ssam
749105197Ssam	saidx = &sav->sah->saidx;
750120585Ssam	IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
751105197Ssam		saidx->dst.sa.sa_family == AF_INET6,
752120585Ssam		("unexpected protocol family %u", saidx->dst.sa.sa_family));
753105197Ssam
754105197Ssam	ahx = (struct auth_hash *) sav->tdb_authalgxform;
755105197Ssam
756105197Ssam	/* Check for crypto errors. */
757105197Ssam	if (crp->crp_etype) {
758105197Ssam		if (sav->tdb_cryptoid != 0)
759105197Ssam			sav->tdb_cryptoid = crp->crp_sid;
760105197Ssam
761228009Spjd		if (crp->crp_etype == EAGAIN)
762228009Spjd			return (crypto_dispatch(crp));
763105197Ssam
764252028Sae		AHSTAT_INC(ahs_noxform);
765120585Ssam		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
766105197Ssam		error = crp->crp_etype;
767105197Ssam		goto bad;
768105197Ssam	} else {
769252028Sae		AHSTAT_INC(ahs_hist[sav->alg_auth]);
770105197Ssam		crypto_freereq(crp);		/* No longer needed. */
771105197Ssam		crp = NULL;
772105197Ssam	}
773105197Ssam
774105197Ssam	/* Shouldn't happen... */
775105197Ssam	if (m == NULL) {
776252028Sae		AHSTAT_INC(ahs_crypto);
777120585Ssam		DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
778105197Ssam		error = EINVAL;
779105197Ssam		goto bad;
780105197Ssam	}
781105197Ssam
782105197Ssam	/* Figure out header size. */
783105197Ssam	rplen = HDRSIZE(sav);
784105197Ssam	authsize = AUTHSIZE(sav);
785105197Ssam
786105197Ssam	/* Copy authenticator off the packet. */
787105197Ssam	m_copydata(m, skip + rplen, authsize, calc);
788105197Ssam
789105197Ssam	/*
790105197Ssam	 * If we have an mtag, we don't need to verify the authenticator --
791105197Ssam	 * it has been verified by an IPsec-aware NIC.
792105197Ssam	 */
793105197Ssam	if (mtag == NULL) {
794105197Ssam		ptr = (caddr_t) (tc + 1);
795105197Ssam
796105197Ssam		/* Verify authenticator. */
797105197Ssam		if (bcmp(ptr + skip + rplen, calc, authsize)) {
798120585Ssam			DPRINTF(("%s: authentication hash mismatch for packet "
799120585Ssam			    "in SA %s/%08lx\n", __func__,
800105197Ssam			    ipsec_address(&saidx->dst),
801105197Ssam			    (u_long) ntohl(sav->spi)));
802252028Sae			AHSTAT_INC(ahs_badauth);
803105197Ssam			error = EACCES;
804105197Ssam			goto bad;
805105197Ssam		}
806105197Ssam
807105197Ssam		/* Fix the Next Protocol field. */
808105197Ssam		((u_int8_t *) ptr)[protoff] = nxt;
809105197Ssam
810105197Ssam		/* Copyback the saved (uncooked) network headers. */
811105197Ssam		m_copyback(m, 0, skip, ptr);
812105197Ssam	} else {
813105197Ssam		/* Fix the Next Protocol field. */
814105197Ssam		m_copyback(m, protoff, sizeof(u_int8_t), &nxt);
815105197Ssam	}
816105197Ssam
817105197Ssam	free(tc, M_XDATA), tc = NULL;			/* No longer needed */
818105197Ssam
819105197Ssam	/*
820105197Ssam	 * Header is now authenticated.
821105197Ssam	 */
822105197Ssam	m->m_flags |= M_AUTHIPHDR|M_AUTHIPDGM;
823105197Ssam
824105197Ssam	/*
825105197Ssam	 * Update replay sequence number, if appropriate.
826105197Ssam	 */
827105197Ssam	if (sav->replay) {
828105197Ssam		u_int32_t seq;
829105197Ssam
830105197Ssam		m_copydata(m, skip + offsetof(struct newah, ah_seq),
831105197Ssam			   sizeof (seq), (caddr_t) &seq);
832105197Ssam		if (ipsec_updatereplay(ntohl(seq), sav)) {
833252028Sae			AHSTAT_INC(ahs_replay);
834105197Ssam			error = ENOBUFS;			/*XXX as above*/
835105197Ssam			goto bad;
836105197Ssam		}
837105197Ssam	}
838105197Ssam
839105197Ssam	/*
840105197Ssam	 * Remove the AH header and authenticator from the mbuf.
841105197Ssam	 */
842105197Ssam	error = m_striphdr(m, skip, rplen + authsize);
843105197Ssam	if (error) {
844120585Ssam		DPRINTF(("%s: mangled mbuf chain for SA %s/%08lx\n", __func__,
845105197Ssam		    ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi)));
846105197Ssam
847252028Sae		AHSTAT_INC(ahs_hdrops);
848105197Ssam		goto bad;
849105197Ssam	}
850105197Ssam
851221129Sbz	switch (saidx->dst.sa.sa_family) {
852221129Sbz#ifdef INET6
853221129Sbz	case AF_INET6:
854221129Sbz		error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag);
855221129Sbz		break;
856221129Sbz#endif
857221129Sbz#ifdef INET
858221129Sbz	case AF_INET:
859221129Sbz		error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag);
860221129Sbz		break;
861221129Sbz#endif
862221129Sbz	default:
863221129Sbz		panic("%s: Unexpected address family: %d saidx=%p", __func__,
864221129Sbz		    saidx->dst.sa.sa_family, saidx);
865221129Sbz	}
866105197Ssam
867105197Ssam	KEY_FREESAV(&sav);
868105197Ssam	return error;
869105197Ssambad:
870105197Ssam	if (sav)
871105197Ssam		KEY_FREESAV(&sav);
872105197Ssam	if (m != NULL)
873105197Ssam		m_freem(m);
874105197Ssam	if (tc != NULL)
875105197Ssam		free(tc, M_XDATA);
876105197Ssam	if (crp != NULL)
877105197Ssam		crypto_freereq(crp);
878105197Ssam	return error;
879105197Ssam}
880105197Ssam
881105197Ssam/*
882105197Ssam * AH output routine, called by ipsec[46]_process_packet().
883105197Ssam */
884105197Ssamstatic int
885105197Ssamah_output(
886105197Ssam	struct mbuf *m,
887105197Ssam	struct ipsecrequest *isr,
888105197Ssam	struct mbuf **mp,
889105197Ssam	int skip,
890105197Ssam	int protoff)
891105197Ssam{
892105197Ssam	struct secasvar *sav;
893105197Ssam	struct auth_hash *ahx;
894105197Ssam	struct cryptodesc *crda;
895105197Ssam	struct tdb_crypto *tc;
896105197Ssam	struct mbuf *mi;
897105197Ssam	struct cryptop *crp;
898105197Ssam	u_int16_t iplen;
899105197Ssam	int error, rplen, authsize, maxpacketsize, roff;
900105197Ssam	u_int8_t prot;
901105197Ssam	struct newah *ah;
902105197Ssam
903105197Ssam	sav = isr->sav;
904120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
905105197Ssam	ahx = sav->tdb_authalgxform;
906120585Ssam	IPSEC_ASSERT(ahx != NULL, ("null authentication xform"));
907105197Ssam
908252028Sae	AHSTAT_INC(ahs_output);
909105197Ssam
910105197Ssam	/* Figure out header size. */
911105197Ssam	rplen = HDRSIZE(sav);
912105197Ssam
913105197Ssam	/* Check for maximum packet size violations. */
914105197Ssam	switch (sav->sah->saidx.dst.sa.sa_family) {
915105197Ssam#ifdef INET
916105197Ssam	case AF_INET:
917105197Ssam		maxpacketsize = IP_MAXPACKET;
918105197Ssam		break;
919105197Ssam#endif /* INET */
920105197Ssam#ifdef INET6
921105197Ssam	case AF_INET6:
922105197Ssam		maxpacketsize = IPV6_MAXPACKET;
923105197Ssam		break;
924105197Ssam#endif /* INET6 */
925105197Ssam	default:
926120585Ssam		DPRINTF(("%s: unknown/unsupported protocol family %u, "
927120585Ssam		    "SA %s/%08lx\n", __func__,
928105197Ssam		    sav->sah->saidx.dst.sa.sa_family,
929105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
930105197Ssam		    (u_long) ntohl(sav->spi)));
931252028Sae		AHSTAT_INC(ahs_nopf);
932105197Ssam		error = EPFNOSUPPORT;
933105197Ssam		goto bad;
934105197Ssam	}
935105197Ssam	authsize = AUTHSIZE(sav);
936105197Ssam	if (rplen + authsize + m->m_pkthdr.len > maxpacketsize) {
937120585Ssam		DPRINTF(("%s: packet in SA %s/%08lx got too big "
938120585Ssam		    "(len %u, max len %u)\n", __func__,
939105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
940105197Ssam		    (u_long) ntohl(sav->spi),
941105197Ssam		    rplen + authsize + m->m_pkthdr.len, maxpacketsize));
942252028Sae		AHSTAT_INC(ahs_toobig);
943105197Ssam		error = EMSGSIZE;
944105197Ssam		goto bad;
945105197Ssam	}
946105197Ssam
947105197Ssam	/* Update the counters. */
948252028Sae	AHSTAT_ADD(ahs_obytes, m->m_pkthdr.len - skip);
949105197Ssam
950156756Ssam	m = m_unshare(m, M_NOWAIT);
951105197Ssam	if (m == NULL) {
952120585Ssam		DPRINTF(("%s: cannot clone mbuf chain, SA %s/%08lx\n", __func__,
953105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
954105197Ssam		    (u_long) ntohl(sav->spi)));
955252028Sae		AHSTAT_INC(ahs_hdrops);
956105197Ssam		error = ENOBUFS;
957105197Ssam		goto bad;
958105197Ssam	}
959105197Ssam
960105197Ssam	/* Inject AH header. */
961105197Ssam	mi = m_makespace(m, skip, rplen + authsize, &roff);
962105197Ssam	if (mi == NULL) {
963120585Ssam		DPRINTF(("%s: failed to inject %u byte AH header for SA "
964120585Ssam		    "%s/%08lx\n", __func__,
965105197Ssam		    rplen + authsize,
966105197Ssam		    ipsec_address(&sav->sah->saidx.dst),
967105197Ssam		    (u_long) ntohl(sav->spi)));
968252028Sae		AHSTAT_INC(ahs_hdrops);		/*XXX differs from openbsd */
969105197Ssam		error = ENOBUFS;
970105197Ssam		goto bad;
971105197Ssam	}
972105197Ssam
973105197Ssam	/*
974105197Ssam	 * The AH header is guaranteed by m_makespace() to be in
975105197Ssam	 * contiguous memory, at roff bytes offset into the returned mbuf.
976105197Ssam	 */
977105197Ssam	ah = (struct newah *)(mtod(mi, caddr_t) + roff);
978105197Ssam
979105197Ssam	/* Initialize the AH header. */
980105197Ssam	m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &ah->ah_nxt);
981105197Ssam	ah->ah_len = (rplen + authsize - sizeof(struct ah)) / sizeof(u_int32_t);
982105197Ssam	ah->ah_reserve = 0;
983105197Ssam	ah->ah_spi = sav->spi;
984105197Ssam
985105197Ssam	/* Zeroize authenticator. */
986105197Ssam	m_copyback(m, skip + rplen, authsize, ipseczeroes);
987105197Ssam
988105197Ssam	/* Insert packet replay counter, as requested.  */
989105197Ssam	if (sav->replay) {
990105197Ssam		if (sav->replay->count == ~0 &&
991105197Ssam		    (sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
992120585Ssam			DPRINTF(("%s: replay counter wrapped for SA %s/%08lx\n",
993120585Ssam				__func__,
994105197Ssam				ipsec_address(&sav->sah->saidx.dst),
995105197Ssam				(u_long) ntohl(sav->spi)));
996252028Sae			AHSTAT_INC(ahs_wrap);
997105197Ssam			error = EINVAL;
998105197Ssam			goto bad;
999105197Ssam		}
1000157634Spjd#ifdef REGRESSION
1001157613Spjd		/* Emulate replay attack when ipsec_replay is TRUE. */
1002181803Sbz		if (!V_ipsec_replay)
1003157634Spjd#endif
1004157613Spjd			sav->replay->count++;
1005105197Ssam		ah->ah_seq = htonl(sav->replay->count);
1006105197Ssam	}
1007105197Ssam
1008105197Ssam	/* Get crypto descriptors. */
1009105197Ssam	crp = crypto_getreq(1);
1010105197Ssam	if (crp == NULL) {
1011120585Ssam		DPRINTF(("%s: failed to acquire crypto descriptors\n",
1012120585Ssam			__func__));
1013252028Sae		AHSTAT_INC(ahs_crypto);
1014105197Ssam		error = ENOBUFS;
1015105197Ssam		goto bad;
1016105197Ssam	}
1017105197Ssam
1018105197Ssam	crda = crp->crp_desc;
1019105197Ssam
1020105197Ssam	crda->crd_skip = 0;
1021105197Ssam	crda->crd_inject = skip + rplen;
1022105197Ssam	crda->crd_len = m->m_pkthdr.len;
1023105197Ssam
1024105197Ssam	/* Authentication operation. */
1025105197Ssam	crda->crd_alg = ahx->type;
1026157123Sgnn	crda->crd_key = sav->key_auth->key_data;
1027105197Ssam	crda->crd_klen = _KEYBITS(sav->key_auth);
1028105197Ssam
1029105197Ssam	/* Allocate IPsec-specific opaque crypto info. */
1030105197Ssam	tc = (struct tdb_crypto *) malloc(
1031105197Ssam		sizeof(struct tdb_crypto) + skip, M_XDATA, M_NOWAIT|M_ZERO);
1032105197Ssam	if (tc == NULL) {
1033105197Ssam		crypto_freereq(crp);
1034120585Ssam		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
1035252028Sae		AHSTAT_INC(ahs_crypto);
1036105197Ssam		error = ENOBUFS;
1037105197Ssam		goto bad;
1038105197Ssam	}
1039105197Ssam
1040105197Ssam	/* Save the skipped portion of the packet. */
1041105197Ssam	m_copydata(m, 0, skip, (caddr_t) (tc + 1));
1042105197Ssam
1043105197Ssam	/*
1044105197Ssam	 * Fix IP header length on the header used for
1045105197Ssam	 * authentication. We don't need to fix the original
1046105197Ssam	 * header length as it will be fixed by our caller.
1047105197Ssam	 */
1048105197Ssam	switch (sav->sah->saidx.dst.sa.sa_family) {
1049105197Ssam#ifdef INET
1050105197Ssam	case AF_INET:
1051105197Ssam		bcopy(((caddr_t)(tc + 1)) +
1052105197Ssam		    offsetof(struct ip, ip_len),
1053105197Ssam		    (caddr_t) &iplen, sizeof(u_int16_t));
1054105197Ssam		iplen = htons(ntohs(iplen) + rplen + authsize);
1055105197Ssam		m_copyback(m, offsetof(struct ip, ip_len),
1056105197Ssam		    sizeof(u_int16_t), (caddr_t) &iplen);
1057105197Ssam		break;
1058105197Ssam#endif /* INET */
1059105197Ssam
1060105197Ssam#ifdef INET6
1061105197Ssam	case AF_INET6:
1062105197Ssam		bcopy(((caddr_t)(tc + 1)) +
1063105197Ssam		    offsetof(struct ip6_hdr, ip6_plen),
1064105197Ssam		    (caddr_t) &iplen, sizeof(u_int16_t));
1065105197Ssam		iplen = htons(ntohs(iplen) + rplen + authsize);
1066105197Ssam		m_copyback(m, offsetof(struct ip6_hdr, ip6_plen),
1067105197Ssam		    sizeof(u_int16_t), (caddr_t) &iplen);
1068105197Ssam		break;
1069105197Ssam#endif /* INET6 */
1070105197Ssam	}
1071105197Ssam
1072105197Ssam	/* Fix the Next Header field in saved header. */
1073105197Ssam	((u_int8_t *) (tc + 1))[protoff] = IPPROTO_AH;
1074105197Ssam
1075105197Ssam	/* Update the Next Protocol field in the IP header. */
1076105197Ssam	prot = IPPROTO_AH;
1077105197Ssam	m_copyback(m, protoff, sizeof(u_int8_t), (caddr_t) &prot);
1078105197Ssam
1079105197Ssam	/* "Massage" the packet headers for crypto processing. */
1080105197Ssam	error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family,
1081105197Ssam			skip, ahx->type, 1);
1082105197Ssam	if (error != 0) {
1083105197Ssam		m = NULL;	/* mbuf was free'd by ah_massage_headers. */
1084105197Ssam		free(tc, M_XDATA);
1085105197Ssam		crypto_freereq(crp);
1086105197Ssam		goto bad;
1087105197Ssam	}
1088105197Ssam
1089105197Ssam	/* Crypto operation descriptor. */
1090105197Ssam	crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
1091117058Ssam	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
1092105197Ssam	crp->crp_buf = (caddr_t) m;
1093105197Ssam	crp->crp_callback = ah_output_cb;
1094105197Ssam	crp->crp_sid = sav->tdb_cryptoid;
1095105197Ssam	crp->crp_opaque = (caddr_t) tc;
1096105197Ssam
1097105197Ssam	/* These are passed as-is to the callback. */
1098105197Ssam	tc->tc_isr = isr;
1099220206Sfabient	KEY_ADDREFSA(sav);
1100220206Sfabient	tc->tc_sav = sav;
1101105197Ssam	tc->tc_spi = sav->spi;
1102105197Ssam	tc->tc_dst = sav->sah->saidx.dst;
1103105197Ssam	tc->tc_proto = sav->sah->saidx.proto;
1104105197Ssam	tc->tc_skip = skip;
1105105197Ssam	tc->tc_protoff = protoff;
1106105197Ssam
1107105197Ssam	return crypto_dispatch(crp);
1108105197Ssambad:
1109105197Ssam	if (m)
1110105197Ssam		m_freem(m);
1111105197Ssam	return (error);
1112105197Ssam}
1113105197Ssam
1114105197Ssam/*
1115105197Ssam * AH output callback from the crypto driver.
1116105197Ssam */
1117105197Ssamstatic int
1118105197Ssamah_output_cb(struct cryptop *crp)
1119105197Ssam{
1120105197Ssam	int skip, protoff, error;
1121105197Ssam	struct tdb_crypto *tc;
1122105197Ssam	struct ipsecrequest *isr;
1123105197Ssam	struct secasvar *sav;
1124105197Ssam	struct mbuf *m;
1125105197Ssam	caddr_t ptr;
1126105197Ssam
1127105197Ssam	tc = (struct tdb_crypto *) crp->crp_opaque;
1128120585Ssam	IPSEC_ASSERT(tc != NULL, ("null opaque data area!"));
1129105197Ssam	skip = tc->tc_skip;
1130105197Ssam	protoff = tc->tc_protoff;
1131105197Ssam	ptr = (caddr_t) (tc + 1);
1132105197Ssam	m = (struct mbuf *) crp->crp_buf;
1133105197Ssam
1134105197Ssam	isr = tc->tc_isr;
1135120585Ssam	IPSECREQUEST_LOCK(isr);
1136220206Sfabient	sav = tc->tc_sav;
1137220206Sfabient	/* With the isr lock released SA pointer can be updated. */
1138220206Sfabient	if (sav != isr->sav) {
1139252028Sae		AHSTAT_INC(ahs_notdb);
1140120585Ssam		DPRINTF(("%s: SA expired while in crypto\n", __func__));
1141105197Ssam		error = ENOBUFS;		/*XXX*/
1142105197Ssam		goto bad;
1143105197Ssam	}
1144105197Ssam
1145105197Ssam	/* Check for crypto errors. */
1146105197Ssam	if (crp->crp_etype) {
1147105197Ssam		if (sav->tdb_cryptoid != 0)
1148105197Ssam			sav->tdb_cryptoid = crp->crp_sid;
1149105197Ssam
1150105197Ssam		if (crp->crp_etype == EAGAIN) {
1151120585Ssam			IPSECREQUEST_UNLOCK(isr);
1152228009Spjd			return (crypto_dispatch(crp));
1153105197Ssam		}
1154105197Ssam
1155252028Sae		AHSTAT_INC(ahs_noxform);
1156120585Ssam		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
1157105197Ssam		error = crp->crp_etype;
1158105197Ssam		goto bad;
1159105197Ssam	}
1160105197Ssam
1161105197Ssam	/* Shouldn't happen... */
1162105197Ssam	if (m == NULL) {
1163252028Sae		AHSTAT_INC(ahs_crypto);
1164120585Ssam		DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
1165105197Ssam		error = EINVAL;
1166105197Ssam		goto bad;
1167105197Ssam	}
1168252028Sae	AHSTAT_INC(ahs_hist[sav->alg_auth]);
1169105197Ssam
1170105197Ssam	/*
1171105197Ssam	 * Copy original headers (with the new protocol number) back
1172105197Ssam	 * in place.
1173105197Ssam	 */
1174105197Ssam	m_copyback(m, 0, skip, ptr);
1175105197Ssam
1176105197Ssam	/* No longer needed. */
1177105197Ssam	free(tc, M_XDATA);
1178105197Ssam	crypto_freereq(crp);
1179105197Ssam
1180157634Spjd#ifdef REGRESSION
1181157613Spjd	/* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */
1182181803Sbz	if (V_ipsec_integrity) {
1183157613Spjd		int alen;
1184157613Spjd
1185157613Spjd		/*
1186157613Spjd		 * Corrupt HMAC if we want to test integrity verification of
1187157613Spjd		 * the other side.
1188157613Spjd		 */
1189157613Spjd		alen = AUTHSIZE(sav);
1190157613Spjd		m_copyback(m, m->m_pkthdr.len - alen, alen, ipseczeroes);
1191157613Spjd	}
1192157634Spjd#endif
1193157613Spjd
1194105197Ssam	/* NB: m is reclaimed by ipsec_process_done. */
1195228010Spjd	error = ipsec_process_done(m, isr);
1196105197Ssam	KEY_FREESAV(&sav);
1197120585Ssam	IPSECREQUEST_UNLOCK(isr);
1198228010Spjd	return error;
1199105197Ssambad:
1200105197Ssam	if (sav)
1201105197Ssam		KEY_FREESAV(&sav);
1202120585Ssam	IPSECREQUEST_UNLOCK(isr);
1203105197Ssam	if (m)
1204105197Ssam		m_freem(m);
1205105197Ssam	free(tc, M_XDATA);
1206105197Ssam	crypto_freereq(crp);
1207105197Ssam	return error;
1208105197Ssam}
1209105197Ssam
1210105197Ssamstatic struct xformsw ah_xformsw = {
1211105197Ssam	XF_AH,		XFT_AUTH,	"IPsec AH",
1212105197Ssam	ah_init,	ah_zeroize,	ah_input,	ah_output,
1213105197Ssam};
1214105197Ssam
1215105197Ssamstatic void
1216105197Ssamah_attach(void)
1217105197Ssam{
1218185088Szec
1219190787Szec	xform_register(&ah_xformsw);
1220190787Szec}
1221190787Szec
1222105197SsamSYSINIT(ah_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ah_attach, NULL);
1223