svn commit: r366758 - head/sys/netipsec
Marcin Wojtas
mw at FreeBSD.org
Fri Oct 16 11:25:46 UTC 2020
Author: mw
Date: Fri Oct 16 11:25:45 2020
New Revision: 366758
URL: https://svnweb.freebsd.org/changeset/base/366758
Log:
Add support for IPsec ESN and pass relevant information to crypto layer
Implement support for including IPsec ESN (Extended Sequence Number) to
both encrypt and authenticate mode (eg. AES-CBC and SHA256) and combined
mode (eg. AES-GCM). Both ESP and AH protocols are updated. Additionally
pass relevant information about ESN to crypto layer.
For the ETA mode the ESN is stored in separate crp_esn buffer because
the high-order 32 bits of the sequence number are appended after the
Next Header (RFC 4303).
For the AEAD modes the high-order 32 bits of the sequence number
[e.g. RFC 4106, Chapter 5 AAD Construction] are included as part of
crp_aad (SPI + ESN (32 high order bits) + Seq nr (32 low order bits)).
Submitted by: Grzegorz Jaszczyk <jaz at semihalf.com>
Patryk Duda <pdk at semihalf.com>
Reviewed by: jhb, gnn
Differential revision: https://reviews.freebsd.org/D22369
Obtained from: Semihalf
Sponsored by: Stormshield
Modified:
head/sys/netipsec/keydb.h
head/sys/netipsec/xform_ah.c
head/sys/netipsec/xform_esp.c
Modified: head/sys/netipsec/keydb.h
==============================================================================
--- head/sys/netipsec/keydb.h Fri Oct 16 11:24:12 2020 (r366757)
+++ head/sys/netipsec/keydb.h Fri Oct 16 11:25:45 2020 (r366758)
@@ -197,6 +197,8 @@ struct secasvar {
#define SAV_ISCTR(_sav) ((_sav)->alg_enc == SADB_X_EALG_AESCTR)
#define SAV_ISCTRORGCM(_sav) (SAV_ISCTR((_sav)) || SAV_ISGCM((_sav)))
+#define IPSEC_SEQH_SHIFT 32
+
/* Replay prevention, protected by SECASVAR_LOCK:
* (m) locked by mtx
* (c) read only except during creation / free
Modified: head/sys/netipsec/xform_ah.c
==============================================================================
--- head/sys/netipsec/xform_ah.c Fri Oct 16 11:24:12 2020 (r366757)
+++ head/sys/netipsec/xform_ah.c Fri Oct 16 11:25:45 2020 (r366758)
@@ -236,6 +236,10 @@ ah_init(struct secasvar *sav, struct xformsw *xsp)
memset(&csp, 0, sizeof(csp));
csp.csp_mode = CSP_MODE_DIGEST;
+
+ if (sav->flags & SADB_X_SAFLAGS_ESN)
+ csp.csp_flags |= CSP_F_ESN;
+
error = ah_init0(sav, xsp, &csp);
return error ? error :
crypto_newsession(&sav->tdb_cryptoid, &csp, V_crypto_support);
@@ -654,6 +658,12 @@ ah_input(struct mbuf *m, struct secasvar *sav, int ski
crp->crp_callback = ah_input_cb;
crp->crp_opaque = xd;
+ if (sav->flags & SADB_X_SAFLAGS_ESN &&
+ sav->replay != NULL && sav->replay->wsize != 0) {
+ seqh = htonl(seqh);
+ memcpy(crp->crp_esn, &seqh, sizeof(seqh));
+ }
+
/* These are passed as-is to the callback. */
xd->sav = sav;
xd->nxt = hl;
@@ -834,6 +844,7 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct
uint16_t iplen;
int error, rplen, authsize, ahsize, maxpacketsize, roff;
uint8_t prot;
+ uint32_t seqh;
IPSEC_ASSERT(sav != NULL, ("null SA"));
ahx = sav->tdb_authalgxform;
@@ -1030,6 +1041,11 @@ ah_output(struct mbuf *m, struct secpolicy *sp, struct
crypto_use_mbuf(crp, m);
crp->crp_callback = ah_output_cb;
crp->crp_opaque = xd;
+
+ if (sav->flags & SADB_X_SAFLAGS_ESN && sav->replay != NULL) {
+ seqh = htonl((uint32_t)(sav->replay->count >> IPSEC_SEQH_SHIFT));
+ memcpy(crp->crp_esn, &seqh, sizeof(seqh));
+ }
/* These are passed as-is to the callback. */
xd->sp = sp;
Modified: head/sys/netipsec/xform_esp.c
==============================================================================
--- head/sys/netipsec/xform_esp.c Fri Oct 16 11:24:12 2020 (r366757)
+++ head/sys/netipsec/xform_esp.c Fri Oct 16 11:25:45 2020 (r366758)
@@ -80,6 +80,8 @@
#include <opencrypto/cryptodev.h>
#include <opencrypto/xform.h>
+#define SPI_SIZE 4
+
VNET_DEFINE(int, esp_enable) = 1;
VNET_DEFINE_STATIC(int, esp_ctr_compatibility) = 1;
#define V_esp_ctr_compatibility VNET(esp_ctr_compatibility)
@@ -219,9 +221,13 @@ esp_init(struct secasvar *sav, struct xformsw *xsp)
return EINVAL;
}
csp.csp_mode = CSP_MODE_AEAD;
- } else if (sav->alg_auth != 0)
+ if (sav->flags & SADB_X_SAFLAGS_ESN)
+ csp.csp_flags |= CSP_F_SEPARATE_AAD;
+ } else if (sav->alg_auth != 0) {
csp.csp_mode = CSP_MODE_ETA;
- else
+ if (sav->flags & SADB_X_SAFLAGS_ESN)
+ csp.csp_flags |= CSP_F_ESN;
+ } else
csp.csp_mode = CSP_MODE_CIPHER;
/* Initialize crypto session. */
@@ -263,6 +269,7 @@ esp_input(struct mbuf *m, struct secasvar *sav, int sk
crypto_session_t cryptoid;
int alen, error, hlen, plen;
uint32_t seqh;
+ const struct crypto_session_params *csp;
IPSEC_ASSERT(sav != NULL, ("null SA"));
IPSEC_ASSERT(sav->tdb_encalgxform != NULL, ("null encoding xform"));
@@ -329,6 +336,7 @@ esp_input(struct mbuf *m, struct secasvar *sav, int sk
error = EACCES;
goto bad;
}
+ seqh = htonl(seqh);
}
cryptoid = sav->tdb_cryptoid;
SECASVAR_UNLOCK(sav);
@@ -350,19 +358,49 @@ esp_input(struct mbuf *m, struct secasvar *sav, int sk
xd = malloc(sizeof(*xd), M_XDATA, M_NOWAIT | M_ZERO);
if (xd == NULL) {
DPRINTF(("%s: failed to allocate xform_data\n", __func__));
- ESPSTAT_INC(esps_crypto);
- crypto_freereq(crp);
- error = ENOBUFS;
- goto bad;
+ goto xd_fail;
}
if (esph != NULL) {
crp->crp_op = CRYPTO_OP_VERIFY_DIGEST;
- crp->crp_aad_start = skip;
if (SAV_ISGCM(sav))
crp->crp_aad_length = 8; /* RFC4106 5, SPI + SN */
else
crp->crp_aad_length = hlen;
+
+ csp = crypto_get_params(crp->crp_session);
+ if ((csp->csp_flags & CSP_F_SEPARATE_AAD) &&
+ (sav->replay != NULL) && (sav->replay->wsize != 0)) {
+ int aad_skip;
+
+ crp->crp_aad_length += sizeof(seqh);
+ crp->crp_aad = malloc(crp->crp_aad_length, M_XDATA, M_NOWAIT);
+ if (crp->crp_aad == NULL) {
+ DPRINTF(("%s: failed to allocate xform_data\n",
+ __func__));
+ goto crp_aad_fail;
+ }
+
+ /* SPI */
+ m_copydata(m, skip, SPI_SIZE, crp->crp_aad);
+ aad_skip = SPI_SIZE;
+
+ /* ESN */
+ bcopy(&seqh, (char *)crp->crp_aad + aad_skip, sizeof(seqh));
+ aad_skip += sizeof(seqh);
+
+ /* Rest of aad */
+ if (crp->crp_aad_length - aad_skip > 0)
+ m_copydata(m, skip + SPI_SIZE,
+ crp->crp_aad_length - aad_skip,
+ (char *)crp->crp_aad + aad_skip);
+ } else
+ crp->crp_aad_start = skip;
+
+ if (csp->csp_flags & CSP_F_ESN &&
+ sav->replay != NULL && sav->replay->wsize != 0)
+ memcpy(crp->crp_esn, &seqh, sizeof(seqh));
+
crp->crp_digest_start = m->m_pkthdr.len - alen;
}
@@ -423,6 +461,13 @@ esp_input(struct mbuf *m, struct secasvar *sav, int sk
crp->crp_iv_start = skip + hlen - sav->ivlen;
return (crypto_dispatch(crp));
+
+crp_aad_fail:
+ free(xd, M_XDATA);
+xd_fail:
+ crypto_freereq(crp);
+ ESPSTAT_INC(esps_crypto);
+ error = ENOBUFS;
bad:
m_freem(m);
key_freesav(&sav);
@@ -505,6 +550,7 @@ esp_input_cb(struct cryptop *crp)
/* Release the crypto descriptors */
free(xd, M_XDATA), xd = NULL;
+ free(crp->crp_aad, M_XDATA), crp->crp_aad = NULL;
crypto_freereq(crp), crp = NULL;
/*
@@ -614,8 +660,10 @@ bad:
m_freem(m);
if (xd != NULL)
free(xd, M_XDATA);
- if (crp != NULL)
+ if (crp != NULL) {
+ free(crp->crp_aad, M_XDATA);
crypto_freereq(crp);
+ }
return error;
}
/*
@@ -639,6 +687,8 @@ esp_output(struct mbuf *m, struct secpolicy *sp, struc
int hlen, rlen, padding, blks, alen, i, roff;
int error, maxpacketsize;
uint8_t prot;
+ uint32_t seqh;
+ const struct crypto_session_params *csp;
IPSEC_ASSERT(sav != NULL, ("null SA"));
esph = sav->tdb_authalgxform;
@@ -745,6 +795,8 @@ esp_output(struct mbuf *m, struct secpolicy *sp, struc
bcopy((caddr_t) &replay, mtod(mo, caddr_t) + roff +
sizeof(uint32_t), sizeof(uint32_t));
+
+ seqh = htonl((uint32_t)(sav->replay->count >> IPSEC_SEQH_SHIFT));
}
cryptoid = sav->tdb_cryptoid;
if (SAV_ISCTRORGCM(sav))
@@ -801,13 +853,10 @@ esp_output(struct mbuf *m, struct secpolicy *sp, struc
}
/* IPsec-specific opaque crypto info. */
- xd = malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO);
+ xd = malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO);
if (xd == NULL) {
- crypto_freereq(crp);
DPRINTF(("%s: failed to allocate xform_data\n", __func__));
- ESPSTAT_INC(esps_crypto);
- error = ENOBUFS;
- goto bad;
+ goto xd_fail;
}
/* Encryption descriptor. */
@@ -855,15 +904,54 @@ esp_output(struct mbuf *m, struct secpolicy *sp, struc
if (esph) {
/* Authentication descriptor. */
crp->crp_op |= CRYPTO_OP_COMPUTE_DIGEST;
- crp->crp_aad_start = skip;
if (SAV_ISGCM(sav))
crp->crp_aad_length = 8; /* RFC4106 5, SPI + SN */
else
crp->crp_aad_length = hlen;
+
+ csp = crypto_get_params(crp->crp_session);
+ if (csp->csp_flags & CSP_F_SEPARATE_AAD &&
+ sav->replay != NULL) {
+ int aad_skip;
+
+ crp->crp_aad_length += sizeof(seqh);
+ crp->crp_aad = malloc(crp->crp_aad_length, M_XDATA, M_NOWAIT);
+ if (crp->crp_aad == NULL) {
+ DPRINTF(("%s: failed to allocate xform_data\n",
+ __func__));
+ goto crp_aad_fail;
+ }
+
+ /* SPI */
+ m_copydata(m, skip, SPI_SIZE, crp->crp_aad);
+ aad_skip = SPI_SIZE;
+
+ /* ESN */
+ bcopy(&seqh, (char *)crp->crp_aad + aad_skip, sizeof(seqh));
+ aad_skip += sizeof(seqh);
+
+ /* Rest of aad */
+ if (crp->crp_aad_length - aad_skip > 0)
+ m_copydata(m, skip + SPI_SIZE,
+ crp->crp_aad_length - aad_skip,
+ (char *)crp->crp_aad + aad_skip);
+ } else
+ crp->crp_aad_start = skip;
+
+ if (csp->csp_flags & CSP_F_ESN && sav->replay != NULL)
+ memcpy(crp->crp_esn, &seqh, sizeof(seqh));
+
crp->crp_digest_start = m->m_pkthdr.len - alen;
}
return crypto_dispatch(crp);
+
+crp_aad_fail:
+ free(xd, M_XDATA);
+xd_fail:
+ crypto_freereq(crp);
+ ESPSTAT_INC(esps_crypto);
+ error = ENOBUFS;
bad:
if (m)
m_freem(m);
@@ -918,6 +1006,7 @@ esp_output_cb(struct cryptop *crp)
goto bad;
}
free(xd, M_XDATA);
+ free(crp->crp_aad, M_XDATA);
crypto_freereq(crp);
ESPSTAT_INC(esps_hist[sav->alg_enc]);
if (sav->tdb_authalgxform != NULL)
@@ -951,6 +1040,7 @@ esp_output_cb(struct cryptop *crp)
bad:
CURVNET_RESTORE();
free(xd, M_XDATA);
+ free(crp->crp_aad, M_XDATA);
crypto_freereq(crp);
key_freesav(&sav);
key_freesp(&sp);
More information about the svn-src-all
mailing list