git: de705beeef63 - stable/13 - crypto: Permit variable-sized IVs for ciphers with a reinit hook.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 21 Oct 2021 22:04:09 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=de705beeef63413ca56807a5df810135c7ddf925

commit de705beeef63413ca56807a5df810135c7ddf925
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2021-10-06 21:08:46 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2021-10-21 20:47:58 +0000

    crypto: Permit variable-sized IVs for ciphers with a reinit hook.
    
    Add a 'len' argument to the reinit hook in 'struct enc_xform' to
    permit support for AEAD ciphers such as AES-CCM and Chacha20-Poly1305
    which support different nonce lengths.
    
    Reviewed by:    markj
    Sponsored by:   Chelsio Communications, The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D32105
    
    (cherry picked from commit 1833d6042c9a0116e8a1198256fd8fbc99cb11ad)
    (cherry picked from commit d586c978b9b4216869e589daa5bbcc33225a0e35)
---
 stand/libsa/geli/geliboot.c              |  2 +-
 stand/libsa/geli/geliboot_crypto.c       |  7 ++++---
 stand/libsa/geli/geliboot_internal.h     |  2 +-
 sys/crypto/chacha20/chacha-sw.c          |  5 +++--
 sys/dev/cxgbe/crypto/t4_crypto.c         | 10 +++++++---
 sys/opencrypto/cryptosoft.c              | 20 +++++++++++---------
 sys/opencrypto/xform_aes_icm.c           | 22 ++++++++++++++--------
 sys/opencrypto/xform_aes_xts.c           |  9 +++++++--
 sys/opencrypto/xform_chacha20_poly1305.c |  5 ++++-
 sys/opencrypto/xform_enc.h               |  2 +-
 10 files changed, 53 insertions(+), 31 deletions(-)

diff --git a/stand/libsa/geli/geliboot.c b/stand/libsa/geli/geliboot.c
index 954a3ec34044..56499e96b295 100644
--- a/stand/libsa/geli/geliboot.c
+++ b/stand/libsa/geli/geliboot.c
@@ -345,7 +345,7 @@ geli_io(struct geli_dev *gdev, geli_op_t enc, off_t offset, u_char *buf,
 		g_eli_key_fill(&gdev->sc, &gkey, keyno);
 
 		error = geliboot_crypt(gdev->sc.sc_ealgo, enc, pbuf, secsize,
-		    gkey.gek_key, gdev->sc.sc_ekeylen, iv);
+		    gkey.gek_key, gdev->sc.sc_ekeylen, iv, sizeof(iv));
 
 		if (error != 0) {
 			explicit_bzero(&gkey, sizeof(gkey));
diff --git a/stand/libsa/geli/geliboot_crypto.c b/stand/libsa/geli/geliboot_crypto.c
index 8478d2754d6f..fcc5d7bcd7fb 100644
--- a/stand/libsa/geli/geliboot_crypto.c
+++ b/stand/libsa/geli/geliboot_crypto.c
@@ -36,7 +36,7 @@
 
 int
 geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize,
-    const u_char *key, size_t keysize, u_char *iv)
+    const u_char *key, size_t keysize, u_char *iv, size_t ivlen)
 {
 	keyInstance aeskey;
 	cipherInstance cipher;
@@ -81,7 +81,7 @@ geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize,
 		ctxp = &xtsctx;
 
 		enc_xform_aes_xts.setkey(ctxp, key, xts_len / 8);
-		enc_xform_aes_xts.reinit(ctxp, iv);
+		enc_xform_aes_xts.reinit(ctxp, iv, ivlen);
 
 		switch (enc) {
 		case GELI_DECRYPT:
@@ -113,7 +113,8 @@ g_eli_crypto_cipher(u_int algo, geli_op_t enc, u_char *data, size_t datasize,
 	u_char iv[keysize];
 
 	explicit_bzero(iv, sizeof(iv));
-	return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv));
+	return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv,
+	    sizeof(iv)));
 }
 
 int
diff --git a/stand/libsa/geli/geliboot_internal.h b/stand/libsa/geli/geliboot_internal.h
index 2af74466179f..2318690297f8 100644
--- a/stand/libsa/geli/geliboot_internal.h
+++ b/stand/libsa/geli/geliboot_internal.h
@@ -68,6 +68,6 @@ struct geli_dev {
 };
 
 int geliboot_crypt(u_int algo, geli_op_t  enc, u_char *data, size_t datasize,
-    const u_char *key, size_t keysize, u_char *iv);
+    const u_char *key, size_t keysize, u_char *iv, size_t ivlen);
 
 #endif /* _GELIBOOT_INTERNAL_H_ */
diff --git a/sys/crypto/chacha20/chacha-sw.c b/sys/crypto/chacha20/chacha-sw.c
index 2c28b9a0c459..ef62e67316c0 100644
--- a/sys/crypto/chacha20/chacha-sw.c
+++ b/sys/crypto/chacha20/chacha-sw.c
@@ -18,9 +18,10 @@ chacha20_xform_setkey(void *ctx, const uint8_t *key, int len)
 }
 
 static void
-chacha20_xform_reinit(void *ctx, const uint8_t *iv)
+chacha20_xform_reinit(void *ctx, const uint8_t *iv, size_t ivlen)
 {
-
+	KASSERT(ivlen == CHACHA_NONCELEN + CHACHA_CTRLEN,
+	    ("%s: invalid IV length", __func__));
 	chacha_ivsetup(ctx, iv + 8, iv);
 }
 
diff --git a/sys/dev/cxgbe/crypto/t4_crypto.c b/sys/dev/cxgbe/crypto/t4_crypto.c
index ea1272758eaf..9d410da6e030 100644
--- a/sys/dev/cxgbe/crypto/t4_crypto.c
+++ b/sys/dev/cxgbe/crypto/t4_crypto.c
@@ -1,8 +1,12 @@
 /*-
  * Copyright (c) 2017 Chelsio Communications, Inc.
+ * Copyright (c) 2021 The FreeBSD Foundation
  * All rights reserved.
  * Written by: John Baldwin <jhb@FreeBSD.org>
  *
+ * 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
  * are met:
@@ -1458,7 +1462,7 @@ ccr_gcm_soft(struct ccr_session *s, struct cryptop *crp)
 		}
 	}
 
-	exf->reinit(kschedule, iv);
+	exf->reinit(kschedule, iv, sizeof(iv));
 
 	/* Do encryption with MAC */
 	for (i = 0; i < crp->crp_payload_length; i += sizeof(block)) {
@@ -1935,7 +1939,7 @@ ccr_ccm_soft(struct ccr_session *s, struct cryptop *crp)
 	if (error)
 		goto out;
 
-	exf->reinit(kschedule, iv);
+	exf->reinit(kschedule, iv, sizeof(iv));
 
 	/* Do encryption/decryption with MAC */
 	for (i = 0; i < crp->crp_payload_length; i += sizeof(block)) {
@@ -1970,7 +1974,7 @@ ccr_ccm_soft(struct ccr_session *s, struct cryptop *crp)
 			error = 0;
 
 			/* Tag matches, decrypt data. */
-			exf->reinit(kschedule, iv);
+			exf->reinit(kschedule, iv, sizeof(iv));
 			for (i = 0; i < crp->crp_payload_length;
 			     i += sizeof(block)) {
 				len = imin(crp->crp_payload_length - i,
diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c
index 9e551ba9652b..a85d7d6d3b7b 100644
--- a/sys/opencrypto/cryptosoft.c
+++ b/sys/opencrypto/cryptosoft.c
@@ -9,13 +9,16 @@
  * supported the development of this code.
  *
  * Copyright (c) 2000, 2001 Angelos D. Keromytis
- * Copyright (c) 2014 The FreeBSD Foundation
+ * Copyright (c) 2014-2021 The FreeBSD Foundation
  * All rights reserved.
  *
  * Portions of this software were developed by John-Mark Gurney
  * under sponsorship of the FreeBSD Foundation and
  * Rubicon Communications, LLC (Netgate).
  *
+ * Portions of this software were developed by Ararat River
+ * Consulting, LLC under sponsorship of the FreeBSD Foundation.
+ *
  * Permission to use, copy, and modify this software with or without fee
  * is hereby granted, provided that this entire notice is included in
  * all source code copies of any software which is or includes a copy or
@@ -106,7 +109,7 @@ swcr_encdec(struct swcr_session *ses, struct cryptop *crp)
 	struct swcr_encdec *sw;
 	struct enc_xform *exf;
 	size_t inlen, outlen;
-	int i, blks, ivlen, resid;
+	int i, blks, resid;
 	struct crypto_buffer_cursor cc_in, cc_out;
 	const unsigned char *inblk;
 	unsigned char *outblk;
@@ -117,7 +120,7 @@ swcr_encdec(struct swcr_session *ses, struct cryptop *crp)
 
 	sw = &ses->swcr_encdec;
 	exf = sw->sw_exf;
-	ivlen = exf->ivsize;
+	csp = crypto_get_params(crp->crp_session);
 
 	if (exf->native_blocksize == 0) {
 		/* Check for non-padded data */
@@ -133,7 +136,6 @@ swcr_encdec(struct swcr_session *ses, struct cryptop *crp)
 		return (EINVAL);
 
 	if (crp->crp_cipher_key != NULL) {
-		csp = crypto_get_params(crp->crp_session);
 		error = exf->setkey(sw->sw_kschedule,
 		    crp->crp_cipher_key, csp->csp_cipher_klen);
 		if (error)
@@ -147,7 +149,7 @@ swcr_encdec(struct swcr_session *ses, struct cryptop *crp)
 		 * xforms that provide a reinit method perform all IV
 		 * handling themselves.
 		 */
-		exf->reinit(sw->sw_kschedule, iv);
+		exf->reinit(sw->sw_kschedule, iv, csp->csp_ivlen);
 	}
 
 	ivp = iv;
@@ -534,7 +536,7 @@ swcr_gcm(struct swcr_session *ses, struct cryptop *crp)
 	if (crp->crp_cipher_key != NULL)
 		exf->setkey(swe->sw_kschedule, crp->crp_cipher_key,
 		    crypto_get_params(crp->crp_session)->csp_cipher_klen);
-	exf->reinit(swe->sw_kschedule, iv);
+	exf->reinit(swe->sw_kschedule, iv, ivlen);
 
 	/* Do encryption with MAC */
 	crypto_cursor_init(&cc_in, &crp->crp_buf);
@@ -753,7 +755,7 @@ swcr_ccm(struct swcr_session *ses, struct cryptop *crp)
 	if (crp->crp_cipher_key != NULL)
 		exf->setkey(swe->sw_kschedule, crp->crp_cipher_key,
 		    crypto_get_params(crp->crp_session)->csp_cipher_klen);
-	exf->reinit(swe->sw_kschedule, iv);
+	exf->reinit(swe->sw_kschedule, iv, ivlen);
 
 	/* Do encryption/decryption with MAC */
 	crypto_cursor_init(&cc_in, &crp->crp_buf);
@@ -824,7 +826,7 @@ swcr_ccm(struct swcr_session *ses, struct cryptop *crp)
 		}
 
 		/* tag matches, decrypt data */
-		exf->reinit(swe->sw_kschedule, iv);
+		exf->reinit(swe->sw_kschedule, iv, ivlen);
 		crypto_cursor_init(&cc_in, &crp->crp_buf);
 		crypto_cursor_advance(&cc_in, crp->crp_payload_start);
 		for (resid = crp->crp_payload_length; resid > blksz;
@@ -915,7 +917,7 @@ swcr_chacha20_poly1305(struct swcr_session *ses, struct cryptop *crp)
 	if (crp->crp_cipher_key != NULL)
 		exf->setkey(swe->sw_kschedule, crp->crp_cipher_key,
 		    csp->csp_cipher_klen);
-	exf->reinit(swe->sw_kschedule, crp->crp_iv);
+	exf->reinit(swe->sw_kschedule, crp->crp_iv, csp->csp_ivlen);
 
 	/* Do encryption with MAC */
 	crypto_cursor_init(&cc_in, &crp->crp_buf);
diff --git a/sys/opencrypto/xform_aes_icm.c b/sys/opencrypto/xform_aes_icm.c
index 5f81f8df8a87..45da8267ca7d 100644
--- a/sys/opencrypto/xform_aes_icm.c
+++ b/sys/opencrypto/xform_aes_icm.c
@@ -55,9 +55,9 @@ __FBSDID("$FreeBSD$");
 static	int aes_icm_setkey(void *, const uint8_t *, int);
 static	void aes_icm_crypt(void *, const uint8_t *, uint8_t *);
 static	void aes_icm_crypt_last(void *, const uint8_t *, uint8_t *, size_t);
-static	void aes_icm_reinit(void *, const uint8_t *);
-static	void aes_gcm_reinit(void *, const uint8_t *);
-static	void aes_ccm_reinit(void *, const uint8_t *);
+static	void aes_icm_reinit(void *, const uint8_t *, size_t);
+static	void aes_gcm_reinit(void *, const uint8_t *, size_t);
+static	void aes_ccm_reinit(void *, const uint8_t *, size_t);
 
 /* Encryption instances */
 struct enc_xform enc_xform_aes_icm = {
@@ -114,20 +114,24 @@ struct enc_xform enc_xform_ccm = {
  * Encryption wrapper routines.
  */
 static void
-aes_icm_reinit(void *key, const uint8_t *iv)
+aes_icm_reinit(void *key, const uint8_t *iv, size_t ivlen)
 {
 	struct aes_icm_ctx *ctx;
 
 	ctx = key;
-	bcopy(iv, ctx->ac_block, AESICM_BLOCKSIZE);
+	KASSERT(ivlen <= sizeof(ctx->ac_block),
+	    ("%s: ivlen too large", __func__));
+	bcopy(iv, ctx->ac_block, ivlen);
 }
 
 static void
-aes_gcm_reinit(void *key, const uint8_t *iv)
+aes_gcm_reinit(void *key, const uint8_t *iv, size_t ivlen)
 {
 	struct aes_icm_ctx *ctx;
 
-	aes_icm_reinit(key, iv);
+	KASSERT(ivlen == AES_GCM_IV_LEN,
+	    ("%s: invalid IV length", __func__));
+	aes_icm_reinit(key, iv, ivlen);
 
 	ctx = key;
 	/* GCM starts with 2 as counter 1 is used for final xor of tag. */
@@ -136,10 +140,12 @@ aes_gcm_reinit(void *key, const uint8_t *iv)
 }
 
 static void
-aes_ccm_reinit(void *key, const uint8_t *iv)
+aes_ccm_reinit(void *key, const uint8_t *iv, size_t ivlen)
 {
 	struct aes_icm_ctx *ctx;
 
+	KASSERT(ivlen == AES_CCM_IV_LEN,
+	    ("%s: invalid IV length", __func__));
 	ctx = key;
 
 	/* CCM has flags, then the IV, then the counter, which starts at 1 */
diff --git a/sys/opencrypto/xform_aes_xts.c b/sys/opencrypto/xform_aes_xts.c
index 0b415f1d6346..d7f807752aa6 100644
--- a/sys/opencrypto/xform_aes_xts.c
+++ b/sys/opencrypto/xform_aes_xts.c
@@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$");
 static	int aes_xts_setkey(void *, const uint8_t *, int);
 static	void aes_xts_encrypt(void *, const uint8_t *, uint8_t *);
 static	void aes_xts_decrypt(void *, const uint8_t *, uint8_t *);
-static	void aes_xts_reinit(void *, const uint8_t *);
+static	void aes_xts_reinit(void *, const uint8_t *, size_t);
 
 /* Encryption instances */
 struct enc_xform enc_xform_aes_xts = {
@@ -77,12 +77,17 @@ struct enc_xform enc_xform_aes_xts = {
  * Encryption wrapper routines.
  */
 static void
-aes_xts_reinit(void *key, const uint8_t *iv)
+aes_xts_reinit(void *key, const uint8_t *iv, size_t ivlen)
 {
 	struct aes_xts_ctx *ctx = key;
 	uint64_t blocknum;
 	u_int i;
 
+#ifndef _STANDALONE
+	KASSERT(ivlen == sizeof(blocknum),
+	    ("%s: invalid IV length", __func__));
+#endif
+
 	/*
 	 * Prepare tweak as E_k2(IV). IV is specified as LE representation
 	 * of a 64-bit block number which we allow to be passed in directly.
diff --git a/sys/opencrypto/xform_chacha20_poly1305.c b/sys/opencrypto/xform_chacha20_poly1305.c
index 3a72c06f931b..e893287145f2 100644
--- a/sys/opencrypto/xform_chacha20_poly1305.c
+++ b/sys/opencrypto/xform_chacha20_poly1305.c
@@ -50,10 +50,13 @@ chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len)
 }
 
 static void
-chacha20_poly1305_reinit(void *vctx, const uint8_t *iv)
+chacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen)
 {
 	struct chacha20_poly1305_cipher_ctx *ctx = vctx;
 
+	KASSERT(ivlen == sizeof(ctx->nonce),
+	    ("%s: invalid nonce length", __func__));
+
 	/* Block 0 is used for the poly1305 key. */
 	memcpy(ctx->nonce, iv, sizeof(ctx->nonce));
 	ctx->ic = 1;
diff --git a/sys/opencrypto/xform_enc.h b/sys/opencrypto/xform_enc.h
index e8325f20917b..1c800ed428fe 100644
--- a/sys/opencrypto/xform_enc.h
+++ b/sys/opencrypto/xform_enc.h
@@ -62,7 +62,7 @@ struct enc_xform {
 	void (*encrypt) (void *, const uint8_t *, uint8_t *);
 	void (*decrypt) (void *, const uint8_t *, uint8_t *);
 	int (*setkey) (void *, const uint8_t *, int len);
-	void (*reinit) (void *, const uint8_t *);
+	void (*reinit) (void *, const uint8_t *, size_t);
 
 	/*
 	 * For stream ciphers, encrypt/decrypt the final partial block