crypto: Support multiple nonce lengths for AES-CCM.
Permit nonces of lengths 7 through 13 in the OCF framework and the
cryptosoft driver. A helper function (ccm_max_payload_length) can be
used in OCF drivers to reject CCM requests which are too large for the
specified nonce length.
Reviewed by: sef
Sponsored by: Chelsio Communications, The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D32111
(cherry picked from commit ae18720d27
)
This commit is contained in:
parent
8581b350dd
commit
fd464d2f78
@ -1,9 +1,13 @@
|
||||
.\" Copyright (c) 2014 The FreeBSD Foundation
|
||||
.\" Copyright (c) 2014-2021 The FreeBSD Foundation
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This documentation was written by John-Mark Gurney under
|
||||
.\" the sponsorship of the FreeBSD Foundation and
|
||||
.\" Portions of this documentation were written by John-Mark Gurney
|
||||
.\" under the sponsorship of the FreeBSD Foundation and
|
||||
.\" Rubicon Communications, LLC (Netgate).
|
||||
.\"
|
||||
.\" Portions of this documentation were written by Ararat River
|
||||
.\" Consulting, LLC under sponsorship of the FreeBSD Foundation.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
@ -27,7 +31,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 3, 2021
|
||||
.Dd October 6, 2021
|
||||
.Dt CRYPTO 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -153,13 +157,15 @@ This nonce must be provided in
|
||||
via the
|
||||
.Dv CRYPTO_F_IV_SEPARATE
|
||||
flag.
|
||||
Some AEAD algorithms support multiple nonce sizes.
|
||||
The first size listed is the default nonce size.
|
||||
.Pp
|
||||
The following AEAD algorithms are supported:
|
||||
.Bl -column "CRYPTO_AES_NIST_GCM_16" "Nonce" "16, 24, 32" "Tag"
|
||||
.Bl -column "CRYPTO_AES_NIST_GCM_16" "12, 7-13" "16, 24, 32" "Tag"
|
||||
.It Sy Name Ta Sy Nonce Ta Sy Key Sizes Ta Sy Tag Ta Sy Description
|
||||
.It Dv CRYPTO_AES_NIST_GCM_16 Ta 12 Ta 16, 24, 32 Ta 16 Ta
|
||||
AES Galois/Counter Mode
|
||||
.It Dv CRYPTO_AES_CCM_16 Ta 12 Ta 16, 24, 32 Ta 16 Ta
|
||||
.It Dv CRYPTO_AES_CCM_16 Ta 12, 7-13 Ta 16, 24, 32 Ta 16 Ta
|
||||
AES Counter with CBC-MAC
|
||||
.It Dv CRYPTO_CHACHA20_POLY1305 Ta 12 Ta 32 Ta 16 Ta
|
||||
ChaCha20-Poly1305
|
||||
|
@ -1,5 +1,9 @@
|
||||
/*-
|
||||
* Copyright (c) 2002-2006 Sam Leffler. All rights reserved.
|
||||
* Copyright (c) 2021 The FreeBSD Foundation
|
||||
*
|
||||
* Portions of this software were developed by Ararat River
|
||||
* Consulting, LLC under sponsorship of the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -743,6 +747,24 @@ alg_is_aead(int alg)
|
||||
return (alg_type(alg) == ALG_AEAD);
|
||||
}
|
||||
|
||||
static bool
|
||||
ccm_tag_length_valid(int len)
|
||||
{
|
||||
/* RFC 3610 */
|
||||
switch (len) {
|
||||
case 4:
|
||||
case 6:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
return (true);
|
||||
default:
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
#define SUPPORTED_SES (CSP_F_SEPARATE_OUTPUT | CSP_F_SEPARATE_AAD | CSP_F_ESN)
|
||||
|
||||
/* Various sanity checks on crypto session parameters. */
|
||||
@ -800,8 +822,21 @@ check_csp(const struct crypto_session_params *csp)
|
||||
return (false);
|
||||
|
||||
/* IV is optional for digests (e.g. GMAC). */
|
||||
if (csp->csp_ivlen >= EALG_MAX_BLOCK_LEN)
|
||||
return (false);
|
||||
switch (csp->csp_auth_alg) {
|
||||
case CRYPTO_AES_CCM_CBC_MAC:
|
||||
if (csp->csp_ivlen < 7 || csp->csp_ivlen > 13)
|
||||
return (false);
|
||||
break;
|
||||
case CRYPTO_AES_NIST_GMAC:
|
||||
if (csp->csp_ivlen != AES_GCM_IV_LEN)
|
||||
return (false);
|
||||
break;
|
||||
default:
|
||||
if (csp->csp_ivlen != 0)
|
||||
return (false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!alg_is_digest(csp->csp_auth_alg))
|
||||
return (false);
|
||||
|
||||
@ -820,6 +855,10 @@ check_csp(const struct crypto_session_params *csp)
|
||||
axf = crypto_auth_hash(csp);
|
||||
if (axf == NULL || csp->csp_auth_mlen > axf->hashsize)
|
||||
return (false);
|
||||
|
||||
if (csp->csp_auth_alg == CRYPTO_AES_CCM_CBC_MAC &&
|
||||
!ccm_tag_length_valid(csp->csp_auth_mlen))
|
||||
return (false);
|
||||
}
|
||||
break;
|
||||
case CSP_MODE_AEAD:
|
||||
@ -833,13 +872,16 @@ check_csp(const struct crypto_session_params *csp)
|
||||
if (csp->csp_auth_alg != 0 || csp->csp_auth_klen != 0)
|
||||
return (false);
|
||||
|
||||
/*
|
||||
* XXX: Would be nice to have a better way to get this
|
||||
* value.
|
||||
*/
|
||||
switch (csp->csp_cipher_alg) {
|
||||
case CRYPTO_AES_NIST_GCM_16:
|
||||
case CRYPTO_AES_CCM_16:
|
||||
if (csp->csp_auth_mlen != 0 &&
|
||||
!ccm_tag_length_valid(csp->csp_auth_mlen))
|
||||
return (false);
|
||||
|
||||
if (csp->csp_ivlen < 7 || csp->csp_ivlen > 13)
|
||||
return (false);
|
||||
break;
|
||||
case CRYPTO_AES_NIST_GCM_16:
|
||||
case CRYPTO_CHACHA20_POLY1305:
|
||||
if (csp->csp_auth_mlen > 16)
|
||||
return (false);
|
||||
|
@ -753,5 +753,34 @@ crypto_read_iv(struct cryptop *crp, void *iv)
|
||||
crypto_copydata(crp, crp->crp_iv_start, csp->csp_ivlen, iv);
|
||||
}
|
||||
|
||||
static __inline size_t
|
||||
ccm_max_payload_length(const struct crypto_session_params *csp)
|
||||
{
|
||||
/* RFC 3160 */
|
||||
const u_int L = 15 - csp->csp_ivlen;
|
||||
|
||||
switch (L) {
|
||||
case 2:
|
||||
return (0xffff);
|
||||
case 3:
|
||||
return (0xffffff);
|
||||
#ifdef __LP64__
|
||||
case 4:
|
||||
return (0xffffffff);
|
||||
case 5:
|
||||
return (0xffffffffff);
|
||||
case 6:
|
||||
return (0xffffffffffff);
|
||||
case 7:
|
||||
return (0xffffffffffffff);
|
||||
default:
|
||||
return (0xffffffffffffffff);
|
||||
#else
|
||||
default:
|
||||
return (0xffffffff);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _CRYPTO_CRYPTO_H_ */
|
||||
|
@ -642,17 +642,19 @@ swcr_ccm_cbc_mac(struct swcr_session *ses, struct cryptop *crp)
|
||||
u_char tag[AES_CBC_MAC_HASH_LEN];
|
||||
u_char iv[AES_BLOCK_LEN];
|
||||
union authctx ctx;
|
||||
const struct crypto_session_params *csp;
|
||||
struct swcr_auth *swa;
|
||||
struct auth_hash *axf;
|
||||
int error, ivlen;
|
||||
|
||||
csp = crypto_get_params(crp->crp_session);
|
||||
swa = &ses->swcr_auth;
|
||||
axf = swa->sw_axf;
|
||||
|
||||
bcopy(swa->sw_ictx, &ctx, axf->ctxsize);
|
||||
|
||||
/* Initialize the IV */
|
||||
ivlen = AES_CCM_IV_LEN;
|
||||
ivlen = csp->csp_ivlen;
|
||||
crypto_read_iv(crp, iv);
|
||||
|
||||
/*
|
||||
@ -694,6 +696,7 @@ swcr_ccm_cbc_mac(struct swcr_session *ses, struct cryptop *crp)
|
||||
static int
|
||||
swcr_ccm(struct swcr_session *ses, struct cryptop *crp)
|
||||
{
|
||||
const struct crypto_session_params *csp;
|
||||
uint32_t blkbuf[howmany(AES_BLOCK_LEN, sizeof(uint32_t))];
|
||||
u_char *blk = (u_char *)blkbuf;
|
||||
u_char tag[AES_CBC_MAC_HASH_LEN];
|
||||
@ -708,6 +711,7 @@ swcr_ccm(struct swcr_session *ses, struct cryptop *crp)
|
||||
size_t len;
|
||||
int blksz, error, ivlen, r, resid;
|
||||
|
||||
csp = crypto_get_params(crp->crp_session);
|
||||
swa = &ses->swcr_auth;
|
||||
axf = swa->sw_axf;
|
||||
|
||||
@ -721,10 +725,13 @@ swcr_ccm(struct swcr_session *ses, struct cryptop *crp)
|
||||
KASSERT(axf->blocksize == exf->native_blocksize,
|
||||
("%s: blocksize mismatch", __func__));
|
||||
|
||||
if (crp->crp_payload_length > ccm_max_payload_length(csp))
|
||||
return (EMSGSIZE);
|
||||
|
||||
if ((crp->crp_flags & CRYPTO_F_IV_SEPARATE) == 0)
|
||||
return (EINVAL);
|
||||
|
||||
ivlen = AES_CCM_IV_LEN;
|
||||
ivlen = csp->csp_ivlen;
|
||||
|
||||
/*
|
||||
* AES CCM-CBC-MAC needs to know the length of both the auth
|
||||
@ -1130,7 +1137,6 @@ swcr_setup_cipher(struct swcr_session *ses,
|
||||
|
||||
swe = &ses->swcr_encdec;
|
||||
txf = crypto_cipher(csp);
|
||||
MPASS(txf->ivsize == csp->csp_ivlen);
|
||||
if (txf->ctxsize != 0) {
|
||||
swe->sw_kschedule = malloc(txf->ctxsize, M_CRYPTO_DATA,
|
||||
M_NOWAIT);
|
||||
@ -1282,9 +1288,6 @@ swcr_setup_ccm(struct swcr_session *ses,
|
||||
struct swcr_auth *swa;
|
||||
struct auth_hash *axf;
|
||||
|
||||
if (csp->csp_ivlen != AES_CCM_IV_LEN)
|
||||
return (EINVAL);
|
||||
|
||||
/* First, setup the auth side. */
|
||||
swa = &ses->swcr_auth;
|
||||
switch (csp->csp_cipher_klen * 8) {
|
||||
@ -1392,8 +1395,6 @@ swcr_auth_supported(const struct crypto_session_params *csp)
|
||||
}
|
||||
if (csp->csp_auth_key == NULL)
|
||||
return (false);
|
||||
if (csp->csp_ivlen != AES_CCM_IV_LEN)
|
||||
return (false);
|
||||
break;
|
||||
}
|
||||
return (true);
|
||||
|
@ -144,15 +144,14 @@ aes_ccm_reinit(void *key, const uint8_t *iv, size_t ivlen)
|
||||
{
|
||||
struct aes_icm_ctx *ctx;
|
||||
|
||||
KASSERT(ivlen == AES_CCM_IV_LEN,
|
||||
KASSERT(ivlen >= 7 && ivlen <= 13,
|
||||
("%s: invalid IV length", __func__));
|
||||
ctx = key;
|
||||
|
||||
/* CCM has flags, then the IV, then the counter, which starts at 1 */
|
||||
bzero(ctx->ac_block, sizeof(ctx->ac_block));
|
||||
/* 3 bytes for length field; this gives a nonce of 12 bytes */
|
||||
ctx->ac_block[0] = (15 - AES_CCM_IV_LEN) - 1;
|
||||
bcopy(iv, ctx->ac_block+1, AES_CCM_IV_LEN);
|
||||
ctx->ac_block[0] = (15 - ivlen) - 1;
|
||||
bcopy(iv, ctx->ac_block + 1, ivlen);
|
||||
ctx->ac_block[AESICM_BLOCKSIZE - 1] = 1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user