svn commit: r345124 - in stable/12: sys/conf sys/modules/crypto sys/opencrypto tools/tools/crypto

Sean Eric Fagan sef at FreeBSD.org
Thu Mar 14 02:46:06 UTC 2019


Author: sef
Date: Thu Mar 14 02:46:03 2019
New Revision: 345124
URL: https://svnweb.freebsd.org/changeset/base/345124

Log:
  MFC r344140,r344141,r344142,r344143,r344388,r344547
  
  r344140:
  Add CBC-MAC authentication.
  
  r344141:
  Add AES-CCM encryption, and plumb into OCF.
  
  r344142:
  Pasting in a source control line missed the last quote.  Fixed.
  
  r344143:
  Fix another issue from r344141, having to do with size of a shift amount.
  This did not show up in my testing.
  
  r344388:
  It turns out that setting the IV length is necessary with CCM in OpenSSL.
  This adds that back.
  
  r344547:
  Fix another bug introduced during the review process of r344140:
  the tag wasn't being computed properly due to chaning a >= comparison
  to an == comparison.

Added:
  stable/12/sys/opencrypto/cbc_mac.c
     - copied, changed from r344140, head/sys/opencrypto/cbc_mac.c
  stable/12/sys/opencrypto/cbc_mac.h
     - copied unchanged from r344140, head/sys/opencrypto/cbc_mac.h
  stable/12/sys/opencrypto/xform_cbc_mac.c
     - copied unchanged from r344140, head/sys/opencrypto/xform_cbc_mac.c
Modified:
  stable/12/sys/conf/files
  stable/12/sys/modules/crypto/Makefile
  stable/12/sys/opencrypto/cryptodev.c
  stable/12/sys/opencrypto/cryptodev.h
  stable/12/sys/opencrypto/cryptosoft.c
  stable/12/sys/opencrypto/xform_aes_icm.c
  stable/12/sys/opencrypto/xform_auth.h
  stable/12/sys/opencrypto/xform_enc.h
  stable/12/tools/tools/crypto/cryptocheck.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/conf/files
==============================================================================
--- stable/12/sys/conf/files	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/conf/files	Thu Mar 14 02:46:03 2019	(r345124)
@@ -4856,6 +4856,8 @@ crypto/libsodium/randombytes.c	optional crypto \
 	compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include -I$S/crypto/libsodium"
 crypto/libsodium/utils.c	optional crypto \
 	compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include -I$S/crypto/libsodium"
+opencrypto/cbc_mac.c		optional crypto
+opencrypto/xform_cbc_mac.c	optional crypto
 rpc/auth_none.c			optional krpc | nfslockd | nfscl | nfsd
 rpc/auth_unix.c			optional krpc | nfslockd | nfscl | nfsd
 rpc/authunix_prot.c		optional krpc | nfslockd | nfscl | nfsd

Modified: stable/12/sys/modules/crypto/Makefile
==============================================================================
--- stable/12/sys/modules/crypto/Makefile	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/modules/crypto/Makefile	Thu Mar 14 02:46:03 2019	(r345124)
@@ -68,5 +68,7 @@ CFLAGS.utils.c			+= -I${LIBSODIUM_INC} -I${LIBSODIUM_C
 
 SRCS	+= opt_param.h cryptodev_if.h bus_if.h device_if.h
 SRCS	+= opt_ddb.h
+SRCS	+= cbc_mac.c
+SRCS	+= xform_cbc_mac.c
 
 .include <bsd.kmod.mk>

Copied and modified: stable/12/sys/opencrypto/cbc_mac.c (from r344140, head/sys/opencrypto/cbc_mac.c)
==============================================================================
--- head/sys/opencrypto/cbc_mac.c	Fri Feb 15 03:46:39 2019	(r344140, copy source)
+++ stable/12/sys/opencrypto/cbc_mac.c	Thu Mar 14 02:46:03 2019	(r345124)
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$);
+__FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
 #include <sys/systm.h>
@@ -124,23 +124,31 @@ AES_CBC_MAC_Reinit(struct aes_cbc_mac_ctx *ctx, const 
 	rijndaelEncrypt(ctx->keysched, ctx->rounds, b0, ctx->block);
 	/* If there is auth data, we need to set up the staging block */
 	if (ctx->authDataLength) {
+		size_t addLength;
 		if (ctx->authDataLength < ((1<<16) - (1<<8))) {
 			uint16_t sizeVal = htobe16(ctx->authDataLength);
 			bcopy(&sizeVal, ctx->staging_block, sizeof(sizeVal));
-			ctx->blockIndex = sizeof(sizeVal);
-		} else if (ctx->authDataLength < (1UL<<32)) {
+			addLength = sizeof(sizeVal);
+		} else if (ctx->authDataLength < (1ULL<<32)) {
 			uint32_t sizeVal = htobe32(ctx->authDataLength);
 			ctx->staging_block[0] = 0xff;
 			ctx->staging_block[1] = 0xfe;
 			bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal));
-			ctx->blockIndex = 2 + sizeof(sizeVal);
+			addLength = 2 + sizeof(sizeVal);
 		} else {
 			uint64_t sizeVal = htobe64(ctx->authDataLength);
 			ctx->staging_block[0] = 0xff;
 			ctx->staging_block[1] = 0xff;
 			bcopy(&sizeVal, ctx->staging_block+2, sizeof(sizeVal));
-			ctx->blockIndex = 2 + sizeof(sizeVal);
+			addLength = 2 + sizeof(sizeVal);
 		}
+		ctx->blockIndex = addLength;
+		/*
+		 * The length descriptor goes into the AAD buffer, so we
+		 * need to account for it.
+		 */
+		ctx->authDataLength += addLength;
+		ctx->authDataCount = addLength;
 	}
 }
 
@@ -181,10 +189,9 @@ AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *ctx, const 
 			ctx->authDataCount += copy_amt;
 			ctx->blockIndex += copy_amt;
 			ctx->blockIndex %= sizeof(ctx->staging_block);
-			if (ctx->authDataCount == ctx->authDataLength)
-				length = 0;
+
 			if (ctx->blockIndex == 0 ||
-			    ctx->authDataCount >= ctx->authDataLength) {
+			    ctx->authDataCount == ctx->authDataLength) {
 				/*
 				 * We're done with this block, so we
 				 * xor staging_block with block, and then
@@ -193,8 +200,17 @@ AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *ctx, const 
 				xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
 				bzero(ctx->staging_block, sizeof(ctx->staging_block));
 				ctx->blockIndex = 0;
+				if (ctx->authDataCount >= ctx->authDataLength)
+					break;
 			}
 		}
+		/*
+		 * We'd like to be able to check length == 0 and return
+		 * here, but the way OCF calls us, length is always
+		 * blksize (16, in this case).  So we have to count on
+		 * the fact that OCF calls us separately for the AAD and
+		 * for the real data.
+		 */
 		return (0);
 	}
 	/*

Copied: stable/12/sys/opencrypto/cbc_mac.h (from r344140, head/sys/opencrypto/cbc_mac.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sys/opencrypto/cbc_mac.h	Thu Mar 14 02:46:03 2019	(r345124, copy of r344140, head/sys/opencrypto/cbc_mac.h)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * Copyright (c) 2018, iXsystems Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Sean Eric Fagan, with lots of references
+ * to existing AES-CCM (gmac) code.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$FreeBSD$
+ *
+ */
+
+#ifndef _CBC_CCM_H
+# define _CBC_CCM_H
+
+# include <sys/types.h>
+# include <crypto/rijndael/rijndael.h>
+
+# define CCM_CBC_BLOCK_LEN	16	/* 128 bits */
+# define CCM_CBC_MAX_DIGEST_LEN	16
+# define CCM_CBC_MIN_DIGEST_LEN	4
+
+/*
+ * This is the authentication context structure;
+ * the encryption one is similar.
+ */
+struct aes_cbc_mac_ctx {
+	uint64_t	authDataLength, authDataCount;
+	uint64_t	cryptDataLength, cryptDataCount;
+	int		blockIndex;
+	uint8_t		staging_block[CCM_CBC_BLOCK_LEN];
+	uint8_t		block[CCM_CBC_BLOCK_LEN];
+	const uint8_t	*nonce;
+	int		nonceLength;	/* This one is in bytes, not bits! */
+	/* AES state data */
+	int		rounds;
+	uint32_t	keysched[4*(RIJNDAEL_MAXNR+1)];
+};
+
+void AES_CBC_MAC_Init(struct aes_cbc_mac_ctx *);
+void AES_CBC_MAC_Setkey(struct aes_cbc_mac_ctx *, const uint8_t *, uint16_t);
+void AES_CBC_MAC_Reinit(struct aes_cbc_mac_ctx *, const uint8_t *, uint16_t);
+int AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *, const uint8_t *, uint16_t);
+void AES_CBC_MAC_Final(uint8_t *, struct aes_cbc_mac_ctx *);
+
+#endif /* _CBC_CCM_H */

Modified: stable/12/sys/opencrypto/cryptodev.c
==============================================================================
--- stable/12/sys/opencrypto/cryptodev.c	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/opencrypto/cryptodev.c	Thu Mar 14 02:46:03 2019	(r345124)
@@ -444,6 +444,9 @@ cryptof_ioctl(
 		case CRYPTO_CHACHA20:
 			txform = &enc_xform_chacha20;
 			break;
+		case CRYPTO_AES_CCM_16:
+			txform = &enc_xform_ccm;
+			break;
 
 		default:
 			CRYPTDEB("invalid cipher");
@@ -488,6 +491,25 @@ cryptof_ioctl(
 			thash = &auth_hash_nist_gmac_aes_256;
 			break;
 
+		case CRYPTO_AES_CCM_CBC_MAC:
+			switch (sop->keylen) {
+			case 16:
+				thash = &auth_hash_ccm_cbc_mac_128;
+				break;
+			case 24:
+				thash = &auth_hash_ccm_cbc_mac_192;
+				break;
+			case 32:
+				thash = &auth_hash_ccm_cbc_mac_256;
+				break;
+			default:
+				CRYPTDEB("Invalid CBC MAC key size %d",
+				    sop->keylen);
+				SDT_PROBE1(opencrypto, dev, ioctl,
+				    error, __LINE__);
+				return (EINVAL);
+			}
+			break;
 #ifdef notdef
 		case CRYPTO_MD5:
 			thash = &auth_hash_md5;
@@ -1003,12 +1025,13 @@ cryptodev_aead(
 	}
 
 	/*
-	 * For GCM, crd_len covers only the AAD.  For other ciphers
+	 * For GCM/CCM, crd_len covers only the AAD.  For other ciphers
 	 * chained with an HMAC, crd_len covers both the AAD and the
 	 * cipher text.
 	 */
 	crda->crd_skip = 0;
-	if (cse->cipher == CRYPTO_AES_NIST_GCM_16)
+	if (cse->cipher == CRYPTO_AES_NIST_GCM_16 ||
+	    cse->cipher == CRYPTO_AES_CCM_16)
 		crda->crd_len = caead->aadlen;
 	else
 		crda->crd_len = caead->aadlen + caead->len;

Modified: stable/12/sys/opencrypto/cryptodev.h
==============================================================================
--- stable/12/sys/opencrypto/cryptodev.h	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/opencrypto/cryptodev.h	Thu Mar 14 02:46:03 2019	(r345124)
@@ -86,6 +86,7 @@
 #define	SHA1_KPDK_HASH_LEN	20
 #define	AES_GMAC_HASH_LEN	16
 #define	POLY1305_HASH_LEN	16
+#define	AES_CBC_MAC_HASH_LEN	16
 /* Maximum hash algorithm result length */
 #define	HASH_MAX_LEN		SHA2_512_HASH_LEN /* Keep this updated */
 
@@ -107,6 +108,9 @@
 #define	AES_128_GMAC_KEY_LEN		16
 #define	AES_192_GMAC_KEY_LEN		24
 #define	AES_256_GMAC_KEY_LEN		32
+#define	AES_128_CBC_MAC_KEY_LEN		16
+#define	AES_192_CBC_MAC_KEY_LEN		24
+#define	AES_256_CBC_MAC_KEY_LEN		32
 
 #define	POLY1305_KEY_LEN		32
 
@@ -129,6 +133,7 @@
 
 #define	ARC4_IV_LEN		1
 #define	AES_GCM_IV_LEN		12
+#define	AES_CCM_IV_LEN		12
 #define	AES_XTS_IV_LEN		8
 #define	AES_XTS_ALPHA		0x87	/* GF(2^128) generator polynomial */
 
@@ -199,7 +204,9 @@
 #define	CRYPTO_SHA2_384		36
 #define	CRYPTO_SHA2_512		37
 #define	CRYPTO_POLY1305		38
-#define	CRYPTO_ALGORITHM_MAX	38 /* Keep updated - see below */
+#define	CRYPTO_AES_CCM_CBC_MAC	39	/* auth side */
+#define	CRYPTO_AES_CCM_16	40	/* cipher side */
+#define	CRYPTO_ALGORITHM_MAX	40	/* Keep updated - see below */
 
 #define	CRYPTO_ALGO_VALID(x)	((x) >= CRYPTO_ALGORITHM_MIN && \
 				 (x) <= CRYPTO_ALGORITHM_MAX)

Modified: stable/12/sys/opencrypto/cryptosoft.c
==============================================================================
--- stable/12/sys/opencrypto/cryptosoft.c	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/opencrypto/cryptosoft.c	Thu Mar 14 02:46:03 2019	(r345124)
@@ -62,6 +62,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/bus.h>
 #include "cryptodev_if.h"
 
+_Static_assert(AES_CCM_IV_LEN == AES_GCM_IV_LEN,
+    "AES_GCM_IV_LEN must currently be the same as AES_CCM_IV_LEN");
+
 static	int32_t swcr_id;
 
 u_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN];
@@ -506,6 +509,7 @@ swcr_authenc(struct cryptop *crp)
 	caddr_t buf = (caddr_t)crp->crp_buf;
 	uint32_t *blkp;
 	int aadlen, blksz, i, ivlen, len, iskip, oskip, r;
+	int isccm = 0;
 
 	ivlen = blksz = iskip = oskip = 0;
 
@@ -520,13 +524,18 @@ swcr_authenc(struct cryptop *crp)
 
 		sw = &ses->swcr_algorithms[i];
 		switch (sw->sw_alg) {
+		case CRYPTO_AES_CCM_16:
 		case CRYPTO_AES_NIST_GCM_16:
 		case CRYPTO_AES_NIST_GMAC:
 			swe = sw;
 			crde = crd;
 			exf = swe->sw_exf;
-			ivlen = 12;
+			/* AES_CCM_IV_LEN and AES_GCM_IV_LEN are both 12 */
+			ivlen = AES_CCM_IV_LEN;
 			break;
+		case CRYPTO_AES_CCM_CBC_MAC:
+			isccm = 1;
+			/* FALLTHROUGH */
 		case CRYPTO_AES_128_NIST_GMAC:
 		case CRYPTO_AES_192_NIST_GMAC:
 		case CRYPTO_AES_256_NIST_GMAC:
@@ -544,8 +553,26 @@ swcr_authenc(struct cryptop *crp)
 	}
 	if (crde == NULL || crda == NULL)
 		return (EINVAL);
+	/*
+	 * We need to make sure that the auth algorithm matches the
+	 * encr algorithm.  Specifically, for AES-GCM must go with
+	 * AES NIST GMAC, and AES-CCM must go with CBC-MAC.
+	 */
+	if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16) {
+		switch (crda->crd_alg) {
+		case CRYPTO_AES_128_NIST_GMAC:
+		case CRYPTO_AES_192_NIST_GMAC:
+		case CRYPTO_AES_256_NIST_GMAC:
+			break;	/* Good! */
+		default:
+			return (EINVAL);	/* Not good! */
+		}
+	} else if (crde->crd_alg == CRYPTO_AES_CCM_16 &&
+	    crda->crd_alg != CRYPTO_AES_CCM_CBC_MAC)
+		return (EINVAL);
 
-	if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16 &&
+	if ((crde->crd_alg == CRYPTO_AES_NIST_GCM_16 ||
+	     crde->crd_alg == CRYPTO_AES_CCM_16) &&
 	    (crde->crd_flags & CRD_F_IV_EXPLICIT) == 0)
 		return (EINVAL);
 
@@ -576,6 +603,15 @@ swcr_authenc(struct cryptop *crp)
 		}
 	}
 
+	if (swa->sw_alg == CRYPTO_AES_CCM_CBC_MAC) {
+		/*
+		 * AES CCM-CBC needs to know the length of
+		 * both the auth data, and payload data, before
+		 * doing the auth computation.
+		 */
+		ctx.aes_cbc_mac_ctx.authDataLength = crda->crd_len;
+		ctx.aes_cbc_mac_ctx.cryptDataLength = crde->crd_len;
+	}
 	/* Supply MAC with IV */
 	if (axf->Reinit)
 		axf->Reinit(&ctx, iv, ivlen);
@@ -610,16 +646,30 @@ swcr_authenc(struct cryptop *crp)
 			bzero(blk, blksz);
 		crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len,
 		    blk);
+		/*
+		 * One of the problems with CCM+CBC is that the authentication
+		 * is done on the unecncrypted data.  As a result, we have
+		 * to do the authentication update at different times,
+		 * depending on whether it's CCM or not.
+		 */
 		if (crde->crd_flags & CRD_F_ENCRYPT) {
+			if (isccm)
+				axf->Update(&ctx, blk, len);
 			if (exf->encrypt_multi != NULL)
 				exf->encrypt_multi(swe->sw_kschedule, blk,
 				    len);
 			else
 				exf->encrypt(swe->sw_kschedule, blk);
-			axf->Update(&ctx, blk, len);
+			if (!isccm)
+				axf->Update(&ctx, blk, len);
 			crypto_copyback(crp->crp_flags, buf,
 			    crde->crd_skip + i, len, blk);
 		} else {
+			if (isccm) {
+				KASSERT(exf->encrypt_multi == NULL,
+				    ("assume CCM is single-block only"));
+				exf->decrypt(swe->sw_kschedule, blk);
+			}
 			axf->Update(&ctx, blk, len);
 		}
 	}
@@ -650,6 +700,11 @@ swcr_authenc(struct cryptop *crp)
 		r = timingsafe_bcmp(aalg, uaalg, axf->hashsize);
 		if (r == 0) {
 			/* tag matches, decrypt data */
+			if (isccm) {
+				KASSERT(exf->reinit != NULL,
+				    ("AES-CCM reinit function must be set"));
+				exf->reinit(swe->sw_kschedule, iv);
+			}
 			for (i = 0; i < crde->crd_len; i += blksz) {
 				len = MIN(crde->crd_len - i, blksz);
 				if (len < blksz)
@@ -799,6 +854,9 @@ swcr_newsession(device_t dev, crypto_session_t cses, s
 		case CRYPTO_AES_NIST_GCM_16:
 			txf = &enc_xform_aes_nist_gcm;
 			goto enccommon;
+		case CRYPTO_AES_CCM_16:
+			txf = &enc_xform_ccm;
+			goto enccommon;
 		case CRYPTO_AES_NIST_GMAC:
 			txf = &enc_xform_aes_nist_gmac;
 			swd->sw_exf = txf;
@@ -943,6 +1001,22 @@ swcr_newsession(device_t dev, crypto_session_t cses, s
 			swd->sw_axf = axf;
 			break;
 
+		case CRYPTO_AES_CCM_CBC_MAC:
+			switch (cri->cri_klen) {
+			case 128:
+				axf = &auth_hash_ccm_cbc_mac_128;
+				break;
+			case 192:
+				axf = &auth_hash_ccm_cbc_mac_192;
+				break;
+			case 256:
+				axf = &auth_hash_ccm_cbc_mac_256;
+				break;
+			default:
+				swcr_freesession(dev, cses);
+				return EINVAL;
+			}
+			goto auth4common;
 		case CRYPTO_AES_128_NIST_GMAC:
 			axf = &auth_hash_nist_gmac_aes_128;
 			goto auth4common;
@@ -1042,6 +1116,7 @@ swcr_freesession(device_t dev, crypto_session_t cses)
 		case CRYPTO_CAMELLIA_CBC:
 		case CRYPTO_NULL_CBC:
 		case CRYPTO_CHACHA20:
+		case CRYPTO_AES_CCM_16:
 			txf = swd->sw_exf;
 
 			if (swd->sw_kschedule)
@@ -1056,6 +1131,7 @@ swcr_freesession(device_t dev, crypto_session_t cses)
 		case CRYPTO_SHA2_512_HMAC:
 		case CRYPTO_RIPEMD160_HMAC:
 		case CRYPTO_NULL_HMAC:
+		case CRYPTO_AES_CCM_CBC_MAC:
 			axf = swd->sw_axf;
 
 			if (swd->sw_ictx) {
@@ -1201,6 +1277,8 @@ swcr_process(device_t dev, struct cryptop *crp, int hi
 		case CRYPTO_AES_128_NIST_GMAC:
 		case CRYPTO_AES_192_NIST_GMAC:
 		case CRYPTO_AES_256_NIST_GMAC:
+		case CRYPTO_AES_CCM_16:
+		case CRYPTO_AES_CCM_CBC_MAC:
 			crp->crp_etype = swcr_authenc(crp);
 			goto done;
 
@@ -1291,6 +1369,8 @@ swcr_attach(device_t dev)
 	REGISTER(CRYPTO_BLAKE2B);
 	REGISTER(CRYPTO_BLAKE2S);
 	REGISTER(CRYPTO_CHACHA20);
+	REGISTER(CRYPTO_AES_CCM_16);
+	REGISTER(CRYPTO_AES_CCM_CBC_MAC);
 	REGISTER(CRYPTO_POLY1305);
 #undef REGISTER
 

Modified: stable/12/sys/opencrypto/xform_aes_icm.c
==============================================================================
--- stable/12/sys/opencrypto/xform_aes_icm.c	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/opencrypto/xform_aes_icm.c	Thu Mar 14 02:46:03 2019	(r345124)
@@ -57,6 +57,7 @@ static	void aes_icm_crypt(caddr_t, u_int8_t *);
 static	void aes_icm_zerokey(u_int8_t **);
 static	void aes_icm_reinit(caddr_t, u_int8_t *);
 static	void aes_gcm_reinit(caddr_t, u_int8_t *);
+static	void aes_ccm_reinit(caddr_t, u_int8_t *);
 
 /* Encryption instances */
 struct enc_xform enc_xform_aes_icm = {
@@ -79,6 +80,18 @@ struct enc_xform enc_xform_aes_nist_gcm = {
 	aes_gcm_reinit,
 };
 
+struct enc_xform enc_xform_ccm = {
+	.type = CRYPTO_AES_CCM_16,
+	.name = "AES-CCM",
+	.blocksize = AES_ICM_BLOCK_LEN, .ivsize = AES_CCM_IV_LEN,
+	.minkey = AES_MIN_KEY, .maxkey = AES_MAX_KEY,
+	.encrypt = aes_icm_crypt,
+	.decrypt = aes_icm_crypt,
+	.setkey = aes_icm_setkey,
+	.zerokey = aes_icm_zerokey,
+	.reinit = aes_ccm_reinit,
+};
+
 /*
  * Encryption wrapper routines.
  */
@@ -102,6 +115,21 @@ aes_gcm_reinit(caddr_t key, u_int8_t *iv)
 	/* GCM starts with 2 as counter 1 is used for final xor of tag. */
 	bzero(&ctx->ac_block[AESICM_BLOCKSIZE - 4], 4);
 	ctx->ac_block[AESICM_BLOCKSIZE - 1] = 2;
+}
+
+static void
+aes_ccm_reinit(caddr_t key, u_int8_t *iv)
+{
+	struct aes_icm_ctx *ctx;
+
+	ctx = (struct aes_icm_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[AESICM_BLOCKSIZE - 1] = 1;
 }
 
 static void

Modified: stable/12/sys/opencrypto/xform_auth.h
==============================================================================
--- stable/12/sys/opencrypto/xform_auth.h	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/opencrypto/xform_auth.h	Thu Mar 14 02:46:03 2019	(r345124)
@@ -42,6 +42,7 @@
 #include <crypto/sha2/sha512.h>
 #include <opencrypto/rmd160.h>
 #include <opencrypto/gmac.h>
+#include <opencrypto/cbc_mac.h>
 
 #include <opencrypto/cryptodev.h>
 #include <opencrypto/xform_userland.h>
@@ -85,6 +86,9 @@ extern struct auth_hash auth_hash_nist_gmac_aes_256;
 extern struct auth_hash auth_hash_blake2b;
 extern struct auth_hash auth_hash_blake2s;
 extern struct auth_hash auth_hash_poly1305;
+extern struct auth_hash auth_hash_ccm_cbc_mac_128;
+extern struct auth_hash auth_hash_ccm_cbc_mac_192;
+extern struct auth_hash auth_hash_ccm_cbc_mac_256;
 
 union authctx {
 	MD5_CTX md5ctx;
@@ -95,6 +99,7 @@ union authctx {
 	SHA384_CTX sha384ctx;
 	SHA512_CTX sha512ctx;
 	struct aes_gmac_ctx aes_gmac_ctx;
+	struct aes_cbc_mac_ctx aes_cbc_mac_ctx;
 };
 
 #endif /* _CRYPTO_XFORM_AUTH_H_ */

Copied: stable/12/sys/opencrypto/xform_cbc_mac.c (from r344140, head/sys/opencrypto/xform_cbc_mac.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sys/opencrypto/xform_cbc_mac.c	Thu Mar 14 02:46:03 2019	(r345124, copy of r344140, head/sys/opencrypto/xform_cbc_mac.c)
@@ -0,0 +1,55 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/cbc_mac.h>
+#include <opencrypto/xform_auth.h>
+
+/* Authentication instances */
+struct auth_hash auth_hash_ccm_cbc_mac_128 = {
+	.type = CRYPTO_AES_CCM_CBC_MAC,
+	.name = "CBC-CCM-AES-128",
+	.keysize = AES_128_CBC_MAC_KEY_LEN,
+	.hashsize = AES_CBC_MAC_HASH_LEN,
+	.ctxsize = sizeof(struct aes_cbc_mac_ctx),
+	.blocksize = CCM_CBC_BLOCK_LEN,
+	.Init = (void (*)(void *)) AES_CBC_MAC_Init,
+	.Setkey =
+	    (void (*)(void *, const u_int8_t *, u_int16_t))AES_CBC_MAC_Setkey,
+	.Reinit =
+	    (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+	.Update =
+	    (int  (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+	.Final = (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final,
+};
+struct auth_hash auth_hash_ccm_cbc_mac_192 = {
+	.type = CRYPTO_AES_CCM_CBC_MAC,
+	.name = "CBC-CCM-AES-192",
+	.keysize = AES_192_CBC_MAC_KEY_LEN,
+	.hashsize = AES_CBC_MAC_HASH_LEN,
+	.ctxsize = sizeof(struct aes_cbc_mac_ctx),
+	.blocksize = CCM_CBC_BLOCK_LEN,
+	.Init = (void (*)(void *)) AES_CBC_MAC_Init,
+	.Setkey =
+	    (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+	.Reinit =
+	    (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+	.Update =
+	    (int  (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+	.Final = (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final,
+};
+struct auth_hash auth_hash_ccm_cbc_mac_256 = {
+	.type = CRYPTO_AES_CCM_CBC_MAC,
+	.name = "CBC-CCM-AES-256",
+	.keysize = AES_256_CBC_MAC_KEY_LEN,
+	.hashsize = AES_CBC_MAC_HASH_LEN,
+	.ctxsize = sizeof(struct aes_cbc_mac_ctx),
+	.blocksize = CCM_CBC_BLOCK_LEN,
+	.Init = (void (*)(void *)) AES_CBC_MAC_Init,
+	.Setkey =
+	    (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+	.Reinit =
+	    (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+	.Update =
+	    (int  (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+	.Final = (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final,
+};

Modified: stable/12/sys/opencrypto/xform_enc.h
==============================================================================
--- stable/12/sys/opencrypto/xform_enc.h	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/sys/opencrypto/xform_enc.h	Thu Mar 14 02:46:03 2019	(r345124)
@@ -84,6 +84,7 @@ extern struct enc_xform enc_xform_aes_xts;
 extern struct enc_xform enc_xform_arc4;
 extern struct enc_xform enc_xform_camellia;
 extern struct enc_xform enc_xform_chacha20;
+extern struct enc_xform enc_xform_ccm;
 
 struct aes_icm_ctx {
 	u_int32_t	ac_ek[4*(RIJNDAEL_MAXNR + 1)];

Modified: stable/12/tools/tools/crypto/cryptocheck.c
==============================================================================
--- stable/12/tools/tools/crypto/cryptocheck.c	Thu Mar 14 00:58:57 2019	(r345123)
+++ stable/12/tools/tools/crypto/cryptocheck.c	Thu Mar 14 02:46:03 2019	(r345124)
@@ -105,6 +105,9 @@
  *	aes-gcm		128-bit aes gcm
  *	aes-gcm192	192-bit aes gcm
  *	aes-gcm256	256-bit aes gcm
+ *	aes-ccm		128-bit aes ccm
+ *	aes-ccm192	192-bit aes ccm
+ *	aes-ccm256	256-bit aes ccm
  */
 
 #include <sys/param.h>
@@ -131,7 +134,7 @@ struct alg {
 	const char *name;
 	int cipher;
 	int mac;
-	enum { T_HASH, T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type;
+	enum { T_HASH, T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM, T_CCM } type;
 	const EVP_CIPHER *(*evp_cipher)(void);
 	const EVP_MD *(*evp_md)(void);
 } algs[] = {
@@ -186,6 +189,15 @@ struct alg {
 	{ .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16,
 	  .mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM,
 	  .evp_cipher = EVP_aes_256_gcm },
+	{ .name = "aes-ccm", .cipher = CRYPTO_AES_CCM_16,
+	  .mac = CRYPTO_AES_CCM_CBC_MAC, .type = T_CCM,
+	  .evp_cipher = EVP_aes_128_ccm },
+	{ .name = "aes-ccm192", .cipher = CRYPTO_AES_CCM_16,
+	  .mac = CRYPTO_AES_CCM_CBC_MAC, .type = T_CCM,
+	  .evp_cipher = EVP_aes_192_ccm },
+	{ .name = "aes-ccm256", .cipher = CRYPTO_AES_CCM_16,
+	  .mac = CRYPTO_AES_CCM_CBC_MAC, .type = T_CCM,
+	  .evp_cipher = EVP_aes_256_ccm },
 };
 
 static bool verbose;
@@ -1159,6 +1171,217 @@ out:
 }
 
 static void
+openssl_ccm_encrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
+    const char *iv, size_t iv_len, const char *aad, size_t aad_len,
+		    const char *input, char *output, size_t size, char *tag)
+{
+	EVP_CIPHER_CTX *ctx;
+	int outl, total;
+
+	ctx = EVP_CIPHER_CTX_new();
+	if (ctx == NULL)
+		errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
+		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, NULL) != 1)
+		errx(1, "OpenSSL %s (%zu) setting iv length failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, AES_CBC_MAC_HASH_LEN, NULL) != 1)
+		errx(1, "OpenSSL %s (%zu) setting tag length failed: %s", alg->name,
+		     size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_EncryptInit_ex(ctx, NULL, NULL, (const u_char *)key,
+	    (const u_char *)iv) != 1)
+		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	if (EVP_EncryptUpdate(ctx, NULL, &outl, NULL, size) != 1)
+		errx(1, "OpenSSL %s (%zu) unable to set data length: %s", alg->name,
+		     size, ERR_error_string(ERR_get_error(), NULL));
+
+	if (aad != NULL) {
+		if (EVP_EncryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
+		    aad_len) != 1)
+			errx(1, "OpenSSL %s (%zu) aad update failed: %s",
+			    alg->name, size,
+			    ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (EVP_EncryptUpdate(ctx, (u_char *)output, &outl,
+	    (const u_char *)input, size) != 1)
+		errx(1, "OpenSSL %s (%zu) encrypt update failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	total = outl;
+	if (EVP_EncryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
+		errx(1, "OpenSSL %s (%zu) encrypt final failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	total += outl;
+	if (total != size)
+		errx(1, "OpenSSL %s (%zu) encrypt size mismatch: %d", alg->name,
+		    size, total);
+	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, AES_CBC_MAC_HASH_LEN,
+	    tag) != 1)
+		errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
+		    size, ERR_error_string(ERR_get_error(), NULL));
+	EVP_CIPHER_CTX_free(ctx);
+}
+
+static bool
+ocf_ccm(struct alg *alg, const char *key, size_t key_len, const char *iv,
+    size_t iv_len, const char *aad, size_t aad_len, const char *input,
+    char *output, size_t size, char *tag, int enc, int *cridp)
+{
+	struct session2_op sop;
+	struct crypt_aead caead;
+	int fd;
+	bool rv;
+
+	memset(&sop, 0, sizeof(sop));
+	memset(&caead, 0, sizeof(caead));
+	sop.crid = crid;
+	sop.keylen = key_len;
+	sop.key = (char *)key;
+	sop.cipher = alg->cipher;
+	sop.mackeylen = key_len;
+	sop.mackey = (char *)key;
+	sop.mac = alg->mac;
+	fd = crget();
+	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
+		warn("cryptodev %s not supported for device %s",
+		    alg->name, crfind(crid));
+		close(fd);
+		return (false);
+	}
+
+	caead.ses = sop.ses;
+	caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
+	caead.len = size;
+	caead.aadlen = aad_len;
+	caead.ivlen = iv_len;
+	caead.src = (char *)input;
+	caead.dst = output;
+	caead.aad = (char *)aad;
+	caead.tag = tag;
+	caead.iv = (char *)iv;
+
+	if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
+		warn("cryptodev %s (%zu) failed for device %s",
+		    alg->name, size, crfind(crid));
+		rv = false;
+	} else
+		rv = true;
+
+	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
+		warn("ioctl(CIOCFSESSION)");
+
+	close(fd);
+	*cridp = sop.crid;
+	return (rv);
+}
+
+static void
+run_ccm_test(struct alg *alg, size_t size)
+{
+	const EVP_CIPHER *cipher;
+	char *aad, *buffer, *cleartext, *ciphertext;
+	char *iv, *key;
+	u_int iv_len, key_len;
+	int crid;
+	char control_tag[AES_CBC_MAC_HASH_LEN], test_tag[AES_CBC_MAC_HASH_LEN];
+
+	cipher = alg->evp_cipher();
+	if (size % EVP_CIPHER_block_size(cipher) != 0) {
+		if (verbose)
+			printf(
+			    "%s (%zu): invalid buffer size (block size %d)\n",
+			    alg->name, size, EVP_CIPHER_block_size(cipher));
+		return;
+	}
+
+	memset(control_tag, 0x3c, sizeof(control_tag));
+	memset(test_tag, 0x3c, sizeof(test_tag));
+
+	/*
+	 * We only have one algorithm constant for CBC-MAC; however, the
+	 * alg structure uses the different openssl types, which gives us
+	 * the key length.  We need that for the OCF code.
+	 */
+	key_len = EVP_CIPHER_key_length(cipher);
+
+	/*
+	 * AES-CCM can have varying IV lengths; however, for the moment
+	 * we only support AES_CCM_IV_LEN (12).  So if the sizes are
+	 * different, we'll fail.
+	 */
+	iv_len = EVP_CIPHER_iv_length(cipher);
+	if (iv_len != AES_CCM_IV_LEN) {
+		if (verbose)
+			printf("OpenSSL CCM IV length (%d) != AES_CCM_IV_LEN",
+			    iv_len);
+		return;
+	} 
+
+	key = alloc_buffer(key_len);
+	iv = generate_iv(iv_len, alg);
+	cleartext = alloc_buffer(size);
+	buffer = malloc(size);
+	ciphertext = malloc(size);
+	if (aad_len != 0)
+		aad = alloc_buffer(aad_len);
+	else
+		aad = NULL;
+
+	/* OpenSSL encrypt */
+	openssl_ccm_encrypt(alg, cipher, key, iv, iv_len, aad, aad_len, cleartext,
+	    ciphertext, size, control_tag);
+
+	/* OCF encrypt */
+	if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, cleartext,
+	    buffer, size, test_tag, 1, &crid))
+		goto out;
+	if (memcmp(ciphertext, buffer, size) != 0) {
+		printf("%s (%zu) encryption mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(ciphertext, size, NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(buffer, size, NULL, 0);
+		goto out;
+	}
+	if (memcmp(control_tag, test_tag, sizeof(control_tag)) != 0) {
+		printf("%s (%zu) enc tag mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(control_tag, sizeof(control_tag), NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(test_tag, sizeof(test_tag), NULL, 0);
+		goto out;
+	}
+
+	/* OCF decrypt */
+	if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, ciphertext,
+	    buffer, size, control_tag, 0, &crid))
+		goto out;
+	if (memcmp(cleartext, buffer, size) != 0) {
+		printf("%s (%zu) decryption mismatch:\n", alg->name, size);
+		printf("control:\n");
+		hexdump(cleartext, size, NULL, 0);
+		printf("test (cryptodev device %s):\n", crfind(crid));
+		hexdump(buffer, size, NULL, 0);
+		goto out;
+	}
+
+	if (verbose)
+		printf("%s (%zu) matched (cryptodev device %s)\n",
+		    alg->name, size, crfind(crid));
+
+out:
+	free(aad);
+	free(ciphertext);
+	free(buffer);
+	free(cleartext);
+	free(iv);
+	free(key);
+}
+
+static void
 run_test(struct alg *alg, size_t size)
 {
 
@@ -1178,6 +1401,9 @@ run_test(struct alg *alg, size_t size)
 	case T_GCM:
 		run_gcm_test(alg, size);
 		break;
+	case T_CCM:
+		run_ccm_test(alg, size);
+		break;
 	}
 }
 
@@ -1247,7 +1473,8 @@ run_aead_tests(size_t *sizes, u_int nsizes)
 	u_int i;
 
 	for (i = 0; i < nitems(algs); i++)
-		if (algs[i].type == T_GCM)
+		if (algs[i].type == T_GCM ||
+		    algs[i].type == T_CCM)
 			run_test_sizes(&algs[i], sizes, nsizes);
 }
 


More information about the svn-src-all mailing list