Skip to content

Commit

Permalink
PKCS11: Add support for KDF when deriving ECDH keys
Browse files Browse the repository at this point in the history
  • Loading branch information
aveenismail committed Feb 1, 2024
1 parent aa2606e commit 4b41568
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 29 deletions.
5 changes: 5 additions & 0 deletions pkcs11/pkcs11y.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@
#define CKM_YUBICO_AES_CCM_WRAP \
(CKM_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_WRAP_KEY)

#define CKD_SHA1_KDF_SP800 0x0000000EUL
#define CKD_SHA256_KDF_SP800 0x00000010UL
#define CKD_SHA384_KDF_SP800 0x00000011UL
#define CKD_SHA512_KDF_SP800 0x00000012UL

#endif
93 changes: 66 additions & 27 deletions pkcs11/util_pkcs11.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ CK_RV get_mechanism_list(yubihsm_pkcs11_slot *slot,
}
}

CK_MECHANISM_TYPE buffer[128] = {0}; // NOTE: this is a bit hardcoded, but much more
CK_MECHANISM_TYPE buffer[128] = {
0}; // NOTE: this is a bit hardcoded, but much more
// than what we might add below.
CK_ULONG items = 0;

Expand Down Expand Up @@ -1028,14 +1029,14 @@ static void get_capability_attribute(yh_object_descriptor *object,
}

static CK_RV add_mech_type(CK_BYTE_PTR value, CK_ULONG max, CK_ULONG_PTR length,
CK_MECHANISM_TYPE mech) {
CK_MECHANISM_TYPE mech) {
for (CK_ULONG i = 0; i < *length; i += sizeof(CK_MECHANISM_TYPE)) {
if (*(CK_MECHANISM_TYPE_PTR) (value + i) == mech)
if (*(CK_MECHANISM_TYPE_PTR)(value + i) == mech)
return CKR_OK;
}
if(*length + sizeof(CK_MECHANISM_TYPE) > max)
if (*length + sizeof(CK_MECHANISM_TYPE) > max)
return CKR_BUFFER_TOO_SMALL;
*(CK_MECHANISM_TYPE_PTR) (value + *length) = mech;
*(CK_MECHANISM_TYPE_PTR)(value + *length) = mech;
*length += sizeof(CK_MECHANISM_TYPE);
return CKR_OK;
}
Expand All @@ -1052,83 +1053,83 @@ static CK_RV get_allowed_mechs(yh_object_descriptor *object, CK_BYTE_PTR value,
if (yh_is_rsa(object->algorithm)) {
if (yh_check_capability(&object->capabilities, "sign-pkcs")) {
rv = add_mech_type(value, max, length, CKM_RSA_PKCS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA1_RSA_PKCS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA256_RSA_PKCS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA384_RSA_PKCS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA512_RSA_PKCS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
if (yh_check_capability(&object->capabilities, "sign-pss")) {
rv = add_mech_type(value, max, length, CKM_RSA_PKCS_PSS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA1_RSA_PKCS_PSS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA256_RSA_PKCS_PSS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA384_RSA_PKCS_PSS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_SHA512_RSA_PKCS_PSS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
if (yh_check_capability(&object->capabilities, "decrypt-pkcs")) {
rv = add_mech_type(value, max, length, CKM_RSA_PKCS);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
if (yh_check_capability(&object->capabilities, "decrypt-oaep")) {
rv = add_mech_type(value, max, length, CKM_RSA_PKCS_OAEP);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
} else if (yh_is_ec(object->algorithm)) {
if (yh_check_capability(&object->capabilities, "sign-ecdsa")) {
rv = add_mech_type(value, max, length, CKM_ECDSA);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_ECDSA_SHA1);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_ECDSA_SHA256);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_ECDSA_SHA384);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_ECDSA_SHA512);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
if (yh_check_capability(&object->capabilities, "derive-ecdh")) {
rv = add_mech_type(value, max, length, CKM_ECDH1_DERIVE);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
} else if (yh_is_aes(object->algorithm)) {
if (yh_check_capability(&object->capabilities, "aes-ecb")) {
rv = add_mech_type(value, max, length, CKM_AES_ECB);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
if (yh_check_capability(&object->capabilities, "aes-cbc")) {
rv = add_mech_type(value, max, length, CKM_AES_CBC);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
rv = add_mech_type(value, max, length, CKM_AES_CBC_PAD);
if(rv != CKR_OK)
if (rv != CKR_OK)
return rv;
}
} else {
Expand Down Expand Up @@ -2189,6 +2190,43 @@ static CK_RV get_attribute_ecsession_key(CK_ATTRIBUTE_TYPE type,
return CKR_OK;
}

CK_RV apply_hash_function(const EVP_MD *md, uint8_t *value, size_t value_len,
uint8_t *hashed_value, size_t *hashed_value_len) {
if (md == NULL) {
hashed_value = value;
return CKR_OK;
}
CK_RV rv = CKR_OK;

EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
if (mdctx == NULL) {
rv = CKR_HOST_MEMORY;
goto hash_out;
}

if (EVP_DigestInit_ex(mdctx, md, NULL) == 0) {
rv = CKR_DATA_INVALID;
goto hash_out;
}

if (EVP_DigestUpdate(mdctx, value, value_len) != 1) {
rv = CKR_FUNCTION_FAILED;
goto hash_out;
}
if (EVP_DigestFinal_ex(mdctx, hashed_value,
(unsigned int *) hashed_value_len) != 1) {
rv = CKR_FUNCTION_FAILED;
goto hash_out;
}

hash_out:

if (mdctx != NULL) {
EVP_MD_CTX_destroy(mdctx);
}
return rv;
}

CK_RV check_sign_mechanism(yubihsm_pkcs11_slot *slot,
CK_MECHANISM_PTR pMechanism) {

Expand Down Expand Up @@ -5270,7 +5308,8 @@ CK_RV validate_derive_key_attribute(CK_ATTRIBUTE_TYPE type, void *value) {
break;

case CKA_KEY_TYPE:
if (*((CK_ULONG_PTR) value) != CKK_GENERIC_SECRET) {
if (*((CK_ULONG_PTR) value) != CKK_GENERIC_SECRET &&
*((CK_ULONG_PTR) value) != CKK_AES) {
DBG_ERR("Derived key type is unsupported");
return CKR_ATTRIBUTE_VALUE_INVALID;
}
Expand Down
3 changes: 3 additions & 0 deletions pkcs11/util_pkcs11.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ yubihsm_pkcs11_object_desc *_get_object_desc(yubihsm_pkcs11_slot *slot,
uint16_t id, uint8_t type,
uint16_t sequence);

CK_RV apply_hash_function(const EVP_MD *md, uint8_t *value, size_t value_len,
uint8_t *hashed_value, size_t *hashed_value_len);

CK_RV check_sign_mechanism(yubihsm_pkcs11_slot *slot,
CK_MECHANISM_PTR pMechanism);

Expand Down
30 changes: 28 additions & 2 deletions pkcs11/yubihsm_pkcs11.c
Original file line number Diff line number Diff line change
Expand Up @@ -5633,7 +5633,10 @@ CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey)

CK_ECDH1_DERIVE_PARAMS *params = pMechanism->pParameter;

if (params->kdf == CKD_NULL) {
if (params->kdf == CKD_NULL || params->kdf == CKD_SHA1_KDF_SP800 ||
params->kdf == CKD_SHA256_KDF_SP800 ||
params->kdf == CKD_SHA384_KDF_SP800 ||
params->kdf == CKD_SHA512_KDF_SP800) {
if ((params->pSharedData != NULL) || (params->ulSharedDataLen != 0)) {
DBG_ERR("Mechanism parameters incompatible with key derivation function "
"CKD_NULL");
Expand Down Expand Up @@ -5671,11 +5674,34 @@ CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey)
yh_rc rc = yh_util_derive_ecdh(session->slot->device_session, privkey_id,
pubkey, in_len, ecdh_key.ecdh_key, &out_len);
if (rc != YHR_SUCCESS) {
DBG_ERR("Unable to derive ECDH key: %s", yh_strerror(rc));
DBG_ERR("Unable to derive raw ECDH key: %s", yh_strerror(rc));
rv = yrc_to_rv(rc);
goto c_drv_out;
}

const EVP_MD *md = NULL;
switch (params->kdf) {
case CKD_SHA1_KDF_SP800:
md = EVP_sha1();
break;
case CKD_SHA256_KDF_SP800:
md = EVP_sha256();
break;
case CKD_SHA384_KDF_SP800:
md = EVP_sha384();
break;
case CKD_SHA512_KDF_SP800:
md = EVP_sha512();
break;
default:
// do nothing
break;
}
if (md != NULL) {
apply_hash_function(md, ecdh_key.ecdh_key, out_len, ecdh_key.ecdh_key,
&out_len);
}

if ((expected_key_length > 0) && (expected_key_length != out_len)) {
DBG_ERR("Failed to derive a key with the expected length");
rv = CKR_DATA_LEN_RANGE;
Expand Down

0 comments on commit 4b41568

Please sign in to comment.