diff options
author | Jason King <jason.king@joyent.com> | 2018-01-25 18:49:57 +0000 |
---|---|---|
committer | Jason King <jason.king@joyent.com> | 2018-10-05 09:35:58 -0500 |
commit | 6dfc9cdf26a31c05ac54748aa413187e43a0a214 (patch) | |
tree | e6154404cd96f5090928e071c88a0718f138e59e | |
parent | b1917065992b99886121c8fbeeb447643cb0a1fb (diff) | |
download | illumos-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>
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(¶m, sizeof (param)); + cryptotest_t args; args.out = N; - args.param = ¶m; 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 |