Index: head/share/man/man9/crypto_request.9 =================================================================== --- head/share/man/man9/crypto_request.9 +++ head/share/man/man9/crypto_request.9 @@ -30,7 +30,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 25, 2020 +.Dd June 22, 2020 .Dt CRYPTO_REQUEST 9 .Os .Sh NAME @@ -181,7 +181,7 @@ .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 @@ 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 Index: head/share/man/man9/crypto_session.9 =================================================================== --- head/share/man/man9/crypto_session.9 +++ head/share/man/man9/crypto_session.9 @@ -30,7 +30,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 25, 2020 +.Dd June 22, 2020 .Dt CRYPTO_SESSION 9 .Os .Sh NAME @@ -194,6 +194,13 @@ 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 Index: head/sys/opencrypto/crypto.c =================================================================== --- head/sys/opencrypto/crypto.c +++ head/sys/opencrypto/crypto.c @@ -755,7 +755,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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) { Index: head/sys/opencrypto/cryptodev.h =================================================================== --- head/sys/opencrypto/cryptodev.h +++ head/sys/opencrypto/cryptodev.h @@ -384,6 +384,7 @@ 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 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 Index: head/sys/opencrypto/cryptodev.c =================================================================== --- head/sys/opencrypto/cryptodev.c +++ head/sys/opencrypto/cryptodev.c @@ -283,6 +283,7 @@ char *buf; char *obuf; + char *aad; bool done; }; @@ -297,6 +298,11 @@ &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 @@ 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 @@ 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 @@ 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 @@ } } - 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 @@ } } - 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 @@ } 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 + Index: head/sys/opencrypto/cryptosoft.c =================================================================== --- head/sys/opencrypto/cryptosoft.c +++ head/sys/opencrypto/cryptosoft.c @@ -335,8 +335,11 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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: