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
This commit is contained in:
parent
e16b207739
commit
9b774dc0c5
@ -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
|
||||
|
@ -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 input and output
|
||||
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
|
||||
|
@ -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) {
|
||||
|
@ -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_output, CTLFLAG_RW,
|
||||
&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 @@ cryptof_ioctl(
|
||||
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 +
|
||||
|
@ -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
|
||||
|
@ -335,8 +335,11 @@ swcr_authcompute(struct swcr_session *ses, struct cryptop *crp)
|
||||
|
||||
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,25 +523,38 @@ 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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
axf->Update(&ctx, inblk, len);
|
||||
}
|
||||
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 cryptop *crp)
|
||||
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:
|
||||
|
Loading…
Reference in New Issue
Block a user