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-head mailing list