aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2020-05-04 10:37:24 +0200
committerJérôme Forissier <jerome@forissier.org>2020-07-14 18:42:38 +0200
commit63f89caa9022ecf51d1b82dc78af35ba9e38466d (patch)
treec0acd5caa9c6bb6e0ccbf162980fc2049409bf1a
parent55dcd3cc83c75032cb58ef579ac2054cca440466 (diff)
ta: pkcs11: attribute helper functions
* Helper functions for object attributes management. * Helper functions to safely parse client attributes template to create a list of attributes for a object in the PKCS11 ta. * Helper functions for assigning or checking object attributes according to PKCS#11 specification. * Add id-to-string conversion for attribute/class/key types. * Helper functions to analyze object attributes. Reviewed-by: Ricardo Salveti <ricardo@foundries.io> Co-developed-by: Etienne Carriere <etienne.carriere@linaro.org> Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r--ta/pkcs11/src/attributes.c299
-rw-r--r--ta/pkcs11/src/attributes.h248
-rw-r--r--ta/pkcs11/src/pkcs11_attributes.c775
-rw-r--r--ta/pkcs11/src/pkcs11_attributes.h137
-rw-r--r--ta/pkcs11/src/pkcs11_helpers.c327
-rw-r--r--ta/pkcs11/src/pkcs11_helpers.h43
-rw-r--r--ta/pkcs11/src/sanitize_object.c429
-rw-r--r--ta/pkcs11/src/sanitize_object.h41
-rw-r--r--ta/pkcs11/src/sub.mk3
9 files changed, 2302 insertions, 0 deletions
diff --git a/ta/pkcs11/src/attributes.c b/ta/pkcs11/src/attributes.c
new file mode 100644
index 00000000..67b5e4e4
--- /dev/null
+++ b/ta/pkcs11/src/attributes.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2020, Linaro Limited
+ */
+
+#include <assert.h>
+#include <compiler.h>
+#include <pkcs11_ta.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_ext.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <trace.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "pkcs11_helpers.h"
+#include "serializer.h"
+
+enum pkcs11_rc init_attributes_head(struct obj_attrs **head)
+{
+ *head = TEE_Malloc(sizeof(**head), TEE_MALLOC_FILL_ZERO);
+ if (!*head)
+ return PKCS11_CKR_DEVICE_MEMORY;
+
+ return PKCS11_CKR_OK;
+}
+
+enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute,
+ void *data, size_t size)
+{
+ size_t buf_len = sizeof(struct obj_attrs) + (*head)->attrs_size;
+ char **bstart = (void *)head;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ uint32_t data32 = 0;
+
+ data32 = attribute;
+ rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
+ if (rc)
+ return rc;
+
+ data32 = size;
+ rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
+ if (rc)
+ return rc;
+
+ rc = serialize(bstart, &buf_len, data, size);
+ if (rc)
+ return rc;
+
+ /* Alloced buffer is always well aligned */
+ head = (void *)bstart;
+ (*head)->attrs_size += 2 * sizeof(uint32_t) + size;
+ (*head)->attrs_count++;
+
+ return rc;
+}
+
+void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute,
+ void **attr, uint32_t *attr_size, size_t *count)
+{
+ char *cur = (char *)head + sizeof(struct obj_attrs);
+ char *end = cur + head->attrs_size;
+ size_t next_off = 0;
+ size_t max_found = *count;
+ size_t found = 0;
+ void **attr_ptr = attr;
+ uint32_t *attr_size_ptr = attr_size;
+
+ for (; cur < end; cur += next_off) {
+ /* Structure aligned copy of the pkcs11_ref in the object */
+ struct pkcs11_attribute_head pkcs11_ref = { };
+
+ TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
+ next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
+
+ if (pkcs11_ref.id != attribute)
+ continue;
+
+ found++;
+
+ if (!max_found)
+ continue; /* only count matching attributes */
+
+ if (attr)
+ *attr_ptr++ = cur + sizeof(pkcs11_ref);
+
+ if (attr_size)
+ *attr_size_ptr++ = pkcs11_ref.size;
+
+ if (found == max_found)
+ break;
+ }
+
+ /* Sanity */
+ if (cur > end) {
+ DMSG("Exceeding serial object length");
+ TEE_Panic(0);
+ }
+
+ *count = found;
+}
+
+enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute,
+ void **attr_ptr, uint32_t *attr_size)
+{
+ size_t count = 1;
+
+ get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count);
+
+ if (!count)
+ return PKCS11_RV_NOT_FOUND;
+
+ if (count != 1)
+ return PKCS11_CKR_GENERAL_ERROR;
+
+ return PKCS11_CKR_OK;
+}
+
+enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute,
+ void *attr, uint32_t *attr_size)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ void *attr_ptr = NULL;
+ uint32_t size = 0;
+
+ rc = get_attribute_ptr(head, attribute, &attr_ptr, &size);
+ if (rc)
+ return rc;
+
+ if (attr_size && *attr_size != size) {
+ *attr_size = size;
+ /* This reuses buffer-to-small for any bad size matching */
+ return PKCS11_CKR_BUFFER_TOO_SMALL;
+ }
+
+ if (attr)
+ TEE_MemMove(attr, attr_ptr, size);
+
+ if (attr_size)
+ *attr_size = size;
+
+ return PKCS11_CKR_OK;
+}
+
+bool get_bool(struct obj_attrs *head, uint32_t attribute)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ uint8_t bbool = 0;
+ uint32_t size = sizeof(bbool);
+
+ rc = get_attribute(head, attribute, &bbool, &size);
+
+ if (rc == PKCS11_RV_NOT_FOUND)
+ return false;
+
+ assert(rc == PKCS11_CKR_OK);
+ return bbool;
+}
+
+#if CFG_TEE_TA_LOG_LEVEL > 0
+/*
+ * Debug: dump CK attribute array to output trace
+ */
+#define ATTR_TRACE_FMT "%s attr %s / %s\t(0x%04"PRIx32" %"PRIu32"-byte"
+#define ATTR_FMT_0BYTE ATTR_TRACE_FMT ")"
+#define ATTR_FMT_1BYTE ATTR_TRACE_FMT ": %02x)"
+#define ATTR_FMT_2BYTE ATTR_TRACE_FMT ": %02x %02x)"
+#define ATTR_FMT_3BYTE ATTR_TRACE_FMT ": %02x %02x %02x)"
+#define ATTR_FMT_4BYTE ATTR_TRACE_FMT ": %02x %02x %02x %02x)"
+#define ATTR_FMT_ARRAY ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)"
+
+static void __trace_attributes(char *prefix, void *src, void *end)
+{
+ size_t next_off = 0;
+ char *prefix2 = NULL;
+ size_t prefix_len = strlen(prefix);
+ char *cur = src;
+
+ /* append 4 spaces to the prefix plus terminal '\0' */
+ prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
+ if (!prefix2)
+ return;
+
+ TEE_MemMove(prefix2, prefix, prefix_len + 1);
+ TEE_MemFill(prefix2 + prefix_len, ' ', 4);
+ *(prefix2 + prefix_len + 4) = '\0';
+
+ for (; cur < (char *)end; cur += next_off) {
+ struct pkcs11_attribute_head pkcs11_ref = { };
+ uint8_t data[4] = { 0 };
+
+ TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
+ TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
+ MIN(pkcs11_ref.size, sizeof(data)));
+
+ next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
+
+ switch (pkcs11_ref.size) {
+ case 0:
+ IMSG_RAW(ATTR_FMT_0BYTE,
+ prefix, id2str_attr(pkcs11_ref.id), "*",
+ pkcs11_ref.id, pkcs11_ref.size);
+ break;
+ case 1:
+ IMSG_RAW(ATTR_FMT_1BYTE,
+ prefix, id2str_attr(pkcs11_ref.id),
+ id2str_attr_value(pkcs11_ref.id,
+ pkcs11_ref.size,
+ cur + sizeof(pkcs11_ref)),
+ pkcs11_ref.id, pkcs11_ref.size, data[0]);
+ break;
+ case 2:
+ IMSG_RAW(ATTR_FMT_2BYTE,
+ prefix, id2str_attr(pkcs11_ref.id),
+ id2str_attr_value(pkcs11_ref.id,
+ pkcs11_ref.size,
+ cur + sizeof(pkcs11_ref)),
+ pkcs11_ref.id, pkcs11_ref.size, data[0],
+ data[1]);
+ break;
+ case 3:
+ IMSG_RAW(ATTR_FMT_3BYTE,
+ prefix, id2str_attr(pkcs11_ref.id),
+ id2str_attr_value(pkcs11_ref.id,
+ pkcs11_ref.size,
+ cur + sizeof(pkcs11_ref)),
+ pkcs11_ref.id, pkcs11_ref.size,
+ data[0], data[1], data[2]);
+ break;
+ case 4:
+ IMSG_RAW(ATTR_FMT_4BYTE,
+ prefix, id2str_attr(pkcs11_ref.id),
+ id2str_attr_value(pkcs11_ref.id,
+ pkcs11_ref.size,
+ cur + sizeof(pkcs11_ref)),
+ pkcs11_ref.id, pkcs11_ref.size,
+ data[0], data[1], data[2], data[3]);
+ break;
+ default:
+ IMSG_RAW(ATTR_FMT_ARRAY,
+ prefix, id2str_attr(pkcs11_ref.id),
+ id2str_attr_value(pkcs11_ref.id,
+ pkcs11_ref.size,
+ cur + sizeof(pkcs11_ref)),
+ pkcs11_ref.id, pkcs11_ref.size,
+ data[0], data[1], data[2], data[3]);
+ break;
+ }
+
+ switch (pkcs11_ref.id) {
+ case PKCS11_CKA_WRAP_TEMPLATE:
+ case PKCS11_CKA_UNWRAP_TEMPLATE:
+ case PKCS11_CKA_DERIVE_TEMPLATE:
+ trace_attributes(prefix2, cur + sizeof(pkcs11_ref));
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Sanity */
+ if (cur != end)
+ EMSG("Warning: unexpected alignment in object attributes");
+
+ TEE_Free(prefix2);
+}
+
+void trace_attributes(const char *prefix, void *ref)
+{
+ struct obj_attrs head;
+ char *pre = NULL;
+
+ TEE_MemMove(&head, ref, sizeof(head));
+
+ pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
+ if (!pre) {
+ EMSG("%s: out of memory", prefix);
+ return;
+ }
+
+ if (prefix)
+ TEE_MemMove(pre, prefix, strlen(prefix));
+
+ IMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
+ IMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
+ pre, head.attrs_count, head.attrs_size);
+
+ pre[prefix ? strlen(prefix) : 0] = '|';
+ __trace_attributes(pre, (char *)ref + sizeof(head),
+ (char *)ref + sizeof(head) + head.attrs_size);
+
+ IMSG_RAW("%s`-----------------------", prefix ? prefix : "");
+
+ TEE_Free(pre);
+}
+#endif /*CFG_TEE_TA_LOG_LEVEL*/
diff --git a/ta/pkcs11/src/attributes.h b/ta/pkcs11/src/attributes.h
new file mode 100644
index 00000000..1dfa7b92
--- /dev/null
+++ b/ta/pkcs11/src/attributes.h
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2020, Linaro Limited
+ */
+
+#ifndef PKCS11_TA_ATTRIBUTES_H
+#define PKCS11_TA_ATTRIBUTES_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <util.h>
+
+#include "pkcs11_helpers.h"
+
+/*
+ * Boolean property attributes (BPA): bit position in a 64 bit mask
+ * for boolean properties object can mandate as attribute, depending
+ * on the object. These attributes are often accessed and it is
+ * quicker to get them from a 64 bit field in the object instance
+ * rather than searching into the object attributes.
+ */
+#define PKCS11_BOOLPROPS_BASE 0
+#define PKCS11_BOOLPROPS_MAX_COUNT 64
+
+enum boolprop_attr {
+ BPA_TOKEN = 0,
+ BPA_PRIVATE,
+ BPA_TRUSTED,
+ BPA_SENSITIVE,
+ BPA_ENCRYPT,
+ BPA_DECRYPT,
+ BPA_WRAP,
+ BPA_UNWRAP,
+ BPA_SIGN,
+ BPA_SIGN_RECOVER,
+ BPA_VERIFY,
+ BPA_VERIFY_RECOVER,
+ BPA_DERIVE,
+ BPA_EXTRACTABLE,
+ BPA_LOCAL,
+ BPA_NEVER_EXTRACTABLE,
+ BPA_ALWAYS_SENSITIVE,
+ BPA_MODIFIABLE,
+ BPA_COPYABLE,
+ BPA_DESTROYABLE,
+ BPA_ALWAYS_AUTHENTICATE,
+ BPA_WRAP_WITH_TRUSTED,
+};
+
+/*
+ * Header of a serialized memory object inside PKCS11 TA.
+ *
+ * @attrs_size: byte size of the serialized data
+ * @attrs_count: number of items in the blob
+ * @attrs: then starts the blob binary data
+ */
+struct obj_attrs {
+ uint32_t attrs_size;
+ uint32_t attrs_count;
+ uint8_t attrs[];
+};
+
+/*
+ * init_attributes_head() - Allocate a reference for serialized attributes
+ * @head: *@head holds the retrieved pointer
+ *
+ * Retrieved pointer can be freed from a simple TEE_Free(reference).
+ *
+ * Return a PKCS11_OK on success or a PKCS11 return code.
+ */
+enum pkcs11_rc init_attributes_head(struct obj_attrs **head);
+
+/*
+ * add_attribute() - Update serialized attributes to add an entry.
+ *
+ * @head: *@head points to serialized attributes,
+ * can be reallocated as attributes are added
+ * @attribute: Attribute ID to add
+ * @data: Opaque data of attribute
+ * @size: Size of data
+ *
+ * Return a PKCS11_OK on success or a PKCS11 return code.
+ */
+enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute,
+ void *data, size_t size);
+
+/*
+ * get_attribute_ptrs() - Get pointers to attributes with a given ID
+ * @head: Pointer to serialized attributes
+ * @attribute: Attribute ID to look for
+ * @attr: Array of pointers to the data inside @head
+ * @attr_size: Array of uint32_t holding the sizes of each value pointed to
+ * by @attr
+ * @count: Number of elements in the arrays above
+ *
+ * If *count == 0, count and return in *count the number of attributes matching
+ * the input attribute ID.
+ *
+ * If *count != 0, return the address and size of the attributes found, up to
+ * the occurrence number *count. attr and attr_size are expected large
+ * enough. attr is the output array of the values found. attr_size is the
+ * output array of the size of each value found.
+ *
+ * If attr_size != NULL, return in *attr_size attribute value size.
+ * If attr != NULL return in *attr the address of the attribute value.
+ */
+void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute,
+ void **attr, uint32_t *attr_size, size_t *count);
+
+/*
+ * get_attribute_ptrs() - Get pointer to the attribute of a given ID
+ * @head: Pointer to serialized attributes
+ * @attribute: Attribute ID
+ * @attr: *@attr holds the retrieved pointer to the attribute value
+ * @attr_size: Size of the attribute value
+ *
+ * If no matching attributes is found return PKCS11_RV_NOT_FOUND.
+ * If attr_size != NULL, return in *attr_size attribute value size.
+ * If attr != NULL, return in *attr the address of the attribute value.
+ *
+ * Return a PKCS11_OK or PKCS11_RV_NOT_FOUND on success, or a PKCS11 return
+ * code.
+ */
+enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute,
+ void **attr_ptr, uint32_t *attr_size);
+/*
+ * get_attribute() - Copy out the attribute of a given ID
+ * @head: Pointer to serialized attributes
+ * @attribute: Attribute ID to look for
+ * @attr: holds the retrieved attribute value
+ * @attr_size: Size of the attribute value
+ *
+ * If attribute is not found, return PKCS11_RV_NOT_FOUND.
+ * If attr_size != NULL, check *attr_size matches attributes size and return
+ * PKCS11_CKR_BUFFER_TOO_SMALL with expected size in *attr_size.
+ * If attr != NULL and attr_size is NULL or gives expected buffer size,
+ * copy attribute value into attr.
+ *
+ * Return a PKCS11_OK or PKCS11_RV_NOT_FOUND on success, or a PKCS11 return
+ * code.
+ */
+enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute,
+ void *attr, uint32_t *attr_size);
+
+/*
+ * get_u32_attribute() - Copy out the 32-bit attribute value of a given ID
+ * @head: Pointer to serialized attributes
+ * @attribute: Attribute ID
+ * @attr: holds the retrieved 32-bit attribute value
+ *
+ * If attribute is not found, return PKCS11_RV_NOT_FOUND.
+ * If the retreived attribute doesn't have a 4 byte sized value
+ * PKCS11_CKR_GENERAL_ERROR is returned.
+ *
+ * Return a PKCS11_OK or PKCS11_RV_NOT_FOUND on success, or a PKCS11 return
+ * code.
+ */
+
+static inline enum pkcs11_rc get_u32_attribute(struct obj_attrs *head,
+ uint32_t attribute,
+ uint32_t *attr)
+{
+ uint32_t size = sizeof(uint32_t);
+ enum pkcs11_rc rc = get_attribute(head, attribute, attr, &size);
+
+ if (!rc && size != sizeof(uint32_t))
+ return PKCS11_CKR_GENERAL_ERROR;
+
+ return rc;
+}
+
+/*
+ * get_class() - Get class ID of an object
+ * @head: Pointer to serialized attributes
+ *
+ * Returns the class ID of an object on succes or returns
+ * PKCS11_CKO_UNDEFINED_ID on error.
+ */
+static inline enum pkcs11_class_id get_class(struct obj_attrs *head)
+{
+ uint32_t class = 0;
+ uint32_t size = sizeof(class);
+
+ if (get_attribute(head, PKCS11_CKA_CLASS, &class, &size))
+ return PKCS11_CKO_UNDEFINED_ID;
+
+ return class;
+}
+
+/*
+ * get_key_type() - Get the key type of an object
+ * @head: Pointer to serialized attributes
+ *
+ * Returns the key type of an object on success or returns
+ * PKCS11_CKK_UNDEFINED_ID on error.
+ */
+static inline enum pkcs11_key_type get_key_type(struct obj_attrs *head)
+{
+ uint32_t type = 0;
+ uint32_t size = sizeof(type);
+
+ if (get_attribute(head, PKCS11_CKA_KEY_TYPE, &type, &size))
+ return PKCS11_CKK_UNDEFINED_ID;
+
+ return type;
+}
+
+/*
+ * get_mechanism_type() - Get the mechanism type of an object
+ * @head: Pointer to serialized attributes
+ *
+ * Returns the mechanism type of an object on success or returns
+ * PKCS11_CKM_UNDEFINED_ID on error.
+ */
+static inline enum pkcs11_mechanism_id get_mechanism_type(struct obj_attrs *head)
+{
+ uint32_t type = 0;
+ uint32_t size = sizeof(type);
+
+ if (get_attribute(head, PKCS11_CKA_MECHANISM_TYPE, &type, &size))
+ return PKCS11_CKM_UNDEFINED_ID;
+
+ return type;
+}
+
+/*
+ * get_bool() - Get the bool value of an attribute
+ * @head: Pointer to serialized attributes
+ * @attribute: Attribute ID to look for
+ *
+ * May assert if attribute ID isn't of the boolean type.
+ *
+ * Returns the bool value of the supplied attribute ID on success if found
+ * else false.
+ */
+bool get_bool(struct obj_attrs *head, uint32_t attribute);
+
+#if CFG_TEE_TA_LOG_LEVEL > 0
+/* Debug: dump object attributes to IMSG() trace console */
+void trace_attributes(const char *prefix, void *ref);
+#else
+static inline void trace_attributes(const char *prefix __unused,
+ void *ref __unused)
+{
+}
+#endif /*CFG_TEE_TA_LOG_LEVEL*/
+#endif /*PKCS11_TA_ATTRIBUTES_H*/
diff --git a/ta/pkcs11/src/pkcs11_attributes.c b/ta/pkcs11/src/pkcs11_attributes.c
new file mode 100644
index 00000000..0f669e52
--- /dev/null
+++ b/ta/pkcs11/src/pkcs11_attributes.c
@@ -0,0 +1,775 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2020, Linaro Limited
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <pkcs11_ta.h>
+#include <stdlib.h>
+#include <string_ext.h>
+#include <tee_internal_api_extensions.h>
+#include <tee_internal_api.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "handle.h"
+#include "pkcs11_attributes.h"
+#include "pkcs11_helpers.h"
+#include "pkcs11_token.h"
+#include "sanitize_object.h"
+#include "serializer.h"
+#include "token_capabilities.h"
+
+/* Byte size of CKA_ID attribute when generated locally */
+#define PKCS11_CKA_DEFAULT_SIZE 16
+
+/*
+ * Object default boolean attributes as per PKCS#11
+ */
+static uint8_t *pkcs11_object_default_boolprop(uint32_t attribute)
+{
+ static const uint8_t bool_true = 1;
+ static const uint8_t bool_false;
+
+ switch (attribute) {
+ /* As per PKCS#11 default value */
+ case PKCS11_CKA_MODIFIABLE:
+ case PKCS11_CKA_COPYABLE:
+ case PKCS11_CKA_DESTROYABLE:
+ return (uint8_t *)&bool_true;
+ case PKCS11_CKA_TOKEN:
+ case PKCS11_CKA_PRIVATE:
+ /* symkey false, privkey: token specific */
+ case PKCS11_CKA_SENSITIVE:
+ return (uint8_t *)&bool_false;
+ /* Token specific default value */
+ case PKCS11_CKA_SIGN:
+ case PKCS11_CKA_VERIFY:
+ return (uint8_t *)&bool_true;
+ case PKCS11_CKA_DERIVE:
+ case PKCS11_CKA_ENCRYPT:
+ case PKCS11_CKA_DECRYPT:
+ case PKCS11_CKA_SIGN_RECOVER:
+ case PKCS11_CKA_VERIFY_RECOVER:
+ case PKCS11_CKA_WRAP:
+ case PKCS11_CKA_UNWRAP:
+ case PKCS11_CKA_EXTRACTABLE:
+ case PKCS11_CKA_WRAP_WITH_TRUSTED:
+ case PKCS11_CKA_ALWAYS_AUTHENTICATE:
+ case PKCS11_CKA_TRUSTED:
+ return (uint8_t *)&bool_false;
+ default:
+ DMSG("No default for boolprop attribute %#"PRIx32, attribute);
+ return NULL;
+ }
+}
+
+/*
+ * Object expects several boolean attributes to be set to a default value
+ * or to a validate client configuration value. This function append the input
+ * attribute (id/size/value) in the serialized object.
+ */
+static enum pkcs11_rc pkcs11_import_object_boolprop(struct obj_attrs **out,
+ struct obj_attrs *templ,
+ uint32_t attribute)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ uint8_t bbool = 0;
+ uint32_t size = sizeof(uint8_t);
+ void *attr = NULL;
+
+ rc = get_attribute(templ, attribute, &bbool, &size);
+ if (rc) {
+ if (rc != PKCS11_RV_NOT_FOUND)
+ return rc;
+ attr = pkcs11_object_default_boolprop(attribute);
+ if (!attr)
+ return PKCS11_CKR_TEMPLATE_INCOMPLETE;
+ } else {
+ attr = &bbool;
+ }
+
+ /* Boolean attributes are 1byte in the ABI, no alignment issue */
+ return add_attribute(out, attribute, attr, sizeof(uint8_t));
+}
+
+static enum pkcs11_rc set_mandatory_boolprops(struct obj_attrs **out,
+ struct obj_attrs *temp,
+ uint32_t const *bp,
+ size_t bp_count)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ size_t n = 0;
+
+ for (n = 0; n < bp_count; n++) {
+ rc = pkcs11_import_object_boolprop(out, temp, bp[n]);
+ if (rc)
+ return rc;
+ }
+
+ return rc;
+}
+
+static enum pkcs11_rc set_mandatory_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp,
+ uint32_t const *bp,
+ size_t bp_count)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ size_t n = 0;
+
+ for (n = 0; n < bp_count; n++) {
+ uint32_t size = 0;
+ void *value = NULL;
+
+ if (get_attribute_ptr(temp, bp[n], &value, &size))
+ return PKCS11_CKR_TEMPLATE_INCOMPLETE;
+
+ rc = add_attribute(out, bp[n], value, size);
+ if (rc)
+ return rc;
+ }
+
+ return rc;
+}
+
+static enum pkcs11_rc get_default_value(enum pkcs11_attr_id id, void **value,
+ uint32_t *size)
+{
+ /* should have been taken care of already */
+ assert(!pkcs11_attr_is_boolean(id));
+
+ if (id == PKCS11_CKA_PUBLIC_KEY_INFO) {
+ EMSG("Cannot provide default PUBLIC_KEY_INFO");
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+
+ /* All other attributes have an empty default value */
+ *value = NULL;
+ *size = 0;
+ return PKCS11_CKR_OK;
+}
+
+static enum pkcs11_rc set_optional_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp,
+ uint32_t const *bp,
+ size_t bp_count)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ size_t n = 0;
+
+ for (n = 0; n < bp_count; n++) {
+ uint32_t size = 0;
+ void *value = NULL;
+
+ rc = get_attribute_ptr(temp, bp[n], &value, &size);
+ if (rc == PKCS11_RV_NOT_FOUND)
+ rc = get_default_value(bp[n], &value, &size);
+ if (rc)
+ return rc;
+
+ rc = add_attribute(out, bp[n], value, size);
+ if (rc)
+ return rc;
+ }
+
+ return rc;
+}
+
+/*
+ * Below are listed the mandated or optional expected attributes for
+ * PKCS#11 storage objects.
+ *
+ * Note: boolprops (mandated boolean attributes) PKCS11_CKA_ALWAYS_SENSITIVE,
+ * and PKCS11_CKA_NEVER_EXTRACTABLE are set by the token, not provided
+ * in the client template.
+ */
+
+/* PKCS#11 specification for any object (session/token) of the storage */
+static const uint32_t pkcs11_any_object_boolprops[] = {
+ PKCS11_CKA_TOKEN, PKCS11_CKA_PRIVATE,
+ PKCS11_CKA_MODIFIABLE, PKCS11_CKA_COPYABLE, PKCS11_CKA_DESTROYABLE,
+};
+
+static const uint32_t pkcs11_any_object_optional[] = {
+ PKCS11_CKA_LABEL,
+};
+
+/* PKCS#11 specification for raw data object (+pkcs11_any_object_xxx) */
+const uint32_t pkcs11_raw_data_optional[] = {
+ PKCS11_CKA_OBJECT_ID, PKCS11_CKA_APPLICATION, PKCS11_CKA_VALUE,
+};
+
+/* PKCS#11 specification for any key object (+pkcs11_any_object_xxx) */
+static const uint32_t pkcs11_any_key_boolprops[] = {
+ PKCS11_CKA_DERIVE,
+};
+
+static const uint32_t pkcs11_any_key_optional[] = {
+ PKCS11_CKA_ID,
+ PKCS11_CKA_START_DATE, PKCS11_CKA_END_DATE,
+ PKCS11_CKA_ALLOWED_MECHANISMS,
+};
+
+/* PKCS#11 specification for any symmetric key (+pkcs11_any_key_xxx) */
+static const uint32_t pkcs11_symm_key_boolprops[] = {
+ PKCS11_CKA_ENCRYPT, PKCS11_CKA_DECRYPT,
+ PKCS11_CKA_SIGN, PKCS11_CKA_VERIFY,
+ PKCS11_CKA_WRAP, PKCS11_CKA_UNWRAP,
+ PKCS11_CKA_SENSITIVE, PKCS11_CKA_EXTRACTABLE,
+ PKCS11_CKA_WRAP_WITH_TRUSTED, PKCS11_CKA_TRUSTED,
+};
+
+static const uint32_t pkcs11_symm_key_optional[] = {
+ PKCS11_CKA_WRAP_TEMPLATE, PKCS11_CKA_UNWRAP_TEMPLATE,
+ PKCS11_CKA_DERIVE_TEMPLATE,
+ PKCS11_CKA_VALUE, PKCS11_CKA_VALUE_LEN,
+};
+
+/* PKCS#11 specification for any asymmetric public key (+pkcs11_any_key_xxx) */
+static const uint32_t pkcs11_public_key_boolprops[] = {
+ PKCS11_CKA_ENCRYPT, PKCS11_CKA_VERIFY, PKCS11_CKA_VERIFY_RECOVER,
+ PKCS11_CKA_WRAP,
+ PKCS11_CKA_TRUSTED,
+};
+
+static const uint32_t pkcs11_public_key_mandated[] = {
+ PKCS11_CKA_SUBJECT
+};
+
+static const uint32_t pkcs11_public_key_optional[] = {
+ PKCS11_CKA_WRAP_TEMPLATE, PKCS11_CKA_PUBLIC_KEY_INFO,
+};
+
+/* PKCS#11 specification for any asymmetric private key (+pkcs11_any_key_xxx) */
+static const uint32_t pkcs11_private_key_boolprops[] = {
+ PKCS11_CKA_DECRYPT, PKCS11_CKA_SIGN, PKCS11_CKA_SIGN_RECOVER,
+ PKCS11_CKA_UNWRAP,
+ PKCS11_CKA_SENSITIVE, PKCS11_CKA_EXTRACTABLE,
+ PKCS11_CKA_WRAP_WITH_TRUSTED, PKCS11_CKA_ALWAYS_AUTHENTICATE,
+};
+
+static const uint32_t pkcs11_private_key_mandated[] = {
+ PKCS11_CKA_SUBJECT
+};
+
+static const uint32_t pkcs11_private_key_optional[] = {
+ PKCS11_CKA_UNWRAP_TEMPLATE, PKCS11_CKA_PUBLIC_KEY_INFO,
+};
+
+/* PKCS#11 specification for any RSA key (+pkcs11_public/private_key_xxx) */
+static const uint32_t pkcs11_rsa_public_key_mandated[] = {
+ PKCS11_CKA_MODULUS_BITS,
+};
+
+static const uint32_t pkcs11_rsa_public_key_optional[] = {
+ PKCS11_CKA_MODULUS, PKCS11_CKA_PUBLIC_EXPONENT,
+};
+
+static const uint32_t pkcs11_rsa_private_key_optional[] = {
+ PKCS11_CKA_MODULUS, PKCS11_CKA_PUBLIC_EXPONENT,
+ PKCS11_CKA_PRIVATE_EXPONENT,
+ PKCS11_CKA_PRIME_1, PKCS11_CKA_PRIME_2,
+ PKCS11_CKA_EXPONENT_1, PKCS11_CKA_EXPONENT_2, PKCS11_CKA_COEFFICIENT,
+};
+
+/* PKCS#11 specification for any EC key (+pkcs11_public/private_key_xxx) */
+static const uint32_t pkcs11_ec_public_key_mandated[] = {
+ PKCS11_CKA_EC_PARAMS,
+};
+
+static const uint32_t pkcs11_ec_public_key_optional[] = {
+ PKCS11_CKA_EC_POINT,
+};
+
+static const uint32_t pkcs11_ec_private_key_mandated[] = {
+ PKCS11_CKA_EC_PARAMS,
+};
+
+static const uint32_t pkcs11_ec_private_key_optional[] = {
+ PKCS11_CKA_VALUE,
+};
+
+static enum pkcs11_rc create_storage_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp)
+{
+ enum pkcs11_class_id class = PKCS11_CKO_UNDEFINED_ID;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+
+ rc = init_attributes_head(out);
+ if (rc)
+ return rc;
+
+ /* Object class is mandatory */
+ class = get_class(temp);
+ if (class == PKCS11_CKO_UNDEFINED_ID) {
+ EMSG("Class attribute not found");
+
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+ rc = add_attribute(out, PKCS11_CKA_CLASS, &class, sizeof(uint32_t));
+ if (rc)
+ return rc;
+
+ rc = set_mandatory_boolprops(out, temp, pkcs11_any_object_boolprops,
+ ARRAY_SIZE(pkcs11_any_object_boolprops));
+ if (rc)
+ return rc;
+
+ return set_optional_attributes(out, temp, pkcs11_any_object_optional,
+ ARRAY_SIZE(pkcs11_any_object_optional));
+}
+
+static enum pkcs11_rc create_genkey_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp)
+{
+ uint32_t type = PKCS11_CKO_UNDEFINED_ID;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+
+ rc = create_storage_attributes(out, temp);
+ if (rc)
+ return rc;
+
+ type = get_key_type(temp);
+ if (type == PKCS11_CKK_UNDEFINED_ID) {
+ EMSG("Key type attribute not found");
+
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+ rc = add_attribute(out, PKCS11_CKA_KEY_TYPE, &type, sizeof(uint32_t));
+ if (rc)
+ return rc;
+
+ rc = set_mandatory_boolprops(out, temp, pkcs11_any_key_boolprops,
+ ARRAY_SIZE(pkcs11_any_key_boolprops));
+ if (rc)
+ return rc;
+
+ return set_optional_attributes(out, temp, pkcs11_any_key_optional,
+ ARRAY_SIZE(pkcs11_any_key_optional));
+}
+
+static enum pkcs11_rc create_symm_key_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+
+ assert(get_class(temp) == PKCS11_CKO_SECRET_KEY);
+
+ rc = create_genkey_attributes(out, temp);
+ if (rc)
+ return rc;
+
+ assert(get_class(*out) == PKCS11_CKO_SECRET_KEY);
+
+ switch (get_key_type(*out)) {
+ case PKCS11_CKK_GENERIC_SECRET:
+ case PKCS11_CKK_AES:
+ 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:
+ break;
+ default:
+ EMSG("Invalid key type %#"PRIx32"/%s",
+ get_key_type(*out), id2str_key_type(get_key_type(*out)));
+
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+
+ rc = set_mandatory_boolprops(out, temp, pkcs11_symm_key_boolprops,
+ ARRAY_SIZE(pkcs11_symm_key_boolprops));
+ if (rc)
+ return rc;
+
+ return set_optional_attributes(out, temp, pkcs11_symm_key_optional,
+ ARRAY_SIZE(pkcs11_symm_key_optional));
+}
+
+static enum pkcs11_rc create_data_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+
+ assert(get_class(temp) == PKCS11_CKO_DATA);
+
+ rc = create_storage_attributes(out, temp);
+ if (rc)
+ return rc;
+
+ assert(get_class(*out) == PKCS11_CKO_DATA);
+
+ return set_optional_attributes(out, temp, pkcs11_raw_data_optional,
+ ARRAY_SIZE(pkcs11_raw_data_optional));
+}
+
+static enum pkcs11_rc create_pub_key_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp)
+{
+ uint32_t const *mandated = NULL;
+ uint32_t const *optional = NULL;
+ size_t mandated_count = 0;
+ size_t optional_count = 0;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+
+ assert(get_class(temp) == PKCS11_CKO_PUBLIC_KEY);
+
+ rc = create_genkey_attributes(out, temp);
+ if (rc)
+ return rc;
+
+ assert(get_class(*out) == PKCS11_CKO_PUBLIC_KEY);
+
+ rc = set_mandatory_boolprops(out, temp, pkcs11_public_key_boolprops,
+ ARRAY_SIZE(pkcs11_public_key_boolprops));
+ if (rc)
+ return rc;
+
+ rc = set_mandatory_attributes(out, temp, pkcs11_public_key_mandated,
+ ARRAY_SIZE(pkcs11_public_key_mandated));
+ if (rc)
+ return rc;
+
+ rc = set_optional_attributes(out, temp, pkcs11_public_key_optional,
+ ARRAY_SIZE(pkcs11_public_key_optional));
+ if (rc)
+ return rc;
+
+ switch (get_key_type(*out)) {
+ case PKCS11_CKK_RSA:
+ mandated = pkcs11_rsa_public_key_mandated;
+ optional = pkcs11_rsa_public_key_optional;
+ mandated_count = ARRAY_SIZE(pkcs11_rsa_public_key_mandated);
+ optional_count = ARRAY_SIZE(pkcs11_rsa_public_key_optional);
+ break;
+ case PKCS11_CKK_EC:
+ mandated = pkcs11_ec_public_key_mandated;
+ optional = pkcs11_ec_public_key_optional;
+ mandated_count = ARRAY_SIZE(pkcs11_ec_public_key_mandated);
+ optional_count = ARRAY_SIZE(pkcs11_ec_public_key_optional);
+ break;
+ default:
+ EMSG("Invalid key type %#"PRIx32"/%s",
+ get_key_type(*out), id2str_key_type(get_key_type(*out)));
+
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+
+ rc = set_mandatory_attributes(out, temp, mandated, mandated_count);
+ if (rc)
+ return rc;
+
+ return set_optional_attributes(out, temp, optional, optional_count);
+}
+
+static enum pkcs11_rc create_priv_key_attributes(struct obj_attrs **out,
+ struct obj_attrs *temp)
+{
+ uint32_t const *mandated = NULL;
+ uint32_t const *optional = NULL;
+ size_t mandated_count = 0;
+ size_t optional_count = 0;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+
+ assert(get_class(temp) == PKCS11_CKO_PRIVATE_KEY);
+
+ rc = create_genkey_attributes(out, temp);
+ if (rc)
+ return rc;
+
+ assert(get_class(*out) == PKCS11_CKO_PRIVATE_KEY);
+
+ rc = set_mandatory_boolprops(out, temp, pkcs11_private_key_boolprops,
+ ARRAY_SIZE(pkcs11_private_key_boolprops));
+ if (rc)
+ return rc;
+
+ rc = set_mandatory_attributes(out, temp, pkcs11_private_key_mandated,
+ ARRAY_SIZE(pkcs11_private_key_mandated));
+ if (rc)
+ return rc;
+
+ rc = set_optional_attributes(out, temp, pkcs11_private_key_optional,
+ ARRAY_SIZE(pkcs11_private_key_optional));
+ if (rc)
+ return rc;
+
+ switch (get_key_type(*out)) {
+ case PKCS11_CKK_RSA:
+ optional = pkcs11_rsa_private_key_optional;
+ optional_count = ARRAY_SIZE(pkcs11_rsa_private_key_optional);
+ break;
+ case PKCS11_CKK_EC:
+ mandated = pkcs11_ec_private_key_mandated;
+ optional = pkcs11_ec_private_key_optional;
+ mandated_count = ARRAY_SIZE(pkcs11_ec_private_key_mandated);
+ optional_count = ARRAY_SIZE(pkcs11_ec_private_key_optional);
+ break;
+ default:
+ EMSG("Invalid key type %#"PRIx32"/%s",
+ get_key_type(*out), id2str_key_type(get_key_type(*out)));
+
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+
+ rc = set_mandatory_attributes(out, temp, mandated, mandated_count);
+ if (rc)
+ return rc;
+
+ return set_optional_attributes(out, temp, optional, optional_count);
+}
+
+/*
+ * Create an attribute list for a new object from a template and a parent
+ * object (optional) for an object generation function (generate, copy,
+ * derive...).
+ *
+ * PKCS#11 directives on the supplied template and expected return value:
+ * - template has an invalid attribute ID: ATTRIBUTE_TYPE_INVALID
+ * - template has an invalid value for an attribute: ATTRIBUTE_VALID_INVALID
+ * - template has value for a read-only attribute: ATTRIBUTE_READ_ONLY
+ * - template+default+parent => still miss an attribute: TEMPLATE_INCONSISTENT
+ *
+ * INFO on PKCS11_CMD_COPY_OBJECT:
+ * - parent PKCS11_CKA_COPYIABLE=false => return ACTION_PROHIBITED.
+ * - template can specify PKCS11_CKA_TOKEN, PKCS11_CKA_PRIVATE,
+ * PKCS11_CKA_MODIFIABLE, PKCS11_CKA_DESTROYABLE.
+ * - SENSITIVE can change from false to true, not from true to false.
+ * - LOCAL is the parent LOCAL
+ */
+enum pkcs11_rc
+create_attributes_from_template(struct obj_attrs **out, void *template,
+ size_t template_size,
+ struct obj_attrs *parent __unused,
+ enum processing_func function,
+ enum pkcs11_mechanism_id mecha __unused)
+{
+ struct obj_attrs *temp = NULL;
+ struct obj_attrs *attrs = NULL;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ uint8_t local = 0;
+ uint8_t always_sensitive = 0;
+ uint8_t never_extract = 0;
+ uint32_t mechanism_id = PKCS11_CKM_UNDEFINED_ID;
+
+#ifdef DEBUG /* Sanity: check function argument */
+ trace_attributes_from_api_head("template", template, template_size);
+ switch (function) {
+ case PKCS11_FUNCTION_IMPORT:
+ break;
+ default:
+ TEE_Panic(TEE_ERROR_NOT_SUPPORTED);
+ }
+#endif
+
+ rc = sanitize_client_object(&temp, template, template_size);
+ if (rc)
+ goto out;
+
+ /* If class/type not defined, match from mechanism */
+ if (get_class(temp) == PKCS11_UNDEFINED_ID &&
+ get_key_type(temp) == PKCS11_UNDEFINED_ID) {
+ EMSG("Unable to define class/type from mechanism");
+ rc = PKCS11_CKR_TEMPLATE_INCOMPLETE;
+ goto out;
+ }
+
+ if (!sanitize_consistent_class_and_type(temp)) {
+ EMSG("Inconsistent class/type");
+ rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ goto out;
+ }
+
+ switch (get_class(temp)) {
+ case PKCS11_CKO_DATA:
+ rc = create_data_attributes(&attrs, temp);
+ break;
+ case PKCS11_CKO_SECRET_KEY:
+ rc = create_symm_key_attributes(&attrs, temp);
+ break;
+ case PKCS11_CKO_PUBLIC_KEY:
+ rc = create_pub_key_attributes(&attrs, temp);
+ break;
+ case PKCS11_CKO_PRIVATE_KEY:
+ rc = create_priv_key_attributes(&attrs, temp);
+ break;
+ default:
+ DMSG("Invalid object class %#"PRIx32"/%s",
+ get_class(temp), id2str_class(get_class(temp)));
+
+ rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ break;
+ }
+ if (rc)
+ goto out;
+
+ if (get_attribute(attrs, PKCS11_CKA_LOCAL, NULL, NULL) !=
+ PKCS11_RV_NOT_FOUND)
+ goto out;
+
+ if (get_attribute(attrs, PKCS11_CKA_KEY_GEN_MECHANISM, NULL, NULL) !=
+ PKCS11_RV_NOT_FOUND)
+ goto out;
+
+ switch (function) {
+ case PKCS11_FUNCTION_IMPORT:
+ default:
+ local = PKCS11_FALSE;
+ break;
+ }
+ rc = add_attribute(&attrs, PKCS11_CKA_LOCAL, &local, sizeof(local));
+ if (rc)
+ goto out;
+
+ switch (get_class(attrs)) {
+ case PKCS11_CKO_SECRET_KEY:
+ case PKCS11_CKO_PRIVATE_KEY:
+ case PKCS11_CKO_PUBLIC_KEY:
+ always_sensitive = PKCS11_FALSE;
+ never_extract = PKCS11_FALSE;
+
+ rc = add_attribute(&attrs, PKCS11_CKA_ALWAYS_SENSITIVE,
+ &always_sensitive, sizeof(always_sensitive));
+ if (rc)
+ goto out;
+
+ rc = add_attribute(&attrs, PKCS11_CKA_NEVER_EXTRACTABLE,
+ &never_extract, sizeof(never_extract));
+ if (rc)
+ goto out;
+
+ /* Keys mandate attribute PKCS11_CKA_KEY_GEN_MECHANISM */
+ mechanism_id = PKCS11_CK_UNAVAILABLE_INFORMATION;
+ rc = add_attribute(&attrs, PKCS11_CKA_KEY_GEN_MECHANISM,
+ &mechanism_id, sizeof(mechanism_id));
+ if (rc)
+ goto out;
+ break;
+
+ default:
+ break;
+ }
+
+ *out = attrs;
+
+#ifdef DEBUG
+ trace_attributes("object", attrs);
+#endif
+
+out:
+ TEE_Free(temp);
+ if (rc)
+ TEE_Free(attrs);
+
+ return rc;
+}
+
+static enum pkcs11_rc check_attrs_misc_integrity(struct obj_attrs *head)
+{
+ if (get_bool(head, PKCS11_CKA_NEVER_EXTRACTABLE) &&
+ get_bool(head, PKCS11_CKA_EXTRACTABLE)) {
+ DMSG("Never/Extractable attributes mismatch %d/%d",
+ get_bool(head, PKCS11_CKA_NEVER_EXTRACTABLE),
+ get_bool(head, PKCS11_CKA_EXTRACTABLE));
+
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+
+ if (get_bool(head, PKCS11_CKA_ALWAYS_SENSITIVE) &&
+ !get_bool(head, PKCS11_CKA_SENSITIVE)) {
+ DMSG("Sensitive/always attributes mismatch %d/%d",
+ get_bool(head, PKCS11_CKA_SENSITIVE),
+ get_bool(head, PKCS11_CKA_ALWAYS_SENSITIVE));
+
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+
+ return PKCS11_CKR_OK;
+}
+
+/*
+ * Check the attributes of a to-be-created object matches the token state
+ */
+enum pkcs11_rc check_created_attrs_against_token(struct pkcs11_session *session,
+ struct obj_attrs *head)
+{
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+
+ rc = check_attrs_misc_integrity(head);
+ if (rc)
+ return rc;
+
+ if (get_bool(head, PKCS11_CKA_TRUSTED) &&
+ !pkcs11_session_is_so(session)) {
+ DMSG("Can't create trusted object");
+
+ return PKCS11_CKR_KEY_FUNCTION_NOT_PERMITTED;
+ }
+
+ if (get_bool(head, PKCS11_CKA_TOKEN) &&
+ !pkcs11_session_is_read_write(session)) {
+ DMSG("Can't create persistent object");
+
+ return PKCS11_CKR_SESSION_READ_ONLY;
+ }
+
+ /*
+ * TODO: START_DATE and END_DATE: complies with current time?
+ */
+ return PKCS11_CKR_OK;
+}
+
+#define DMSG_BAD_BBOOL(attr, proc, head) \
+ do { \
+ uint32_t __maybe_unused _attr = (attr); \
+ uint8_t __maybe_unused _bvalue = 0; \
+ enum pkcs11_rc __maybe_unused _rc = PKCS11_CKR_OK; \
+ \
+ _rc = get_attribute((head), _attr, &_bvalue, NULL); \
+ DMSG("%s issue for %s: %sfound, value %"PRIu8, \
+ id2str_attr(_attr), id2str_proc((proc)), \
+ _rc ? "not " : "", _bvalue); \
+ } while (0)
+
+static bool __maybe_unused check_attr_bval(uint32_t proc_id __maybe_unused,
+ struct obj_attrs *head,
+ uint32_t attribute, bool val)
+{
+ uint8_t bbool = 0;
+ uint32_t sz = sizeof(bbool);
+
+ if (!get_attribute(head, attribute, &bbool, &sz) && !!bbool == val)
+ return true;
+
+ DMSG_BAD_BBOOL(attribute, proc_id, head);
+ return false;
+}
+
+/*
+ * Check the attributes of a new secret match the processing/mechanism
+ * used to create it.
+ *
+ * @proc_id - PKCS11_CKM_xxx
+ * @head - head of the attributes of the to-be-created object.
+ */
+enum pkcs11_rc check_created_attrs_against_processing(uint32_t proc_id,
+ struct obj_attrs *head)
+{
+ /*
+ * Processings that do not create secrets are not expected to call
+ * this function which would panic.
+ */
+ switch (proc_id) {
+ case PKCS11_PROCESSING_IMPORT:
+ assert(check_attr_bval(proc_id, head, PKCS11_CKA_LOCAL, false));
+ break;
+ default:
+ TEE_Panic(proc_id);
+ break;
+ }
+
+ return PKCS11_CKR_OK;
+}
diff --git a/ta/pkcs11/src/pkcs11_attributes.h b/ta/pkcs11/src/pkcs11_attributes.h
new file mode 100644
index 00000000..05f70049
--- /dev/null
+++ b/ta/pkcs11/src/pkcs11_attributes.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2020, Linaro Limited
+ */
+
+#ifndef PKCS11_TA_PKCS11_ATTRIBUTES_H
+#define PKCS11_TA_PKCS11_ATTRIBUTES_H
+
+#include <inttypes.h>
+
+#include "serializer.h"
+
+struct obj_attrs;
+struct pkcs11_object;
+struct pkcs11_session;
+
+/*
+ * PKCS#11 directives on object attributes.
+ * Those with a '*' are optional, other must be defined, either by caller
+ * or by some known default value.
+ *
+ * [all] objects: class
+ *
+ * [stored] objects: persistent, need_authen, modifiable, copyable,
+ * destroyable, label*.
+ *
+ * [data] objects: [all], [stored], application_id*, object_id*, value.
+ *
+ * [key] objects: [all], [stored], type, id*, start_date/end_date*,
+ * derive, local, allowed_mechanisms*.
+ *
+ * [symm-key]: [key], sensitive, encrypt, decrypt, sign, verify, wrap,
+ * unwrap, extractable, wrap_with_trusted, trusted,
+ * wrap_template, unwrap_template, derive_template.
+ */
+
+/*
+ * Utils to check compliance of attributes at various processing steps.
+ * Any processing operation is exclusively one of the following.
+ *
+ * Case 1: Create a secret from some local random value (C_CreateKey & friends)
+ * - client provides an attributes list template, PKCS11 TA completes with
+ * default attribute values. Object is created if attributes are
+ * consistent and comply token/session state.
+ * - PKCS11 sequence:
+ * - check/set token/session state
+ * - create an attribute list from client template and default values.
+ * - check new secret attributes complies requested mechanism.
+ * - check new secret attributes complies token/session state.
+ * - Generate the value for the secret.
+ * - Set some runtime attributes in the new secret.
+ * - Register the new secret and return a handle for it.
+ *
+ * Case 2: Create a secret from a client clear data (C_CreateObject)
+ * - client provides an attributes list template, PKCS11 TA completes with
+ * default attribute values. Object is created if attributes are
+ * consistent and comply token/session state.
+ * - check/set token/session state
+ * - create an attribute list from client template and default values.
+ * - check new secret attributes complies requested mechanism (raw-import).
+ * - check new secret attributes complies token/session state.
+ * - Set some runtime attributes in the new secret.
+ * - Register the new secret and return a handle for it.
+
+ * Case 3: Use a secret for data processing
+ * - client provides a mechanism ID and the secret handle.
+ * - PKCS11 checks mechanism and secret comply, if mechanism and token/session
+ * state comply and last if secret and token/session state comply.
+ * - check/set token/session state
+ * - check secret's parent attributes complies requested processing.
+ * - check secret's parent attributes complies token/session state.
+ * - check new secret attributes complies secret's parent attributes.
+ * - check new secret attributes complies requested mechanism.
+ * - check new secret attributes complies token/session state.
+ *
+ * Case 4: Create a secret from a client template and a secret's parent
+ * (i.e derive a symmetric key)
+ * - client args: new-key template, mechanism ID, parent-key handle.
+ * - PKCS11 create a new-key attribute list based on template + default values +
+ * inheritance from the parent key attributes.
+ * - PKCS11 checks:
+ * - token/session state
+ * - parent-key vs mechanism
+ * - parent-key vs token/session state
+ * - parent-key vs new-key
+ * - new-key vs mechanism
+ * - new-key vs token/session state
+ * - then do processing
+ * - then finalize object creation
+ */
+
+enum processing_func {
+ PKCS11_FUNCTION_DIGEST,
+ PKCS11_FUNCTION_GENERATE,
+ PKCS11_FUNCTION_GENERATE_PAIR,
+ PKCS11_FUNCTION_DERIVE,
+ PKCS11_FUNCTION_WRAP,
+ PKCS11_FUNCTION_UNWRAP,
+ PKCS11_FUNCTION_ENCRYPT,
+ PKCS11_FUNCTION_DECRYPT,
+ PKCS11_FUNCTION_SIGN,
+ PKCS11_FUNCTION_VERIFY,
+ PKCS11_FUNCTION_SIGN_RECOVER,
+ PKCS11_FUNCTION_VERIFY_RECOVER,
+ PKCS11_FUNCTION_IMPORT,
+ PKCS11_FUNCTION_COPY,
+ PKCS11_FUNCTION_MODIFY,
+ PKCS11_FUNCTION_DESTROY,
+};
+
+enum processing_step {
+ PKCS11_FUNC_STEP_INIT,
+ PKCS11_FUNC_STEP_ONESHOT,
+ PKCS11_FUNC_STEP_UPDATE,
+ PKCS11_FUNC_STEP_FINAL,
+};
+
+/* Create an attribute list for a new object */
+enum pkcs11_rc
+create_attributes_from_template(struct obj_attrs **out, void *template,
+ size_t template_size, struct obj_attrs *parent,
+ enum processing_func func,
+ enum pkcs11_mechanism_id proc_mecha);
+
+/*
+ * The various checks to be performed before a processing:
+ * - create a new object in the current token state
+ * - use a parent object in the processing
+ * - use a mechanism with provided configuration
+ */
+enum pkcs11_rc check_created_attrs_against_token(struct pkcs11_session *session,
+ struct obj_attrs *head);
+
+enum pkcs11_rc check_created_attrs_against_processing(uint32_t proc_id,
+ struct obj_attrs *head);
+
+#endif /*PKCS11_TA_PKCS11_ATTRIBUTES_H*/
diff --git a/ta/pkcs11/src/pkcs11_helpers.c b/ta/pkcs11/src/pkcs11_helpers.c
index 5ae482f1..72057ad7 100644
--- a/ta/pkcs11/src/pkcs11_helpers.c
+++ b/ta/pkcs11/src/pkcs11_helpers.c
@@ -8,10 +8,84 @@
#include <tee_internal_api.h>
#include <util.h>
+#include "attributes.h"
+#include "pkcs11_attributes.h"
#include "pkcs11_helpers.h"
static const char __maybe_unused unknown[] = "<unknown-identifier>";
+struct attr_size {
+ uint32_t id;
+ uint32_t size;
+#if CFG_TEE_TA_LOG_LEVEL > 0
+ const char *string;
+#endif
+};
+
+#if CFG_TEE_TA_LOG_LEVEL > 0
+#define PKCS11_ID_SZ(_id, _sz) \
+ { .id = (uint32_t)(_id), .size = (_sz), .string = #_id }
+#else
+#define PKCS11_ID_SZ(_id, _sz) \
+ { .id = (uint32_t)(_id), .size = (_sz) }
+#endif
+
+static const struct attr_size attr_ids[] = {
+ PKCS11_ID_SZ(PKCS11_CKA_CLASS, 4),
+ PKCS11_ID_SZ(PKCS11_CKA_KEY_TYPE, 4),
+ PKCS11_ID_SZ(PKCS11_CKA_VALUE, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_VALUE_LEN, 4),
+ PKCS11_ID_SZ(PKCS11_CKA_LABEL, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_WRAP_TEMPLATE, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_UNWRAP_TEMPLATE, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_DERIVE_TEMPLATE, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_START_DATE, 4),
+ PKCS11_ID_SZ(PKCS11_CKA_END_DATE, 4),
+ PKCS11_ID_SZ(PKCS11_CKA_OBJECT_ID, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_APPLICATION, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_MECHANISM_TYPE, 4),
+ PKCS11_ID_SZ(PKCS11_CKA_ID, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_ALLOWED_MECHANISMS, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_EC_POINT, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_EC_PARAMS, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_MODULUS, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_MODULUS_BITS, 4),
+ PKCS11_ID_SZ(PKCS11_CKA_PUBLIC_EXPONENT, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_PRIVATE_EXPONENT, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_PRIME_1, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_PRIME_2, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_EXPONENT_1, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_EXPONENT_2, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_COEFFICIENT, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_SUBJECT, 0),
+ PKCS11_ID_SZ(PKCS11_CKA_PUBLIC_KEY_INFO, 0),
+ /* Below are boolean attributes */
+ PKCS11_ID_SZ(PKCS11_CKA_TOKEN, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_PRIVATE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_TRUSTED, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_SENSITIVE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_ENCRYPT, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_DECRYPT, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_WRAP, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_UNWRAP, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_SIGN, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_SIGN_RECOVER, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_VERIFY, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_VERIFY_RECOVER, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_DERIVE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_EXTRACTABLE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_LOCAL, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_NEVER_EXTRACTABLE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_ALWAYS_SENSITIVE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_MODIFIABLE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_COPYABLE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_DESTROYABLE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_ALWAYS_AUTHENTICATE, 1),
+ PKCS11_ID_SZ(PKCS11_CKA_WRAP_WITH_TRUSTED, 1),
+ /* Specific PKCS11 TA internal attribute ID */
+ PKCS11_ID_SZ(PKCS11_CKA_UNDEFINED_ID, 0),
+};
+
struct any_id {
uint32_t id;
#if CFG_TEE_TA_LOG_LEVEL > 0
@@ -168,6 +242,45 @@ static const struct any_id __maybe_unused string_rc[] = {
PKCS11_ID(PKCS11_RV_NOT_IMPLEMENTED),
};
+static const struct any_id __maybe_unused string_class[] = {
+ PKCS11_ID(PKCS11_CKO_SECRET_KEY),
+ PKCS11_ID(PKCS11_CKO_PUBLIC_KEY),
+ PKCS11_ID(PKCS11_CKO_PRIVATE_KEY),
+ PKCS11_ID(PKCS11_CKO_OTP_KEY),
+ PKCS11_ID(PKCS11_CKO_CERTIFICATE),
+ PKCS11_ID(PKCS11_CKO_DATA),
+ PKCS11_ID(PKCS11_CKO_DOMAIN_PARAMETERS),
+ PKCS11_ID(PKCS11_CKO_HW_FEATURE),
+ PKCS11_ID(PKCS11_CKO_MECHANISM),
+ PKCS11_ID(PKCS11_CKO_UNDEFINED_ID)
+};
+
+static const struct any_id __maybe_unused string_key_type[] = {
+ PKCS11_ID(PKCS11_CKK_AES),
+ PKCS11_ID(PKCS11_CKK_GENERIC_SECRET),
+ PKCS11_ID(PKCS11_CKK_MD5_HMAC),
+ PKCS11_ID(PKCS11_CKK_SHA_1_HMAC),
+ PKCS11_ID(PKCS11_CKK_SHA224_HMAC),
+ PKCS11_ID(PKCS11_CKK_SHA256_HMAC),
+ PKCS11_ID(PKCS11_CKK_SHA384_HMAC),
+ PKCS11_ID(PKCS11_CKK_SHA512_HMAC),
+ PKCS11_ID(PKCS11_CKK_EC),
+ PKCS11_ID(PKCS11_CKK_RSA),
+ PKCS11_ID(PKCS11_CKK_UNDEFINED_ID)
+};
+
+/*
+ * Processing IDs not exported in the TA API.
+ * PKCS11_CKM_* mechanism IDs are looked up from mechanism_string_id().
+ */
+static const struct any_id __maybe_unused string_internal_processing[] = {
+ PKCS11_ID(PKCS11_PROCESSING_IMPORT),
+};
+
+static const struct any_id __maybe_unused string_functions[] = {
+ PKCS11_ID(PKCS11_FUNCTION_IMPORT),
+};
+
/*
* Conversion between PKCS11 TA and GPD TEE return codes
*/
@@ -195,6 +308,138 @@ enum pkcs11_rc tee2pkcs_error(TEE_Result res)
}
}
+/*
+ * Helper functions to analyse PKCS11 identifiers
+ */
+
+/* Check attribute ID is known and size matches if fixed */
+bool valid_pkcs11_attribute_id(uint32_t id, uint32_t size)
+{
+ size_t n = 0;
+
+ for (n = 0; n < ARRAY_SIZE(attr_ids); n++)
+ if (id == attr_ids[n].id)
+ return !attr_ids[n].size || size == attr_ids[n].size;
+
+ return false;
+}
+
+size_t pkcs11_attr_is_type(uint32_t attribute_id)
+{
+ enum pkcs11_attr_id id = attribute_id;
+
+ switch (id) {
+ case PKCS11_CKA_KEY_TYPE:
+ case PKCS11_CKA_MECHANISM_TYPE:
+ case PKCS11_CKA_KEY_GEN_MECHANISM:
+ return sizeof(uint32_t);
+ default:
+ return 0;
+ }
+}
+
+bool pkcs11_class_has_type(uint32_t class)
+{
+ enum pkcs11_class_id class_id = class;
+
+ switch (class_id) {
+ case PKCS11_CKO_CERTIFICATE:
+ case PKCS11_CKO_PUBLIC_KEY:
+ case PKCS11_CKO_PRIVATE_KEY:
+ case PKCS11_CKO_SECRET_KEY:
+ case PKCS11_CKO_MECHANISM:
+ case PKCS11_CKO_HW_FEATURE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool pkcs11_attr_class_is_key(uint32_t class)
+{
+ enum pkcs11_class_id class_id = class;
+
+ switch (class_id) {
+ case PKCS11_CKO_SECRET_KEY:
+ case PKCS11_CKO_PUBLIC_KEY:
+ case PKCS11_CKO_PRIVATE_KEY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool key_type_is_symm_key(uint32_t id)
+{
+ enum pkcs11_key_type key_type = id;
+
+ switch (key_type) {
+ case PKCS11_CKK_AES:
+ case PKCS11_CKK_GENERIC_SECRET:
+ case PKCS11_CKK_MD5_HMAC:
+ case PKCS11_CKK_SHA_1_HMAC:
+ case PKCS11_CKK_SHA224_HMAC:
+ case PKCS11_CKK_SHA256_HMAC:
+ case PKCS11_CKK_SHA384_HMAC:
+ case PKCS11_CKK_SHA512_HMAC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool key_type_is_asymm_key(uint32_t id)
+{
+ enum pkcs11_key_type key_type = id;
+
+ switch (key_type) {
+ case PKCS11_CKK_EC:
+ case PKCS11_CKK_RSA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * Returns shift position or -1 on error.
+ * Mainly used when PKCS11_SHEAD_WITH_BOOLPROPS is enabled
+ */
+int pkcs11_attr2boolprop_shift(uint32_t attr)
+{
+ static const uint32_t bpa[] = {
+ [BPA_TOKEN] = PKCS11_CKA_TOKEN,
+ [BPA_PRIVATE] = PKCS11_CKA_PRIVATE,
+ [BPA_TRUSTED] = PKCS11_CKA_TRUSTED,
+ [BPA_SENSITIVE] = PKCS11_CKA_SENSITIVE,
+ [BPA_ENCRYPT] = PKCS11_CKA_ENCRYPT,
+ [BPA_DECRYPT] = PKCS11_CKA_DECRYPT,
+ [BPA_WRAP] = PKCS11_CKA_WRAP,
+ [BPA_UNWRAP] = PKCS11_CKA_UNWRAP,
+ [BPA_SIGN] = PKCS11_CKA_SIGN,
+ [BPA_SIGN_RECOVER] = PKCS11_CKA_SIGN_RECOVER,
+ [BPA_VERIFY] = PKCS11_CKA_VERIFY,
+ [BPA_VERIFY_RECOVER] = PKCS11_CKA_VERIFY_RECOVER,
+ [BPA_DERIVE] = PKCS11_CKA_DERIVE,
+ [BPA_EXTRACTABLE] = PKCS11_CKA_EXTRACTABLE,
+ [BPA_LOCAL] = PKCS11_CKA_LOCAL,
+ [BPA_NEVER_EXTRACTABLE] = PKCS11_CKA_NEVER_EXTRACTABLE,
+ [BPA_ALWAYS_SENSITIVE] = PKCS11_CKA_ALWAYS_SENSITIVE,
+ [BPA_MODIFIABLE] = PKCS11_CKA_MODIFIABLE,
+ [BPA_COPYABLE] = PKCS11_CKA_COPYABLE,
+ [BPA_DESTROYABLE] = PKCS11_CKA_DESTROYABLE,
+ [BPA_ALWAYS_AUTHENTICATE] = PKCS11_CKA_ALWAYS_AUTHENTICATE,
+ [BPA_WRAP_WITH_TRUSTED] = PKCS11_CKA_WRAP_WITH_TRUSTED,
+ };
+ size_t pos = 0;
+
+ for (pos = 0; pos < ARRAY_SIZE(bpa); pos++)
+ if (bpa[pos] == attr)
+ return (int)pos;
+
+ return -1;
+}
+
#if CFG_TEE_TA_LOG_LEVEL > 0
const char *id2str_rc(uint32_t id)
{
@@ -225,4 +470,86 @@ const char *id2str_session_state(uint32_t id)
{
return ID2STR(id, string_session_state, "PKCS11_CKS_");
}
+
+const char *id2str_attr(uint32_t id)
+{
+ size_t n = 0;
+
+ for (n = 0; n < ARRAY_SIZE(attr_ids); n++) {
+ if (id == attr_ids[n].id) {
+ /* Skip PKCS11_CKA_ prefix */
+ return attr_ids[n].string + strlen("PKCS11_CKA_");
+ }
+ }
+
+ return unknown;
+}
+
+const char *id2str_class(uint32_t id)
+{
+ return ID2STR(id, string_class, "PKCS11_CKO_");
+}
+
+const char *id2str_type(uint32_t id, uint32_t class)
+{
+ enum pkcs11_class_id class_id = class;
+ enum pkcs11_key_type key_type = id;
+
+ switch (class_id) {
+ case PKCS11_CKO_SECRET_KEY:
+ case PKCS11_CKO_PUBLIC_KEY:
+ case PKCS11_CKO_PRIVATE_KEY:
+ return id2str_key_type(key_type);
+ default:
+ return unknown;
+ }
+}
+
+const char *id2str_key_type(uint32_t id)
+{
+ return ID2STR(id, string_key_type, "PKCS11_CKK_");
+}
+
+const char *id2str_attr_value(uint32_t id, size_t size, void *value)
+{
+ static const char str_true[] = "TRUE";
+ static const char str_false[] = "FALSE";
+ static const char str_unknown[] = "*";
+ uint32_t type = 0;
+
+ if (pkcs11_attr2boolprop_shift(id) >= 0)
+ return *(uint8_t *)value ? str_true : str_false;
+
+ if (size < sizeof(uint32_t))
+ return str_unknown;
+
+ TEE_MemMove(&type, value, sizeof(uint32_t));
+
+ switch (id) {
+ case PKCS11_CKA_CLASS:
+ return id2str_class(type);
+ case PKCS11_CKA_KEY_TYPE:
+ return id2str_key_type(type);
+ case PKCS11_CKA_MECHANISM_TYPE:
+ return id2str_mechanism(type);
+ default:
+ return str_unknown;
+ }
+}
+
+const char *id2str_proc(uint32_t id)
+{
+ const char *str = ID2STR(id, string_internal_processing,
+ "PKCS11_PROCESSING_");
+
+ if (str != unknown)
+ return str;
+
+ return id2str_mechanism(id);
+}
+
+const char *id2str_function(uint32_t id)
+{
+ return ID2STR(id, string_functions, "PKCS11_FUNCTION_");
+}
#endif /*CFG_TEE_TA_LOG_LEVEL*/
diff --git a/ta/pkcs11/src/pkcs11_helpers.h b/ta/pkcs11/src/pkcs11_helpers.h
index e1a2b467..a87353f8 100644
--- a/ta/pkcs11/src/pkcs11_helpers.h
+++ b/ta/pkcs11/src/pkcs11_helpers.h
@@ -20,6 +20,42 @@
/* GPD TEE to PKCS11 status conversion */
enum pkcs11_rc tee2pkcs_error(TEE_Result res);
+/*
+ * Return true if and only if attribute ID with companion attribute value
+ * size do match a valid attribute identifier.
+ *
+ * @attribute_id - Target PKCS11 attribute ID
+ * @size - Byte size of the attribute value, 0 if non-constant size
+ */
+bool valid_pkcs11_attribute_id(uint32_t attribute_id, uint32_t size);
+
+/*
+ * Return type attribute byte size if @attribute_id is the ID of a type
+ * attribute or 0 if not.
+ */
+size_t pkcs11_attr_is_type(uint32_t attribute_id);
+
+/* Return true if the object class is related to a type-in-class */
+bool pkcs11_class_has_type(uint32_t class_id);
+
+/* Return true if the object class relates to a key */
+bool pkcs11_attr_class_is_key(uint32_t class_id);
+
+/* Return true if the key type @key_type_id relates to a symmetric key */
+bool key_type_is_symm_key(uint32_t key_type_id);
+
+/* Return true if the key type @key_type_id relates to an asymmetric key */
+bool key_type_is_asymm_key(uint32_t key_type_id);
+
+/* Boolprop flag shift position if @attribute_id is boolean, else -1 */
+int pkcs11_attr2boolprop_shift(uint32_t attribute_id);
+
+/* Return true if attribute is a boolean, false otherwise */
+static inline bool pkcs11_attr_is_boolean(enum pkcs11_attr_id id)
+{
+ return pkcs11_attr2boolprop_shift(id) >= 0;
+}
+
#if CFG_TEE_TA_LOG_LEVEL > 0
/* Id-to-string conversions only for trace support */
const char *id2str_ta_cmd(uint32_t id);
@@ -28,6 +64,13 @@ const char *id2str_slot_flag(uint32_t id);
const char *id2str_token_flag(uint32_t id);
const char *id2str_session_flag(uint32_t id);
const char *id2str_session_state(uint32_t id);
+const char *id2str_attr(uint32_t id);
+const char *id2str_class(uint32_t id);
+const char *id2str_type(uint32_t id, uint32_t class);
+const char *id2str_key_type(uint32_t id);
+const char *id2str_attr_value(uint32_t id, size_t size, void *value);
+const char *id2str_proc(uint32_t id);
+const char *id2str_function(uint32_t id);
static inline const char *id2str_mechanism(enum pkcs11_mechanism_id id)
{
diff --git a/ta/pkcs11/src/sanitize_object.c b/ta/pkcs11/src/sanitize_object.c
new file mode 100644
index 00000000..de9eaa98
--- /dev/null
+++ b/ta/pkcs11/src/sanitize_object.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2020, Linaro Limited
+ */
+
+#include <bitstring.h>
+#include <pkcs11_ta.h>
+#include <stdlib.h>
+#include <string.h>
+#include <util.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <trace.h>
+
+#include "attributes.h"
+#include "pkcs11_helpers.h"
+#include "sanitize_object.h"
+#include "serializer.h"
+#include "token_capabilities.h"
+
+/*
+ * Functions to generate a serialized object.
+ * References are pointers to struct serializer.
+ */
+
+bool sanitize_consistent_class_and_type(struct obj_attrs *attrs)
+{
+ switch (get_class(attrs)) {
+ case PKCS11_CKO_DATA:
+ return true;
+ case PKCS11_CKO_SECRET_KEY:
+ return key_type_is_symm_key(get_key_type(attrs));
+ case PKCS11_CKO_MECHANISM:
+ return mechanism_is_valid(get_mechanism_type(attrs));
+ case PKCS11_CKO_PUBLIC_KEY:
+ case PKCS11_CKO_PRIVATE_KEY:
+ return key_type_is_asymm_key(get_key_type(attrs));
+ case PKCS11_CKO_OTP_KEY:
+ case PKCS11_CKO_CERTIFICATE:
+ case PKCS11_CKO_DOMAIN_PARAMETERS:
+ case PKCS11_CKO_HW_FEATURE:
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+static enum pkcs11_rc read_attr_advance(void *buf, size_t blen, size_t *pos,
+ struct pkcs11_attribute_head *attr,
+ void **data)
+{
+ uint8_t *b = buf;
+ size_t data_pos = 0;
+ size_t next_pos = 0;
+
+ if (ADD_OVERFLOW(*pos, sizeof(*attr), &data_pos) || data_pos > blen)
+ return PKCS11_CKR_FUNCTION_FAILED;
+ TEE_MemMove(attr, b + *pos, sizeof(*attr));
+
+ if (ADD_OVERFLOW(data_pos, attr->size, &next_pos) || next_pos > blen)
+ return PKCS11_CKR_FUNCTION_FAILED;
+
+ *data = b + data_pos;
+ *pos = next_pos;
+
+ return PKCS11_CKR_OK;
+}
+
+/* Sanitize class/type in a client attribute list */
+static enum pkcs11_rc sanitize_class_and_type(struct obj_attrs **dst, void *src,
+ size_t src_size)
+{
+ uint32_t class_found = PKCS11_CKO_UNDEFINED_ID;
+ size_t pos = sizeof(struct pkcs11_object_head);
+ struct pkcs11_attribute_head cli_ref = { };
+ uint32_t type_found = PKCS11_UNDEFINED_ID;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ void *data = NULL;
+
+ while (pos != src_size) {
+ rc = read_attr_advance(src, src_size, &pos, &cli_ref, &data);
+ if (rc)
+ goto err;
+
+ if (cli_ref.id == PKCS11_CKA_CLASS) {
+ uint32_t class = 0;
+
+ if (cli_ref.size != sizeof(class)) {
+ rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ goto err;
+ }
+
+ TEE_MemMove(&class, data, sizeof(class));
+
+ if (class_found != PKCS11_CKO_UNDEFINED_ID &&
+ class_found != class) {
+ EMSG("Conflicting class value");
+ rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ goto err;
+ }
+
+ class_found = class;
+ continue;
+ }
+
+ /* The attribute is a type-in-class */
+ if (pkcs11_attr_is_type(cli_ref.id)) {
+ uint32_t type = 0;
+
+ if (cli_ref.size != sizeof(type)) {
+ rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ goto err;
+ }
+
+ TEE_MemMove(&type, data, sizeof(type));
+
+ if (type_found != PKCS11_CKK_UNDEFINED_ID &&
+ type_found != type) {
+ EMSG("Conflicting type-in-class value");
+ rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ goto err;
+ }
+
+ type_found = type;
+ }
+ }
+
+ if (class_found != PKCS11_CKO_UNDEFINED_ID) {
+ rc = add_attribute(dst, PKCS11_CKA_CLASS,
+ &class_found, sizeof(class_found));
+ if (rc)
+ return rc;
+ }
+
+ if (type_found != PKCS11_UNDEFINED_ID) {
+ rc = add_attribute(dst, PKCS11_CKA_KEY_TYPE,
+ &type_found, sizeof(type_found));
+ if (rc)
+ return rc;
+ }
+
+ return PKCS11_CKR_OK;
+
+err:
+ trace_attributes_from_api_head("bad-template", src, src_size);
+
+ return rc;
+}
+
+static enum pkcs11_rc sanitize_boolprops(struct obj_attrs **dst, void *src,
+ size_t src_size)
+{
+ bitstr_t bit_decl(seen_attrs, PKCS11_BOOLPROPS_MAX_COUNT) = { 0 };
+ bitstr_t bit_decl(boolprops, PKCS11_BOOLPROPS_MAX_COUNT) = { 0 };
+ size_t pos = sizeof(struct pkcs11_object_head);
+ struct pkcs11_attribute_head cli_ref = { };
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ bool value = false;
+ void *data = NULL;
+ int idx = 0;
+
+ /*
+ * We're keeping track of seen boolean attributes in the bitstring
+ * seen_attrs. The bitstring boolprops holds the recorded value
+ * once seen_attrs has been updated.
+ */
+
+ while (pos != src_size) {
+ rc = read_attr_advance(src, src_size, &pos, &cli_ref, &data);
+ if (rc)
+ return rc;
+
+ idx = pkcs11_attr2boolprop_shift(cli_ref.id);
+ if (idx < 0)
+ continue; /* skipping non-boolean attributes */
+
+ if (idx >= PKCS11_BOOLPROPS_MAX_COUNT ||
+ cli_ref.size != sizeof(uint8_t))
+ return PKCS11_CKR_FUNCTION_FAILED;
+
+ value = *(uint8_t *)data;
+
+ /*
+ * If this attribute has already been seen, check that it
+ * still holds the same value as last time.
+ */
+ if (bit_test(seen_attrs, idx) &&
+ value != (bool)bit_test(boolprops, idx))
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+
+ if (value)
+ bit_set(boolprops, idx);
+
+ if (!bit_test(seen_attrs, idx)) {
+ uint8_t pkcs11_bool = value;
+
+ rc = add_attribute(dst, cli_ref.id, &pkcs11_bool,
+ sizeof(pkcs11_bool));
+ if (rc)
+ return rc;
+ }
+ bit_set(seen_attrs, idx);
+ }
+
+ return PKCS11_CKR_OK;
+}
+
+static uint32_t sanitize_indirect_attr(struct obj_attrs **dst,
+ struct pkcs11_attribute_head *cli_ref,
+ char *data)
+{
+ struct obj_attrs *obj2 = NULL;
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ enum pkcs11_class_id class = get_class(*dst);
+
+ if (class == PKCS11_CKO_UNDEFINED_ID)
+ return PKCS11_CKR_GENERAL_ERROR;
+
+ /*
+ * Serialized attributes: current applicable only to the key
+ * templates which are tables of attributes.
+ */
+ switch (cli_ref->id) {
+ case PKCS11_CKA_WRAP_TEMPLATE:
+ case PKCS11_CKA_UNWRAP_TEMPLATE:
+ case PKCS11_CKA_DERIVE_TEMPLATE:
+ break;
+ default:
+ return PKCS11_RV_NOT_FOUND;
+ }
+ /* Such attributes are expected only for keys (and vendor defined) */
+ if (pkcs11_attr_class_is_key(class))
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+
+ rc = init_attributes_head(&obj2);
+ if (rc)
+ return rc;
+
+ /* Build a new serial object while sanitizing the attributes list */
+ rc = sanitize_client_object(&obj2, data, cli_ref->size);
+ if (rc)
+ goto out;
+
+ rc = add_attribute(dst, cli_ref->id, obj2,
+ sizeof(*obj2) + obj2->attrs_size);
+out:
+ TEE_Free(obj2);
+ return rc;
+}
+
+enum pkcs11_rc sanitize_client_object(struct obj_attrs **dst, void *src,
+ size_t size)
+{
+ struct pkcs11_attribute_head cli_ref = { };
+ struct pkcs11_object_head head = { };
+ enum pkcs11_rc rc = PKCS11_CKR_OK;
+ size_t pos = sizeof(head);
+ size_t sz_from_hdr = 0;
+ void *data = NULL;
+
+ if (size < sizeof(head))
+ return PKCS11_CKR_ARGUMENTS_BAD;
+
+ TEE_MemMove(&head, src, sizeof(head));
+
+ if (ADD_OVERFLOW(sizeof(head), head.attrs_size, &sz_from_hdr) ||
+ size < sz_from_hdr)
+ return PKCS11_CKR_ARGUMENTS_BAD;
+
+ rc = init_attributes_head(dst);
+ if (rc)
+ return rc;
+
+ rc = sanitize_class_and_type(dst, src, sz_from_hdr);
+ if (rc)
+ return rc;
+
+ rc = sanitize_boolprops(dst, src, sz_from_hdr);
+ if (rc)
+ return rc;
+
+ while (pos != sz_from_hdr) {
+ rc = read_attr_advance(src, sz_from_hdr, &pos, &cli_ref, &data);
+ if (rc)
+ return rc;
+
+ if (cli_ref.id == PKCS11_CKA_CLASS ||
+ pkcs11_attr_is_type(cli_ref.id) ||
+ pkcs11_attr_is_boolean(cli_ref.id))
+ continue;
+
+ rc = sanitize_indirect_attr(dst, &cli_ref, data);
+ if (rc == PKCS11_CKR_OK)
+ continue;
+ if (rc != PKCS11_RV_NOT_FOUND)
+ return rc;
+
+ if (!valid_pkcs11_attribute_id(cli_ref.id, cli_ref.size)) {
+ EMSG("Invalid attribute id %#"PRIx32, cli_ref.id);
+ return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+ }
+
+ rc = add_attribute(dst, cli_ref.id, data, cli_ref.size);
+ if (rc)
+ return rc;
+ }
+
+ return rc;
+}
+
+/*
+ * Debug: dump object attribute array to output trace
+ */
+
+static void __trace_attributes(char *prefix, void *src, void *end)
+{
+ size_t next = 0;
+ char *prefix2 = NULL;
+ size_t prefix_len = strlen(prefix);
+ char *cur = src;
+
+ /* append 4 spaces to the prefix plus terminal '\0' */
+ prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
+ if (!prefix2)
+ return;
+
+ TEE_MemMove(prefix2, prefix, prefix_len + 1);
+ TEE_MemFill(prefix2 + prefix_len, ' ', 4);
+ *(prefix2 + prefix_len + 4) = '\0';
+
+ for (; cur < (char *)end; cur += next) {
+ struct pkcs11_attribute_head pkcs11_ref;
+ uint8_t data[4] = { 0 };
+ uint32_t data_u32 = 0;
+
+ TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
+ TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
+ MIN(pkcs11_ref.size, sizeof(data)));
+ TEE_MemMove(&data_u32, cur + sizeof(pkcs11_ref),
+ sizeof(data_u32));
+
+ next = sizeof(pkcs11_ref) + pkcs11_ref.size;
+
+ DMSG_RAW("%s Attr %s / %s (%#04"PRIx32" %"PRIu32"-byte)",
+ prefix, id2str_attr(pkcs11_ref.id),
+ id2str_attr_value(pkcs11_ref.id, pkcs11_ref.size,
+ cur + sizeof(pkcs11_ref)),
+ pkcs11_ref.id, pkcs11_ref.size);
+
+ switch (pkcs11_ref.size) {
+ case 0:
+ break;
+ case 1:
+ DMSG_RAW("%s Attr byte value: %02x", prefix, data[0]);
+ break;
+ case 2:
+ DMSG_RAW("%s Attr byte value: %02x %02x",
+ prefix, data[0], data[1]);
+ break;
+ case 3:
+ DMSG_RAW("%s Attr byte value: %02x %02x %02x",
+ prefix, data[0], data[1], data[2]);
+ break;
+ case 4:
+ DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x",
+ prefix, data[0], data[1], data[2], data[3]);
+ break;
+ default:
+ DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x ...",
+ prefix, data[0], data[1], data[2], data[3]);
+ break;
+ }
+
+ switch (pkcs11_ref.id) {
+ case PKCS11_CKA_WRAP_TEMPLATE:
+ case PKCS11_CKA_UNWRAP_TEMPLATE:
+ case PKCS11_CKA_DERIVE_TEMPLATE:
+ trace_attributes_from_api_head(prefix2,
+ cur + sizeof(pkcs11_ref),
+ (char *)end - cur);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Sanity */
+ if (cur != (char *)end)
+ EMSG("Warning: unexpected alignment issue");
+
+ TEE_Free(prefix2);
+}
+
+void trace_attributes_from_api_head(const char *prefix, void *ref, size_t size)
+{
+ struct pkcs11_object_head head = { };
+ char *pre = NULL;
+ size_t offset = 0;
+
+ TEE_MemMove(&head, ref, sizeof(head));
+
+ if (size > sizeof(head) + head.attrs_size) {
+ EMSG("template overflows client buffer (%zu/%zu)",
+ size, sizeof(head) + head.attrs_size);
+ return;
+ }
+
+ pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
+ if (!pre) {
+ EMSG("%s: out of memory", prefix);
+ return;
+ }
+ if (prefix)
+ TEE_MemMove(pre, prefix, strlen(prefix));
+
+ DMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
+ DMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
+ pre, head.attrs_count, head.attrs_size);
+
+ offset = sizeof(head);
+ pre[prefix ? strlen(prefix) : 0] = '|';
+ __trace_attributes(pre, (char *)ref + offset,
+ (char *)ref + offset + head.attrs_size);
+
+ DMSG_RAW("%s`-----------------------", prefix ? prefix : "");
+
+ TEE_Free(pre);
+}
diff --git a/ta/pkcs11/src/sanitize_object.h b/ta/pkcs11/src/sanitize_object.h
new file mode 100644
index 00000000..ddbdccef
--- /dev/null
+++ b/ta/pkcs11/src/sanitize_object.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2020, Linaro Limited
+ */
+
+#ifndef PKCS11_TA_SANITIZE_OBJECT_H
+#define PKCS11_TA_SANITIZE_OBJECT_H
+
+#include "serializer.h"
+
+/*
+ * sanitize_consistent_class_and_type - Check object type matches object class
+ *
+ * @attrs - object attributes
+ * Return true if class/type matches, else return false
+ */
+bool sanitize_consistent_class_and_type(struct obj_attrs *attrs);
+
+/**
+ * sanitize_client_object - Setup a serializer from a serialized object
+ *
+ * @dst - output structure tracking the generated serial object
+ * @head - pointer to the formatted serialized object (its head)
+ * @size - byte size of the serialized binary blob
+ *
+ * This function copies an attribute list from a client API attribute head
+ * into a PKCS11 TA internal attribute structure. It generates a serialized
+ * attribute list with a consistent format and identified attribute IDs.
+ *
+ * @head points to a blob starting with a pkcs11 attribute header.
+ * @head may point to an unaligned address.
+ * This function allocates, fills and returns a serialized attribute list
+ * into a serializer container.
+ */
+enum pkcs11_rc sanitize_client_object(struct obj_attrs **dst, void *head,
+ size_t size);
+
+/* Debug: dump attribute content as debug traces */
+void trace_attributes_from_api_head(const char *prefix, void *ref, size_t size);
+
+#endif /*PKCS11_TA_SANITIZE_OBJECT_H*/
diff --git a/ta/pkcs11/src/sub.mk b/ta/pkcs11/src/sub.mk
index f03ce326..7681c5d6 100644
--- a/ta/pkcs11/src/sub.mk
+++ b/ta/pkcs11/src/sub.mk
@@ -1,7 +1,10 @@
+srcs-y += attributes.c
srcs-y += entry.c
srcs-y += handle.c
srcs-y += persistent_token.c
+srcs-y += pkcs11_attributes.c
srcs-y += pkcs11_helpers.c
srcs-y += pkcs11_token.c
+srcs-y += sanitize_object.c
srcs-y += serializer.c
srcs-y += token_capabilities.c