Author: jhb
Date: Mon Jun 22 23:20:43 2020
New Revision: 362517
URL: https://svnweb.freebsd.org/changeset/base/362517

Log:
  Add support to the crypto framework for separate AAD buffers.
  
  This permits requests to provide the AAD in a separate side buffer
  instead of as a region in the crypto request input buffer.  This is
  useful when the main data buffer might not contain the full AAD
  (e.g. for TLS or IPsec with ESN).
  
  Unlike separate IVs which are constrained in size and stored in an
  array in struct cryptop, separate AAD is provided by the caller
  setting a new crp_aad pointer to the buffer.  The caller must ensure
  the pointer remains valid and the buffer contents static until the
  request is completed (e.g. when the callback routine is invoked).
  
  As with separate output buffers, not all drivers support this feature.
  Consumers must request use of this feature via a new session flag.
  
  To aid in driver testing, kern.crypto.cryptodev_separate_aad can be
  set to force /dev/crypto requests to use a separate AAD buffer.
  
  Discussed with:       cem
  Sponsored by: Chelsio Communications
  Differential Revision:        https://reviews.freebsd.org/D25288

Modified:
  head/share/man/man9/crypto_request.9
  head/share/man/man9/crypto_session.9
  head/sys/opencrypto/crypto.c
  head/sys/opencrypto/cryptodev.c
  head/sys/opencrypto/cryptodev.h
  head/sys/opencrypto/cryptosoft.c

Modified: head/share/man/man9/crypto_request.9
==============================================================================
--- head/share/man/man9/crypto_request.9        Mon Jun 22 23:13:14 2020        
(r362516)
+++ head/share/man/man9/crypto_request.9        Mon Jun 22 23:20:43 2020        
(r362517)
@@ -30,7 +30,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 25, 2020
+.Dd June 22, 2020
 .Dt CRYPTO_REQUEST 9
 .Os
 .Sh NAME
@@ -181,7 +181,7 @@ The following regions are defined:
 .Bl -column "Payload Output" "Input/Output"
 .It Sy Region Ta Sy Buffer Ta Sy Description
 .It AAD Ta Input Ta
-Additional Authenticated Data
+Embedded Additional Authenticated Data
 .It IV Ta Input Ta
 Embedded IV or nonce
 .It Payload Ta Input Ta
@@ -256,6 +256,15 @@ If the digests do not match,
 fail the request with
 .Er EBADMSG .
 .El
+.Ss Request AAD
+AEAD and Encrypt-then-Authenticate requests may optionally include
+Additional Authenticated Data.
+AAD may either be supplied in the AAD region of the input buffer or
+as a single buffer pointed to by
+.Fa crp_aad .
+In either case,
+.Fa crp_aad_length
+always indicates the amount of AAD in bytes.
 .Ss Request IV and/or Nonce
 Some cryptographic operations require an IV or nonce as an input.
 An IV may be stored either in the IV region of the data buffer or in

Modified: head/share/man/man9/crypto_session.9
==============================================================================
--- head/share/man/man9/crypto_session.9        Mon Jun 22 23:13:14 2020        
(r362516)
+++ head/share/man/man9/crypto_session.9        Mon Jun 22 23:20:43 2020        
(r362517)
@@ -30,7 +30,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 25, 2020
+.Dd June 22, 2020
 .Dt CRYPTO_SESSION 9
 .Os
 .Sh NAME
@@ -194,6 +194,13 @@ that is modified in-place, or requests with separate i
 buffers.
 Sessions without this flag only permit requests with a single buffer that
 is modified in-place.
+.It Dv CSP_F_SEPARATE_AAD
+Support requests that use a separate buffer for AAD rather than providing
+AAD as a region in the input buffer.
+Sessions with this flag set permit requests with AAD passed in either in
+a region of the input buffer or in a single, virtually-contiguous buffer.
+Sessions without this flag only permit requests with AAD passed in as
+a region in the input buffer.
 .El
 .It Fa csp_ivlen
 If either the cipher or authentication algorithms require an explicit

Modified: head/sys/opencrypto/crypto.c
==============================================================================
--- head/sys/opencrypto/crypto.c        Mon Jun 22 23:13:14 2020        
(r362516)
+++ head/sys/opencrypto/crypto.c        Mon Jun 22 23:20:43 2020        
(r362517)
@@ -755,7 +755,8 @@ check_csp(const struct crypto_session_params *csp)
        struct auth_hash *axf;
 
        /* Mode-independent checks. */
-       if ((csp->csp_flags & ~CSP_F_SEPARATE_OUTPUT) != 0)
+       if ((csp->csp_flags & ~(CSP_F_SEPARATE_OUTPUT | CSP_F_SEPARATE_AAD)) !=
+           0)
                return (false);
        if (csp->csp_ivlen < 0 || csp->csp_cipher_klen < 0 ||
            csp->csp_auth_klen < 0 || csp->csp_auth_mlen < 0)
@@ -771,6 +772,8 @@ check_csp(const struct crypto_session_params *csp)
                        return (false);
                if (csp->csp_flags & CSP_F_SEPARATE_OUTPUT)
                        return (false);
+               if (csp->csp_flags & CSP_F_SEPARATE_AAD)
+                       return (false);
                if (csp->csp_cipher_klen != 0 || csp->csp_ivlen != 0 ||
                    csp->csp_auth_alg != 0 || csp->csp_auth_klen != 0 ||
                    csp->csp_auth_mlen != 0)
@@ -779,6 +782,8 @@ check_csp(const struct crypto_session_params *csp)
        case CSP_MODE_CIPHER:
                if (!alg_is_cipher(csp->csp_cipher_alg))
                        return (false);
+               if (csp->csp_flags & CSP_F_SEPARATE_AAD)
+                       return (false);
                if (csp->csp_cipher_alg != CRYPTO_NULL_CBC) {
                        if (csp->csp_cipher_klen == 0)
                                return (false);
@@ -795,6 +800,9 @@ check_csp(const struct crypto_session_params *csp)
                if (csp->csp_cipher_alg != 0 || csp->csp_cipher_klen != 0)
                        return (false);
 
+               if (csp->csp_flags & CSP_F_SEPARATE_AAD)
+                       return (false);
+
                /* IV is optional for digests (e.g. GMAC). */
                if (csp->csp_ivlen >= EALG_MAX_BLOCK_LEN)
                        return (false);
@@ -1306,16 +1314,27 @@ crp_sanity(struct cryptop *crp)
                break;
        }
        if (csp->csp_mode == CSP_MODE_AEAD || csp->csp_mode == CSP_MODE_ETA) {
-               KASSERT(crp->crp_aad_start == 0 ||
-                   crp->crp_aad_start < ilen,
-                   ("invalid AAD start"));
-               KASSERT(crp->crp_aad_length != 0 || crp->crp_aad_start == 0,
-                   ("AAD with zero length and non-zero start"));
-               KASSERT(crp->crp_aad_length == 0 ||
-                   crp->crp_aad_start + crp->crp_aad_length <= ilen,
-                   ("AAD outside input length"));
+               if (crp->crp_aad == NULL) {
+                       KASSERT(crp->crp_aad_start == 0 ||
+                           crp->crp_aad_start < ilen,
+                           ("invalid AAD start"));
+                       KASSERT(crp->crp_aad_length != 0 ||
+                           crp->crp_aad_start == 0,
+                           ("AAD with zero length and non-zero start"));
+                       KASSERT(crp->crp_aad_length == 0 ||
+                           crp->crp_aad_start + crp->crp_aad_length <= ilen,
+                           ("AAD outside input length"));
+               } else {
+                       KASSERT(csp->csp_flags & CSP_F_SEPARATE_AAD,
+                           ("session doesn't support separate AAD buffer"));
+                       KASSERT(crp->crp_aad_start == 0,
+                           ("separate AAD buffer with non-zero AAD start"));
+                       KASSERT(crp->crp_aad_length != 0,
+                           ("separate AAD buffer with zero length"));
+               }
        } else {
-               KASSERT(crp->crp_aad_start == 0 && crp->crp_aad_length == 0,
+               KASSERT(crp->crp_aad == NULL && crp->crp_aad_start == 0 &&
+                   crp->crp_aad_length == 0,
                    ("AAD region in request not supporting AAD"));
        }
        if (csp->csp_ivlen == 0) {

Modified: head/sys/opencrypto/cryptodev.c
==============================================================================
--- head/sys/opencrypto/cryptodev.c     Mon Jun 22 23:13:14 2020        
(r362516)
+++ head/sys/opencrypto/cryptodev.c     Mon Jun 22 23:20:43 2020        
(r362517)
@@ -283,6 +283,7 @@ struct cryptop_data {
 
        char            *buf;
        char            *obuf;
+       char            *aad;
        bool            done;
 };
 
@@ -297,6 +298,11 @@ SYSCTL_BOOL(_kern_crypto, OID_AUTO, cryptodev_use_outp
     &use_outputbuffers, 0,
     "Use separate output buffers for /dev/crypto requests.");
 
+static bool use_separate_aad;
+SYSCTL_BOOL(_kern_crypto, OID_AUTO, cryptodev_separate_aad, CTLFLAG_RW,
+    &use_separate_aad, 0,
+    "Use separate AAD buffer for /dev/crypto requests.");
+
 static int cryptof_ioctl(struct file *, u_long, void *,
                    struct ucred *, struct thread *);
 static int cryptof_stat(struct file *, struct stat *,
@@ -604,6 +610,14 @@ cryptof_ioctl(
                else
                        csp.csp_mode = CSP_MODE_DIGEST;
 
+               switch (csp.csp_mode) {
+               case CSP_MODE_AEAD:
+               case CSP_MODE_ETA:
+                       if (use_separate_aad)
+                               csp.csp_flags |= CSP_F_SEPARATE_AAD;
+                       break;
+               }
+
                if (txform) {
                        csp.csp_cipher_alg = txform->type;
                        csp.csp_cipher_klen = sop->keylen;
@@ -819,14 +833,19 @@ bail:
 static int cryptodev_cb(struct cryptop *);
 
 static struct cryptop_data *
-cod_alloc(struct csession *cse, size_t len, struct thread *td)
+cod_alloc(struct csession *cse, size_t aad_len, size_t len, struct thread *td)
 {
        struct cryptop_data *cod;
 
        cod = malloc(sizeof(struct cryptop_data), M_XDATA, M_WAITOK | M_ZERO);
 
        cod->cse = cse;
-       cod->buf = malloc(len, M_XDATA, M_WAITOK);
+       if (crypto_get_params(cse->cses)->csp_flags & CSP_F_SEPARATE_AAD) {
+               if (aad_len != 0)
+                       cod->aad = malloc(aad_len, M_XDATA, M_WAITOK);
+               cod->buf = malloc(len, M_XDATA, M_WAITOK);
+       } else
+               cod->buf = malloc(aad_len + len, M_XDATA, M_WAITOK);
        if (crypto_get_params(cse->cses)->csp_flags & CSP_F_SEPARATE_OUTPUT)
                cod->obuf = malloc(len, M_XDATA, M_WAITOK);
        return (cod);
@@ -836,6 +855,7 @@ static void
 cod_free(struct cryptop_data *cod)
 {
 
+       free(cod->aad, M_XDATA);
        free(cod->obuf, M_XDATA);
        free(cod->buf, M_XDATA);
        free(cod, M_XDATA);
@@ -881,7 +901,7 @@ cryptodev_op(
                }
        }
 
-       cod = cod_alloc(cse, cop->len + cse->hashsize, td);
+       cod = cod_alloc(cse, 0, cop->len + cse->hashsize, td);
 
        crp = crypto_getreq(cse->cses, M_WAITOK);
 
@@ -1087,29 +1107,38 @@ cryptodev_aead(
                }
        }
 
-       cod = cod_alloc(cse, caead->aadlen + caead->len + cse->hashsize, td);
+       cod = cod_alloc(cse, caead->aadlen, caead->len + cse->hashsize, td);
 
        crp = crypto_getreq(cse->cses, M_WAITOK);
 
-       error = copyin(caead->aad, cod->buf, caead->aadlen);
+       if (cod->aad != NULL)
+               error = copyin(caead->aad, cod->aad, caead->aadlen);
+       else
+               error = copyin(caead->aad, cod->buf, caead->aadlen);
        if (error) {
                SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
                goto bail;
        }
+       crp->crp_aad = cod->aad;
        crp->crp_aad_start = 0;
        crp->crp_aad_length = caead->aadlen;
 
-       error = copyin(caead->src, cod->buf + caead->aadlen, caead->len);
+       if (cod->aad != NULL)
+               crp->crp_payload_start = 0;
+       else
+               crp->crp_payload_start = caead->aadlen;
+       error = copyin(caead->src, cod->buf + crp->crp_payload_start,
+           caead->len);
        if (error) {
                SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
                goto bail;
        }
-       crp->crp_payload_start = caead->aadlen;
        crp->crp_payload_length = caead->len;
        if (caead->op == COP_ENCRYPT && cod->obuf != NULL)
-               crp->crp_digest_start = caead->len;
+               crp->crp_digest_start = crp->crp_payload_output_start +
+                   caead->len;
        else
-               crp->crp_digest_start = caead->aadlen + caead->len;
+               crp->crp_digest_start = crp->crp_payload_start + caead->len;
 
        switch (cse->mode) {
        case CSP_MODE_AEAD:
@@ -1136,7 +1165,7 @@ cryptodev_aead(
        }
 
        crp->crp_flags = CRYPTO_F_CBIMM | (caead->flags & COP_F_BATCH);
-       crypto_use_buf(crp, cod->buf, caead->aadlen + caead->len +
+       crypto_use_buf(crp, cod->buf, crp->crp_payload_start + caead->len +
            cse->hashsize);
        if (cod->obuf != NULL)
                crypto_use_output_buf(crp, cod->obuf, caead->len +

Modified: head/sys/opencrypto/cryptodev.h
==============================================================================
--- head/sys/opencrypto/cryptodev.h     Mon Jun 22 23:13:14 2020        
(r362516)
+++ head/sys/opencrypto/cryptodev.h     Mon Jun 22 23:20:43 2020        
(r362517)
@@ -384,6 +384,7 @@ struct crypto_session_params {
        int             csp_flags;
 
 #define        CSP_F_SEPARATE_OUTPUT   0x0001  /* Requests can use separate 
output */
+#define        CSP_F_SEPARATE_AAD      0x0002  /* Requests can use separate 
AAD */
 
        int             csp_ivlen;      /* IV length in bytes. */
 
@@ -479,6 +480,7 @@ struct cryptop {
        struct crypto_buffer crp_buf;
        struct crypto_buffer crp_obuf;
 
+       void            *crp_aad;       /* AAD buffer. */
        int             crp_aad_start;  /* Location of AAD. */
        int             crp_aad_length; /* 0 => no AAD. */
        int             crp_iv_start;   /* Location of IV.  IV length is from

Modified: head/sys/opencrypto/cryptosoft.c
==============================================================================
--- head/sys/opencrypto/cryptosoft.c    Mon Jun 22 23:13:14 2020        
(r362516)
+++ head/sys/opencrypto/cryptosoft.c    Mon Jun 22 23:20:43 2020        
(r362517)
@@ -335,8 +335,11 @@ swcr_authcompute(struct swcr_session *ses, struct cryp
 
        bcopy(sw->sw_ictx, &ctx, axf->ctxsize);
 
-       err = crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length,
-           axf->Update, &ctx);
+       if (crp->crp_aad != NULL)
+               err = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
+       else
+               err = crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length,
+                   axf->Update, &ctx);
        if (err)
                return err;
 
@@ -503,7 +506,7 @@ swcr_gcm(struct swcr_session *ses, struct cryptop *crp
        blksz = GMAC_BLOCK_LEN;
        KASSERT(axf->blocksize == blksz, ("%s: axf block size mismatch",
            __func__));
-       
+
        swe = &ses->swcr_encdec;
        exf = swe->sw_exf;
        KASSERT(axf->blocksize == exf->native_blocksize,
@@ -520,26 +523,39 @@ swcr_gcm(struct swcr_session *ses, struct cryptop *crp
        axf->Reinit(&ctx, iv, ivlen);
 
        /* Supply MAC with AAD */
-       crypto_cursor_init(&cc_in, &crp->crp_buf);
-       crypto_cursor_advance(&cc_in, crp->crp_aad_start);
-       for (resid = crp->crp_aad_length; resid >= blksz; resid -= len) {
-               len = crypto_cursor_seglen(&cc_in);
-               if (len >= blksz) {
-                       inblk = crypto_cursor_segbase(&cc_in);
-                       len = rounddown(MIN(len, resid), blksz);
-                       crypto_cursor_advance(&cc_in, len);
-               } else {
-                       len = blksz;
-                       crypto_cursor_copydata(&cc_in, len, blk);
-                       inblk = blk;
+       if (crp->crp_aad != NULL) {
+               len = rounddown(crp->crp_aad_length, blksz);
+               if (len != 0)
+                       axf->Update(&ctx, crp->crp_aad, len);
+               if (crp->crp_aad_length != len) {
+                       memset(blk, 0, blksz);
+                       memcpy(blk, (char *)crp->crp_aad + len,
+                           crp->crp_aad_length - len);
+                       axf->Update(&ctx, blk, blksz);
                }
-               axf->Update(&ctx, inblk, len);
+       } else {
+               crypto_cursor_init(&cc_in, &crp->crp_buf);
+               crypto_cursor_advance(&cc_in, crp->crp_aad_start);
+               for (resid = crp->crp_aad_length; resid >= blksz;
+                    resid -= len) {
+                       len = crypto_cursor_seglen(&cc_in);
+                       if (len >= blksz) {
+                               inblk = crypto_cursor_segbase(&cc_in);
+                               len = rounddown(MIN(len, resid), blksz);
+                               crypto_cursor_advance(&cc_in, len);
+                       } else {
+                               len = blksz;
+                               crypto_cursor_copydata(&cc_in, len, blk);
+                               inblk = blk;
+                       }
+                       axf->Update(&ctx, inblk, len);
+               }
+               if (resid > 0) {
+                       memset(blk, 0, blksz);
+                       crypto_cursor_copydata(&cc_in, resid, blk);
+                       axf->Update(&ctx, blk, blksz);
+               }
        }
-       if (resid > 0) {
-               memset(blk, 0, blksz);
-               crypto_cursor_copydata(&cc_in, resid, blk);
-               axf->Update(&ctx, blk, blksz);
-       }
 
        exf->reinit(swe->sw_kschedule, iv);
 
@@ -607,7 +623,7 @@ swcr_gcm(struct swcr_session *ses, struct cryptop *crp
                        error = EBADMSG;
                        goto out;
                }
-               
+
                /* tag matches, decrypt data */
                crypto_cursor_init(&cc_in, &crp->crp_buf);
                crypto_cursor_advance(&cc_in, crp->crp_payload_start);
@@ -675,8 +691,11 @@ swcr_ccm_cbc_mac(struct swcr_session *ses, struct cryp
        ctx.aes_cbc_mac_ctx.cryptDataLength = 0;
 
        axf->Reinit(&ctx, iv, ivlen);
-       error = crypto_apply(crp, crp->crp_payload_start,
-           crp->crp_payload_length, axf->Update, &ctx);
+       if (crp->crp_aad != NULL)
+               error = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
+       else
+               error = crypto_apply(crp, crp->crp_payload_start,
+                   crp->crp_payload_length, axf->Update, &ctx);
        if (error)
                return (error);
 
@@ -724,7 +743,7 @@ swcr_ccm(struct swcr_session *ses, struct cryptop *crp
        blksz = AES_BLOCK_LEN;
        KASSERT(axf->blocksize == blksz, ("%s: axf block size mismatch",
            __func__));
-       
+
        swe = &ses->swcr_encdec;
        exf = swe->sw_exf;
        KASSERT(axf->blocksize == exf->native_blocksize,
@@ -748,8 +767,11 @@ swcr_ccm(struct swcr_session *ses, struct cryptop *crp
        axf->Reinit(&ctx, iv, ivlen);
 
        /* Supply MAC with AAD */
-       error = crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length,
-           axf->Update, &ctx);
+       if (crp->crp_aad != NULL)
+               error = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
+       else
+               error = crypto_apply(crp, crp->crp_aad_start,
+                   crp->crp_aad_length, axf->Update, &ctx);
        if (error)
                return (error);
 
@@ -1013,7 +1035,7 @@ swcr_setup_auth(struct swcr_session *ses,
        swa->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, M_NOWAIT);
        if (swa->sw_ictx == NULL)
                return (ENOBUFS);
-       
+
        switch (csp->csp_auth_alg) {
        case CRYPTO_SHA1_HMAC:
        case CRYPTO_SHA2_224_HMAC:
@@ -1236,7 +1258,8 @@ static int
 swcr_probesession(device_t dev, const struct crypto_session_params *csp)
 {
 
-       if ((csp->csp_flags & ~(CSP_F_SEPARATE_OUTPUT)) != 0)
+       if ((csp->csp_flags & ~(CSP_F_SEPARATE_OUTPUT | CSP_F_SEPARATE_AAD)) !=
+           0)
                return (EINVAL);
        switch (csp->csp_mode) {
        case CSP_MODE_COMPRESS:
_______________________________________________
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