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 <j...@semihalf.com>
                          Patryk Duda <p...@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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to