summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason King <jason.king@joyent.com>2018-01-25 18:49:57 +0000
committerJason King <jason.king@joyent.com>2018-10-05 09:35:58 -0500
commit6dfc9cdf26a31c05ac54748aa413187e43a0a214 (patch)
treee6154404cd96f5090928e071c88a0718f138e59e
parentb1917065992b99886121c8fbeeb447643cb0a1fb (diff)
downloadillumos-joyent-6dfc9cdf26a31c05ac54748aa413187e43a0a214.tar.gz
OS-6576 Add CCM and GCM mode support to AES in pkcs11_softtoken
Reviewed by: Dan McDonald <danmcd@joyent.com> Reviewed by: Robert Mustacchi <rm@joyent.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/common/crypto/aes/aes_impl.h5
-rw-r--r--usr/src/common/crypto/aes/aes_modes.c23
-rw-r--r--usr/src/common/crypto/modes/gcm.c6
-rw-r--r--usr/src/common/crypto/modes/modes.h4
-rw-r--r--usr/src/lib/pkcs11/libpkcs11/common/metaCrypt.c16
-rw-r--r--usr/src/lib/pkcs11/libsoftcrypto/Makefile.com4
-rw-r--r--usr/src/lib/pkcs11/libsoftcrypto/Makefile.targ6
-rw-r--r--usr/src/lib/pkcs11/libsoftcrypto/amd64/Makefile9
-rw-r--r--usr/src/lib/pkcs11/libsoftcrypto/common/mapfile-vers15
-rw-r--r--usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDecrypt.c24
-rw-r--r--usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEncrypt.c37
-rw-r--r--usr/src/lib/pkcs11/pkcs11_kernel/common/kernelGlobal.h2
-rw-r--r--usr/src/lib/pkcs11/pkcs11_kernel/common/kernelUtil.c15
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softAESCrypt.c1678
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softCrypt.h50
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softDecryptUtil.c256
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncrypt.c11
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncryptUtil.c311
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softKeystore.c52
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softSignUtil.c4
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softSlotToken.c8
-rw-r--r--usr/src/lib/pkcs11/pkcs11_softtoken/common/softVerifyUtil.c13
-rw-r--r--usr/src/test/crypto-tests/tests/common/cryptotest.h9
-rw-r--r--usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c19
-rw-r--r--usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c20
-rw-r--r--usr/src/test/crypto-tests/tests/modes/aes/Makefile.subdirs3
-rw-r--r--usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c72
-rw-r--r--usr/src/uts/common/crypto/io/aes.c17
-rw-r--r--usr/src/uts/common/crypto/io/crypto.c3
-rw-r--r--usr/src/uts/common/crypto/io/dprov.c4
30 files changed, 1232 insertions, 1464 deletions
diff --git a/usr/src/common/crypto/aes/aes_impl.h b/usr/src/common/crypto/aes/aes_impl.h
index d73729c03d..7021276162 100644
--- a/usr/src/common/crypto/aes/aes_impl.h
+++ b/usr/src/common/crypto/aes/aes_impl.h
@@ -21,6 +21,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018, Joyent, Inc.
*/
#ifndef _AES_IMPL_H
@@ -135,9 +137,10 @@ extern int aes_decrypt_block(const void *ks, const uint8_t *ct, uint8_t *pt);
/*
* AES mode functions.
- * The first 2 functions operate on 16-byte AES blocks.
+ * The first 3 functions operate on 16-byte AES blocks.
*/
extern void aes_copy_block(uint8_t *in, uint8_t *out);
+extern void aes_copy_block64(uint8_t *in, uint64_t *out);
extern void aes_xor_block(uint8_t *data, uint8_t *dst);
/* Note: ctx is a pointer to aes_ctx_t defined in modes.h */
diff --git a/usr/src/common/crypto/aes/aes_modes.c b/usr/src/common/crypto/aes/aes_modes.c
index 884bfa934c..b23c78d65c 100644
--- a/usr/src/common/crypto/aes/aes_modes.c
+++ b/usr/src/common/crypto/aes/aes_modes.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018, Joyent, Inc.
*/
#include <sys/types.h>
@@ -50,6 +51,24 @@ aes_copy_block(uint8_t *in, uint8_t *out)
}
}
+/*
+ * Copy a 16-byte AES block in 64-bit chunks if the input address is aligned
+ * to 64-bits
+ */
+void
+aes_copy_block64(uint8_t *in, uint64_t *out)
+{
+ if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
+ /* LINTED: pointer alignment */
+ out[0] = *(uint64_t *)&in[0];
+ /* LINTED: pointer alignment */
+ out[1] = *(uint64_t *)&in[8];
+ } else {
+ uint8_t *iv8 = (uint8_t *)&out[0];
+
+ AES_COPY_BLOCK(in, iv8);
+ }
+}
/* XOR a 16-byte AES block of data into dst */
void
@@ -83,7 +102,6 @@ aes_encrypt_contiguous_blocks(void *ctx, char *data, size_t length,
if (aes_ctx->ac_flags & CTR_MODE) {
rv = ctr_mode_contiguous_blocks(ctx, data, length, out,
AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
-#ifdef _KERNEL
} else if (aes_ctx->ac_flags & CCM_MODE) {
rv = ccm_mode_encrypt_contiguous_blocks(ctx, data, length,
out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
@@ -92,7 +110,6 @@ aes_encrypt_contiguous_blocks(void *ctx, char *data, size_t length,
rv = gcm_mode_encrypt_contiguous_blocks(ctx, data, length,
out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
aes_xor_block);
-#endif
} else if (aes_ctx->ac_flags & (CBC_MODE|CMAC_MODE)) {
rv = cbc_encrypt_contiguous_blocks(ctx,
data, length, out, AES_BLOCK_LEN, aes_encrypt_block,
@@ -120,7 +137,6 @@ aes_decrypt_contiguous_blocks(void *ctx, char *data, size_t length,
AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
if (rv == CRYPTO_DATA_LEN_RANGE)
rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
-#ifdef _KERNEL
} else if (aes_ctx->ac_flags & CCM_MODE) {
rv = ccm_mode_decrypt_contiguous_blocks(ctx, data, length,
out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
@@ -129,7 +145,6 @@ aes_decrypt_contiguous_blocks(void *ctx, char *data, size_t length,
rv = gcm_mode_decrypt_contiguous_blocks(ctx, data, length,
out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
aes_xor_block);
-#endif
} else if (aes_ctx->ac_flags & CBC_MODE) {
rv = cbc_decrypt_contiguous_blocks(ctx, data, length, out,
AES_BLOCK_LEN, aes_decrypt_block, aes_copy_block,
diff --git a/usr/src/common/crypto/modes/gcm.c b/usr/src/common/crypto/modes/gcm.c
index f75b0b70dd..564507abdc 100644
--- a/usr/src/common/crypto/modes/gcm.c
+++ b/usr/src/common/crypto/modes/gcm.c
@@ -20,17 +20,17 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018, Joyent, Inc.
*/
#ifndef _KERNEL
#include <strings.h>
#include <limits.h>
-#include <assert.h>
#include <security/cryptoki.h>
#endif /* _KERNEL */
-
+#include <sys/debug.h>
#include <sys/types.h>
#include <sys/kmem.h>
#include <modes/modes.h>
@@ -419,7 +419,7 @@ gcm_decrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
int processed = 0, rv;
- ASSERT(ctx->gcm_processed_data_len == ctx->gcm_pt_buf_len);
+ ASSERT3U(ctx->gcm_processed_data_len, ==, ctx->gcm_pt_buf_len);
pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
ghash = (uint8_t *)ctx->gcm_ghash;
diff --git a/usr/src/common/crypto/modes/modes.h b/usr/src/common/crypto/modes/modes.h
index efb3770eea..0ad18b0c25 100644
--- a/usr/src/common/crypto/modes/modes.h
+++ b/usr/src/common/crypto/modes/modes.h
@@ -23,6 +23,7 @@
* Use is subject to license terms.
*
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#ifndef _COMMON_CRYPTO_MODES_H
@@ -241,15 +242,14 @@ typedef struct aes_ctx {
ecb_ctx_t acu_ecb;
cbc_ctx_t acu_cbc;
ctr_ctx_t acu_ctr;
-#ifdef _KERNEL
ccm_ctx_t acu_ccm;
gcm_ctx_t acu_gcm;
-#endif
} acu;
} aes_ctx_t;
#define ac_flags acu.acu_ecb.ecb_common.cc_flags
#define ac_remainder_len acu.acu_ecb.ecb_common.cc_remainder_len
+#define ac_remainder acu.acu_ecb.ecb_common.cc_remainder
#define ac_keysched acu.acu_ecb.ecb_common.cc_keysched
#define ac_keysched_len acu.acu_ecb.ecb_common.cc_keysched_len
#define ac_iv acu.acu_ecb.ecb_common.cc_iv
diff --git a/usr/src/lib/pkcs11/libpkcs11/common/metaCrypt.c b/usr/src/lib/pkcs11/libpkcs11/common/metaCrypt.c
index 272469b54e..0df7ea84b3 100644
--- a/usr/src/lib/pkcs11/libpkcs11/common/metaCrypt.c
+++ b/usr/src/lib/pkcs11/libpkcs11/common/metaCrypt.c
@@ -21,10 +21,9 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018, Joyent, Inc.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Encryption and Decryption Functions
* (as defined in PKCS#11 spec sections 11.8 and 11.9)
@@ -83,7 +82,18 @@ meta_Encrypt(CK_SESSION_HANDLE hSession,
if (rv != CKR_OK)
return (rv);
- if (pData == NULL || pulEncryptedDataLen == NULL) {
+ if (pulEncryptedDataLen == NULL) {
+ meta_operation_cleanup(session, CKF_ENCRYPT, FALSE);
+ REFRELEASE(session);
+ return (CKR_ARGUMENTS_BAD);
+ }
+
+ /*
+ * Allow pData to be NULL as long as the length is 0 in order to
+ * support ciphers that permit 0 byte inputs (e.g. combined mode
+ * ciphers), otherwise consider pData being NULL as invalid.
+ */
+ if (pData == NULL && ulDataLen != 0) {
meta_operation_cleanup(session, CKF_ENCRYPT, FALSE);
REFRELEASE(session);
return (CKR_ARGUMENTS_BAD);
diff --git a/usr/src/lib/pkcs11/libsoftcrypto/Makefile.com b/usr/src/lib/pkcs11/libsoftcrypto/Makefile.com
index b97aa47114..3c01b7ad0c 100644
--- a/usr/src/lib/pkcs11/libsoftcrypto/Makefile.com
+++ b/usr/src/lib/pkcs11/libsoftcrypto/Makefile.com
@@ -21,6 +21,8 @@
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Jason King.
+# Copyright (c) 2018, Joyent, Inc.
#
# AES
@@ -55,7 +57,7 @@ BIGNUM_FLAGS = -I$(BIGNUM_DIR)
# Modes
MODES_DIR = $(SRC)/common/crypto/modes
-MODES_COMMON_OBJS = modes.o ecb.o cbc.o ctr.o
+MODES_COMMON_OBJS = modes.o ecb.o cbc.o ctr.o ccm.o gcm.o
MODES_COMMON_SRC = $(MODES_COMMON_OBJS:%.o=$(MODES_DIR)/%.c)
MODES_FLAGS = -I$(MODES_DIR)
diff --git a/usr/src/lib/pkcs11/libsoftcrypto/Makefile.targ b/usr/src/lib/pkcs11/libsoftcrypto/Makefile.targ
index 21de491517..582780c498 100644
--- a/usr/src/lib/pkcs11/libsoftcrypto/Makefile.targ
+++ b/usr/src/lib/pkcs11/libsoftcrypto/Makefile.targ
@@ -21,6 +21,8 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Jason King.
+# Copyright (c) 2018, Joyent, Inc.
#
AES_DIR = $(SRC)/common/crypto/aes
@@ -70,4 +72,8 @@ pics/%.o: $(PAD_DIR)/%.c
$(COMPILE.c) $(PAD_FLAGS) -o $@ $<
$(POST_PROCESS_O)
+pics/%.o: $(SRC_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/pkcs11/libsoftcrypto/amd64/Makefile b/usr/src/lib/pkcs11/libsoftcrypto/amd64/Makefile
index e5062536aa..1e8872d386 100644
--- a/usr/src/lib/pkcs11/libsoftcrypto/amd64/Makefile
+++ b/usr/src/lib/pkcs11/libsoftcrypto/amd64/Makefile
@@ -21,6 +21,8 @@
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Jason King
+# Copyright (c) 2018, Joyent, Inc.
#
LIBRARY = libsoftcrypto.a
@@ -31,6 +33,7 @@ include ../Makefile.com
AES_PSM_OBJS = aes_amd64.o aes_intel.o aeskey.o
ARCFOUR_PSM_OBJS = arcfour-x86_64.o
BIGNUM_PSM_OBJS = bignum_amd64.o bignum_amd64_asm.o
+MODES_PSM_OBJS = gcm_intel.o
include $(SRC)/lib/Makefile.lib
include $(SRC)/lib/Makefile.lib.64
@@ -46,6 +49,8 @@ ARCFOUR_PSM_SRC = arcfour-x86_64.s
BIGNUM_PSM_SRC = $(BIGNUM_DIR)/$(MACH64)/bignum_amd64.c \
$(BIGNUM_DIR)/$(MACH64)/bignum_amd64_asm.s
+MODES_PSM_SRC = $(MODES_DIR)/$(MACH64)/gcm_intel.s
+
# Sources need to be redefined after Makefile.lib inclusion.
SRCS = $(AES_SRC) $(ARCFOUR_SRC) $(BIGNUM_SRC) $(BLOWFISH_SRC) \
$(DES_SRC) $(MODES_SRC) $(DH_SRC) $(DSA_SRC) $(RSA_SRC) \
@@ -88,6 +93,10 @@ pics/%.o: $(BIGNUM_DIR)/$(MACH64)/%.s
$(COMPILE64.s) $(BIGNUM_FLAGS) -o $@ $<
$(POST_PROCESS_O)
+pics/%.o: $(MODES_DIR)/$(MACH64)/%.s
+ $(COMPILE64.s) $(MODES_FLAGS) -o $@ $<
+ $(POST_PROCESS_O)
+
include ../Makefile.targ
arcfour-x86_64.s: $(ARCFOUR_DIR)/amd64/arcfour-x86_64.pl
diff --git a/usr/src/lib/pkcs11/libsoftcrypto/common/mapfile-vers b/usr/src/lib/pkcs11/libsoftcrypto/common/mapfile-vers
index 377db64fa5..2b732729f0 100644
--- a/usr/src/lib/pkcs11/libsoftcrypto/common/mapfile-vers
+++ b/usr/src/lib/pkcs11/libsoftcrypto/common/mapfile-vers
@@ -21,6 +21,8 @@
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Jason King.
+# Copyright (c) 2018, Joyent, Inc.
#
#
@@ -44,6 +46,7 @@ SYMBOL_VERSION SUNWprivate {
global:
aes_alloc_keysched;
aes_copy_block;
+ aes_copy_block64;
aes_decrypt_block;
aes_decrypt_contiguous_blocks;
aes_encrypt_block;
@@ -78,8 +81,15 @@ SYMBOL_VERSION SUNWprivate {
blowfish_init_keysched;
bytestring2bignum;
cbc_alloc_ctx;
+ cbc_init_ctx;
+ ccm_alloc_ctx;
+ ccm_decrypt_final;
+ ccm_encrypt_final;
+ ccm_init_ctx;
+ cmac_alloc_ctx;
cmac_init_ctx;
cmac_mode_final;
+ ctr_alloc_ctx;
ctr_mode_final;
ctr_init_ctx;
des3_crunch_block;
@@ -94,6 +104,11 @@ SYMBOL_VERSION SUNWprivate {
dsa_genkey_pair;
dsa_sign;
dsa_verify;
+ ecb_alloc_ctx;
+ gcm_alloc_ctx;
+ gcm_decrypt_final;
+ gcm_encrypt_final;
+ gcm_init_ctx;
pkcs1_decode;
pkcs1_encode;
pkcs7_decode;
diff --git a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDecrypt.c b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDecrypt.c
index 57b5cbae3a..916bdc0625 100644
--- a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDecrypt.c
+++ b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDecrypt.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018, Joyent, Inc.
*/
#include <pthread.h>
@@ -45,6 +46,7 @@ kernel_decrypt_init(kernel_session_t *session_p, kernel_object_t *key_p,
crypto_mech_type_t k_mech_type;
boolean_t ses_lock_held = B_FALSE;
int r;
+ CK_AES_CCM_PARAMS ccm_params = { 0 };
/* Check to see if key object allows for decryption. */
if (key_p->is_lib_obj && !(key_p->bool_attr_mask & DECRYPT_BOOL_ON)) {
@@ -109,6 +111,23 @@ kernel_decrypt_init(kernel_session_t *session_p, kernel_object_t *key_p,
decrypt_init.di_mech.cm_param = pMechanism->pParameter;
decrypt_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
+ /*
+ * PKCS#11 uses CK_CCM_PARAMS as its mechanism parameter, while the
+ * kernel uses CK_AES_CCM_PARAMS. Unlike
+ * CK_GCM_PARAMS / CK_AES_GCM_PARAMS, the two definitions are not
+ * equivalent -- the fields are defined in different orders, so
+ * we must translate.
+ */
+ if (session_p->decrypt.mech.mechanism == CKM_AES_CCM) {
+ if (pMechanism->ulParameterLen != sizeof (CK_CCM_PARAMS)) {
+ rv = CKR_MECHANISM_PARAM_INVALID;
+ goto clean_exit;
+ }
+ p11_to_kernel_ccm_params(pMechanism->pParameter, &ccm_params);
+ decrypt_init.di_mech.cm_param = (caddr_t)&ccm_params;
+ decrypt_init.di_mech.cm_param_len = sizeof (ccm_params);
+ }
+
while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_INIT, &decrypt_init)) < 0) {
if (errno != EINTR)
break;
@@ -129,7 +148,10 @@ kernel_decrypt_init(kernel_session_t *session_p, kernel_object_t *key_p,
}
clean_exit:
-
+ /*
+ * ccm_params does not contain any key material -- just lengths and
+ * pointers, therefore it does not need to be zeroed on exit.
+ */
if (!ses_lock_held) {
(void) pthread_mutex_lock(&session_p->session_mutex);
ses_lock_held = B_TRUE;
diff --git a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEncrypt.c b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEncrypt.c
index d27945f877..5932dd0485 100644
--- a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEncrypt.c
+++ b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEncrypt.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018, Joyent, Inc.
*/
#include <pthread.h>
@@ -45,6 +46,7 @@ C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crypto_encrypt_init_t encrypt_init;
crypto_mech_type_t k_mech_type;
int r;
+ CK_AES_CCM_PARAMS ccm_params = { 0 };
if (!kernel_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
@@ -128,6 +130,23 @@ C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
encrypt_init.ei_mech.cm_param = pMechanism->pParameter;
encrypt_init.ei_mech.cm_param_len = pMechanism->ulParameterLen;
+ /*
+ * PKCS#11 uses CK_CCM_PARAMS as its mechanism parameter, while the
+ * kernel uses CK_AES_CCM_PARAMS. Unlike
+ * CK_GCM_PARAMS / CK_AES_GCM_PARAMS, the two definitions are not
+ * equivalent -- the fields are defined in different orders, so
+ * we much translate.
+ */
+ if (session_p->encrypt.mech.mechanism == CKM_AES_CCM) {
+ if (pMechanism->ulParameterLen != sizeof (CK_CCM_PARAMS)) {
+ rv = CKR_MECHANISM_PARAM_INVALID;
+ goto clean_exit;
+ }
+ p11_to_kernel_ccm_params(pMechanism->pParameter, &ccm_params);
+ encrypt_init.ei_mech.cm_param = (caddr_t)&ccm_params;
+ encrypt_init.ei_mech.cm_param_len = sizeof (ccm_params);
+ }
+
while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_INIT, &encrypt_init)) < 0) {
if (errno != EINTR)
break;
@@ -157,6 +176,10 @@ C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
}
clean_exit:
+ /*
+ * ccm_params does not contain any key material -- just lengths and
+ * pointers, therefore it does not need to be zeroed on exit.
+ */
OBJ_REFRELE(key_p);
REFRELE(session_p, ses_lock_held);
return (rv);
@@ -183,11 +206,6 @@ C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
if (rv != CKR_OK)
return (rv);
- if (pData == NULL) {
- rv = CKR_ARGUMENTS_BAD;
- goto clean_exit;
- }
-
/*
* Only check if pulEncryptedDataLen is NULL.
* No need to check if pEncryptedData is NULL because
@@ -199,6 +217,15 @@ C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
goto clean_exit;
}
+ /*
+ * Some encryption algs (often combined mode ciphers such as AES-GCM)
+ * allow 0-byte inputs to encrypt.
+ */
+ if (pData == NULL && ulDataLen != 0) {
+ rv = CKR_ARGUMENTS_BAD;
+ goto clean_exit;
+ }
+
(void) pthread_mutex_lock(&session_p->session_mutex);
ses_lock_held = B_TRUE;
diff --git a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelGlobal.h b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelGlobal.h
index 8cad200b83..20a6afc447 100644
--- a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelGlobal.h
+++ b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelGlobal.h
@@ -98,6 +98,8 @@ CK_RV kernel_decrypt(kernel_session_t *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
CK_ULONG_PTR);
CK_RV kernel_add_extra_attr(CK_ATTRIBUTE_PTR, kernel_object_t *);
+void p11_to_kernel_ccm_params(const CK_CCM_PARAMS *, CK_AES_CCM_PARAMS *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelUtil.c b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelUtil.c
index 670a6c7666..7231b62a08 100644
--- a/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelUtil.c
+++ b/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelUtil.c
@@ -1215,3 +1215,18 @@ get_mechanism_info(kernel_slot_t *pslot, CK_MECHANISM_TYPE type,
return (rv);
}
+
+/*
+ * Unfortunately the kernel and PKCS#11 use a slightly different struct to
+ * specify CCM parameters.
+ */
+void
+p11_to_kernel_ccm_params(const CK_CCM_PARAMS *in, CK_AES_CCM_PARAMS *out)
+{
+ out->ulMACSize = in->ulMACLen;
+ out->ulNonceSize = in->ulNonceLen;
+ out->ulAuthDataSize = in->ulAADLen;
+ out->ulDataSize = in->ulDataLen;
+ out->nonce = in->pNonce;
+ out->authData = in->pAAD;
+}
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softAESCrypt.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softAESCrypt.c
index fd27206e75..80b5dfd395 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softAESCrypt.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softAESCrypt.c
@@ -23,1017 +23,1064 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2017 Jason King.
*/
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
+#include <sys/debug.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <aes_impl.h>
+#include <cryptoutil.h>
#include "softSession.h"
#include "softObject.h"
#include "softCrypt.h"
#include "softOps.h"
/*
- * Allocate context for the active encryption or decryption operation, and
- * generate AES key schedule to speed up the operation.
+ * Check that the mechanism parameter is present and the correct size if
+ * required and allocate an AES context.
*/
-CK_RV
-soft_aes_crypt_init_common(soft_session_t *session_p,
- CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
- boolean_t encrypt)
+static CK_RV
+soft_aes_check_mech_param(CK_MECHANISM_PTR mech, aes_ctx_t **ctxp)
{
- size_t size;
- soft_aes_ctx_t *soft_aes_ctx;
+ void *(*allocf)(int) = NULL;
+ size_t param_len = 0;
+ boolean_t param_req = B_TRUE;
- soft_aes_ctx = calloc(1, sizeof (soft_aes_ctx_t));
- if (soft_aes_ctx == NULL) {
- return (CKR_HOST_MEMORY);
+ switch (mech->mechanism) {
+ case CKM_AES_ECB:
+ param_req = B_FALSE;
+ allocf = ecb_alloc_ctx;
+ break;
+ case CKM_AES_CMAC:
+ param_req = B_FALSE;
+ allocf = cmac_alloc_ctx;
+ break;
+ case CKM_AES_CMAC_GENERAL:
+ param_len = sizeof (CK_MAC_GENERAL_PARAMS);
+ allocf = cmac_alloc_ctx;
+ break;
+ case CKM_AES_CBC:
+ case CKM_AES_CBC_PAD:
+ param_len = AES_BLOCK_LEN;
+ allocf = cbc_alloc_ctx;
+ break;
+ case CKM_AES_CTR:
+ param_len = sizeof (CK_AES_CTR_PARAMS);
+ allocf = ctr_alloc_ctx;
+ break;
+ case CKM_AES_CCM:
+ param_len = sizeof (CK_CCM_PARAMS);
+ allocf = ccm_alloc_ctx;
+ break;
+ case CKM_AES_GCM:
+ param_len = sizeof (CK_GCM_PARAMS);
+ allocf = gcm_alloc_ctx;
+ break;
+ default:
+ return (CKR_MECHANISM_INVALID);
}
- soft_aes_ctx->key_sched = aes_alloc_keysched(&size, 0);
+ if (param_req && (mech->pParameter == NULL ||
+ mech->ulParameterLen != param_len)) {
+ return (CKR_MECHANISM_PARAM_INVALID);
+ }
- if (soft_aes_ctx->key_sched == NULL) {
- free(soft_aes_ctx);
+ *ctxp = allocf(0);
+ if (*ctxp == NULL) {
return (CKR_HOST_MEMORY);
}
- soft_aes_ctx->keysched_len = size;
+ return (CKR_OK);
+}
- (void) pthread_mutex_lock(&session_p->session_mutex);
- if (encrypt) {
- /* Called by C_EncryptInit. */
- session_p->encrypt.context = soft_aes_ctx;
- session_p->encrypt.mech.mechanism = pMechanism->mechanism;
- } else {
- /* Called by C_DecryptInit. */
- session_p->decrypt.context = soft_aes_ctx;
- session_p->decrypt.mech.mechanism = pMechanism->mechanism;
- }
- (void) pthread_mutex_unlock(&session_p->session_mutex);
+/*
+ * Create an AES key schedule for the given AES context from the given key.
+ * If the key is not sensitive, cache a copy of the key schedule in the
+ * key object and/or use the cached copy of the key schedule.
+ *
+ * Must be called before the init function for a given mode is called.
+ */
+static CK_RV
+soft_aes_init_key(aes_ctx_t *aes_ctx, soft_object_t *key_p)
+{
+ void *ks = NULL;
+ size_t size = 0;
+ CK_RV rv = CKR_OK;
+
+ (void) pthread_mutex_lock(&key_p->object_mutex);
/*
- * If this is a non-sensitive key and it does NOT have
- * a key schedule yet, then allocate one and expand it.
- * Otherwise, if it's a non-sensitive key, and it DOES have
- * a key schedule already attached to it, just copy the
- * pre-expanded schedule to the context and avoid the
- * extra key schedule expansion operation.
+ * AES keys should be either 128, 192, or 256 bits long.
+ * soft_object_t stores the key size in bytes, so we check those sizes
+ * in bytes.
+ *
+ * While soft_build_secret_key_object() does these same validations for
+ * keys created by the user, it may be possible that a key loaded from
+ * disk could be invalid or corrupt. We err on the side of caution
+ * and check again that it's the correct size before performing any
+ * AES operations.
*/
- if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
- if (OBJ_KEY_SCHED(key_p) == NULL) {
- void *ks;
-
- (void) pthread_mutex_lock(&key_p->object_mutex);
- if (OBJ_KEY_SCHED(key_p) == NULL) {
- ks = aes_alloc_keysched(&size, 0);
- if (ks == NULL) {
- (void) pthread_mutex_unlock(
- &key_p->object_mutex);
- free(soft_aes_ctx);
- return (CKR_HOST_MEMORY);
- }
+ switch (OBJ_SEC_VALUE_LEN(key_p)) {
+ case AES_MIN_KEY_BYTES:
+ case AES_MAX_KEY_BYTES:
+ case AES_192_KEY_BYTES:
+ break;
+ default:
+ rv = CKR_KEY_SIZE_RANGE;
+ goto done;
+ }
+
+ ks = aes_alloc_keysched(&size, 0);
+ if (ks == NULL) {
+ rv = CKR_HOST_MEMORY;
+ goto done;
+ }
+
+ /* If this is a sensitive key, always expand the key schedule */
+ if (key_p->bool_attr_mask & SENSITIVE_BOOL_ON) {
+ /* aes_init_keysched() requires key length in bits. */
#ifdef __sparcv9
- /* LINTED */
- aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
- (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
+ /* LINTED */
+ aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
+ (OBJ_SEC_VALUE_LEN(key_p) * NBBY), ks);
#else /* !__sparcv9 */
- aes_init_keysched(OBJ_SEC_VALUE(key_p),
- (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
+ aes_init_keysched(OBJ_SEC_VALUE(key_p),
+ (OBJ_SEC_VALUE_LEN(key_p) * NBBY), ks);
#endif /* __sparcv9 */
- OBJ_KEY_SCHED_LEN(key_p) = size;
- OBJ_KEY_SCHED(key_p) = ks;
- }
- (void) pthread_mutex_unlock(&key_p->object_mutex);
+
+ goto done;
+ }
+
+ /* If a non-sensitive key and doesn't have a key schedule, create it */
+ if (OBJ_KEY_SCHED(key_p) == NULL) {
+ void *obj_ks = NULL;
+
+ obj_ks = aes_alloc_keysched(&size, 0);
+ if (obj_ks == NULL) {
+ rv = CKR_HOST_MEMORY;
+ goto done;
}
- (void) memcpy(soft_aes_ctx->key_sched, OBJ_KEY_SCHED(key_p),
- OBJ_KEY_SCHED_LEN(key_p));
- soft_aes_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
- } else {
- /*
- * Initialize key schedule for AES. aes_init_keysched()
- * requires key length in bits.
- */
+
#ifdef __sparcv9
/* LINTED */
- aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
- (OBJ_SEC_VALUE_LEN(key_p) * 8), soft_aes_ctx->key_sched);
+ aes_init_keysched(OBJ_SEC_VALUE(key_p),
+ (uint_t)(OBJ_SEC_VALUE_LEN(key_p) * 8), obj_ks);
#else /* !__sparcv9 */
aes_init_keysched(OBJ_SEC_VALUE(key_p),
- (OBJ_SEC_VALUE_LEN(key_p) * 8), soft_aes_ctx->key_sched);
+ (OBJ_SEC_VALUE_LEN(key_p) * 8), obj_ks);
#endif /* __sparcv9 */
+
+ OBJ_KEY_SCHED_LEN(key_p) = size;
+ OBJ_KEY_SCHED(key_p) = obj_ks;
}
- return (CKR_OK);
+
+ (void) memcpy(ks, OBJ_KEY_SCHED(key_p), OBJ_KEY_SCHED_LEN(key_p));
+
+done:
+ (void) pthread_mutex_unlock(&key_p->object_mutex);
+
+ if (rv == CKR_OK) {
+ aes_ctx->ac_keysched = ks;
+ aes_ctx->ac_keysched_len = size;
+ } else {
+ freezero(ks, size);
+ }
+
+ return (rv);
}
+/*
+ * Initialize the AES context for the given mode, including allocating and
+ * expanding the key schedule if required.
+ */
+static CK_RV
+soft_aes_init_ctx(aes_ctx_t *aes_ctx, CK_MECHANISM_PTR mech_p,
+ boolean_t encrypt)
+{
+ int rc = CRYPTO_SUCCESS;
+
+ switch (mech_p->mechanism) {
+ case CKM_AES_ECB:
+ aes_ctx->ac_flags |= ECB_MODE;
+ break;
+ case CKM_AES_CMAC:
+ case CKM_AES_CMAC_GENERAL:
+ rc = cmac_init_ctx((cbc_ctx_t *)aes_ctx, AES_BLOCK_LEN);
+ break;
+ case CKM_AES_CBC:
+ case CKM_AES_CBC_PAD:
+ rc = cbc_init_ctx((cbc_ctx_t *)aes_ctx, mech_p->pParameter,
+ mech_p->ulParameterLen, AES_BLOCK_LEN, aes_copy_block64);
+ break;
+ case CKM_AES_CTR:
+ {
+ /*
+ * soft_aes_check_param() verifies this is !NULL and is the
+ * correct size.
+ */
+ CK_AES_CTR_PARAMS *pp = (CK_AES_CTR_PARAMS *)mech_p->pParameter;
+
+ rc = ctr_init_ctx((ctr_ctx_t *)aes_ctx, pp->ulCounterBits,
+ pp->cb, aes_copy_block);
+ break;
+ }
+ case CKM_AES_CCM: {
+ /* LINTED: pointer alignment */
+ CK_CCM_PARAMS *pp = (CK_CCM_PARAMS *)mech_p->pParameter;
+
+ /*
+ * The illumos ccm mode implementation predates the PKCS#11
+ * version that specifies CK_CCM_PARAMS. As a result, the order
+ * and names of the struct members are different, so we must
+ * translate. ccm_init_ctx() does not store a ref ccm_params,
+ * so it is safe to allocate on the stack.
+ */
+ CK_AES_CCM_PARAMS ccm_params = {
+ .ulMACSize = pp->ulMACLen,
+ .ulNonceSize = pp->ulNonceLen,
+ .ulAuthDataSize = pp->ulAADLen,
+ .ulDataSize = pp->ulDataLen,
+ .nonce = pp->pNonce,
+ .authData = pp->pAAD
+ };
+
+ rc = ccm_init_ctx((ccm_ctx_t *)aes_ctx, (char *)&ccm_params, 0,
+ encrypt, AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+ break;
+ }
+ case CKM_AES_GCM:
+ /*
+ * Similar to the ccm mode implementation, the gcm mode also
+ * predates PKCS#11 2.40, however in this instance
+ * CK_AES_GCM_PARAMS and CK_GCM_PARAMS are identical except
+ * for the member names, so we can just pass it along.
+ */
+ rc = gcm_init_ctx((gcm_ctx_t *)aes_ctx, mech_p->pParameter,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+ aes_xor_block);
+ break;
+ }
+
+ return (crypto2pkcs11_error_number(rc));
+}
/*
- * soft_aes_encrypt_common()
- *
- * Arguments:
- * session_p: pointer to soft_session_t struct
- * pData: pointer to the input data to be encrypted
- * ulDataLen: length of the input data
- * pEncrypted: pointer to the output data after encryption
- * pulEncryptedLen: pointer to the length of the output data
- * update: boolean flag indicates caller is soft_encrypt
- * or soft_encrypt_update
- *
- * Description:
- * This function calls the corresponding encrypt routine based
- * on the mechanism.
- *
- * Returns:
- * CKR_OK: success
- * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
- * is too small
- * CKR_FUNCTION_FAILED: encrypt function failed
- * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
+ * Allocate context for the active encryption or decryption operation, and
+ * generate AES key schedule to speed up the operation.
*/
CK_RV
-soft_aes_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
- CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
- CK_ULONG_PTR pulEncryptedLen, boolean_t update)
+soft_aes_crypt_init_common(soft_session_t *session_p,
+ CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
+ boolean_t encrypt)
{
+ aes_ctx_t *aes_ctx = NULL;
+ CK_RV rv = CKR_OK;
+
+ if (key_p->key_type != CKK_AES)
+ return (CKR_KEY_TYPE_INCONSISTENT);
+
+ /* C_{Encrypt,Decrypt}Init() validate pMechanism != NULL */
+ rv = soft_aes_check_mech_param(pMechanism, &aes_ctx);
+ if (rv != CKR_OK) {
+ goto done;
+ }
+
+ rv = soft_aes_init_key(aes_ctx, key_p);
+ if (rv != CKR_OK) {
+ goto done;
+ return (rv);
+ }
+
+ rv = soft_aes_init_ctx(aes_ctx, pMechanism, encrypt);
+ if (rv != CKR_OK) {
+ goto done;
+ return (rv);
+ }
+
+ (void) pthread_mutex_lock(&session_p->session_mutex);
+ if (encrypt) {
+ /* Called by C_EncryptInit. */
+ session_p->encrypt.context = aes_ctx;
+ session_p->encrypt.mech.mechanism = pMechanism->mechanism;
+ } else {
+ /* Called by C_DecryptInit. */
+ session_p->decrypt.context = aes_ctx;
+ session_p->decrypt.mech.mechanism = pMechanism->mechanism;
+ }
+ (void) pthread_mutex_unlock(&session_p->session_mutex);
+
+done:
+ if (rv != CKR_OK) {
+ soft_aes_free_ctx(aes_ctx);
+ }
+
+ return (rv);
+}
+
- int rc = 0;
+CK_RV
+soft_aes_encrypt(soft_session_t *session_p, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
+ CK_ULONG_PTR pulEncryptedDataLen)
+{
+ aes_ctx_t *aes_ctx = session_p->encrypt.context;
+ CK_MECHANISM_TYPE mech = session_p->encrypt.mech.mechanism;
+ size_t length_needed;
+ size_t remainder;
+ int rc = CRYPTO_SUCCESS;
CK_RV rv = CKR_OK;
- soft_aes_ctx_t *soft_aes_ctx =
- (soft_aes_ctx_t *)session_p->encrypt.context;
- aes_ctx_t *aes_ctx;
- CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
- CK_BYTE *in_buf = NULL;
- CK_BYTE *out_buf = NULL;
- CK_ULONG out_len;
- CK_ULONG total_len;
- CK_ULONG remain;
-
- if (mechanism == CKM_AES_CTR)
- goto do_encryption;
+ crypto_data_t out = {
+ .cd_format = CRYPTO_DATA_RAW,
+ .cd_offset = 0,
+ .cd_length = *pulEncryptedDataLen,
+ .cd_raw.iov_base = (char *)pEncryptedData,
+ .cd_raw.iov_len = *pulEncryptedDataLen
+ };
/*
- * AES only takes input length that is a multiple of blocksize
- * for C_Encrypt function with the mechanism CKM_AES_ECB or
- * CKM_AES_CBC.
- *
- * AES allows any input length for C_Encrypt function with the
- * mechanism CKM_AES_CBC_PAD and for C_EncryptUpdate function.
+ * A bit unusual, but it's permissible for ccm and gcm modes to not
+ * encrypt any data. This ends up being equivalent to CKM_AES_CMAC
+ * or CKM_AES_GMAC of the additional authenticated data (AAD).
*/
- if ((!update) && (mechanism != CKM_AES_CBC_PAD) &&
- (mechanism != CKM_AES_CMAC)) {
- if ((ulDataLen % AES_BLOCK_LEN) != 0) {
+ if ((pData == NULL || ulDataLen == 0) &&
+ !(aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|CMAC_MODE))) {
+ return (CKR_ARGUMENTS_BAD);
+ }
+
+ remainder = ulDataLen & (AES_BLOCK_LEN - 1);
+
+ /*
+ * CTR, CCM, CMAC, and GCM modes do not require the plaintext
+ * to be a multiple of the AES block size. CKM_AES_CBC_PAD as the
+ * name suggests pads it's output, so it can also accept any
+ * size plaintext.
+ */
+ switch (mech) {
+ case CKM_AES_CBC_PAD:
+ case CKM_AES_CMAC:
+ case CKM_AES_CMAC_GENERAL:
+ case CKM_AES_CTR:
+ case CKM_AES_CCM:
+ case CKM_AES_GCM:
+ break;
+ default:
+ if (remainder != 0) {
rv = CKR_DATA_LEN_RANGE;
goto cleanup;
}
}
- if (!update) {
- /*
- * Called by C_Encrypt
- */
- if (mechanism == CKM_AES_CBC_PAD) {
- /*
- * For CKM_AES_CBC_PAD, compute output length to
- * count for the padding. If the length of input
- * data is a multiple of blocksize, then make output
- * length to be the sum of the input length and
- * one blocksize. Otherwise, output length will
- * be rounded up to the next multiple of blocksize.
- */
- out_len = AES_BLOCK_LEN *
- (ulDataLen / AES_BLOCK_LEN + 1);
- } else if (mechanism == CKM_AES_CMAC) {
- out_len = AES_BLOCK_LEN;
- } else {
- /*
- * For non-padding mode, the output length will
- * be same as the input length.
- */
- out_len = ulDataLen;
+ switch (aes_ctx->ac_flags & (CMAC_MODE|CCM_MODE|GCM_MODE)) {
+ case CCM_MODE:
+ length_needed = ulDataLen + aes_ctx->ac_mac_len;
+ break;
+ case GCM_MODE:
+ length_needed = ulDataLen + aes_ctx->ac_tag_len;
+ break;
+ case CMAC_MODE:
+ length_needed = AES_BLOCK_LEN;
+ break;
+ default:
+ length_needed = ulDataLen;
+
+ /* CKM_AES_CBC_PAD out pads to a multiple of AES_BLOCK_LEN */
+ if (mech == CKM_AES_CBC_PAD) {
+ length_needed += AES_BLOCK_LEN - remainder;
}
+ }
+ if (pEncryptedData == NULL) {
/*
- * If application asks for the length of the output buffer
- * to hold the ciphertext?
+ * The application can ask for the size of the output buffer
+ * with a NULL output buffer (pEncryptedData).
+ * C_Encrypt() guarantees pulEncryptedDataLen != NULL.
*/
- if (pEncrypted == NULL) {
- *pulEncryptedLen = out_len;
- return (CKR_OK);
- }
+ *pulEncryptedDataLen = length_needed;
+ return (CKR_OK);
+ }
- /* Is the application-supplied buffer large enough? */
- if (*pulEncryptedLen < out_len) {
- *pulEncryptedLen = out_len;
- return (CKR_BUFFER_TOO_SMALL);
- }
+ if (*pulEncryptedDataLen < length_needed) {
+ *pulEncryptedDataLen = length_needed;
+ return (CKR_BUFFER_TOO_SMALL);
+ }
- /* Encrypt pad bytes in a separate operation */
- if (mechanism == CKM_AES_CBC_PAD) {
- out_len -= AES_BLOCK_LEN;
- }
+ if (ulDataLen > 0) {
+ rv = soft_aes_encrypt_update(session_p, pData, ulDataLen,
+ pEncryptedData, pulEncryptedDataLen);
- in_buf = pData;
- out_buf = pEncrypted;
- } else {
- /*
- * Called by C_EncryptUpdate
- *
- * Add the lengths of last remaining data and current
- * plaintext together to get the total input length.
- */
- total_len = soft_aes_ctx->remain_len + ulDataLen;
+ if (rv != CKR_OK) {
+ rv = CKR_FUNCTION_FAILED;
+ goto cleanup;
+ }
/*
- * If the total input length is less than one blocksize,
- * or if the total input length is just one blocksize and
- * the mechanism is CKM_AES_CBC_PAD, we will need to delay
- * encryption until when more data comes in next
- * C_EncryptUpdate or when C_EncryptFinal is called.
+ * Some modes (e.g. CCM and GCM) will append data such as a MAC
+ * to the ciphertext after the plaintext has been encrypted.
+ * Update out to reflect the amount of data in pEncryptedData
+ * after encryption.
*/
- out_buf = pEncrypted;
+ out.cd_offset = *pulEncryptedDataLen;
+ }
+ /*
+ * As CKM_AES_CTR is a stream cipher, ctr_mode_final is always
+ * invoked in the _update() functions, so we do not need to call it
+ * here.
+ */
+ if (mech == CKM_AES_CBC_PAD) {
/*
- * We prefer to let the underlying implementation of CMAC handle
- * the storing of extra bytes, and no data is output until
- * *_final, so skip that part of the following validation.
+ * aes_encrypt_contiguous_blocks() accumulates plaintext
+ * in aes_ctx and then encrypts once it has accumulated
+ * a multiple of AES_BLOCK_LEN bytes of plaintext (through one
+ * or more calls). Any leftover plaintext is left in aes_ctx
+ * for subsequent calls. If there is any remaining plaintext
+ * at the end, we pad it out to to AES_BLOCK_LEN using the
+ * amount of padding to add as the value of the pad bytes
+ * (i.e. PKCS#7 padding) and call
+ * aes_encrypt_contiguous_blocks() one last time.
+ *
+ * Even when the input is already a multiple of AES_BLOCK_LEN,
+ * we must add an additional full block so that we can determine
+ * the amount of padding to remove during decryption (by
+ * examining the last byte of the decrypted ciphertext).
*/
- if (mechanism == CKM_AES_CMAC) {
- if (pEncrypted == NULL) {
- *pulEncryptedLen = ulDataLen;
- return (CKR_OK);
- }
+ size_t amt = AES_BLOCK_LEN - remainder;
+ char block[AES_BLOCK_LEN];
- remain = 0;
- in_buf = pData;
- goto do_encryption;
- }
-
- if ((total_len < AES_BLOCK_LEN) ||
- ((mechanism == CKM_AES_CBC_PAD) &&
- (total_len == AES_BLOCK_LEN))) {
- if (pEncrypted != NULL) {
- /*
- * Save input data and its length in
- * the remaining buffer of AES context.
- */
- (void) memcpy(soft_aes_ctx->data +
- soft_aes_ctx->remain_len, pData, ulDataLen);
- soft_aes_ctx->remain_len += ulDataLen;
- }
-
- /* Set encrypted data length to 0. */
- *pulEncryptedLen = 0;
- return (CKR_OK);
- }
-
- /* Compute the length of remaing data. */
- remain = total_len % AES_BLOCK_LEN;
+ ASSERT3U(remainder, ==, aes_ctx->ac_remainder_len);
+ ASSERT3U(amt + remainder, ==, AES_BLOCK_LEN);
/*
- * Make sure that the output length is a multiple of
- * blocksize.
+ * The existing soft_add_pkcs7_padding() interface is
+ * overkill for what is effectively a memset(). A better
+ * RFE would be to create a CBC_PAD mode.
*/
- out_len = total_len - remain;
+ (void) memset(block, amt & 0xff, sizeof (block));
+ rc = aes_encrypt_contiguous_blocks(aes_ctx, block, amt, &out);
+ } else if (aes_ctx->ac_flags & CCM_MODE) {
+ rc = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, &out,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+ } else if (aes_ctx->ac_flags & GCM_MODE) {
+ rc = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, &out,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+ aes_xor_block);
+ } else if (aes_ctx->ac_flags & CMAC_MODE) {
+ rc = cmac_mode_final((cbc_ctx_t *)aes_ctx, &out,
+ aes_encrypt_block, aes_xor_block);
+ aes_ctx->ac_remainder_len = 0;
+ }
- /*
- * If application asks for the length of the output buffer
- * to hold the ciphertext?
- */
- if (pEncrypted == NULL) {
- *pulEncryptedLen = out_len;
- return (CKR_OK);
- }
+cleanup:
+ if (rc != CRYPTO_SUCCESS && rv == CKR_OK) {
+ *pulEncryptedDataLen = 0;
+ rv = crypto2pkcs11_error_number(rc);
+ }
- /* Is the application-supplied buffer large enough? */
- if (*pulEncryptedLen < out_len) {
- *pulEncryptedLen = out_len;
- return (CKR_BUFFER_TOO_SMALL);
- }
+ (void) pthread_mutex_lock(&session_p->session_mutex);
+ soft_aes_free_ctx(aes_ctx);
+ session_p->encrypt.context = NULL;
+ (void) pthread_mutex_unlock(&session_p->session_mutex);
- if (soft_aes_ctx->remain_len != 0) {
- /*
- * Copy last remaining data and current input data
- * to the output buffer.
- */
- (void) memmove(pEncrypted + soft_aes_ctx->remain_len,
- pData, out_len - soft_aes_ctx->remain_len);
- (void) memcpy(pEncrypted, soft_aes_ctx->data,
- soft_aes_ctx->remain_len);
- bzero(soft_aes_ctx->data, soft_aes_ctx->remain_len);
-
- in_buf = pEncrypted;
- } else {
- in_buf = pData;
- }
+ if (rv == CKR_OK) {
+ *pulEncryptedDataLen = out.cd_offset;
}
-do_encryption:
- /*
- * Begin Encryption now.
- */
- switch (mechanism) {
+ return (rv);
+}
- case CKM_AES_ECB:
- {
+CK_RV
+soft_aes_decrypt(soft_session_t *session_p, CK_BYTE_PTR pEncryptedData,
+ CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+ aes_ctx_t *aes_ctx = session_p->decrypt.context;
+ CK_MECHANISM_TYPE mech = session_p->decrypt.mech.mechanism;
+ size_t length_needed;
+ size_t remainder;
+ int rc = CRYPTO_SUCCESS;
+ CK_RV rv = CKR_OK;
+ crypto_data_t out = {
+ .cd_format = CRYPTO_DATA_RAW,
+ .cd_offset = 0,
+ .cd_length = *pulDataLen,
+ .cd_raw.iov_base = (char *)pData,
+ .cd_raw.iov_len = *pulDataLen
+ };
- ulong_t i;
- uint8_t *tmp_inbuf;
- uint8_t *tmp_outbuf;
+ /*
+ * A bit unusual, but it's permissible for ccm and gcm modes to not
+ * decrypt any data. This ends up being equivalent to CKM_AES_CMAC
+ * or CKM_AES_GMAC of the additional authenticated data (AAD).
+ */
+ if ((pEncryptedData == NULL || ulEncryptedDataLen == 0) &&
+ !(aes_ctx->ac_flags & (CCM_MODE|GCM_MODE))) {
+ return (CKR_ARGUMENTS_BAD);
+ }
- for (i = 0; i < out_len; i += AES_BLOCK_LEN) {
- tmp_inbuf = &in_buf[i];
- tmp_outbuf = &out_buf[i];
- /* Crunch one block of data for AES. */
- (void) aes_encrypt_block(soft_aes_ctx->key_sched,
- tmp_inbuf, tmp_outbuf);
- }
+ remainder = ulEncryptedDataLen & (AES_BLOCK_LEN - 1);
- if (update) {
- /*
- * For encrypt update, if there is a remaining
- * data, save it and its length in the context.
- */
- if (remain != 0)
- (void) memcpy(soft_aes_ctx->data, pData +
- (ulDataLen - remain), remain);
- soft_aes_ctx->remain_len = remain;
+ /*
+ * CTR, CCM, CMAC, and GCM modes do not require the ciphertext
+ * to be a multiple of the AES block size. Note that while
+ * CKM_AES_CBC_PAD accepts an arbitrary sized plaintext, the
+ * ciphertext is always a multiple of the AES block size
+ */
+ switch (mech) {
+ case CKM_AES_CMAC:
+ case CKM_AES_CMAC_GENERAL:
+ case CKM_AES_CTR:
+ case CKM_AES_CCM:
+ case CKM_AES_GCM:
+ break;
+ default:
+ if (remainder != 0) {
+ rv = CKR_DATA_LEN_RANGE;
+ goto cleanup;
}
+ }
- *pulEncryptedLen = out_len;
-
+ switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE)) {
+ case CCM_MODE:
+ length_needed = aes_ctx->ac_processed_data_len;
+ break;
+ case GCM_MODE:
+ length_needed = ulEncryptedDataLen - aes_ctx->ac_tag_len;
break;
+ default:
+ /*
+ * Note: for CKM_AES_CBC_PAD, we cannot know exactly how much
+ * space is needed for the plaintext until after we decrypt it.
+ * However, it is permissible to return a value 'somewhat'
+ * larger than necessary (PKCS#11 Base Specification, sec 5.2).
+ *
+ * Since CKM_AES_CBC_PAD adds at most AES_BLOCK_LEN bytes to
+ * the plaintext, we report the ciphertext length as the
+ * required plaintext length. This means we specify at most
+ * AES_BLOCK_LEN additional bytes of memory for the plaintext.
+ *
+ * This behavior is slightly different from the earlier
+ * version of this code which returned the value of
+ * (ulEncryptedDataLen - AES_BLOCK_LEN), which was only ever
+ * correct when the original plaintext was already a multiple
+ * of AES_BLOCK_LEN (i.e. when AES_BLOCK_LEN of padding was
+ * added). This should not be a concern for existing
+ * consumers -- if they were previously using the value of
+ * *pulDataLen to size the outbut buffer, the resulting
+ * plaintext would be truncated anytime the original plaintext
+ * wasn't a multiple of AES_BLOCK_LEN. No consumer should
+ * be relying on such wrong behavior. More likely they are
+ * using the size of the ciphertext or larger for the
+ * buffer to hold the decrypted plaintext (which is always
+ * acceptable).
+ */
+ length_needed = ulEncryptedDataLen;
}
- case CKM_AES_CMAC:
- out_len = ulDataLen;
- /*FALLTHRU*/
- case CKM_AES_CBC:
- case CKM_AES_CBC_PAD:
- {
- crypto_data_t out;
-
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = out_len;
- out.cd_raw.iov_base = (char *)out_buf;
- out.cd_raw.iov_len = out_len;
-
- /* Encrypt multiple blocks of data. */
- rc = aes_encrypt_contiguous_blocks(
- (aes_ctx_t *)soft_aes_ctx->aes_cbc,
- (char *)in_buf, out_len, &out);
+ if (pData == NULL) {
+ /*
+ * The application can ask for the size of the output buffer
+ * with a NULL output buffer (pData).
+ * C_Decrypt() guarantees pulDataLen != NULL.
+ */
+ *pulDataLen = length_needed;
+ return (CKR_OK);
+ }
- if (rc != 0)
- goto encrypt_failed;
+ if (*pulDataLen < length_needed) {
+ *pulDataLen = length_needed;
+ return (CKR_BUFFER_TOO_SMALL);
+ }
- if (update) {
- /*
- * For encrypt update, if there is remaining data,
- * save it and its length in the context.
- */
- if (remain != 0)
- (void) memcpy(soft_aes_ctx->data, pData +
- (ulDataLen - remain), remain);
- soft_aes_ctx->remain_len = remain;
- } else if (mechanism == CKM_AES_CBC_PAD) {
- /*
- * Save the remainder of the input
- * block in a temporary block because
- * we dont want to overrun the buffer
- * by tacking on pad bytes.
- */
- CK_BYTE tmpblock[AES_BLOCK_LEN];
- (void) memcpy(tmpblock, in_buf + out_len,
- ulDataLen - out_len);
- soft_add_pkcs7_padding(tmpblock +
- (ulDataLen - out_len),
- AES_BLOCK_LEN, ulDataLen - out_len);
-
- out.cd_offset = out_len;
- out.cd_length = AES_BLOCK_LEN;
- out.cd_raw.iov_base = (char *)out_buf;
- out.cd_raw.iov_len = out_len + AES_BLOCK_LEN;
-
- /* Encrypt last block containing pad bytes. */
- rc = aes_encrypt_contiguous_blocks(
- (aes_ctx_t *)soft_aes_ctx->aes_cbc,
- (char *)tmpblock, AES_BLOCK_LEN, &out);
-
- out_len += AES_BLOCK_LEN;
- } else if (mechanism == CKM_AES_CMAC) {
- out.cd_length = AES_BLOCK_LEN;
- out.cd_raw.iov_base = (char *)out_buf;
- out.cd_raw.iov_len = AES_BLOCK_LEN;
-
- rc = cmac_mode_final(soft_aes_ctx->aes_cbc, &out,
- aes_encrypt_block, aes_xor_block);
- }
+ if (ulEncryptedDataLen > 0) {
+ rv = soft_aes_decrypt_update(session_p, pEncryptedData,
+ ulEncryptedDataLen, pData, pulDataLen);
+ }
- if (rc == 0) {
- *pulEncryptedLen = out_len;
- break;
- }
-encrypt_failed:
- *pulEncryptedLen = 0;
+ if (rv != CKR_OK) {
rv = CKR_FUNCTION_FAILED;
goto cleanup;
}
- case CKM_AES_CTR:
- {
- crypto_data_t out;
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = *pulEncryptedLen;
- out.cd_raw.iov_base = (char *)pEncrypted;
- out.cd_raw.iov_len = *pulEncryptedLen;
-
- rc = aes_encrypt_contiguous_blocks(soft_aes_ctx->aes_cbc,
- (char *)pData, ulDataLen, &out);
+ /*
+ * Some modes (e.g. CCM and GCM) will output additional data
+ * after the plaintext (such as the MAC). Update out to
+ * reflect the amount of data in pData for the _final() functions.
+ */
+ out.cd_offset = *pulDataLen;
- if (rc != 0) {
- *pulEncryptedLen = 0;
- rv = CKR_FUNCTION_FAILED;
- goto cleanup;
- }
- /*
- * Since AES counter mode is a stream cipher, we call
- * aes_counter_final() to pick up any remaining bytes.
- * It is an internal function that does not destroy
- * the context like *normal* final routines.
- */
- if (((aes_ctx_t *)soft_aes_ctx->aes_cbc)->ac_remainder_len > 0)
- rc = ctr_mode_final(soft_aes_ctx->aes_cbc, &out,
- aes_encrypt_block);
+ /*
+ * As CKM_AES_CTR is a stream cipher, ctr_mode_final is always
+ * invoked in the _update() functions, so we do not need to call it
+ * here.
+ */
+ if (mech == CKM_AES_CBC_PAD) {
+ rv = soft_remove_pkcs7_padding(pData, *pulDataLen, pulDataLen);
+ } else if (aes_ctx->ac_flags & CCM_MODE) {
+ ASSERT3U(aes_ctx->ac_processed_data_len, ==,
+ aes_ctx->ac_data_len);
+ ASSERT3U(aes_ctx->ac_processed_mac_len, ==,
+ aes_ctx->ac_mac_len);
+
+ rc = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, &out,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+ aes_xor_block);
+ } else if (aes_ctx->ac_flags & GCM_MODE) {
+ rc = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, &out,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+ }
- /*
- * Even though success means we've encrypted all of the input,
- * we should still behave like the other functions and return
- * the encrypted length in pulEncryptedLen
- */
- *pulEncryptedLen = ulDataLen;
+cleanup:
+ if (rc != CRYPTO_SUCCESS && rv == CKR_OK) {
+ rv = crypto2pkcs11_error_number(rc);
+ *pulDataLen = 0;
}
- } /* end switch */
- if (update)
- return (CKR_OK);
+ if (rv == CKR_OK) {
+ *pulDataLen = out.cd_offset;
+ }
- /*
- * The following code will be executed if the caller is
- * soft_encrypt() or an error occurred. The encryption
- * operation will be terminated so we need to do some cleanup.
- */
-cleanup:
(void) pthread_mutex_lock(&session_p->session_mutex);
- aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
- switch (mechanism) {
- case CKM_AES_ECB:
- freezero(aes_ctx, sizeof (ecb_ctx_t));
- break;
- case CKM_AES_CMAC:
- case CKM_AES_CBC:
- case CKM_AES_CBC_PAD:
- freezero(aes_ctx, sizeof (cbc_ctx_t));
- break;
- case CKM_AES_CTR:
- freezero(aes_ctx, sizeof (ctr_ctx_t));
- break;
- }
- freezero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
- freezero(session_p->encrypt.context, sizeof (soft_aes_ctx_t));
- session_p->encrypt.context = NULL;
+ soft_aes_free_ctx(aes_ctx);
+ session_p->decrypt.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
-
-/*
- * soft_aes_decrypt_common()
- *
- * Arguments:
- * session_p: pointer to soft_session_t struct
- * pEncrypted: pointer to the input data to be decrypted
- * ulEncryptedLen: length of the input data
- * pData: pointer to the output data
- * pulDataLen: pointer to the length of the output data
- * Update: boolean flag indicates caller is soft_decrypt
- * or soft_decrypt_update
- *
- * Description:
- * This function calls the corresponding decrypt routine based
- * on the mechanism.
- *
- * Returns:
- * CKR_OK: success
- * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
- * is too small
- * CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
- * of blocksize
- * CKR_FUNCTION_FAILED: decrypt function failed
- */
CK_RV
-soft_aes_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
- CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
- CK_ULONG_PTR pulDataLen, boolean_t update)
+soft_aes_encrypt_update(soft_session_t *session_p, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
+ CK_ULONG_PTR pulEncryptedDataLen)
{
-
- int rc = 0;
+ aes_ctx_t *aes_ctx = session_p->encrypt.context;
+ crypto_data_t out = {
+ .cd_format = CRYPTO_DATA_RAW,
+ .cd_offset = 0,
+ .cd_length = *pulEncryptedDataLen,
+ .cd_raw.iov_base = (char *)pEncryptedData,
+ .cd_raw.iov_len = *pulEncryptedDataLen
+ };
+ CK_MECHANISM_TYPE mech = session_p->encrypt.mech.mechanism;
CK_RV rv = CKR_OK;
- soft_aes_ctx_t *soft_aes_ctx =
- (soft_aes_ctx_t *)session_p->decrypt.context;
- aes_ctx_t *aes_ctx;
- CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
- CK_BYTE *in_buf = NULL;
- CK_BYTE *out_buf = NULL;
- CK_ULONG out_len;
- CK_ULONG total_len;
- CK_ULONG remain;
-
- if (mechanism == CKM_AES_CTR)
- goto do_decryption;
+ size_t out_len = aes_ctx->ac_remainder_len + ulDataLen;
+ int rc;
- /*
- * AES only takes input length that is a multiple of 16 bytes
- * for C_Decrypt function with the mechanism CKM_AES_ECB,
- * CKM_AES_CBC or CKM_AES_CBC_PAD.
- *
- * AES allows any input length for C_DecryptUpdate function.
- */
- if (!update) {
+ /* Check size of the output buffer */
+ if (mech == CKM_AES_CBC_PAD && (out_len <= AES_BLOCK_LEN)) {
/*
- * Called by C_Decrypt
+ * Since there is currently no CBC_PAD mode, we must stash any
+ * remainder ourselves. For all other modes,
+ * aes_encrypt_contiguous_blocks() will call the mode specific
+ * encrypt function and will stash any reminder if required.
*/
- if ((ulEncryptedLen % AES_BLOCK_LEN) != 0) {
- rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
- goto cleanup;
+ if (pData != NULL) {
+ uint8_t *dest = (uint8_t *)aes_ctx->ac_remainder +
+ aes_ctx->ac_remainder_len;
+
+ bcopy(pData, dest, ulDataLen);
+ aes_ctx->ac_remainder_len += ulDataLen;
}
+ *pulEncryptedDataLen = 0;
+ return (CKR_OK);
+ } else if (aes_ctx->ac_flags & CMAC_MODE) {
/*
- * If application asks for the length of the output buffer
- * to hold the plaintext?
+ * The underlying CMAC implementation handles the storing of
+ * extra bytes and does not output any data until *_final,
+ * so do not bother looking at the size of the output
+ * buffer at this time.
*/
if (pData == NULL) {
- *pulDataLen = ulEncryptedLen;
+ *pulEncryptedDataLen = 0;
return (CKR_OK);
}
-
- /* Is the application-supplied buffer large enough? */
- if (mechanism != CKM_AES_CBC_PAD) {
- if (*pulDataLen < ulEncryptedLen) {
- *pulDataLen = ulEncryptedLen;
- return (CKR_BUFFER_TOO_SMALL);
- }
- out_len = ulEncryptedLen;
- } else {
- /*
- * For CKM_AES_CBC_PAD, we don't know how
- * many bytes for padding at this time, so
- * we'd assume one block was padded.
- */
- if (*pulDataLen < (ulEncryptedLen - AES_BLOCK_LEN)) {
- *pulDataLen = ulEncryptedLen - AES_BLOCK_LEN;
- return (CKR_BUFFER_TOO_SMALL);
- }
- out_len = ulEncryptedLen - AES_BLOCK_LEN;
- }
- in_buf = pEncrypted;
- out_buf = pData;
} else {
/*
- * Called by C_DecryptUpdate
- *
- * Add the lengths of last remaining data and current
- * input data together to get the total input length.
+ * The number of complete blocks we can encrypt right now.
+ * The underlying implementation will buffer any remaining data
+ * until the next *_update call.
*/
- total_len = soft_aes_ctx->remain_len + ulEncryptedLen;
+ out_len &= ~(AES_BLOCK_LEN - 1);
- /*
- * If the total input length is less than one blocksize,
- * or if the total input length is just one blocksize and
- * the mechanism is CKM_AES_CBC_PAD, we will need to delay
- * decryption until when more data comes in next
- * C_DecryptUpdate or when C_DecryptFinal is called.
- */
- if ((total_len < AES_BLOCK_LEN) ||
- ((mechanism == CKM_AES_CBC_PAD) &&
- (total_len == AES_BLOCK_LEN))) {
- if (pData != NULL) {
- /*
- * Save input data and its length in
- * the remaining buffer of AES context.
- */
- (void) memcpy(soft_aes_ctx->data +
- soft_aes_ctx->remain_len,
- pEncrypted, ulEncryptedLen);
- soft_aes_ctx->remain_len += ulEncryptedLen;
- }
-
- /* Set output data length to 0. */
- *pulDataLen = 0;
+ if (pEncryptedData == NULL) {
+ *pulEncryptedDataLen = out_len;
return (CKR_OK);
}
- /* Compute the length of remaing data. */
- remain = total_len % AES_BLOCK_LEN;
-
- /*
- * Make sure that the output length is a multiple of
- * blocksize.
- */
- out_len = total_len - remain;
-
- if (mechanism == CKM_AES_CBC_PAD) {
- /*
- * If the input data length is a multiple of
- * blocksize, then save the last block of input
- * data in the remaining buffer. C_DecryptFinal
- * will handle this last block of data.
- */
- if (remain == 0) {
- remain = AES_BLOCK_LEN;
- out_len -= AES_BLOCK_LEN;
- }
+ if (*pulEncryptedDataLen < out_len) {
+ *pulEncryptedDataLen = out_len;
+ return (CKR_BUFFER_TOO_SMALL);
}
+ }
- /*
- * If application asks for the length of the output buffer
- * to hold the plaintext?
- */
- if (pData == NULL) {
- *pulDataLen = out_len;
- return (CKR_OK);
- }
+ rc = aes_encrypt_contiguous_blocks(aes_ctx, (char *)pData, ulDataLen,
+ &out);
- /*
- * Is the application-supplied buffer large enough?
- */
- if (*pulDataLen < out_len) {
- *pulDataLen = out_len;
- return (CKR_BUFFER_TOO_SMALL);
- }
+ /*
+ * Since out.cd_offset is set to 0 initially and the underlying
+ * implementation increments out.cd_offset by the amount of output
+ * written, so we can just use the value as the amount written.
+ */
+ *pulEncryptedDataLen = out.cd_offset;
- if (soft_aes_ctx->remain_len != 0) {
- /*
- * Copy last remaining data and current input data
- * to the output buffer.
- */
- (void) memmove(pData + soft_aes_ctx->remain_len,
- pEncrypted, out_len - soft_aes_ctx->remain_len);
- (void) memcpy(pData, soft_aes_ctx->data,
- soft_aes_ctx->remain_len);
- bzero(soft_aes_ctx->data, soft_aes_ctx->remain_len);
-
- in_buf = pData;
- } else {
- in_buf = pEncrypted;
- }
- out_buf = pData;
+ if (rc != CRYPTO_SUCCESS) {
+ rv = CKR_FUNCTION_FAILED;
+ goto done;
}
-do_decryption:
/*
- * Begin Decryption.
+ * Since AES counter mode is a stream cipher, we call ctr_mode_final()
+ * to pick up any remaining bytes. It is an internal function that
+ * does not destroy the context like *normal* final routines.
*/
- switch (mechanism) {
+ if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
+ rc = ctr_mode_final((ctr_ctx_t *)aes_ctx, &out,
+ aes_encrypt_block);
+ }
- case CKM_AES_ECB:
- {
+done:
+ if (rc != CRYPTO_SUCCESS && rv == CKR_OK) {
+ rv = crypto2pkcs11_error_number(rc);
+ }
- ulong_t i;
- uint8_t *tmp_inbuf;
- uint8_t *tmp_outbuf;
+ return (rv);
+}
- for (i = 0; i < out_len; i += AES_BLOCK_LEN) {
- tmp_inbuf = &in_buf[i];
- tmp_outbuf = &out_buf[i];
- /* Crunch one block of data for AES. */
- (void) aes_decrypt_block(soft_aes_ctx->key_sched,
- tmp_inbuf, tmp_outbuf);
- }
+CK_RV
+soft_aes_decrypt_update(soft_session_t *session_p, CK_BYTE_PTR pEncryptedData,
+ CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+ aes_ctx_t *aes_ctx = session_p->decrypt.context;
+ crypto_data_t out = {
+ .cd_format = CRYPTO_DATA_RAW,
+ .cd_offset = 0,
+ .cd_length = *pulDataLen,
+ .cd_raw.iov_base = (char *)pData,
+ .cd_raw.iov_len = *pulDataLen
+ };
+ CK_MECHANISM_TYPE mech = session_p->decrypt.mech.mechanism;
+ CK_RV rv = CKR_OK;
+ size_t out_len = 0;
+ int rc = CRYPTO_SUCCESS;
- if (update) {
- /*
- * For decrypt update, if there is a remaining
- * data, save it and its length in the context.
- */
- if (remain != 0)
- (void) memcpy(soft_aes_ctx->data, pEncrypted +
- (ulEncryptedLen - remain), remain);
- soft_aes_ctx->remain_len = remain;
+ if ((aes_ctx->ac_flags & (CCM_MODE|GCM_MODE)) == 0) {
+ out_len = aes_ctx->ac_remainder_len + ulEncryptedDataLen;
+
+ if (mech == CKM_AES_CBC_PAD && out_len <= AES_BLOCK_LEN) {
+ uint8_t *dest = (uint8_t *)aes_ctx->ac_remainder +
+ aes_ctx->ac_remainder_len;
+
+ bcopy(pEncryptedData, dest, ulEncryptedDataLen);
+ aes_ctx->ac_remainder_len += ulEncryptedDataLen;
+ return (CKR_OK);
}
+ out_len &= ~(AES_BLOCK_LEN - 1);
+ }
+ if (pData == NULL) {
*pulDataLen = out_len;
+ return (CKR_OK);
+ }
- break;
+ if (*pulDataLen < out_len) {
+ *pulDataLen = out_len;
+ return (CKR_BUFFER_TOO_SMALL);
}
- case CKM_AES_CBC:
- case CKM_AES_CBC_PAD:
- {
- crypto_data_t out;
- CK_ULONG rem_len;
- uint8_t last_block[AES_BLOCK_LEN];
-
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = out_len;
- out.cd_raw.iov_base = (char *)out_buf;
- out.cd_raw.iov_len = out_len;
-
- /* Decrypt multiple blocks of data. */
- rc = aes_decrypt_contiguous_blocks(
- (aes_ctx_t *)soft_aes_ctx->aes_cbc,
- (char *)in_buf, out_len, &out);
-
- if (rc != 0)
- goto decrypt_failed;
-
- if ((mechanism == CKM_AES_CBC_PAD) && (!update)) {
- /* Decrypt last block containing pad bytes. */
- out.cd_offset = 0;
- out.cd_length = AES_BLOCK_LEN;
- out.cd_raw.iov_base = (char *)last_block;
- out.cd_raw.iov_len = AES_BLOCK_LEN;
-
- /* Decrypt last block containing pad bytes. */
- rc = aes_decrypt_contiguous_blocks(
- (aes_ctx_t *)soft_aes_ctx->aes_cbc,
- (char *)in_buf + out_len, AES_BLOCK_LEN, &out);
-
- if (rc != 0)
- goto decrypt_failed;
+ rc = aes_decrypt_contiguous_blocks(aes_ctx, (char *)pEncryptedData,
+ ulEncryptedDataLen, &out);
- /*
- * Remove padding bytes after decryption of
- * ciphertext block to produce the original
- * plaintext.
- */
- rv = soft_remove_pkcs7_padding(last_block,
- AES_BLOCK_LEN, &rem_len);
- if (rv == CKR_OK) {
- if (rem_len != 0)
- (void) memcpy(out_buf + out_len,
- last_block, rem_len);
- *pulDataLen = out_len + rem_len;
- } else {
- *pulDataLen = 0;
- goto cleanup;
- }
- } else {
- *pulDataLen = out_len;
- }
+ if (rc != CRYPTO_SUCCESS) {
+ rv = CKR_FUNCTION_FAILED;
+ goto done;
+ }
- if (update) {
- /*
- * For decrypt update, if there is remaining data,
- * save it and its length in the context.
- */
- if (remain != 0)
- (void) memcpy(soft_aes_ctx->data, pEncrypted +
- (ulEncryptedLen - remain), remain);
- soft_aes_ctx->remain_len = remain;
- }
+ *pulDataLen = out.cd_offset;
- if (rc == 0)
- break;
-decrypt_failed:
- *pulDataLen = 0;
- rv = CKR_FUNCTION_FAILED;
- goto cleanup;
+ if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
+ rc = ctr_mode_final((ctr_ctx_t *)aes_ctx, &out,
+ aes_encrypt_block);
}
- case CKM_AES_CTR:
- {
- crypto_data_t out;
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = *pulDataLen;
- out.cd_raw.iov_base = (char *)pData;
- out.cd_raw.iov_len = *pulDataLen;
+done:
+ if (rc != CRYPTO_SUCCESS && rv == CKR_OK) {
+ rv = crypto2pkcs11_error_number(rc);
+ }
- rc = aes_decrypt_contiguous_blocks(soft_aes_ctx->aes_cbc,
- (char *)pEncrypted, ulEncryptedLen, &out);
+ return (rv);
+}
- if (rc != 0) {
- *pulDataLen = 0;
- rv = CKR_FUNCTION_FAILED;
- goto cleanup;
+CK_RV
+soft_aes_encrypt_final(soft_session_t *session_p,
+ CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
+{
+ aes_ctx_t *aes_ctx = session_p->encrypt.context;
+ crypto_data_t data = {
+ .cd_format = CRYPTO_DATA_RAW,
+ .cd_offset = 0,
+ .cd_length = *pulLastEncryptedPartLen,
+ .cd_raw.iov_base = (char *)pLastEncryptedPart,
+ .cd_raw.iov_len = *pulLastEncryptedPartLen
+ };
+ int rc = CRYPTO_SUCCESS;
+ CK_RV rv = CKR_OK;
+
+ if (session_p->encrypt.mech.mechanism == CKM_AES_CBC_PAD) {
+ char block[AES_BLOCK_LEN] = { 0 };
+ size_t padlen = AES_BLOCK_LEN - aes_ctx->ac_remainder_len;
+
+ (void) memset(block, padlen & 0xff, sizeof (block));
+ if (padlen > 0) {
+ rc = aes_encrypt_contiguous_blocks(aes_ctx, block,
+ padlen, &data);
+ }
+ } else if (aes_ctx->ac_flags & CTR_MODE) {
+ if (pLastEncryptedPart == NULL) {
+ *pulLastEncryptedPartLen = aes_ctx->ac_remainder_len;
+ return (CKR_OK);
}
- /*
- * Since AES counter mode is a stream cipher, we call
- * aes_counter_final() to pick up any remaining bytes.
- * It is an internal function that does not destroy
- * the context like *normal* final routines.
- */
- if (((aes_ctx_t *)soft_aes_ctx->aes_cbc)->ac_remainder_len
- > 0) {
- rc = ctr_mode_final(soft_aes_ctx->aes_cbc, &out,
+ if (aes_ctx->ac_remainder_len > 0) {
+ rc = ctr_mode_final((ctr_ctx_t *)aes_ctx, &data,
aes_encrypt_block);
- if (rc == CRYPTO_DATA_LEN_RANGE)
- rc = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
+ if (rc == CRYPTO_BUFFER_TOO_SMALL) {
+ rv = CKR_BUFFER_TOO_SMALL;
+ }
+ }
+ } else if (aes_ctx->ac_flags & CCM_MODE) {
+ rc = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, &data,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+ } else if (aes_ctx->ac_flags & GCM_MODE) {
+ rc = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, &data,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+ aes_xor_block);
+ } else if (aes_ctx->ac_flags & CMAC_MODE) {
+ if (pLastEncryptedPart == NULL) {
+ *pulLastEncryptedPartLen = AES_BLOCK_LEN;
+ return (CKR_OK);
}
+ rc = cmac_mode_final((cbc_ctx_t *)aes_ctx, &data,
+ aes_encrypt_block, aes_xor_block);
+ } else {
/*
- * Even though success means we've decrypted all of the input,
- * we should still behave like the other functions and return
- * the decrypted length in pulDataLen
+ * There must be no unprocessed plaintext.
+ * This happens if the length of the last data is not a
+ * multiple of the AES block length.
*/
- *pulDataLen = ulEncryptedLen;
-
+ *pulLastEncryptedPartLen = 0;
+ if (aes_ctx->ac_remainder_len > 0) {
+ rv = CKR_DATA_LEN_RANGE;
+ }
}
- } /* end switch */
-
- if (update)
- return (CKR_OK);
- /*
- * The following code will be executed if the caller is
- * soft_decrypt() or an error occurred. The decryption
- * operation will be terminated so we need to do some cleanup.
- */
-cleanup:
- (void) pthread_mutex_lock(&session_p->session_mutex);
- aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
- free(aes_ctx);
- freezero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
- freezero(session_p->decrypt.context, sizeof (soft_aes_ctx_t));
- session_p->decrypt.context = NULL;
- (void) pthread_mutex_unlock(&session_p->session_mutex);
+ if (rc != CRYPTO_SUCCESS && rv == CKR_OK) {
+ rv = crypto2pkcs11_error_number(rc);
+ }
+ soft_aes_free_ctx(aes_ctx);
+ session_p->encrypt.context = NULL;
return (rv);
}
-
-/*
- * Allocate and initialize a context for AES CBC mode of operation.
- */
-void *
-aes_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
+CK_RV
+soft_aes_decrypt_final(soft_session_t *session_p, CK_BYTE_PTR pLastPart,
+ CK_ULONG_PTR pulLastPartLen)
{
+ aes_ctx_t *aes_ctx = session_p->decrypt.context;
+ CK_MECHANISM_TYPE mech = session_p->decrypt.mech.mechanism;
+ CK_RV rv = CKR_OK;
+ int rc = CRYPTO_SUCCESS;
+ crypto_data_t out = {
+ .cd_format = CRYPTO_DATA_RAW,
+ .cd_offset = 0,
+ .cd_length = *pulLastPartLen,
+ .cd_raw.iov_base = (char *)pLastPart,
+ .cd_raw.iov_len = *pulLastPartLen
+ };
+
+ if (aes_ctx->ac_remainder_len > 0) {
+ switch (mech) {
+ case CKM_AES_CBC_PAD:
+ /*
+ * Since we cannot know the amount of padding present
+ * until after we decrypt the final block, and since
+ * we don't know which block is the last block until
+ * C_DecryptFinal() is called, we must always defer
+ * decrypting the most recent block of ciphertext
+ * until C_DecryptFinal() is called. As a consequence,
+ * we should always have a remainder, and it should
+ * always be equal to AES_BLOCK_LEN.
+ */
+ if (aes_ctx->ac_remainder_len != AES_BLOCK_LEN) {
+ return (CKR_ENCRYPTED_DATA_LEN_RANGE);
+ }
- cbc_ctx_t *cbc_ctx;
-
- if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
- return (NULL);
-
- cbc_ctx->cbc_keysched = key_sched;
- cbc_ctx->cbc_keysched_len = size;
-
- (void) memcpy(&cbc_ctx->cbc_iv[0], ivec, AES_BLOCK_LEN);
-
- cbc_ctx->cbc_lastp = (uint8_t *)cbc_ctx->cbc_iv;
- cbc_ctx->cbc_flags |= CBC_MODE;
- cbc_ctx->max_remain = AES_BLOCK_LEN;
-
- return (cbc_ctx);
-}
+ if (*pulLastPartLen < AES_BLOCK_LEN) {
+ *pulLastPartLen = AES_BLOCK_LEN;
+ return (CKR_BUFFER_TOO_SMALL);
+ }
-void *
-aes_cmac_ctx_init(void *key_sched, size_t size)
-{
+ rc = aes_decrypt_contiguous_blocks(aes_ctx,
+ (char *)pLastPart, AES_BLOCK_LEN, &out);
- cbc_ctx_t *cbc_ctx;
+ if (rc != CRYPTO_SUCCESS) {
+ break;
+ }
- if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
- return (NULL);
+ rv = soft_remove_pkcs7_padding(pLastPart, AES_BLOCK_LEN,
+ pulLastPartLen);
+ break;
+ case CKM_AES_CTR:
+ rc = ctr_mode_final((ctr_ctx_t *)aes_ctx, &out,
+ aes_encrypt_block);
+ break;
+ default:
+ /* There must be no unprocessed ciphertext */
+ return (CKR_ENCRYPTED_DATA_LEN_RANGE);
+ }
+ } else {
+ /*
+ * We should never have no remainder for AES_CBC_PAD -- see
+ * above.
+ */
+ ASSERT3U(mech, !=, CKM_AES_CBC_PAD);
+ }
- cbc_ctx->cbc_keysched = key_sched;
- cbc_ctx->cbc_keysched_len = size;
+ if (aes_ctx->ac_flags & CCM_MODE) {
+ size_t pt_len = aes_ctx->ac_data_len;
- cbc_ctx->cbc_lastp = (uint8_t *)cbc_ctx->cbc_iv;
- cbc_ctx->cbc_flags |= CMAC_MODE;
- cbc_ctx->max_remain = AES_BLOCK_LEN + 1;
+ if (*pulLastPartLen < pt_len) {
+ *pulLastPartLen = pt_len;
+ return (CKR_BUFFER_TOO_SMALL);
+ }
- return (cbc_ctx);
-}
+ ASSERT3U(aes_ctx->ac_processed_data_len, ==, pt_len);
+ ASSERT3U(aes_ctx->ac_processed_mac_len, ==,
+ aes_ctx->ac_mac_len);
-/*
- * Allocate and initialize a context for AES CTR mode of operation.
- */
-void *
-aes_ctr_ctx_init(void *key_sched, size_t size, uint8_t *param)
-{
+ rc = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, &out,
+ AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+ aes_xor_block);
- ctr_ctx_t *ctr_ctx;
- CK_AES_CTR_PARAMS *pp;
+ if (rc != CRYPTO_SUCCESS) {
+ *pulLastPartLen = out.cd_offset;
+ }
+ } else if (aes_ctx->ac_flags & GCM_MODE) {
+ gcm_ctx_t *gcm_ctx = (gcm_ctx_t *)aes_ctx;
+ size_t pt_len = gcm_ctx->gcm_processed_data_len -
+ gcm_ctx->gcm_tag_len;
- /* LINTED: pointer alignment */
- pp = (CK_AES_CTR_PARAMS *)param;
+ if (*pulLastPartLen < pt_len) {
+ *pulLastPartLen = pt_len;
+ return (CKR_BUFFER_TOO_SMALL);
+ }
- if ((ctr_ctx = calloc(1, sizeof (ctr_ctx_t))) == NULL)
- return (NULL);
+ rc = gcm_decrypt_final(gcm_ctx, &out, AES_BLOCK_LEN,
+ aes_encrypt_block, aes_xor_block);
- ctr_ctx->ctr_keysched = key_sched;
- ctr_ctx->ctr_keysched_len = size;
+ if (rc != CRYPTO_SUCCESS) {
+ *pulLastPartLen = out.cd_offset;
+ }
+ }
- if (ctr_init_ctx(ctr_ctx, pp->ulCounterBits, pp->cb, aes_copy_block)
- != CRYPTO_SUCCESS) {
- free(ctr_ctx);
- return (NULL);
+ if (rv == CKR_OK && rc != CRYPTO_SUCCESS) {
+ rv = crypto2pkcs11_error_number(rc);
}
- return (ctr_ctx);
+ soft_aes_free_ctx(aes_ctx);
+ session_p->decrypt.context = NULL;
+
+ return (rv);
}
/*
- * Allocate and initialize AES contexts for both signing and encrypting,
- * saving both context pointers in the session struct. For general-length AES
- * MAC, check the length in the parameter to see if it is in the right range.
+ * Allocate and initialize AES contexts for sign and verify operations
+ * (including the underlying encryption context needed to sign or verify) --
+ * called by C_SignInit() and C_VerifyInit() to perform the CKM_AES_* MAC
+ * mechanisms. For general-length AES MAC, also validate the MAC length.
*/
CK_RV
soft_aes_sign_verify_init_common(soft_session_t *session_p,
CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t sign_op)
{
- soft_aes_ctx_t *soft_aes_ctx;
- CK_MECHANISM encrypt_mech;
- CK_RV rv;
+ soft_aes_sign_ctx_t *ctx = NULL;
+ /* For AES CMAC (the only AES MAC currently), iv is always 0 */
+ CK_BYTE iv[AES_BLOCK_LEN] = { 0 };
+ CK_MECHANISM encrypt_mech = {
+ .mechanism = CKM_AES_CMAC,
+ .pParameter = iv,
+ .ulParameterLen = sizeof (iv)
+ };
+ CK_RV rv;
+ size_t mac_len = AES_BLOCK_LEN;
- if (key_p->key_type != CKK_AES) {
+ if (key_p->key_type != CKK_AES)
return (CKR_KEY_TYPE_INCONSISTENT);
- }
-
- /* allocate memory for the sign/verify context */
- soft_aes_ctx = malloc(sizeof (soft_aes_ctx_t));
- if (soft_aes_ctx == NULL) {
- return (CKR_HOST_MEMORY);
- }
-
- /* initialization vector is zero for AES CMAC */
- bzero(soft_aes_ctx->ivec, AES_BLOCK_LEN);
-
- switch (pMechanism->mechanism) {
-
- case CKM_AES_CMAC_GENERAL:
- if (pMechanism->ulParameterLen !=
- sizeof (CK_MAC_GENERAL_PARAMS)) {
- free(soft_aes_ctx);
+ /* C_{Sign,Verify}Init() validate pMechanism != NULL */
+ if (pMechanism->mechanism == CKM_AES_CMAC_GENERAL) {
+ if (pMechanism->pParameter == NULL) {
return (CKR_MECHANISM_PARAM_INVALID);
}
- if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter >
- AES_BLOCK_LEN) {
- free(soft_aes_ctx);
+ mac_len = *(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
+
+ if (mac_len > AES_BLOCK_LEN) {
return (CKR_MECHANISM_PARAM_INVALID);
}
+ }
- soft_aes_ctx->mac_len = *((CK_MAC_GENERAL_PARAMS_PTR)
- pMechanism->pParameter);
+ ctx = calloc(1, sizeof (*ctx));
+ if (ctx == NULL) {
+ return (CKR_HOST_MEMORY);
+ }
- /*FALLTHRU*/
- case CKM_AES_CMAC:
+ rv = soft_aes_check_mech_param(pMechanism, &ctx->aes_ctx);
+ if (rv != CKR_OK) {
+ soft_aes_free_ctx(ctx->aes_ctx);
+ goto done;
+ }
- /*
- * For non-general AES MAC, output is always block size
- */
- if (pMechanism->mechanism == CKM_AES_CMAC) {
- soft_aes_ctx->mac_len = AES_BLOCK_LEN;
- }
+ if ((rv = soft_encrypt_init_internal(session_p, &encrypt_mech,
+ key_p)) != CKR_OK) {
+ soft_aes_free_ctx(ctx->aes_ctx);
+ goto done;
+ }
- /* allocate a context for AES encryption */
- encrypt_mech.mechanism = CKM_AES_CMAC;
- encrypt_mech.pParameter = (void *)soft_aes_ctx->ivec;
- encrypt_mech.ulParameterLen = AES_BLOCK_LEN;
- rv = soft_encrypt_init_internal(session_p, &encrypt_mech,
- key_p);
- if (rv != CKR_OK) {
- free(soft_aes_ctx);
- return (rv);
- }
+ ctx->mac_len = mac_len;
- (void) pthread_mutex_lock(&session_p->session_mutex);
+ (void) pthread_mutex_lock(&session_p->session_mutex);
- if (sign_op) {
- session_p->sign.context = soft_aes_ctx;
- session_p->sign.mech.mechanism = pMechanism->mechanism;
- } else {
- session_p->verify.context = soft_aes_ctx;
- session_p->verify.mech.mechanism =
- pMechanism->mechanism;
- }
+ if (sign_op) {
+ session_p->sign.context = ctx;
+ session_p->sign.mech.mechanism = pMechanism->mechanism;
+ } else {
+ session_p->verify.context = ctx;
+ session_p->verify.mech.mechanism = pMechanism->mechanism;
+ }
- (void) pthread_mutex_unlock(&session_p->session_mutex);
+ (void) pthread_mutex_unlock(&session_p->session_mutex);
- break;
+done:
+ if (rv != CKR_OK) {
+ soft_aes_free_ctx(ctx->aes_ctx);
+ free(ctx);
}
- return (CKR_OK);
+
+ return (rv);
}
-/*
- * Called by soft_sign(), soft_sign_final(), soft_verify() or
- * soft_verify_final().
- */
CK_RV
soft_aes_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSigned, CK_ULONG_PTR pulSignedLen,
boolean_t sign_op, boolean_t Final)
{
- soft_aes_ctx_t *soft_aes_ctx_sign_verify;
+ soft_aes_sign_ctx_t *soft_aes_ctx_sign_verify;
CK_RV rv;
CK_BYTE *pEncrypted = NULL;
CK_ULONG ulEncryptedLen = AES_BLOCK_LEN;
@@ -1041,7 +1088,7 @@ soft_aes_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
if (sign_op) {
soft_aes_ctx_sign_verify =
- (soft_aes_ctx_t *)session_p->sign.context;
+ (soft_aes_sign_ctx_t *)session_p->sign.context;
if (soft_aes_ctx_sign_verify->mac_len == 0) {
*pulSignedLen = 0;
@@ -1061,7 +1108,7 @@ soft_aes_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
}
} else {
soft_aes_ctx_sign_verify =
- (soft_aes_ctx_t *)session_p->verify.context;
+ (soft_aes_sign_ctx_t *)session_p->verify.context;
}
if (Final) {
@@ -1115,6 +1162,31 @@ soft_aes_mac_sign_verify_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
rv = soft_encrypt_update(session_p, pPart, ulPartLen,
buf, &ulEncryptedLen);
+ explicit_bzero(buf, sizeof (buf));
return (rv);
}
+
+void
+soft_aes_free_ctx(aes_ctx_t *ctx)
+{
+ size_t len = 0;
+
+ if (ctx == NULL)
+ return;
+
+ if (ctx->ac_flags & ECB_MODE) {
+ len = sizeof (ecb_ctx_t);
+ } else if (ctx->ac_flags & (CBC_MODE|CMAC_MODE)) {
+ len = sizeof (cbc_ctx_t);
+ } else if (ctx->ac_flags & CTR_MODE) {
+ len = sizeof (ctr_ctx_t);
+ } else if (ctx->ac_flags & CCM_MODE) {
+ len = sizeof (ccm_ctx_t);
+ } else if (ctx->ac_flags & GCM_MODE) {
+ len = sizeof (gcm_ctx_t);
+ }
+
+ freezero(ctx->ac_keysched, ctx->ac_keysched_len);
+ freezero(ctx, len);
+}
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softCrypt.h b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softCrypt.h
index eb9f69e74b..d1ba0e2a6b 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softCrypt.h
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softCrypt.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#ifndef _SOFTCRYPT_H
@@ -52,16 +53,6 @@ typedef struct soft_des_ctx {
size_t mac_len; /* digest len in bytes */
} soft_des_ctx_t;
-typedef struct soft_aes_ctx {
- void *key_sched; /* pointer to key schedule */
- size_t keysched_len; /* Length of the key schedule */
- uint8_t ivec[AES_BLOCK_LEN]; /* initialization vector */
- uint8_t data[AES_BLOCK_LEN]; /* for use by update */
- size_t remain_len; /* for use by update */
- void *aes_cbc; /* to be used by CBC mode */
- size_t mac_len;
-} soft_aes_ctx_t;
-
typedef struct soft_blowfish_ctx {
void *key_sched; /* pointer to key schedule */
size_t keysched_len; /* Length of the key schedule */
@@ -72,6 +63,22 @@ typedef struct soft_blowfish_ctx {
} soft_blowfish_ctx_t;
/*
+ * For sign/verify operations, the hash generated is AES_BLOCK_LEN bytes long,
+ * however for CKM_AES_CMAC_GENERAL, one can specify a smaller hash size if
+ * desired (the output being the output of CKM_AES_CMAC truncated to the
+ * specified size). Since this size is specified in the C_{Sign,Verify}Init()
+ * call, we must carry it through to the C_{Sign,Verify}Final() call via
+ * the mac_len field.
+ *
+ * Note that the context pointed to by aes_ctx is cleaned up as part of the
+ * soft_aes_encrypt() calls.
+ */
+typedef struct soft_aes_sign_ctx {
+ aes_ctx_t *aes_ctx;
+ size_t mac_len;
+} soft_aes_sign_ctx_t;
+
+/*
* Function Prototypes.
*/
void *des_cbc_ctx_init(void *, size_t, uint8_t *, CK_KEY_TYPE);
@@ -104,15 +111,24 @@ CK_RV soft_arcfour_crypt_init(soft_session_t *, CK_MECHANISM_PTR,
CK_RV soft_arcfour_crypt(crypto_active_op_t *, CK_BYTE_PTR, CK_ULONG,
CK_BYTE_PTR, CK_ULONG_PTR);
-void *aes_cbc_ctx_init(void *, size_t, uint8_t *);
-void *aes_cmac_ctx_init(void *, size_t);
-void *aes_ctr_ctx_init(void *, size_t, uint8_t *);
-
CK_RV soft_aes_crypt_init_common(soft_session_t *, CK_MECHANISM_PTR,
soft_object_t *, boolean_t);
-CK_RV soft_aes_encrypt_common(soft_session_t *, CK_BYTE_PTR, CK_ULONG,
- CK_BYTE_PTR, CK_ULONG_PTR, boolean_t);
+CK_RV soft_aes_encrypt(soft_session_t *, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR);
+
+CK_RV soft_aes_decrypt(soft_session_t *, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR);
+
+CK_RV soft_aes_encrypt_update(soft_session_t *, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR);
+
+CK_RV soft_aes_decrypt_update(soft_session_t *, CK_BYTE_PTR, CK_ULONG,
+ CK_BYTE_PTR, CK_ULONG_PTR);
+
+CK_RV soft_aes_encrypt_final(soft_session_t *, CK_BYTE_PTR, CK_ULONG_PTR);
+
+CK_RV soft_aes_decrypt_final(soft_session_t *, CK_BYTE_PTR, CK_ULONG_PTR);
CK_RV soft_aes_decrypt_common(soft_session_t *, CK_BYTE_PTR, CK_ULONG,
CK_BYTE_PTR, CK_ULONG_PTR, boolean_t);
@@ -126,6 +142,8 @@ CK_RV soft_aes_sign_verify_init_common(soft_session_t *, CK_MECHANISM_PTR,
CK_RV soft_aes_mac_sign_verify_update(soft_session_t *, CK_BYTE_PTR, CK_ULONG);
+void soft_aes_free_ctx(aes_ctx_t *);
+
void *blowfish_cbc_ctx_init(void *, size_t, uint8_t *);
CK_RV soft_blowfish_crypt_init_common(soft_session_t *, CK_MECHANISM_PTR,
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDecryptUtil.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDecryptUtil.c
index 27b8edf894..448df73cef 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDecryptUtil.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDecryptUtil.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2017 Jason King.
*/
#include <pthread.h>
@@ -166,100 +167,14 @@ cbc_common:
return (rv);
}
case CKM_AES_ECB:
-
- if (key_p->key_type != CKK_AES) {
- return (CKR_KEY_TYPE_INCONSISTENT);
- }
-
- return (soft_aes_crypt_init_common(session_p, pMechanism,
- key_p, B_FALSE));
-
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
- {
- soft_aes_ctx_t *soft_aes_ctx;
-
- if (key_p->key_type != CKK_AES) {
- return (CKR_KEY_TYPE_INCONSISTENT);
- }
-
- if ((pMechanism->pParameter == NULL) ||
- (pMechanism->ulParameterLen != AES_BLOCK_LEN)) {
- return (CKR_MECHANISM_PARAM_INVALID);
- }
-
- rv = soft_aes_crypt_init_common(session_p, pMechanism,
- key_p, B_FALSE);
-
- if (rv != CKR_OK)
- return (rv);
-
- (void) pthread_mutex_lock(&session_p->session_mutex);
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->decrypt.context;
-
- /* Save Initialization Vector (IV) in the context. */
- (void) memcpy(soft_aes_ctx->ivec, pMechanism->pParameter,
- AES_BLOCK_LEN);
-
- /* Allocate a context for AES cipher-block chaining. */
- soft_aes_ctx->aes_cbc = (void *)aes_cbc_ctx_init(
- soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len,
- soft_aes_ctx->ivec);
-
- if (soft_aes_ctx->aes_cbc == NULL) {
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- freezero(session_p->decrypt.context,
- sizeof (soft_aes_ctx_t));
- session_p->decrypt.context = NULL;
- (void) pthread_mutex_unlock(&session_p->session_mutex);
- return (CKR_HOST_MEMORY);
- }
-
- (void) pthread_mutex_unlock(&session_p->session_mutex);
-
- return (rv);
- }
case CKM_AES_CTR:
- {
- soft_aes_ctx_t *soft_aes_ctx;
-
- if (key_p->key_type != CKK_AES) {
- return (CKR_KEY_TYPE_INCONSISTENT);
- }
-
- if (pMechanism->pParameter == NULL ||
- pMechanism->ulParameterLen != sizeof (CK_AES_CTR_PARAMS)) {
- return (CKR_MECHANISM_PARAM_INVALID);
- }
-
- rv = soft_aes_crypt_init_common(session_p, pMechanism,
- key_p, B_FALSE);
-
- if (rv != CKR_OK)
- return (rv);
-
- (void) pthread_mutex_lock(&session_p->session_mutex);
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->decrypt.context;
- soft_aes_ctx->aes_cbc = aes_ctr_ctx_init(
- soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len,
- pMechanism->pParameter);
-
- if (soft_aes_ctx->aes_cbc == NULL) {
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- freezero(session_p->decrypt.context,
- sizeof (soft_aes_ctx_t));
- session_p->decrypt.context = NULL;
- rv = CKR_HOST_MEMORY;
- }
-
- (void) pthread_mutex_unlock(&session_p->session_mutex);
+ case CKM_AES_GCM:
+ case CKM_AES_CCM:
+ return (soft_aes_crypt_init_common(session_p, pMechanism,
+ key_p, B_FALSE));
- return (rv);
- }
case CKM_BLOWFISH_CBC:
{
soft_blowfish_ctx_t *soft_blowfish_ctx;
@@ -380,17 +295,16 @@ soft_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CTR:
-
- if (ulEncryptedLen == 0) {
- *pulDataLen = 0;
- return (CKR_OK);
- }
- /* FALLTHROUGH */
-
+ case CKM_AES_CCM:
+ case CKM_AES_GCM:
case CKM_AES_CBC_PAD:
-
- return (soft_aes_decrypt_common(session_p, pEncrypted,
- ulEncryptedLen, pData, pulDataLen, Update));
+ if (Update) {
+ return (soft_aes_decrypt_update(session_p, pEncrypted,
+ ulEncryptedLen, pData, pulDataLen));
+ } else {
+ return (soft_aes_decrypt(session_p, pEncrypted,
+ ulEncryptedLen, pData, pulDataLen));
+ }
case CKM_BLOWFISH_CBC:
@@ -489,6 +403,8 @@ soft_decrypt_update(soft_session_t *session_p, CK_BYTE_PTR pEncryptedPart,
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
case CKM_AES_CTR:
+ case CKM_AES_GCM:
+ case CKM_AES_CCM:
case CKM_BLOWFISH_CBC:
case CKM_RC4:
@@ -647,145 +563,15 @@ soft_decrypt_final(soft_session_t *session_p, CK_BYTE_PTR pLastPart,
}
case CKM_AES_CBC_PAD:
- {
-
- soft_aes_ctx_t *soft_aes_ctx;
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->decrypt.context;
-
- /*
- * We should have only one block of data left in the
- * remaining buffer.
- */
- if (soft_aes_ctx->remain_len != AES_BLOCK_LEN) {
- *pulLastPartLen = 0;
- rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
- /* Cleanup memory space. */
- free(soft_aes_ctx->aes_cbc);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
-
- goto clean1;
- }
-
- out_len = AES_BLOCK_LEN;
-
- /*
- * If application asks for the length of the output buffer
- * to hold the plaintext?
- */
- if (pLastPart == NULL) {
- *pulLastPartLen = out_len;
- rv = CKR_OK;
- goto clean2;
- } else {
- crypto_data_t out;
-
- /* Copy remaining data to the output buffer. */
- (void) memcpy(pLastPart, soft_aes_ctx->data,
- AES_BLOCK_LEN);
-
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = AES_BLOCK_LEN;
- out.cd_raw.iov_base = (char *)pLastPart;
- out.cd_raw.iov_len = AES_BLOCK_LEN;
-
- /* Decrypt final block of data. */
- rc = aes_decrypt_contiguous_blocks(
- (aes_ctx_t *)soft_aes_ctx->aes_cbc,
- (char *)pLastPart, AES_BLOCK_LEN, &out);
-
- if (rc == 0) {
- /*
- * Remove padding bytes after decryption of
- * ciphertext block to produce the original
- * plaintext.
- */
- rv = soft_remove_pkcs7_padding(pLastPart,
- AES_BLOCK_LEN, &out_len);
- if (rv != CKR_OK)
- *pulLastPartLen = 0;
- else
- *pulLastPartLen = out_len;
- } else {
- *pulLastPartLen = 0;
- rv = CKR_FUNCTION_FAILED;
- }
-
- /* Cleanup memory space. */
- free(soft_aes_ctx->aes_cbc);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
-
- }
-
- break;
- }
-
case CKM_AES_CBC:
case CKM_AES_ECB:
- {
- soft_aes_ctx_t *soft_aes_ctx;
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->decrypt.context;
- /*
- * CKM_AES_CBC and CKM_AES_ECB does not do any padding,
- * so when the final is called, the remaining buffer
- * should not contain any more data.
- */
- *pulLastPartLen = 0;
- if (soft_aes_ctx->remain_len != 0) {
- rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
- } else {
- if (pLastPart == NULL)
- goto clean2;
- }
-
- /* Cleanup memory space. */
- free(soft_aes_ctx->aes_cbc);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
-
- break;
- }
case CKM_AES_CTR:
- {
- crypto_data_t out;
- soft_aes_ctx_t *soft_aes_ctx;
- ctr_ctx_t *ctr_ctx;
- size_t len;
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->decrypt.context;
- ctr_ctx = soft_aes_ctx->aes_cbc;
- len = ctr_ctx->ctr_remainder_len;
- if (pLastPart == NULL) {
- *pulLastPartLen = len;
- goto clean1;
- }
- if (len > 0) {
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = len;
- out.cd_raw.iov_base = (char *)pLastPart;
- out.cd_raw.iov_len = len;
-
- rv = ctr_mode_final(ctr_ctx, &out, aes_encrypt_block);
- if (rv == CRYPTO_DATA_LEN_RANGE)
- rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
- }
- if (rv == CRYPTO_BUFFER_TOO_SMALL) {
- *pulLastPartLen = len;
- goto clean1;
- }
-
- /* Cleanup memory space. */
- free(ctr_ctx);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
-
+ case CKM_AES_CCM:
+ case CKM_AES_GCM:
+ rv = soft_aes_decrypt_final(session_p, pLastPart,
+ pulLastPartLen);
break;
- }
+
case CKM_BLOWFISH_CBC:
{
soft_blowfish_ctx_t *soft_blowfish_ctx;
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncrypt.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncrypt.c
index 35dc5b1978..69e7817a46 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncrypt.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncrypt.c
@@ -21,6 +21,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <pthread.h>
@@ -118,12 +120,11 @@ C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
return (rv);
/*
- * Only check if input buffer is null. How to handle zero input
- * length depends on the mechanism in use. For secret key mechanisms,
- * unpadded ones yield zero length output, but padded ones always
- * result in greater than zero length output.
+ * How to handle zero input length depends on the mechanism in use.
+ * For secret key mechanisms, unpadded ones yield zero length output,
+ * but padded ones always result in greater than zero length output.
*/
- if (pData == NULL) {
+ if (pData == NULL && ulDataLen != 0) {
rv = CKR_ARGUMENTS_BAD;
goto clean_exit;
}
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncryptUtil.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncryptUtil.c
index fb7da5af3b..49930c10c8 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncryptUtil.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEncryptUtil.c
@@ -23,6 +23,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2017 Jason King.
*/
#include <pthread.h>
@@ -188,109 +189,17 @@ cbc_common:
return (rv);
}
- case CKM_AES_ECB:
-
- if (key_p->key_type != CKK_AES) {
- return (CKR_KEY_TYPE_INCONSISTENT);
- }
-
- return (soft_aes_crypt_init_common(session_p, pMechanism,
- key_p, B_TRUE));
+ case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
- if ((pMechanism->pParameter == NULL) ||
- (pMechanism->ulParameterLen != AES_BLOCK_LEN)) {
- return (CKR_MECHANISM_PARAM_INVALID);
- }
- /* FALLTHRU */
case CKM_AES_CMAC:
- {
- soft_aes_ctx_t *soft_aes_ctx;
-
- if (key_p->key_type != CKK_AES) {
- return (CKR_KEY_TYPE_INCONSISTENT);
- }
-
-
- rv = soft_aes_crypt_init_common(session_p, pMechanism,
- key_p, B_TRUE);
-
- if (rv != CKR_OK)
- return (rv);
-
- (void) pthread_mutex_lock(&session_p->session_mutex);
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
- /* Copy Initialization Vector (IV) into the context. */
- if (pMechanism->mechanism == CKM_AES_CMAC) {
- (void) bzero(soft_aes_ctx->ivec, AES_BLOCK_LEN);
- /* Allocate a context for AES cipher-block chaining. */
- soft_aes_ctx->aes_cbc = (void *)aes_cmac_ctx_init(
- soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- } else {
- (void) memcpy(soft_aes_ctx->ivec,
- pMechanism->pParameter,
- AES_BLOCK_LEN);
- /* Allocate a context for AES cipher-block chaining. */
- soft_aes_ctx->aes_cbc = (void *)aes_cbc_ctx_init(
- soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len,
- soft_aes_ctx->ivec);
- }
- if (soft_aes_ctx->aes_cbc == NULL) {
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- freezero(session_p->encrypt.context,
- sizeof (soft_aes_ctx_t));
- session_p->encrypt.context = NULL;
- rv = CKR_HOST_MEMORY;
- }
-
- (void) pthread_mutex_unlock(&session_p->session_mutex);
-
- return (rv);
- }
case CKM_AES_CTR:
- {
- soft_aes_ctx_t *soft_aes_ctx;
-
- if (key_p->key_type != CKK_AES) {
- return (CKR_KEY_TYPE_INCONSISTENT);
- }
-
- if (pMechanism->pParameter == NULL ||
- pMechanism->ulParameterLen != sizeof (CK_AES_CTR_PARAMS)) {
- return (CKR_MECHANISM_PARAM_INVALID);
- }
-
- rv = soft_aes_crypt_init_common(session_p, pMechanism,
- key_p, B_TRUE);
-
- if (rv != CKR_OK)
- return (rv);
-
- (void) pthread_mutex_lock(&session_p->session_mutex);
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
- soft_aes_ctx->aes_cbc = aes_ctr_ctx_init(
- soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len,
- pMechanism->pParameter);
-
- if (soft_aes_ctx->aes_cbc == NULL) {
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- freezero(session_p->encrypt.context,
- sizeof (soft_aes_ctx_t));
- session_p->encrypt.context = NULL;
- rv = CKR_HOST_MEMORY;
- }
-
- (void) pthread_mutex_unlock(&session_p->session_mutex);
+ case CKM_AES_CCM:
+ case CKM_AES_GCM:
+ return (soft_aes_crypt_init_common(session_p, pMechanism,
+ key_p, B_TRUE));
- return (rv);
- }
case CKM_RC4:
if (key_p->key_type != CKK_RC4) {
@@ -409,18 +318,17 @@ soft_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CTR:
-
- if (ulDataLen == 0) {
- *pulEncryptedLen = 0;
- return (CKR_OK);
- }
- /* FALLTHROUGH */
-
+ case CKM_AES_CCM:
case CKM_AES_CMAC:
case CKM_AES_CBC_PAD:
-
- return (soft_aes_encrypt_common(session_p, pData,
- ulDataLen, pEncrypted, pulEncryptedLen, update));
+ case CKM_AES_GCM:
+ if (update) {
+ return (soft_aes_encrypt_update(session_p, pData,
+ ulDataLen, pEncrypted, pulEncryptedLen));
+ } else {
+ return (soft_aes_encrypt(session_p, pData,
+ ulDataLen, pEncrypted, pulEncryptedLen));
+ }
case CKM_BLOWFISH_CBC:
@@ -476,7 +384,6 @@ soft_encrypt(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
CK_ULONG_PTR pulEncryptedDataLen)
{
-
return (soft_encrypt_common(session_p, pData, ulDataLen,
pEncryptedData, pulEncryptedDataLen, B_FALSE));
}
@@ -520,6 +427,8 @@ soft_encrypt_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
case CKM_AES_CBC_PAD:
case CKM_AES_CMAC:
case CKM_AES_CTR:
+ case CKM_AES_GCM:
+ case CKM_AES_CCM:
case CKM_BLOWFISH_CBC:
case CKM_RC4:
@@ -665,171 +574,16 @@ soft_encrypt_final(soft_session_t *session_p, CK_BYTE_PTR pLastEncryptedPart,
break;
}
case CKM_AES_CBC_PAD:
- {
- soft_aes_ctx_t *soft_aes_ctx;
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
- /*
- * For CKM_AES_CBC_PAD, compute output length with
- * padding. If the remaining buffer has one block
- * of data, then output length will be two blocksize of
- * ciphertext. If the remaining buffer has less than
- * one block of data, then output length will be
- * one blocksize.
- */
- if (soft_aes_ctx->remain_len == AES_BLOCK_LEN)
- out_len = 2 * AES_BLOCK_LEN;
- else
- out_len = AES_BLOCK_LEN;
-
- if (pLastEncryptedPart == NULL) {
- /*
- * Application asks for the length of the output
- * buffer to hold the ciphertext.
- */
- *pulLastEncryptedPartLen = out_len;
- goto clean1;
- } else {
- crypto_data_t out;
-
- /* Copy remaining data to the output buffer. */
- (void) memcpy(pLastEncryptedPart, soft_aes_ctx->data,
- soft_aes_ctx->remain_len);
-
- /*
- * Add padding bytes prior to encrypt final.
- */
- soft_add_pkcs7_padding(pLastEncryptedPart +
- soft_aes_ctx->remain_len, AES_BLOCK_LEN,
- soft_aes_ctx->remain_len);
-
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = out_len;
- out.cd_raw.iov_base = (char *)pLastEncryptedPart;
- out.cd_raw.iov_len = out_len;
-
- /* Encrypt multiple blocks of data. */
- rc = aes_encrypt_contiguous_blocks(
- (aes_ctx_t *)soft_aes_ctx->aes_cbc,
- (char *)pLastEncryptedPart, out_len, &out);
-
- if (rc == 0) {
- *pulLastEncryptedPartLen = out_len;
- } else {
- *pulLastEncryptedPartLen = 0;
- rv = CKR_FUNCTION_FAILED;
- }
-
- /* Cleanup memory space. */
- free(soft_aes_ctx->aes_cbc);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- }
-
- break;
- }
case CKM_AES_CMAC:
- {
- soft_aes_ctx_t *soft_aes_ctx;
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
-
- if (pLastEncryptedPart == NULL) {
- /*
- * Application asks for the length of the output
- * buffer to hold the ciphertext.
- */
- *pulLastEncryptedPartLen = AES_BLOCK_LEN;
- goto clean1;
- } else {
- crypto_data_t out;
-
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = AES_BLOCK_LEN;
- out.cd_raw.iov_base = (char *)pLastEncryptedPart;
- out.cd_raw.iov_len = AES_BLOCK_LEN;
-
- rc = cmac_mode_final(soft_aes_ctx->aes_cbc, &out,
- aes_encrypt_block, aes_xor_block);
-
- if (rc == 0) {
- *pulLastEncryptedPartLen = AES_BLOCK_LEN;
- } else {
- *pulLastEncryptedPartLen = 0;
- rv = CKR_FUNCTION_FAILED;
- }
-
- /* Cleanup memory space. */
- free(soft_aes_ctx->aes_cbc);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- }
-
- break;
- }
case CKM_AES_CBC:
case CKM_AES_ECB:
- {
- soft_aes_ctx_t *soft_aes_ctx;
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
- /*
- * CKM_AES_CBC and CKM_AES_ECB does not do any padding,
- * so when the final is called, the remaining buffer
- * should not contain any more data.
- */
- *pulLastEncryptedPartLen = 0;
- if (soft_aes_ctx->remain_len != 0) {
- rv = CKR_DATA_LEN_RANGE;
- } else {
- if (pLastEncryptedPart == NULL)
- goto clean1;
- }
-
- /* Cleanup memory space. */
- free(soft_aes_ctx->aes_cbc);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
-
- break;
- }
case CKM_AES_CTR:
- {
- crypto_data_t out;
- soft_aes_ctx_t *soft_aes_ctx;
- ctr_ctx_t *ctr_ctx;
- size_t len;
-
- soft_aes_ctx = (soft_aes_ctx_t *)session_p->encrypt.context;
- ctr_ctx = soft_aes_ctx->aes_cbc;
- len = ctr_ctx->ctr_remainder_len;
-
- if (pLastEncryptedPart == NULL) {
- *pulLastEncryptedPartLen = len;
- goto clean1;
- }
- if (len > 0) {
- out.cd_format = CRYPTO_DATA_RAW;
- out.cd_offset = 0;
- out.cd_length = len;
- out.cd_raw.iov_base = (char *)pLastEncryptedPart;
- out.cd_raw.iov_len = len;
-
- rv = ctr_mode_final(ctr_ctx, &out, aes_encrypt_block);
- }
- if (rv == CRYPTO_BUFFER_TOO_SMALL) {
- *pulLastEncryptedPartLen = len;
- goto clean1;
- }
-
- /* Cleanup memory space. */
- free(ctr_ctx);
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
-
+ case CKM_AES_CCM:
+ case CKM_AES_GCM:
+ rv = soft_aes_encrypt_final(session_p, pLastEncryptedPart,
+ pulLastEncryptedPartLen);
break;
- }
+
case CKM_BLOWFISH_CBC:
{
soft_blowfish_ctx_t *soft_blowfish_ctx;
@@ -932,23 +686,12 @@ soft_crypt_cleanup(soft_session_t *session_p, boolean_t encrypt,
case CKM_AES_CBC:
case CKM_AES_CMAC:
case CKM_AES_ECB:
- {
- soft_aes_ctx_t *soft_aes_ctx =
- (soft_aes_ctx_t *)active_op->context;
- aes_ctx_t *aes_ctx;
-
- if (soft_aes_ctx != NULL) {
- aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
- if (aes_ctx != NULL) {
- explicit_bzero(aes_ctx->ac_keysched,
- aes_ctx->ac_keysched_len);
- free(soft_aes_ctx->aes_cbc);
- }
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- }
+ case CKM_AES_GCM:
+ case CKM_AES_CCM:
+ case CKM_AES_CTR:
+ soft_aes_free_ctx(active_op->context);
+ active_op->context = NULL;
break;
- }
case CKM_BLOWFISH_CBC:
{
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softKeystore.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softKeystore.c
index be5b05aeeb..72e16bfe29 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softKeystore.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softKeystore.c
@@ -2267,7 +2267,6 @@ soft_keystore_crypt(soft_object_t *key_p, uchar_t *ivec, boolean_t encrypt,
CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG_PTR out_len)
{
CK_MECHANISM mech;
- soft_aes_ctx_t *soft_aes_ctx;
CK_RV rv;
CK_ULONG tmplen, tmplen1;
@@ -2291,51 +2290,16 @@ soft_keystore_crypt(soft_object_t *key_p, uchar_t *ivec, boolean_t encrypt,
if (rv != CKR_OK)
return (rv);
-
- (void) pthread_mutex_lock(&token_session.session_mutex);
-
- if (encrypt)
- soft_aes_ctx =
- (soft_aes_ctx_t *)token_session.encrypt.context;
- else
- soft_aes_ctx =
- (soft_aes_ctx_t *)token_session.decrypt.context;
-
- /* Copy Initialization Vector (IV) into the context. */
- (void) memcpy(soft_aes_ctx->ivec, ivec, AES_BLOCK_LEN);
-
- /* Allocate a context for AES cipher-block chaining. */
- soft_aes_ctx->aes_cbc = (void *)aes_cbc_ctx_init(
- soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len,
- soft_aes_ctx->ivec);
-
- if (soft_aes_ctx->aes_cbc == NULL) {
- freezero(soft_aes_ctx->key_sched,
- soft_aes_ctx->keysched_len);
- if (encrypt) {
- free(token_session.encrypt.context);
- token_session.encrypt.context = NULL;
- } else {
- free(token_session.encrypt.context);
- token_session.encrypt.context = NULL;
- }
-
- (void) pthread_mutex_unlock(&token_session.
- session_mutex);
- return (CKR_HOST_MEMORY);
- }
-
- (void) pthread_mutex_unlock(&token_session.session_mutex);
/*
* Since out == NULL, the soft_aes_xxcrypt_common() will
* simply return the output buffer length to the caller.
*/
if (encrypt) {
- rv = soft_aes_encrypt_common(&token_session, in,
- in_len, out, out_len, B_FALSE);
+ rv = soft_aes_encrypt(&token_session, in, in_len,
+ out, out_len);
} else {
- rv = soft_aes_decrypt_common(&token_session, in,
- in_len, out, out_len, B_FALSE);
+ rv = soft_aes_decrypt(&token_session, in, in_len,
+ out, out_len);
}
} else {
@@ -2345,8 +2309,8 @@ soft_keystore_crypt(soft_object_t *key_p, uchar_t *ivec, boolean_t encrypt,
*/
tmplen = *out_len;
if (encrypt) {
- rv = soft_aes_encrypt_common(&token_session, in,
- in_len, out, &tmplen, B_TRUE);
+ rv = soft_aes_encrypt_update(&token_session, in,
+ in_len, out, &tmplen);
if (rv == CKR_OK) {
tmplen1 = *out_len - tmplen;
rv = soft_encrypt_final(&token_session,
@@ -2354,8 +2318,8 @@ soft_keystore_crypt(soft_object_t *key_p, uchar_t *ivec, boolean_t encrypt,
*out_len = tmplen + tmplen1;
}
} else {
- rv = soft_aes_decrypt_common(&token_session, in,
- in_len, out, &tmplen, B_TRUE);
+ rv = soft_aes_decrypt_update(&token_session, in,
+ in_len, out, &tmplen);
if (rv == CKR_OK) {
tmplen1 = *out_len - tmplen;
rv = soft_decrypt_final(&token_session,
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSignUtil.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSignUtil.c
index ccf746dc40..e456bff368 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSignUtil.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSignUtil.c
@@ -584,13 +584,13 @@ soft_sign_verify_cleanup(soft_session_t *session_p, boolean_t sign,
case CKM_AES_CMAC_GENERAL:
case CKM_AES_CMAC:
if (session_p->encrypt.context != NULL) {
- free(session_p->encrypt.context);
+ soft_aes_free_ctx(session_p->encrypt.context);
session_p->encrypt.context = NULL;
session_p->encrypt.flags = 0;
}
if (active_op->context != NULL) {
explicit_bzero(active_op->context,
- sizeof (soft_aes_ctx_t));
+ sizeof (soft_aes_sign_ctx_t));
}
break;
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSlotToken.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSlotToken.c
index c8c3753f63..902f04be13 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSlotToken.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSlotToken.c
@@ -60,6 +60,8 @@ static CK_MECHANISM_TYPE soft_mechanisms[] = {
CKM_AES_CMAC,
CKM_AES_ECB,
CKM_AES_KEY_GEN,
+ CKM_AES_GCM,
+ CKM_AES_CCM,
CKM_BLOWFISH_CBC,
CKM_BLOWFISH_KEY_GEN,
CKM_SHA_1,
@@ -171,6 +173,12 @@ static CK_MECHANISM_INFO soft_mechanism_info[] = {
CKF_WRAP|CKF_UNWRAP}, /* CKM_AES_ECB */
{AES_MINBYTES, AES_MAXBYTES,
CKF_GENERATE}, /* CKM_AES_KEY_GEN */
+ {AES_MINBYTES, AES_MAXBYTES,
+ CKF_ENCRYPT|CKF_DECRYPT|
+ CKF_WRAP|CKF_UNWRAP}, /* CKM_AES_GCM */
+ {AES_MINBYTES, AES_MAXBYTES,
+ CKF_ENCRYPT|CKF_DECRYPT|
+ CKF_WRAP|CKF_UNWRAP}, /* CKM_AES_CCM */
{BLOWFISH_MINBYTES, BLOWFISH_MAXBYTES,
CKF_ENCRYPT|CKF_DECRYPT|
CKF_WRAP|CKF_UNWRAP}, /* CKM_BLOWFISH_ECB */
diff --git a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softVerifyUtil.c b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softVerifyUtil.c
index 85c1e64398..fd0f984c08 100644
--- a/usr/src/lib/pkcs11/pkcs11_softtoken/common/softVerifyUtil.c
+++ b/usr/src/lib/pkcs11/pkcs11_softtoken/common/softVerifyUtil.c
@@ -22,6 +22,7 @@
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018, Joyent, Inc.
*/
#include <stdlib.h>
@@ -208,10 +209,10 @@ soft_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
{
CK_ULONG len;
CK_BYTE signature[AES_BLOCK_LEN];
- soft_aes_ctx_t *aes_ctx;
+ aes_ctx_t *aes_ctx;
- aes_ctx = (soft_aes_ctx_t *)session_p->verify.context;
- len = aes_ctx->mac_len;
+ aes_ctx = (aes_ctx_t *)session_p->verify.context;
+ len = aes_ctx->ac_mac_len;
/* Pass local buffer to avoid overflow. */
rv = soft_aes_sign_verify_common(session_p, pData,
@@ -431,10 +432,10 @@ soft_verify_final(soft_session_t *session_p, CK_BYTE_PTR pSignature,
{
CK_ULONG len;
CK_BYTE signature[AES_BLOCK_LEN];
- soft_aes_ctx_t *aes_ctx;
+ aes_ctx_t *aes_ctx;
- aes_ctx = (soft_aes_ctx_t *)session_p->verify.context;
- len = aes_ctx->mac_len;
+ aes_ctx = (aes_ctx_t *)session_p->verify.context;
+ len = aes_ctx->ac_mac_len;
/* Pass local buffer to avoid overflow. */
rv = soft_aes_sign_verify_common(session_p, NULL, 0,
diff --git a/usr/src/test/crypto-tests/tests/common/cryptotest.h b/usr/src/test/crypto-tests/tests/common/cryptotest.h
index 3f091bc80c..e48ddced01 100644
--- a/usr/src/test/crypto-tests/tests/common/cryptotest.h
+++ b/usr/src/test/crypto-tests/tests/common/cryptotest.h
@@ -107,6 +107,15 @@ extern test_fg_t cryptotest_digest_fg;
#define DECR_FG (&cryptotest_decr_fg)
#define DIGEST_FG (&cryptotest_digest_fg)
+/*
+ * KCF and PKCS11 use different structures for the CCM params (CK_AES_CCM_PARAMS
+ * and CK_CCM_PARAMS respectively. Each cryptotest_*.c file implements this
+ * for their respective structs.
+ */
+void ccm_init_params(void *, ulong_t, uchar_t *, ulong_t, uchar_t *, ulong_t,
+ ulong_t);
+size_t ccm_param_len(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c b/usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c
index 525932206c..c4724613ea 100644
--- a/usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c
+++ b/usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c
@@ -439,3 +439,22 @@ digest_final(crypto_op_t *op)
return (kcf_do_ioctl(CRYPTO_DIGEST_FINAL, (uint_t *)&final, "final"));
}
+void
+ccm_init_params(void *buf, ulong_t ulDataLen, uchar_t *pNonce,
+ ulong_t ulNonceLen, uchar_t *pAAD, ulong_t ulAADLen, ulong_t ulMACLen)
+{
+ CK_AES_CCM_PARAMS *pp = buf;
+
+ pp->ulDataSize = ulDataLen;
+ pp->nonce = pNonce;
+ pp->ulNonceSize = ulNonceLen;
+ pp->authData = pAAD;
+ pp->ulAuthDataSize = ulAADLen;
+ pp->ulMACSize = ulMACLen;
+}
+
+size_t
+ccm_param_len(void)
+{
+ return (sizeof (CK_AES_CCM_PARAMS));
+}
diff --git a/usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c b/usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c
index 6bedd08499..e28d00e759 100644
--- a/usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c
+++ b/usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c
@@ -452,3 +452,23 @@ digest_final(crypto_op_t *op)
cryptotest_error("C_DigestFinal", rv);
return (rv);
}
+
+void
+ccm_init_params(void *buf, ulong_t ulDataLen, uchar_t *pNonce,
+ ulong_t ulNonceLen, uchar_t *pAAD, ulong_t ulAADLen, ulong_t ulMACLen)
+{
+ CK_CCM_PARAMS *pp = buf;
+
+ pp->ulDataLen = ulDataLen;
+ pp->pNonce = pNonce;
+ pp->ulNonceLen = ulNonceLen;
+ pp->pAAD = pAAD;
+ pp->ulAADLen = ulAADLen;
+ pp->ulMACLen = ulMACLen;
+}
+
+size_t
+ccm_param_len(void)
+{
+ return (sizeof (CK_CCM_PARAMS));
+}
diff --git a/usr/src/test/crypto-tests/tests/modes/aes/Makefile.subdirs b/usr/src/test/crypto-tests/tests/modes/aes/Makefile.subdirs
index fd431db1f5..4678b6c7f8 100644
--- a/usr/src/test/crypto-tests/tests/modes/aes/Makefile.subdirs
+++ b/usr/src/test/crypto-tests/tests/modes/aes/Makefile.subdirs
@@ -54,7 +54,8 @@ $(CMDS) := FILEMODE = 0555
LINTFLAGS += -xerroff=E_NAME_USED_NOT_DEF2
LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2
-CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I$(COMMONDIR) -I$(SRC)/common/crypto/
+CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+CPPFLAGS += -I$(COMMONDIR) -I$(SRC)/common/crypto/
all: $(PROGS)
diff --git a/usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c b/usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c
index a01129547e..91802aefdd 100644
--- a/usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c
+++ b/usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c
@@ -11,43 +11,49 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018, Joyent, Inc.
*/
#include <strings.h>
#include <stdio.h>
-
+#include <sys/debug.h>
#include "cryptotest.h"
#include "aes_ccm.h"
+/*
+ * Size of param (in 8-byte chunks for alignment) large enough for both
+ * CK_CCM_PARAMS and CK_AES_CCM_PARAMS.
+ */
+#define PARAM_SIZE_64 8
+
int
main(void)
{
int errs = 0;
int i;
uint8_t N[1024];
- CK_AES_CCM_PARAMS param;
- cryptotest_t args;
+ uint64_t param[PARAM_SIZE_64];
- bzero(&param, sizeof (param));
+ cryptotest_t args;
args.out = N;
- args.param = &param;
args.outlen = sizeof (N);
- args.plen = sizeof (param);
args.mechname = SUN_CKM_AES_CCM;
args.updatelen = 1;
- param.authData = CCM_DATA1;
args.key = CCM_KEY1;
args.keylen = sizeof (CCM_KEY1);
for (i = 0; i < 12; i++) {
- param.ulMACSize = MACLEN[i];
- param.ulNonceSize = NONCELEN[i];
- param.ulAuthDataSize = AUTHLEN[i];
- param.ulDataSize = DATALEN[i] - AUTHLEN[i];
- param.nonce = NONCE[i];
+ bzero(param, sizeof (param));
+ ccm_init_params(param, DATALEN[i] - AUTHLEN[i], NONCE[i],
+ NONCELEN[i], CCM_DATA1, AUTHLEN[i], MACLEN[i]);
+
+ args.param = param;
+ args.plen = ccm_param_len();
+
+ VERIFY3U(args.plen, <=, sizeof (param));
args.in = CCM_DATA1 + AUTHLEN[i];
args.inlen = DATALEN[i] - AUTHLEN[i];
@@ -60,12 +66,14 @@ main(void)
args.key = CCM_KEY2;
args.keylen = sizeof (CCM_KEY2);
for (i = 12; i < 24; i++) {
- param.ulMACSize = MACLEN[i];
- param.ulNonceSize = NONCELEN[i];
- param.ulAuthDataSize = AUTHLEN[i];
- param.ulDataSize = DATALEN[i] - AUTHLEN[i];
- param.nonce = NONCE[i];
- param.authData = DATA_2[i-12];
+ bzero(param, sizeof (param));
+ ccm_init_params(param, DATALEN[i] - AUTHLEN[i], NONCE[i],
+ NONCELEN[i], DATA_2[i-12], AUTHLEN[i], MACLEN[i]);
+
+ args.param = param;
+ args.plen = ccm_param_len();
+
+ VERIFY3U(args.plen, <=, sizeof (param));
args.in = DATA_2[i-12] + AUTHLEN[i];
args.inlen = DATALEN[i] - AUTHLEN[i];
@@ -77,15 +85,17 @@ main(void)
(void) fprintf(stderr, "\t\t\t=== decrypt ===\n----------\n\n");
- param.authData = CCM_DATA1;
args.key = CCM_KEY1;
args.keylen = sizeof (CCM_KEY1);
for (i = 0; i < 12; i++) {
- param.ulMACSize = MACLEN[i];
- param.ulNonceSize = NONCELEN[i];
- param.ulAuthDataSize = AUTHLEN[i];
- param.ulDataSize = RESLEN[i] - AUTHLEN[i];
- param.nonce = NONCE[i];
+ bzero(param, sizeof (param));
+ ccm_init_params(param, RESLEN[i] - AUTHLEN[i], NONCE[i],
+ NONCELEN[i], CCM_DATA1, AUTHLEN[i], MACLEN[i]);
+
+ args.param = param;
+ args.plen = ccm_param_len();
+
+ VERIFY3U(args.plen, <=, sizeof (param));
args.in = RES[i] + AUTHLEN[i];
args.inlen = RESLEN[i] - AUTHLEN[i];
@@ -98,12 +108,14 @@ main(void)
args.key = CCM_KEY2;
args.keylen = sizeof (CCM_KEY2);
for (i = 12; i < 24; i++) {
- param.ulMACSize = MACLEN[i];
- param.ulNonceSize = NONCELEN[i];
- param.ulAuthDataSize = AUTHLEN[i];
- param.ulDataSize = RESLEN[i] - AUTHLEN[i];
- param.nonce = NONCE[i];
- param.authData = DATA_2[i-12];
+ bzero(param, sizeof (param));
+ ccm_init_params(param, RESLEN[i] - AUTHLEN[i], NONCE[i],
+ NONCELEN[i], DATA_2[i-12], AUTHLEN[i], MACLEN[i]);
+
+ args.param = param;
+ args.plen = ccm_param_len();
+
+ VERIFY3U(args.plen, <=, sizeof (param));
args.in = RES[i] + AUTHLEN[i];
args.inlen = RESLEN[i] - AUTHLEN[i];
diff --git a/usr/src/uts/common/crypto/io/aes.c b/usr/src/uts/common/crypto/io/aes.c
index a008927cbb..7c6a105777 100644
--- a/usr/src/uts/common/crypto/io/aes.c
+++ b/usr/src/uts/common/crypto/io/aes.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018, Joyent, Inc.
*/
/*
@@ -405,22 +406,6 @@ aes_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
return (CRYPTO_SUCCESS);
}
-static void
-aes_copy_block64(uint8_t *in, uint64_t *out)
-{
- if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
- /* LINTED: pointer alignment */
- out[0] = *(uint64_t *)&in[0];
- /* LINTED: pointer alignment */
- out[1] = *(uint64_t *)&in[8];
- } else {
- uint8_t *iv8 = (uint8_t *)&out[0];
-
- AES_COPY_BLOCK(in, iv8);
- }
-}
-
-
static int
aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
crypto_data_t *ciphertext, crypto_req_handle_t req)
diff --git a/usr/src/uts/common/crypto/io/crypto.c b/usr/src/uts/common/crypto/io/crypto.c
index 812c624d66..3204ad6283 100644
--- a/usr/src/uts/common/crypto/io/crypto.c
+++ b/usr/src/uts/common/crypto/io/crypto.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018, Joyent, Inc.
*/
@@ -157,7 +158,7 @@ size_t crypto_pre_approved_limit = CRYPTO_PRE_APPROVED_LIMIT;
#define INIT_RAW_CRYPTO_DATA(data, len) \
(data).cd_format = CRYPTO_DATA_RAW; \
- (data).cd_raw.iov_base = kmem_alloc(len, KM_SLEEP); \
+ (data).cd_raw.iov_base = (len > 0) ? kmem_alloc(len, KM_SLEEP) : NULL; \
(data).cd_raw.iov_len = len; \
(data).cd_offset = 0; \
(data).cd_length = len;
diff --git a/usr/src/uts/common/crypto/io/dprov.c b/usr/src/uts/common/crypto/io/dprov.c
index 16be9dc4bd..32b3fdb417 100644
--- a/usr/src/uts/common/crypto/io/dprov.c
+++ b/usr/src/uts/common/crypto/io/dprov.c
@@ -22,6 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018, Joyent, Inc.
*/
@@ -2656,7 +2657,8 @@ dprov_valid_sign_verif_mech(crypto_mech_type_t mech_type)
mech_type == SHA384_RSA_PKCS_MECH_INFO_TYPE ||
mech_type == SHA512_RSA_PKCS_MECH_INFO_TYPE ||
mech_type == ECDSA_SHA1_MECH_INFO_TYPE ||
- mech_type == ECDSA_MECH_INFO_TYPE);
+ mech_type == ECDSA_MECH_INFO_TYPE ||
+ mech_type == AES_CMAC_MECH_INFO_TYPE);
}
static int