From nobody Wed Oct 06 21:10:30 2021 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 9143D12D3DF8; Wed, 6 Oct 2021 21:10:32 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4HPnD73mnSz3HdW; Wed, 6 Oct 2021 21:10:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 02DF426FD3; Wed, 6 Oct 2021 21:10:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 196LAU20059017; Wed, 6 Oct 2021 21:10:30 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 196LAU9P059016; Wed, 6 Oct 2021 21:10:30 GMT (envelope-from git) Date: Wed, 6 Oct 2021 21:10:30 GMT Message-Id: <202110062110.196LAU9P059016@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: John Baldwin Subject: git: ae18720d2792 - main - crypto: Support multiple nonce lengths for AES-CCM. List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: jhb X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: ae18720d2792287c9ec658404f1a3173014d4979 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by jhb: URL: https://cgit.FreeBSD.org/src/commit/?id=ae18720d2792287c9ec658404f1a3173014d4979 commit ae18720d2792287c9ec658404f1a3173014d4979 Author: John Baldwin AuthorDate: 2021-10-06 21:08:47 +0000 Commit: John Baldwin CommitDate: 2021-10-06 21:08:47 +0000 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 --- share/man/man7/crypto.7 | 18 +++++++++----- sys/opencrypto/crypto.c | 56 ++++++++++++++++++++++++++++++++++++------ sys/opencrypto/cryptodev.h | 29 ++++++++++++++++++++++ sys/opencrypto/cryptosoft.c | 17 +++++++------ sys/opencrypto/xform_aes_icm.c | 7 +++--- 5 files changed, 102 insertions(+), 25 deletions(-) diff --git a/share/man/man7/crypto.7 b/share/man/man7/crypto.7 index 6e5bd83621aa..d75daa62adcb 100644 --- a/share/man/man7/crypto.7 +++ b/share/man/man7/crypto.7 @@ -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 diff --git a/sys/opencrypto/crypto.c b/sys/opencrypto/crypto.c index ef8422d5f32c..3a71e53129be 100644 --- a/sys/opencrypto/crypto.c +++ b/sys/opencrypto/crypto.c @@ -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 @@ -713,6 +717,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. */ @@ -770,8 +792,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); @@ -790,6 +825,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: @@ -803,13 +842,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); diff --git a/sys/opencrypto/cryptodev.h b/sys/opencrypto/cryptodev.h index b3c79a48f632..6611a8925020 100644 --- a/sys/opencrypto/cryptodev.h +++ b/sys/opencrypto/cryptodev.h @@ -686,5 +686,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_ */ diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c index 19092e56b004..ae71f0d6c096 100644 --- a/sys/opencrypto/cryptosoft.c +++ b/sys/opencrypto/cryptosoft.c @@ -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; const 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; const 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); diff --git a/sys/opencrypto/xform_aes_icm.c b/sys/opencrypto/xform_aes_icm.c index 860dceda5232..09880ee426b8 100644 --- a/sys/opencrypto/xform_aes_icm.c +++ b/sys/opencrypto/xform_aes_icm.c @@ -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; }