Page MenuHomeFreeBSD

D15446.id42595.diff
No OneTemporary

D15446.id42595.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -4830,6 +4830,8 @@
opencrypto/rmd160.c optional crypto | ipsec | ipsec_support
opencrypto/skipjack.c optional crypto | ipsec | ipsec_support
opencrypto/xform.c optional crypto | ipsec | ipsec_support
+opencrypto/ccm-cbc.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
Index: sys/modules/crypto/Makefile
===================================================================
--- sys/modules/crypto/Makefile
+++ sys/modules/crypto/Makefile
@@ -46,5 +46,7 @@
SRCS += chacha-sw.c
SRCS += opt_param.h cryptodev_if.h bus_if.h device_if.h
SRCS += opt_ddb.h
+SRCS += ccm-cbc.c
+SRCS += xform_cbc_mac.c
.include <bsd.kmod.mk>
Index: sys/opencrypto/ccm-cbc.h
===================================================================
--- sys/opencrypto/ccm-cbc.h
+++ sys/opencrypto/ccm-cbc.h
@@ -0,0 +1,70 @@
+/*
+ * 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 _CCM_H
+# define _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;
+ int tagLength;
+ int blockIndex;
+ uint8_t staging_block[CCM_CBC_BLOCK_LEN];
+ uint8_t block[CCM_CBC_BLOCK_LEN];
+ const uint8_t *aes_key;
+ int keyLength; /* This will be in bits, not bytes! */
+ 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 /* _CCM_H */
Index: sys/opencrypto/ccm-cbc.c
===================================================================
--- sys/opencrypto/ccm-cbc.c
+++ sys/opencrypto/ccm-cbc.c
@@ -0,0 +1,206 @@
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <opencrypto/ccm-cbc.h>
+#include <opencrypto/xform_auth.h>
+
+/*
+ * Given two CCM_CBC_BLOCK_LEN blocks, xor
+ * them into dst, and then encrypt dst.
+ */
+static void
+xor_and_encrypt(struct aes_cbc_mac_ctx *ctx,
+ const uint8_t *src, uint8_t *dst)
+{
+ const uint64_t *b1;
+ uint64_t *b2;
+ uint64_t temp_block[CCM_CBC_BLOCK_LEN/sizeof(uint64_t)];
+ b1 = (const uint64_t*)src;
+ b2 = (uint64_t*)dst;
+
+ for (size_t count = 0;
+ count < CCM_CBC_BLOCK_LEN/sizeof(uint64_t);
+ count++) {
+ temp_block[count] = b1[count] ^ b2[count];
+ }
+ rijndaelEncrypt(ctx->keysched, ctx->rounds, (void*)temp_block, dst);
+}
+
+void
+AES_CBC_MAC_Init(struct aes_cbc_mac_ctx *ctx)
+{
+ bzero(ctx, sizeof *ctx);
+ ctx->tagLength = AES_CBC_MAC_HASH_LEN;
+}
+
+void
+AES_CBC_MAC_Setkey(struct aes_cbc_mac_ctx *ctx, const uint8_t *key, uint16_t klen)
+{
+ ctx->rounds = rijndaelKeySetupEnc(ctx->keysched, key, klen * 8);
+ return;
+}
+
+/*
+ * This is called to set the nonce, aka IV.
+ * Before this call, the authDataLength and cryptDataLength fields
+ * MUST have been set. Sadly, there's no way to return an error.
+ *
+ * The CBC-MAC algorithm requires that the first block contain the
+ * nonce, as well as information about the sizes and lengths involved.
+ */
+void
+AES_CBC_MAC_Reinit(struct aes_cbc_mac_ctx *ctx, const uint8_t *nonce, uint16_t nonceLen)
+{
+ uint8_t b0[CCM_CBC_BLOCK_LEN];
+ uint8_t *bp = b0, flags = 0;
+ uint8_t L = 0;
+ uint64_t tmp = ctx->cryptDataLength;
+
+ if (ctx->authDataLength == 0 &&
+ ctx->cryptDataLength == 0) {
+ return;
+ }
+
+ ctx->nonce = nonce;
+ ctx->nonceLength = nonceLen;
+
+ ctx->authDataCount = 0;
+ ctx->blockIndex = 0;
+ explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
+
+ /*
+ * Need to determine the L field value.
+ * This is the number of bytes needed to
+ * specify the length of the message; the
+ * length is whatever is left in the 16 bytes
+ * after specifying flags and the nonce.
+ */
+ L = (15 - nonceLen) & 0xff;
+
+ flags = (ctx->authDataLength > 0) * 64 +
+ ((ctx->tagLength-2) / 2) * 8 +
+ L - 1;
+ /*
+ * Now we need to set up the first block,
+ * which has flags, nonce, and the message length.
+ */
+ b0[0] = flags;
+ bcopy(nonce, b0+1, nonceLen);
+ bp = b0 + 1 + nonceLen;
+
+ /* Need to copy L' [aka L-1] bytes of cryptDataLength */
+ for (uint8_t *dst = b0 + sizeof(b0) - 1;
+ dst >= bp;
+ dst--) {
+ *dst = (tmp & 0xff);
+ tmp >>= 8;
+ }
+ /* Now need to encrypt b0 */
+ rijndaelEncrypt(ctx->keysched, ctx->rounds, b0, ctx->block);
+ /* If there is auth data, we need to set up the staging block */
+ if (ctx->authDataLength) {
+ 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)) {
+ 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);
+ } 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);
+ }
+ }
+ return;
+}
+
+int
+AES_CBC_MAC_Update(struct aes_cbc_mac_ctx *ctx, const uint8_t *data, uint16_t length)
+{
+
+ /*
+ * This will be called in one of two phases:
+ * (1) Applying authentication data, or
+ * (2) Applying the payload data.
+ * Because CBC-MAC puts the authentication data
+ * size before the data, subsequent calls won't
+ * be block-size-aligned. Which complicates things
+ * a fair bit.
+ *
+ * The payload data doesn't have that problem.
+ */
+
+ if (ctx->authDataCount < ctx->authDataLength) {
+ /*
+ * We need to process data as authentication data.
+ * Since we may be out of sync, we may also need
+ * to pad out the staging block.
+ */
+ const uint8_t *ptr = data;
+ while (length) {
+ size_t copy_amt = MIN(length,
+ sizeof(ctx->staging_block) - ctx->blockIndex);
+ bcopy(ptr, ctx->staging_block + ctx->blockIndex, copy_amt);
+ ptr += copy_amt;
+ length -= copy_amt;
+ 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) {
+ /*
+ * We're done with this block, so we
+ * xor staging_block with block, and then
+ * encrypt it.
+ */
+ xor_and_encrypt(ctx, ctx->staging_block, ctx->block);
+ explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
+ ctx->blockIndex = 0;
+ }
+ }
+ return (0);
+ }
+ /*
+ * If we're here, then we're encoding payload data.
+ * This is easier, as we just xor&encrypt.
+ */
+ while (length) {
+ const uint8_t *ptr;
+
+ if (length < sizeof(ctx->block)) {
+ explicit_bzero(ctx->staging_block, sizeof(ctx->staging_block));
+ bcopy(data, ctx->staging_block, length);
+ ptr = ctx->staging_block;
+ length = 0;
+ } else {
+ ptr = data;
+ length -= sizeof(ctx->block);
+ }
+ xor_and_encrypt(ctx, ptr, ctx->block);
+ }
+ return (0);
+}
+
+void
+AES_CBC_MAC_Final(uint8_t *buf, struct aes_cbc_mac_ctx *ctx)
+{
+ uint8_t s0[CCM_CBC_BLOCK_LEN];
+
+ explicit_bzero(s0, sizeof(s0));
+ s0[0] = ((15 - ctx->nonceLength) & 0xff) - 1;
+ bcopy(ctx->nonce, s0+1, ctx->nonceLength);
+ rijndaelEncrypt(ctx->keysched, ctx->rounds, s0, s0);
+ for (size_t indx = 0; indx < ctx->tagLength; indx++)
+ buf[indx] = ctx->block[indx] ^ s0[indx];
+ explicit_bzero(s0, sizeof(s0));
+ return;
+}
Index: sys/opencrypto/cryptodev.h
===================================================================
--- sys/opencrypto/cryptodev.h
+++ sys/opencrypto/cryptodev.h
@@ -80,6 +80,8 @@
#define MD5_KPDK_HASH_LEN 16
#define SHA1_KPDK_HASH_LEN 20
#define AES_GMAC_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 */
@@ -99,6 +101,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
/* Encryption algorithm block sizes */
#define NULL_BLOCK_LEN 4 /* IPsec to maintain alignment */
@@ -182,7 +187,11 @@
#define CRYPTO_BLAKE2B 29 /* Blake2b hash */
#define CRYPTO_BLAKE2S 30 /* Blake2s hash */
#define CRYPTO_CHACHA20 31 /* Chacha20 stream cipher */
-#define CRYPTO_ALGORITHM_MAX 31 /* Keep updated - see below */
+#define CRYPTO_AES_CCM_16 32 /* cipher side */
+#define CRYPTO_AES_128_CCM_CBC_MAC 33 /* auth side */
+#define CRYPTO_AES_192_CCM_CBC_MAC 34 /* auth side */
+#define CRYPTO_AES_256_CCM_CBC_MAC 35 /* auth side */
+#define CRYPTO_ALGORITHM_MAX 35 /* Keep updated - see below */
#define CRYPTO_ALGO_VALID(x) ((x) >= CRYPTO_ALGORITHM_MIN && \
(x) <= CRYPTO_ALGORITHM_MAX)
Index: sys/opencrypto/cryptodev.c
===================================================================
--- sys/opencrypto/cryptodev.c
+++ sys/opencrypto/cryptodev.c
@@ -441,6 +441,9 @@
case CRYPTO_AES_NIST_GCM_16:
txform = &enc_xform_aes_nist_gcm;
break;
+ case CRYPTO_AES_CCM_16:
+ txform = &enc_xform_ccm;
+ break;
case CRYPTO_CHACHA20:
txform = &enc_xform_chacha20;
break;
@@ -482,6 +485,15 @@
thash = &auth_hash_nist_gmac_aes_256;
break;
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ thash = &auth_hash_ccm_cbc_mac_128;
+ break;
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ thash = &auth_hash_ccm_cbc_mac_192;
+ break;
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ thash = &auth_hash_ccm_cbc_mac_256;
+ break;
#ifdef notdef
case CRYPTO_MD5:
thash = &auth_hash_md5;
@@ -984,12 +996,12 @@
}
/*
- * For GCM, crd_len covers only the AAD. For other ciphers
+ * For GCM and 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;
Index: sys/opencrypto/cryptosoft.c
===================================================================
--- sys/opencrypto/cryptosoft.c
+++ sys/opencrypto/cryptosoft.c
@@ -487,6 +487,7 @@
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;
@@ -499,6 +500,8 @@
return (EINVAL);
switch (sw->sw_alg) {
+ case CRYPTO_AES_CCM_16:
+ isccm = 1;
case CRYPTO_AES_NIST_GCM_16:
case CRYPTO_AES_NIST_GMAC:
swe = sw;
@@ -506,6 +509,10 @@
exf = swe->sw_exf;
ivlen = 12;
break;
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ isccm = 1;
case CRYPTO_AES_128_NIST_GMAC:
case CRYPTO_AES_192_NIST_GMAC:
case CRYPTO_AES_256_NIST_GMAC:
@@ -524,7 +531,8 @@
if (crde == NULL || crda == NULL)
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);
@@ -555,6 +563,21 @@
}
}
+ if (swa) {
+ switch (swa->sw_alg) {
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_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;
+ break;
+ }
+ }
/* Supply MAC with IV */
if (axf->Reinit)
axf->Reinit(&ctx, iv, ivlen);
@@ -590,15 +613,20 @@
crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len,
blk);
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)
+ exf->decrypt(swe->sw_kschedule, blk);
axf->Update(&ctx, blk, len);
}
}
@@ -629,6 +657,8 @@
r = timingsafe_bcmp(aalg, uaalg, axf->hashsize);
if (r == 0) {
/* tag matches, decrypt data */
+ if (isccm && exf->reinit)
+ 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)
@@ -821,6 +851,9 @@
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;
@@ -947,6 +980,15 @@
break;
#endif
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ axf = &auth_hash_ccm_cbc_mac_128;
+ goto auth4common;
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ axf = &auth_hash_ccm_cbc_mac_192;
+ goto auth4common;
+ case CRYPTO_AES_256_CCM_CBC_MAC:
+ axf = &auth_hash_ccm_cbc_mac_256;
+ goto auth4common;
case CRYPTO_AES_128_NIST_GMAC:
axf = &auth_hash_nist_gmac_aes_128;
goto auth4common;
@@ -1216,11 +1258,15 @@
goto done;
break;
+ case CRYPTO_AES_CCM_16:
case CRYPTO_AES_NIST_GCM_16:
case CRYPTO_AES_NIST_GMAC:
case CRYPTO_AES_128_NIST_GMAC:
case CRYPTO_AES_192_NIST_GMAC:
case CRYPTO_AES_256_NIST_GMAC:
+ case CRYPTO_AES_128_CCM_CBC_MAC:
+ case CRYPTO_AES_192_CCM_CBC_MAC:
+ case CRYPTO_AES_256_CCM_CBC_MAC:
crp->crp_etype = swcr_authenc(crp);
goto done;
@@ -1305,6 +1351,10 @@
REGISTER(CRYPTO_BLAKE2B);
REGISTER(CRYPTO_BLAKE2S);
REGISTER(CRYPTO_CHACHA20);
+ REGISTER(CRYPTO_AES_CCM_16);
+ REGISTER(CRYPTO_AES_128_CCM_CBC_MAC);
+ REGISTER(CRYPTO_AES_192_CCM_CBC_MAC);
+ REGISTER(CRYPTO_AES_256_CCM_CBC_MAC);
#undef REGISTER
return 0;
Index: sys/opencrypto/xform_aes_icm.c
===================================================================
--- sys/opencrypto/xform_aes_icm.c
+++ sys/opencrypto/xform_aes_icm.c
@@ -57,6 +57,7 @@
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,16 @@
aes_gcm_reinit,
};
+struct enc_xform enc_xform_ccm = {
+ CRYPTO_AES_CCM_16, "AES-CCM",
+ AES_ICM_BLOCK_LEN, AES_GCM_IV_LEN, AES_MIN_KEY, AES_MAX_KEY,
+ aes_icm_crypt,
+ aes_icm_crypt,
+ aes_icm_setkey,
+ aes_icm_zerokey,
+ aes_ccm_reinit,
+};
+
/*
* Encryption wrapper routines.
*/
@@ -105,6 +116,19 @@
}
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 */
+ explicit_bzero(ctx->ac_block, sizeof(ctx->ac_block));
+ ctx->ac_block[0] = (15 - AES_GCM_IV_LEN) - 1; /* 3 bytes for length field; this gives a nonce of 12 bytes */
+ bcopy(iv, ctx->ac_block+1, AES_GCM_IV_LEN);
+ ctx->ac_block[AESICM_BLOCKSIZE - 1] = 1;
+}
+
+static void
aes_icm_crypt(caddr_t key, u_int8_t *data)
{
struct aes_icm_ctx *ctx;
Index: sys/opencrypto/xform_auth.h
===================================================================
--- sys/opencrypto/xform_auth.h
+++ sys/opencrypto/xform_auth.h
@@ -41,6 +41,7 @@
#include <crypto/sha2/sha512.h>
#include <opencrypto/rmd160.h>
#include <opencrypto/gmac.h>
+#include <opencrypto/ccm-cbc.h>
#include <opencrypto/cryptodev.h>
#include <opencrypto/xform_userland.h>
@@ -77,6 +78,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_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;
@@ -86,6 +90,7 @@
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_ */
Index: sys/opencrypto/xform_cbc_mac.c
===================================================================
--- sys/opencrypto/xform_cbc_mac.c
+++ sys/opencrypto/xform_cbc_mac.c
@@ -0,0 +1,37 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/ccm-cbc.h>
+#include <opencrypto/xform_auth.h>
+
+/* Authentication instances */
+struct auth_hash auth_hash_ccm_cbc_mac_128 = {
+ CRYPTO_AES_128_CCM_CBC_MAC, "CBC-CCM-AES-128",
+ AES_128_CBC_MAC_KEY_LEN, AES_CBC_MAC_HASH_LEN, sizeof(struct aes_cbc_mac_ctx),
+ CCM_CBC_BLOCK_LEN,
+ (void (*)(void *)) AES_CBC_MAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final
+};
+struct auth_hash auth_hash_ccm_cbc_mac_192 = {
+ CRYPTO_AES_192_CCM_CBC_MAC, "CBC-CCM-AES-192",
+ AES_192_CBC_MAC_KEY_LEN, AES_CBC_MAC_HASH_LEN, sizeof(struct aes_cbc_mac_ctx),
+ CCM_CBC_BLOCK_LEN,
+ (void (*)(void *)) AES_CBC_MAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final
+};
+struct auth_hash auth_hash_ccm_cbc_mac_256 = {
+ CRYPTO_AES_256_CCM_CBC_MAC, "CBC-CCM-AES-256",
+ AES_256_CBC_MAC_KEY_LEN, AES_CBC_MAC_HASH_LEN, sizeof(struct aes_cbc_mac_ctx),
+ CCM_CBC_BLOCK_LEN,
+ (void (*)(void *)) AES_CBC_MAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_CBC_MAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_CBC_MAC_Final
+};
Index: sys/opencrypto/xform_enc.h
===================================================================
--- sys/opencrypto/xform_enc.h
+++ sys/opencrypto/xform_enc.h
@@ -84,6 +84,7 @@
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)];
Index: tools/tools/crypto/cryptocheck.c
===================================================================
--- tools/tools/crypto/cryptocheck.c
+++ tools/tools/crypto/cryptocheck.c
@@ -131,7 +131,7 @@
const char *name;
int cipher;
int mac;
- enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type;
+ enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM, T_CCM } type;
const EVP_CIPHER *(*evp_cipher)(void);
const EVP_MD *(*evp_md)(void);
} algs[] = {
@@ -143,10 +143,12 @@
.evp_md = EVP_sha384 },
{ .name = "sha512", .mac = CRYPTO_SHA2_512_HMAC, .type = T_HMAC,
.evp_md = EVP_sha512 },
+#if 0
{ .name = "blake2b", .mac = CRYPTO_BLAKE2B, .type = T_HMAC,
.evp_md = EVP_blake2b512 },
{ .name = "blake2s", .mac = CRYPTO_BLAKE2S, .type = T_HMAC,
.evp_md = EVP_blake2s256 },
+#endif
{ .name = "aes-cbc", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
.evp_cipher = EVP_aes_128_cbc },
{ .name = "aes-cbc192", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
@@ -163,8 +165,10 @@
.evp_cipher = EVP_aes_128_xts },
{ .name = "aes-xts256", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
.evp_cipher = EVP_aes_256_xts },
+#if 0
{ .name = "chacha20", .cipher = CRYPTO_CHACHA20, .type = T_BLKCIPHER,
.evp_cipher = EVP_chacha20 },
+#endif
{ .name = "aes-gcm", .cipher = CRYPTO_AES_NIST_GCM_16,
.mac = CRYPTO_AES_128_NIST_GMAC, .type = T_GCM,
.evp_cipher = EVP_aes_128_gcm },
@@ -174,6 +178,15 @@
{ .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_128_CCM_CBC_MAC, .type = T_CCM,
+ .evp_cipher = EVP_aes_128_ccm },
+ { .name = "aes-ccm192", .cipher = CRYPTO_AES_CCM_16,
+ .mac = CRYPTO_AES_192_CCM_CBC_MAC, .type = T_CCM,
+ .evp_cipher = EVP_aes_192_ccm },
+ { .name = "aes-ccm256", .cipher = CRYPTO_AES_CCM_16,
+ .mac = CRYPTO_AES_256_CCM_CBC_MAC, .type = T_CCM,
+ .evp_cipher = EVP_aes_256_ccm },
};
static bool verbose;
@@ -1025,6 +1038,199 @@
}
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_GCM_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;
+
+ 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));
+ close(fd);
+ return (false);
+ }
+
+ if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
+ warn("ioctl(CIOCFSESSION)");
+
+ close(fd);
+ *cridp = sop.crid;
+ return (true);
+}
+
+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));
+
+ key_len = EVP_CIPHER_key_length(cipher);
+ iv_len = EVP_CIPHER_iv_length(cipher);
+
+ 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)
{
@@ -1041,6 +1247,9 @@
case T_GCM:
run_gcm_test(alg, size);
break;
+ case T_CCM:
+ run_ccm_test(alg, size);
+ break;
}
}
@@ -1100,7 +1309,8 @@
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);
}

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 1, 2:38 PM (8 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28391560
Default Alt Text
D15446.id42595.diff (29 KB)

Event Timeline