summaryrefslogtreecommitdiffstats
path: root/sys/netipsec/xform_ah.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netipsec/xform_ah.c')
-rw-r--r--sys/netipsec/xform_ah.c312
1 files changed, 128 insertions, 184 deletions
diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c
index 0d39eeb..e5f8031 100644
--- a/sys/netipsec/xform_ah.c
+++ b/sys/netipsec/xform_ah.c
@@ -46,7 +46,7 @@
#include <sys/syslog.h>
#include <sys/kernel.h>
#include <sys/lock.h>
-#include <sys/rwlock.h>
+#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <net/if.h>
@@ -113,7 +113,7 @@ static int ah_input_cb(struct cryptop*);
static int ah_output_cb(struct cryptop*);
int
-xform_ah_authsize(struct auth_hash *esph)
+xform_ah_authsize(const struct auth_hash *esph)
{
int alen;
@@ -141,43 +141,6 @@ xform_ah_authsize(struct auth_hash *esph)
return alen;
}
-/*
- * NB: this is public for use by the PF_KEY support.
- */
-struct auth_hash *
-ah_algorithm_lookup(int alg)
-{
- if (alg > SADB_AALG_MAX)
- return NULL;
- switch (alg) {
- case SADB_X_AALG_NULL:
- return &auth_hash_null;
- case SADB_AALG_MD5HMAC:
- return &auth_hash_hmac_md5;
- case SADB_AALG_SHA1HMAC:
- return &auth_hash_hmac_sha1;
- case SADB_X_AALG_RIPEMD160HMAC:
- return &auth_hash_hmac_ripemd_160;
- case SADB_X_AALG_MD5:
- return &auth_hash_key_md5;
- case SADB_X_AALG_SHA:
- return &auth_hash_key_sha1;
- case SADB_X_AALG_SHA2_256:
- return &auth_hash_hmac_sha2_256;
- case SADB_X_AALG_SHA2_384:
- return &auth_hash_hmac_sha2_384;
- case SADB_X_AALG_SHA2_512:
- return &auth_hash_hmac_sha2_512;
- case SADB_X_AALG_AES128GMAC:
- return &auth_hash_nist_gmac_aes_128;
- case SADB_X_AALG_AES192GMAC:
- return &auth_hash_nist_gmac_aes_192;
- case SADB_X_AALG_AES256GMAC:
- return &auth_hash_nist_gmac_aes_256;
- }
- return NULL;
-}
-
size_t
ah_hdrsiz(struct secasvar *sav)
{
@@ -202,10 +165,10 @@ ah_hdrsiz(struct secasvar *sav)
int
ah_init0(struct secasvar *sav, struct xformsw *xsp, struct cryptoini *cria)
{
- struct auth_hash *thash;
+ const struct auth_hash *thash;
int keylen;
- thash = ah_algorithm_lookup(sav->alg_auth);
+ thash = auth_algorithm_lookup(sav->alg_auth);
if (thash == NULL) {
DPRINTF(("%s: unsupported authentication algorithm %u\n",
__func__, sav->alg_auth));
@@ -582,13 +545,13 @@ static int
ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
{
char buf[128];
- struct auth_hash *ahx;
- struct tdb_crypto *tc;
- struct newah *ah;
- int hl, rplen, authsize, error;
-
+ const struct auth_hash *ahx;
struct cryptodesc *crda;
struct cryptop *crp;
+ struct xform_data *xd;
+ struct newah *ah;
+ uint64_t cryptoid;
+ int hl, rplen, authsize, error;
IPSEC_ASSERT(sav != NULL, ("null SA"));
IPSEC_ASSERT(sav->key_auth != NULL, ("null authentication key"));
@@ -608,13 +571,18 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
}
/* Check replay window, if applicable. */
- if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) {
+ SECASVAR_LOCK(sav);
+ if (sav->replay != NULL && sav->replay->wsize != 0 &&
+ ipsec_chkreplay(ntohl(ah->ah_seq), sav) == 0) {
+ SECASVAR_UNLOCK(sav);
AHSTAT_INC(ahs_replay);
DPRINTF(("%s: packet replay failure: %s\n", __func__,
- ipsec_logsastr(sav, buf, sizeof(buf))));
+ ipsec_sa2str(sav, buf, sizeof(buf))));
m_freem(m);
- return ENOBUFS;
+ return (EACCES);
}
+ cryptoid = sav->tdb_cryptoid;
+ SECASVAR_UNLOCK(sav);
/* Verify AH header length. */
hl = ah->ah_len * sizeof (u_int32_t);
@@ -635,7 +603,8 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
/* Get crypto descriptors. */
crp = crypto_getreq(1);
if (crp == NULL) {
- DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
+ DPRINTF(("%s: failed to acquire crypto descriptor\n",
+ __func__));
AHSTAT_INC(ahs_crypto);
m_freem(m);
return ENOBUFS;
@@ -654,10 +623,10 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
crda->crd_key = sav->key_auth->key_data;
/* Allocate IPsec-specific opaque crypto info. */
- tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto) +
- skip + rplen + authsize, M_XDATA, M_NOWAIT | M_ZERO);
- if (tc == NULL) {
- DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
+ xd = malloc(sizeof(*xd) + skip + rplen + authsize, M_XDATA,
+ M_NOWAIT | M_ZERO);
+ if (xd == NULL) {
+ DPRINTF(("%s: failed to allocate xform_data\n", __func__));
AHSTAT_INC(ahs_crypto);
crypto_freereq(crp);
m_freem(m);
@@ -668,7 +637,7 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
* Save the authenticator, the skipped portion of the packet,
* and the AH header.
*/
- m_copydata(m, 0, skip + rplen + authsize, (caddr_t)(tc+1));
+ m_copydata(m, 0, skip + rplen + authsize, (caddr_t)(xd + 1));
/* Zeroize the authenticator on the packet. */
m_copyback(m, skip + rplen, authsize, ipseczeroes);
@@ -679,7 +648,7 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
if (error != 0) {
/* NB: mbuf is free'd by ah_massage_headers */
AHSTAT_INC(ahs_hdrops);
- free(tc, M_XDATA);
+ free(xd, M_XDATA);
crypto_freereq(crp);
return (error);
}
@@ -689,18 +658,15 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
crp->crp_buf = (caddr_t) m;
crp->crp_callback = ah_input_cb;
- crp->crp_sid = sav->tdb_cryptoid;
- crp->crp_opaque = (caddr_t) tc;
+ crp->crp_sid = cryptoid;
+ crp->crp_opaque = (caddr_t) xd;
/* These are passed as-is to the callback. */
- tc->tc_spi = sav->spi;
- tc->tc_dst = sav->sah->saidx.dst;
- tc->tc_proto = sav->sah->saidx.proto;
- tc->tc_nxt = ah->ah_nxt;
- tc->tc_protoff = protoff;
- tc->tc_skip = skip;
- KEY_ADDREFSA(sav);
- tc->tc_sav = sav;
+ xd->sav = sav;
+ xd->nxt = ah->ah_nxt;
+ xd->protoff = protoff;
+ xd->skip = skip;
+ xd->cryptoid = cryptoid;
return (crypto_dispatch(crp));
}
@@ -710,46 +676,43 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
static int
ah_input_cb(struct cryptop *crp)
{
- char buf[INET6_ADDRSTRLEN];
- int rplen, error, skip, protoff;
+ char buf[IPSEC_ADDRSTRLEN];
unsigned char calc[AH_ALEN_MAX];
+ const struct auth_hash *ahx;
struct mbuf *m;
struct cryptodesc *crd;
- struct auth_hash *ahx;
- struct tdb_crypto *tc;
+ struct xform_data *xd;
struct secasvar *sav;
struct secasindex *saidx;
- u_int8_t nxt;
caddr_t ptr;
- int authsize;
+ uint64_t cryptoid;
+ int authsize, rplen, error, skip, protoff;
+ uint8_t nxt;
crd = crp->crp_desc;
-
- tc = (struct tdb_crypto *) crp->crp_opaque;
- IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!"));
- skip = tc->tc_skip;
- nxt = tc->tc_nxt;
- protoff = tc->tc_protoff;
m = (struct mbuf *) crp->crp_buf;
-
- sav = tc->tc_sav;
- IPSEC_ASSERT(sav != NULL, ("null SA!"));
-
+ xd = (struct xform_data *) crp->crp_opaque;
+ sav = xd->sav;
+ skip = xd->skip;
+ nxt = xd->nxt;
+ protoff = xd->protoff;
+ cryptoid = xd->cryptoid;
saidx = &sav->sah->saidx;
IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
saidx->dst.sa.sa_family == AF_INET6,
("unexpected protocol family %u", saidx->dst.sa.sa_family));
- ahx = (struct auth_hash *) sav->tdb_authalgxform;
+ ahx = sav->tdb_authalgxform;
/* Check for crypto errors. */
if (crp->crp_etype) {
- if (sav->tdb_cryptoid != 0)
- sav->tdb_cryptoid = crp->crp_sid;
-
- if (crp->crp_etype == EAGAIN)
+ if (crp->crp_etype == EAGAIN) {
+ /* Reset the session ID */
+ if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
+ crypto_freesession(cryptoid);
+ xd->cryptoid = crp->crp_sid;
return (crypto_dispatch(crp));
-
+ }
AHSTAT_INC(ahs_noxform);
DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
error = crp->crp_etype;
@@ -776,7 +739,7 @@ ah_input_cb(struct cryptop *crp)
m_copydata(m, skip + rplen, authsize, calc);
/* Verify authenticator. */
- ptr = (caddr_t) (tc + 1);
+ ptr = (caddr_t) (xd + 1);
if (timingsafe_bcmp(ptr + skip + rplen, calc, authsize)) {
DPRINTF(("%s: authentication hash mismatch for packet "
"in SA %s/%08lx\n", __func__,
@@ -787,11 +750,11 @@ ah_input_cb(struct cryptop *crp)
goto bad;
}
/* Fix the Next Protocol field. */
- ((u_int8_t *) ptr)[protoff] = nxt;
+ ((uint8_t *) ptr)[protoff] = nxt;
/* Copyback the saved (uncooked) network headers. */
m_copyback(m, 0, skip, ptr);
- free(tc, M_XDATA), tc = NULL; /* No longer needed */
+ free(xd, M_XDATA), xd = NULL; /* No longer needed */
/*
* Header is now authenticated.
@@ -806,11 +769,14 @@ ah_input_cb(struct cryptop *crp)
m_copydata(m, skip + offsetof(struct newah, ah_seq),
sizeof (seq), (caddr_t) &seq);
+ SECASVAR_LOCK(sav);
if (ipsec_updatereplay(ntohl(seq), sav)) {
+ SECASVAR_UNLOCK(sav);
AHSTAT_INC(ahs_replay);
- error = ENOBUFS; /*XXX as above*/
+ error = EACCES;
goto bad;
}
+ SECASVAR_UNLOCK(sav);
}
/*
@@ -840,41 +806,38 @@ ah_input_cb(struct cryptop *crp)
panic("%s: Unexpected address family: %d saidx=%p", __func__,
saidx->dst.sa.sa_family, saidx);
}
-
- KEY_FREESAV(&sav);
return error;
bad:
if (sav)
- KEY_FREESAV(&sav);
+ key_freesav(&sav);
if (m != NULL)
m_freem(m);
- if (tc != NULL)
- free(tc, M_XDATA);
+ if (xd != NULL)
+ free(xd, M_XDATA);
if (crp != NULL)
crypto_freereq(crp);
return error;
}
/*
- * AH output routine, called by ipsec[46]_process_packet().
+ * AH output routine, called by ipsec[46]_perform_request().
*/
static int
-ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
- int skip, int protoff)
+ah_output(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
+ u_int idx, int skip, int protoff)
{
- char buf[INET6_ADDRSTRLEN];
- struct secasvar *sav;
- struct auth_hash *ahx;
+ char buf[IPSEC_ADDRSTRLEN];
+ const struct auth_hash *ahx;
struct cryptodesc *crda;
- struct tdb_crypto *tc;
+ struct xform_data *xd;
struct mbuf *mi;
struct cryptop *crp;
- u_int16_t iplen;
- int error, rplen, authsize, maxpacketsize, roff;
- u_int8_t prot;
struct newah *ah;
+ uint64_t cryptoid;
+ uint16_t iplen;
+ int error, rplen, authsize, maxpacketsize, roff;
+ uint8_t prot;
- sav = isr->sav;
IPSEC_ASSERT(sav != NULL, ("null SA"));
ahx = sav->tdb_authalgxform;
IPSEC_ASSERT(ahx != NULL, ("null authentication xform"));
@@ -960,14 +923,16 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
m_copyback(m, skip + rplen, authsize, ipseczeroes);
/* Insert packet replay counter, as requested. */
+ SECASVAR_LOCK(sav);
if (sav->replay) {
if (sav->replay->count == ~0 &&
(sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
+ SECASVAR_UNLOCK(sav);
DPRINTF(("%s: replay counter wrapped for SA %s/%08lx\n",
__func__, ipsec_address(&sav->sah->saidx.dst, buf,
sizeof(buf)), (u_long) ntohl(sav->spi)));
AHSTAT_INC(ahs_wrap);
- error = EINVAL;
+ error = EACCES;
goto bad;
}
#ifdef REGRESSION
@@ -977,6 +942,8 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
sav->replay->count++;
ah->ah_seq = htonl(sav->replay->count);
}
+ cryptoid = sav->tdb_cryptoid;
+ SECASVAR_UNLOCK(sav);
/* Get crypto descriptors. */
crp = crypto_getreq(1);
@@ -989,7 +956,6 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
}
crda = crp->crp_desc;
-
crda->crd_skip = 0;
crda->crd_inject = skip + rplen;
crda->crd_len = m->m_pkthdr.len;
@@ -1000,18 +966,18 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
crda->crd_klen = _KEYBITS(sav->key_auth);
/* Allocate IPsec-specific opaque crypto info. */
- tc = (struct tdb_crypto *) malloc(
- sizeof(struct tdb_crypto) + skip, M_XDATA, M_NOWAIT|M_ZERO);
- if (tc == NULL) {
+ xd = malloc(sizeof(struct xform_data) + skip, M_XDATA,
+ M_NOWAIT | M_ZERO);
+ if (xd == NULL) {
crypto_freereq(crp);
- DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
+ DPRINTF(("%s: failed to allocate xform_data\n", __func__));
AHSTAT_INC(ahs_crypto);
error = ENOBUFS;
goto bad;
}
/* Save the skipped portion of the packet. */
- m_copydata(m, 0, skip, (caddr_t) (tc + 1));
+ m_copydata(m, 0, skip, (caddr_t) (xd + 1));
/*
* Fix IP header length on the header used for
@@ -1021,7 +987,7 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
switch (sav->sah->saidx.dst.sa.sa_family) {
#ifdef INET
case AF_INET:
- bcopy(((caddr_t)(tc + 1)) +
+ bcopy(((caddr_t)(xd + 1)) +
offsetof(struct ip, ip_len),
(caddr_t) &iplen, sizeof(u_int16_t));
iplen = htons(ntohs(iplen) + rplen + authsize);
@@ -1032,29 +998,29 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
#ifdef INET6
case AF_INET6:
- bcopy(((caddr_t)(tc + 1)) +
+ bcopy(((caddr_t)(xd + 1)) +
offsetof(struct ip6_hdr, ip6_plen),
- (caddr_t) &iplen, sizeof(u_int16_t));
+ (caddr_t) &iplen, sizeof(uint16_t));
iplen = htons(ntohs(iplen) + rplen + authsize);
m_copyback(m, offsetof(struct ip6_hdr, ip6_plen),
- sizeof(u_int16_t), (caddr_t) &iplen);
+ sizeof(uint16_t), (caddr_t) &iplen);
break;
#endif /* INET6 */
}
/* Fix the Next Header field in saved header. */
- ((u_int8_t *) (tc + 1))[protoff] = IPPROTO_AH;
+ ((uint8_t *) (xd + 1))[protoff] = IPPROTO_AH;
/* Update the Next Protocol field in the IP header. */
prot = IPPROTO_AH;
- m_copyback(m, protoff, sizeof(u_int8_t), (caddr_t) &prot);
+ m_copyback(m, protoff, sizeof(uint8_t), (caddr_t) &prot);
/* "Massage" the packet headers for crypto processing. */
error = ah_massage_headers(&m, sav->sah->saidx.dst.sa.sa_family,
skip, ahx->type, 1);
if (error != 0) {
m = NULL; /* mbuf was free'd by ah_massage_headers. */
- free(tc, M_XDATA);
+ free(xd, M_XDATA);
crypto_freereq(crp);
goto bad;
}
@@ -1064,19 +1030,15 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
crp->crp_buf = (caddr_t) m;
crp->crp_callback = ah_output_cb;
- crp->crp_sid = sav->tdb_cryptoid;
- crp->crp_opaque = (caddr_t) tc;
+ crp->crp_sid = cryptoid;
+ crp->crp_opaque = (caddr_t) xd;
/* These are passed as-is to the callback. */
- key_addref(isr->sp);
- tc->tc_isr = isr;
- KEY_ADDREFSA(sav);
- tc->tc_sav = sav;
- tc->tc_spi = sav->spi;
- tc->tc_dst = sav->sah->saidx.dst;
- tc->tc_proto = sav->sah->saidx.proto;
- tc->tc_skip = skip;
- tc->tc_protoff = protoff;
+ xd->sp = sp;
+ xd->sav = sav;
+ xd->skip = skip;
+ xd->idx = idx;
+ xd->cryptoid = cryptoid;
return crypto_dispatch(crp);
bad:
@@ -1091,45 +1053,37 @@ bad:
static int
ah_output_cb(struct cryptop *crp)
{
- int skip, protoff, error;
- struct tdb_crypto *tc;
- struct ipsecrequest *isr;
+ struct xform_data *xd;
+ struct secpolicy *sp;
struct secasvar *sav;
struct mbuf *m;
+ uint64_t cryptoid;
caddr_t ptr;
+ u_int idx;
+ int skip, error;
- tc = (struct tdb_crypto *) crp->crp_opaque;
- IPSEC_ASSERT(tc != NULL, ("null opaque data area!"));
- skip = tc->tc_skip;
- protoff = tc->tc_protoff;
- ptr = (caddr_t) (tc + 1);
m = (struct mbuf *) crp->crp_buf;
-
- isr = tc->tc_isr;
- IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp"));
- IPSECREQUEST_LOCK(isr);
- sav = tc->tc_sav;
- /* With the isr lock released SA pointer can be updated. */
- if (sav != isr->sav) {
- AHSTAT_INC(ahs_notdb);
- DPRINTF(("%s: SA expired while in crypto\n", __func__));
- error = ENOBUFS; /*XXX*/
- goto bad;
- }
+ xd = (struct xform_data *) crp->crp_opaque;
+ sp = xd->sp;
+ sav = xd->sav;
+ skip = xd->skip;
+ idx = xd->idx;
+ cryptoid = xd->cryptoid;
+ ptr = (caddr_t) (xd + 1);
/* Check for crypto errors. */
if (crp->crp_etype) {
- if (sav->tdb_cryptoid != 0)
- sav->tdb_cryptoid = crp->crp_sid;
-
if (crp->crp_etype == EAGAIN) {
- IPSECREQUEST_UNLOCK(isr);
+ /* Reset the session ID */
+ if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
+ crypto_freesession(cryptoid);
+ xd->cryptoid = crp->crp_sid;
return (crypto_dispatch(crp));
}
-
AHSTAT_INC(ahs_noxform);
DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
error = crp->crp_etype;
+ m_freem(m);
goto bad;
}
@@ -1140,18 +1094,15 @@ ah_output_cb(struct cryptop *crp)
error = EINVAL;
goto bad;
}
- AHSTAT_INC(ahs_hist[sav->alg_auth]);
-
/*
* Copy original headers (with the new protocol number) back
* in place.
*/
m_copyback(m, 0, skip, ptr);
- /* No longer needed. */
- free(tc, M_XDATA);
+ free(xd, M_XDATA);
crypto_freereq(crp);
-
+ AHSTAT_INC(ahs_hist[sav->alg_auth]);
#ifdef REGRESSION
/* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */
if (V_ipsec_integrity) {
@@ -1167,33 +1118,26 @@ ah_output_cb(struct cryptop *crp)
#endif
/* NB: m is reclaimed by ipsec_process_done. */
- error = ipsec_process_done(m, isr);
- KEY_FREESAV(&sav);
- IPSECREQUEST_UNLOCK(isr);
- KEY_FREESP(&isr->sp);
+ error = ipsec_process_done(m, sp, sav, idx);
return (error);
bad:
- if (sav)
- KEY_FREESAV(&sav);
- IPSECREQUEST_UNLOCK(isr);
- KEY_FREESP(&isr->sp);
- if (m)
- m_freem(m);
- free(tc, M_XDATA);
+ free(xd, M_XDATA);
crypto_freereq(crp);
+ key_freesav(&sav);
+ key_freesp(&sp);
return (error);
}
static struct xformsw ah_xformsw = {
- XF_AH, XFT_AUTH, "IPsec AH",
- ah_init, ah_zeroize, ah_input, ah_output,
+ .xf_type = XF_AH,
+ .xf_name = "IPsec AH",
+ .xf_init = ah_init,
+ .xf_zeroize = ah_zeroize,
+ .xf_input = ah_input,
+ .xf_output = ah_output,
};
-static void
-ah_attach(void)
-{
-
- xform_register(&ah_xformsw);
-}
-
-SYSINIT(ah_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ah_attach, NULL);
+SYSINIT(ah_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
+ xform_attach, &ah_xformsw);
+SYSUNINIT(ah_xform_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
+ xform_detach, &ah_xformsw);
OpenPOWER on IntegriCloud