Skip to content

Commit

Permalink
ta: pkcs11: pkcs11_attributes.c: support PKCS11_CKA_CHECK_VALUE
Browse files Browse the repository at this point in the history
Add PKCS11_CKA_CHECK_VALUE as an optional attribute of symmetric
key and certificate objects . As per the PKCS#11 specification, key
check value attribute is optional therefore add pkcs11 TA configuration
switch CFG_PKCS11_TA_CHECK_VALUE_ATTRIBUTE to embed or not the support.

When supported, as per the spec, the attribute can be either the
legitimate value recomputed by the PKCS#11 token or a zero-sized value
called a no-value for when client does not want the attribute to set
in an object.

This change adds the support for the pcks11 TA commands related to
Cryptoki API functions C_GenerateKey(), C_CreateObject(), C_CopyObject(),
C_SetAttributeValue(), C_UnwrapKey() and C_DeriveKey(). TA command
related to C_FindOjects() support the attribute without any change.

Signed-off-by: Marouene Boubakri <marouene.boubakri@nxp.com>
Reviewed-by: Etienne Carriere <etienne.carriere@foss.st.com>
  • Loading branch information
maroueneboubakri authored and jforissier committed Dec 14, 2023
1 parent fc4adc6 commit bcac212
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 4 deletions.
15 changes: 15 additions & 0 deletions ta/pkcs11/src/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,11 @@ enum pkcs11_rc entry_create_object(struct pkcs11_client *client,
if (rc)
goto out;

/* Set key check value attribute */
rc = set_check_value_attr(&head);
if (rc)
goto out;

/*
* Check target object attributes match target processing
* Check target object attributes match token state
Expand Down Expand Up @@ -1064,6 +1069,11 @@ enum pkcs11_rc entry_set_attribute_value(struct pkcs11_client *client,
if (rc)
goto out;

/* Set key check value attribute */
rc = set_check_value_attr(&obj->attributes);
if (rc)
goto out;

if (get_bool(obj->attributes, PKCS11_CKA_TOKEN)) {
rc = update_persistent_object_attributes(obj);
if (rc)
Expand Down Expand Up @@ -1216,6 +1226,11 @@ enum pkcs11_rc entry_copy_object(struct pkcs11_client *client, uint32_t ptypes,
if (rc)
goto out;

/* Set key check value attribute */
rc = set_check_value_attr(&head_new);
if (rc)
goto out;

/*
* At this stage the object is almost created: all its attributes are
* referenced in @head_new, including the key value and are assumed
Expand Down
214 changes: 211 additions & 3 deletions ta/pkcs11/src/pkcs11_attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include <assert.h>
#include <config.h>
#include <inttypes.h>
#include <mbedtls/asn1write.h>
#include <mbedtls/ecp.h>
Expand Down Expand Up @@ -355,8 +356,12 @@ static const uint32_t pkcs11_certificate_boolprops[] = {
};

static const uint32_t pkcs11_certificate_optional[] = {
PKCS11_CKA_CERTIFICATE_CATEGORY, PKCS11_CKA_CHECK_VALUE,
PKCS11_CKA_START_DATE, PKCS11_CKA_END_DATE, PKCS11_CKA_PUBLIC_KEY_INFO,
PKCS11_CKA_CERTIFICATE_CATEGORY, PKCS11_CKA_START_DATE,
PKCS11_CKA_END_DATE, PKCS11_CKA_PUBLIC_KEY_INFO,
#ifdef CFG_PKCS11_TA_CHECK_VALUE_ATTRIBUTE
/* Consider KCV attribute only when supported */
PKCS11_CKA_CHECK_VALUE,
#endif
};

/*
Expand Down Expand Up @@ -404,6 +409,10 @@ static const uint32_t symm_key_opt_or_null[] = {

static const uint32_t symm_key_optional[] = {
PKCS11_CKA_VALUE_LEN,
#ifdef CFG_PKCS11_TA_CHECK_VALUE_ATTRIBUTE
/* Consider KCV attribute only when supported */
PKCS11_CKA_CHECK_VALUE,
#endif
};

/* PKCS#11 specification for any asymmetric public key (+any_key_xxx) */
Expand Down Expand Up @@ -2173,6 +2182,7 @@ static bool attr_is_modifiable_secret_key(struct pkcs11_attribute_head *attr,
case PKCS11_CKA_VERIFY:
case PKCS11_CKA_WRAP:
case PKCS11_CKA_UNWRAP:
case PKCS11_CKA_CHECK_VALUE:
return true;
/* Can't be modified once set to CK_FALSE - 12 in Table 10 */
case PKCS11_CKA_EXTRACTABLE:
Expand Down Expand Up @@ -2478,7 +2488,11 @@ static enum pkcs11_rc set_secret_key_data(struct obj_attrs **head, void *data,
if (rc != PKCS11_CKR_OK && rc != PKCS11_RV_NOT_FOUND)
return PKCS11_CKR_GENERAL_ERROR;

return add_attribute(head, PKCS11_CKA_VALUE, data, key_length);
rc = add_attribute(head, PKCS11_CKA_VALUE, data, key_length);
if (rc)
return rc;

return set_check_value_attr(head);
}

static enum pkcs11_rc set_private_key_data_rsa(struct obj_attrs **head,
Expand Down Expand Up @@ -2827,3 +2841,197 @@ enum pkcs11_rc add_missing_attribute_id(struct obj_attrs **pub_head,
else
return set_attribute(pub_head, PKCS11_CKA_ID, id2, id2_size);
}

/*
* The key check value is derived from the object by taking the first
* three bytes of the SHA-1 hash of the object's CKA_VALUE attribute.
*/
static enum pkcs11_rc compute_check_value_with_sha1(void *key,
uint32_t key_size,
void *kcv)
{
enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
TEE_Result res = TEE_ERROR_GENERIC;
TEE_OperationHandle op = TEE_HANDLE_NULL;
size_t buf_size = TEE_MAX_HASH_SIZE;
uint8_t *buf = NULL;

assert(key && kcv);

res = TEE_AllocateOperation(&op, TEE_ALG_SHA1, TEE_MODE_DIGEST, 0);
rc = tee2pkcs_error(res);
if (rc != PKCS11_CKR_OK)
goto out;

buf = TEE_Malloc(buf_size, TEE_MALLOC_FILL_ZERO);
if (!buf) {
rc = PKCS11_CKR_DEVICE_MEMORY;
goto out;
}

res = TEE_DigestDoFinal(op, key, key_size, buf, &buf_size);
rc = tee2pkcs_error(res);
if (rc != PKCS11_CKR_OK)
goto out;

TEE_MemMove(kcv, buf, PKCS11_CKA_CHECK_VALUE_SIZE);

out:
TEE_Free(buf);
TEE_FreeOperation(op);

return rc;
}

/*
* The key check value that is calculated as follows:
* 1) Take a buffer of the cipher block size of binary zeros (0x00).
* 2) Encrypt this block in ECB mode.
* 3) Take the first three bytes of cipher text as the check value.
*/
static enum pkcs11_rc compute_check_value_with_ecb(void *key, uint32_t key_size,
void *kcv)
{
enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
TEE_Result res = TEE_ERROR_GENERIC;
TEE_OperationHandle op = TEE_HANDLE_NULL;
TEE_ObjectHandle hkey = TEE_HANDLE_NULL;
TEE_Attribute attr = { };
uint8_t *buf = NULL;
size_t buf_size = 0;

assert(key && kcv);

res = TEE_AllocateOperation(&op, TEE_ALG_AES_ECB_NOPAD,
TEE_MODE_ENCRYPT, key_size * 8);
rc = tee2pkcs_error(res);
if (rc != PKCS11_CKR_OK)
goto out;

res = TEE_AllocateTransientObject(TEE_TYPE_AES, key_size * 8, &hkey);
rc = tee2pkcs_error(res);
if (rc != PKCS11_CKR_OK)
goto out;

attr.attributeID = TEE_ATTR_SECRET_VALUE;
attr.content.ref.buffer = key;
attr.content.ref.length = key_size;

res = TEE_PopulateTransientObject(hkey, &attr, 1);
rc = tee2pkcs_error(res);
if (rc != PKCS11_CKR_OK)
goto out;

res = TEE_SetOperationKey(op, hkey);
rc = tee2pkcs_error(res);
if (rc != PKCS11_CKR_OK)
goto out;

TEE_CipherInit(op, NULL, 0);

buf_size = key_size;
buf = TEE_Malloc(buf_size, TEE_MALLOC_FILL_ZERO);
if (!buf) {
rc = PKCS11_CKR_DEVICE_MEMORY;
goto out;
}

res = TEE_CipherDoFinal(op, buf, buf_size, buf, &buf_size);
rc = tee2pkcs_error(res);
if (rc != PKCS11_CKR_OK)
goto out;

TEE_MemMove(kcv, buf, PKCS11_CKA_CHECK_VALUE_SIZE);

out:
TEE_Free(buf);
TEE_FreeTransientObject(hkey);
TEE_FreeOperation(op);

return rc;
}

enum pkcs11_rc set_check_value_attr(struct obj_attrs **head)
{
enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
uint32_t val_len = 0;
uint32_t kcv2_len = 0;
void *val = NULL;
uint8_t kcv[PKCS11_CKA_CHECK_VALUE_SIZE] = { };
void *kcv2 = NULL;

assert(head && *head);

if (!IS_ENABLED(CFG_PKCS11_TA_CHECK_VALUE_ATTRIBUTE))
return PKCS11_CKR_OK;

switch (get_class(*head)) {
case PKCS11_CKO_SECRET_KEY:
case PKCS11_CKO_CERTIFICATE:
break;
default:
return PKCS11_CKR_ARGUMENTS_BAD;
}

/* Check whether CKA_CHECK_VALUE has been provided in the template */
rc = get_attribute_ptr(*head, PKCS11_CKA_CHECK_VALUE, &kcv2, &kcv2_len);

if (rc != PKCS11_CKR_OK && rc != PKCS11_RV_NOT_FOUND)
return PKCS11_CKR_GENERAL_ERROR;

/*
* The generation of the KCV may be prevented by the application
* supplying the attribute in the template as a no-value (0 length)
* entry.
*/
if (rc == PKCS11_CKR_OK && !kcv2_len)
return PKCS11_CKR_OK;

if (rc == PKCS11_CKR_OK && kcv2_len != PKCS11_CKA_CHECK_VALUE_SIZE)
return PKCS11_CKR_TEMPLATE_INCONSISTENT;

/* Get key CKA_VALUE */
rc = get_attribute_ptr(*head, PKCS11_CKA_VALUE, &val, &val_len);
if (rc)
return rc;

if (get_class(*head) == PKCS11_CKO_SECRET_KEY) {
switch (get_key_type(*head)) {
case PKCS11_CKK_AES:
rc = compute_check_value_with_ecb(val, val_len, kcv);
break;
case PKCS11_CKK_GENERIC_SECRET:
case PKCS11_CKK_MD5_HMAC:
case PKCS11_CKK_SHA_1_HMAC:
case PKCS11_CKK_SHA256_HMAC:
case PKCS11_CKK_SHA384_HMAC:
case PKCS11_CKK_SHA512_HMAC:
case PKCS11_CKK_SHA224_HMAC:
rc = compute_check_value_with_sha1(val, val_len, kcv);
break;
default:
rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
break;
}
} else {
rc = compute_check_value_with_sha1(val, val_len, kcv);
}

if (rc)
return rc;

/*
* If the computed KCV does not match the provided one
* then return CKR_ATTRIBUTE_VALUE_INVALID
*/
if (kcv2_len) {
/* Provided KCV value shall match the computed one */
if (TEE_MemCompare(kcv2, kcv, PKCS11_CKA_CHECK_VALUE_SIZE))
rc = PKCS11_CKR_ATTRIBUTE_VALUE_INVALID;
} else {
rc = add_attribute(head, PKCS11_CKA_CHECK_VALUE, kcv,
PKCS11_CKA_CHECK_VALUE_SIZE);
}

return rc;
}
9 changes: 9 additions & 0 deletions ta/pkcs11/src/pkcs11_attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

#include "serializer.h"

/* The key check value (KCV) attribute for objects is 3 bytes */
#define PKCS11_CKA_CHECK_VALUE_SIZE U(3)

struct obj_attrs;
struct pkcs11_object;
struct pkcs11_session;
Expand Down Expand Up @@ -214,5 +217,11 @@ enum pkcs11_rc alloc_key_data_to_wrap(struct obj_attrs *head, void **data,
*/
enum pkcs11_rc add_missing_attribute_id(struct obj_attrs **pub_head,
struct obj_attrs **priv_head);
/*
* Check an object's check value (Checksum)
* @head: Object attribute where to find KCV to be checked
* Return a pkcs11_rv compliant value
*/
enum pkcs11_rc set_check_value_attr(struct obj_attrs **head);

#endif /*PKCS11_TA_PKCS11_ATTRIBUTES_H*/
5 changes: 4 additions & 1 deletion ta/pkcs11/src/processing.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ size_t get_object_key_bit_size(struct pkcs11_object *obj)
static enum pkcs11_rc generate_random_key_value(struct obj_attrs **head)
{
enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
void *data = NULL;
uint32_t data_size = 0;
uint32_t value_len = 0;
void *value = NULL;
void *data = NULL;

if (!*head)
return PKCS11_CKR_TEMPLATE_INCONSISTENT;
Expand All @@ -196,6 +196,9 @@ static enum pkcs11_rc generate_random_key_value(struct obj_attrs **head)

rc = add_attribute(head, PKCS11_CKA_VALUE, value, value_len);

if (rc == PKCS11_CKR_OK)
rc = set_check_value_attr(head);

TEE_Free(value);

return rc;
Expand Down
3 changes: 3 additions & 0 deletions ta/pkcs11/sub.mk
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ CFG_PKCS11_TA_HEAP_SIZE ?= (32 * 1024)
# Defines the number of PKCS11 token implemented by the PKCS11 TA
CFG_PKCS11_TA_TOKEN_COUNT ?= 3

# When enabled, embed support for object checksum value computation
CFG_PKCS11_TA_CHECK_VALUE_ATTRIBUTE ?= n

global-incdirs-y += include
global-incdirs-y += src
subdirs-y += src

0 comments on commit bcac212

Please sign in to comment.