]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - optee/ti-optee-os.git/commitdiff
ta: pkcs11: Add support for Key Generation
authorRuchika Gupta <ruchika.gupta@linaro.org>
Thu, 10 Dec 2020 09:47:50 +0000 (15:17 +0530)
committerJérôme Forissier <jerome@forissier.org>
Wed, 23 Dec 2020 08:51:29 +0000 (09:51 +0100)
Adds support of mechanisms PKCS11_CKM_GENERIC_SECRET_KEY_GEN,
PKCS11_CKM_AES_KEY_GEN for key generation API.

Co-developed-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Ruchika Gupta <ruchika.gupta@linaro.org>
Reviewed-by: Vesa Jääskeläinen <vesa.jaaskelainen@vaisala.com>
ta/pkcs11/src/attributes.c
ta/pkcs11/src/attributes.h
ta/pkcs11/src/entry.c
ta/pkcs11/src/pkcs11_attributes.c
ta/pkcs11/src/pkcs11_helpers.c
ta/pkcs11/src/processing.c
ta/pkcs11/src/processing.h
ta/pkcs11/src/token_capabilities.c

index 4c23281e50f8b6cb915ab605e8709a95d02b8094..3454f7a8fa1ccd5ad09e49771140cc9ef338acb6 100644 (file)
@@ -58,6 +58,49 @@ enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute,
        return rc;
 }
 
+static enum pkcs11_rc _remove_attribute(struct obj_attrs **head,
+                                       uint32_t attribute, bool empty)
+{
+       struct obj_attrs *h = *head;
+       char *cur = NULL;
+       char *end = NULL;
+       size_t next_off = 0;
+
+       /* Let's find the target attribute */
+       cur = (char *)h + sizeof(struct obj_attrs);
+       end = cur + h->attrs_size;
+       for (; cur < end; cur += next_off) {
+               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;
+
+               if (empty && pkcs11_ref.size)
+                       return PKCS11_CKR_FUNCTION_FAILED;
+
+               TEE_MemMove(cur, cur + next_off, end - (cur + next_off));
+
+               h->attrs_count--;
+               h->attrs_size -= next_off;
+               end -= next_off;
+               next_off = 0;
+
+               return PKCS11_CKR_OK;
+       }
+
+       DMSG("Attribute %s (%#x) not found", id2str_attr(attribute), attribute);
+       return PKCS11_RV_NOT_FOUND;
+}
+
+enum pkcs11_rc remove_empty_attribute(struct obj_attrs **head,
+                                     uint32_t attribute)
+{
+       return _remove_attribute(head, attribute, true /* empty */);
+}
+
 void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute,
                        void **attr, uint32_t *attr_size, size_t *count)
 {
index 293c67fd109d4958c8b2178a62e31848ff4fd1eb..353989f4a43f3f7a7606bb0ae8710437f6d044fd 100644 (file)
@@ -85,6 +85,14 @@ enum pkcs11_rc init_attributes_head(struct obj_attrs **head);
 enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute,
                             void *data, size_t size);
 
+/*
+ * Update serialized attributes to remove an empty entry. Can relocate the
+ * attribute list buffer. Only 1 instance of the entry is expected.
+ *
+ * Return PKCS11_CKR_OK on success or a PKCS11 return code.
+ */
+enum pkcs11_rc remove_empty_attribute(struct obj_attrs **head, uint32_t attrib);
+
 /*
  * get_attribute_ptrs() - Get pointers to attributes with a given ID
  * @head:      Pointer to serialized attributes
index c4bd04d2a26f48dc9d07946f3ad860a826b356c0..947f71bd93ad5ce767204de82effc6cb26bbe7a9 100644 (file)
@@ -285,6 +285,9 @@ TEE_Result TA_InvokeCommandEntryPoint(void *tee_session, uint32_t cmd,
                                           PKCS11_FUNCTION_VERIFY,
                                           PKCS11_FUNC_STEP_FINAL);
                break;
+       case PKCS11_CMD_GENERATE_KEY:
+               rc = entry_generate_secret(client, ptypes, params);
+               break;
        default:
                EMSG("Command %#"PRIx32" is not supported", cmd);
                return TEE_ERROR_NOT_SUPPORTED;
index c183f910ddb3566569a15bd7fea364fb1fdb0a91..2d7148a68a3d663dd37d20a8a2bbeaabb1bc464c 100644 (file)
@@ -684,7 +684,7 @@ 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)
+                               enum pkcs11_mechanism_id mecha)
 {
        struct obj_attrs *temp = NULL;
        struct obj_attrs *attrs = NULL;
@@ -692,11 +692,14 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
        uint8_t local = 0;
        uint8_t always_sensitive = 0;
        uint8_t never_extract = 0;
+       uint32_t class = PKCS11_UNDEFINED_ID;
+       uint32_t type = PKCS11_UNDEFINED_ID;
        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_GENERATE:
        case PKCS11_FUNCTION_IMPORT:
                break;
        default:
@@ -711,9 +714,51 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
        /* 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;
+               switch (mecha) {
+               case PKCS11_CKM_GENERIC_SECRET_KEY_GEN:
+                       class = PKCS11_CKO_SECRET_KEY;
+                       type = PKCS11_CKK_GENERIC_SECRET;
+                       break;
+               case PKCS11_CKM_AES_KEY_GEN:
+                       class = PKCS11_CKO_SECRET_KEY;
+                       type = PKCS11_CKK_AES;
+                       break;
+               default:
+                       EMSG("Unable to define class/type from mechanism");
+                       rc = PKCS11_CKR_TEMPLATE_INCOMPLETE;
+                       goto out;
+               }
+               if (class != PKCS11_UNDEFINED_ID) {
+                       rc = add_attribute(&temp, PKCS11_CKA_CLASS,
+                                          &class, sizeof(uint32_t));
+                       if (rc)
+                               goto out;
+               }
+               if (type != PKCS11_UNDEFINED_ID) {
+                       rc = add_attribute(&temp, PKCS11_CKA_KEY_TYPE,
+                                          &type, sizeof(uint32_t));
+                       if (rc)
+                               goto out;
+               }
+       }
+
+       switch (mecha) {
+       case PKCS11_CKM_GENERIC_SECRET_KEY_GEN:
+               if (get_class(temp) != PKCS11_CKO_SECRET_KEY ||
+                   get_key_type(temp) != PKCS11_CKK_GENERIC_SECRET) {
+                       rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+                       goto out;
+               }
+               break;
+       case PKCS11_CKM_AES_KEY_GEN:
+               if (get_class(temp) != PKCS11_CKO_SECRET_KEY ||
+                   get_key_type(temp) != PKCS11_CKK_AES) {
+                       rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
+                       goto out;
+               }
+               break;
+       default:
+               break;
        }
 
        if (!sanitize_consistent_class_and_type(temp)) {
@@ -758,6 +803,9 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
        }
 
        switch (function) {
+       case PKCS11_FUNCTION_GENERATE:
+               local = PKCS11_TRUE;
+               break;
        case PKCS11_FUNCTION_IMPORT:
        default:
                local = PKCS11_FALSE;
@@ -774,6 +822,17 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
                always_sensitive = PKCS11_FALSE;
                never_extract = PKCS11_FALSE;
 
+               switch (function) {
+               case PKCS11_FUNCTION_GENERATE:
+                       always_sensitive = get_bool(attrs,
+                                                   PKCS11_CKA_SENSITIVE);
+                       never_extract = !get_bool(attrs,
+                                                 PKCS11_CKA_EXTRACTABLE);
+                       break;
+               default:
+                       break;
+               }
+
                rc = add_attribute(&attrs, PKCS11_CKA_ALWAYS_SENSITIVE,
                                   &always_sensitive, sizeof(always_sensitive));
                if (rc)
@@ -785,7 +844,11 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
                        goto out;
 
                /* Keys mandate attribute PKCS11_CKA_KEY_GEN_MECHANISM */
-               mechanism_id = PKCS11_CK_UNAVAILABLE_INFORMATION;
+               if (local)
+                       mechanism_id = mecha;
+               else
+                       mechanism_id = PKCS11_CK_UNAVAILABLE_INFORMATION;
+
                rc = add_attribute(&attrs, PKCS11_CKA_KEY_GEN_MECHANISM,
                                   &mechanism_id, sizeof(mechanism_id));
                if (rc)
@@ -938,11 +1001,27 @@ enum pkcs11_rc check_created_attrs_against_processing(uint32_t proc_id,
        case PKCS11_PROCESSING_IMPORT:
                assert(check_attr_bval(proc_id, head, PKCS11_CKA_LOCAL, false));
                break;
+       case PKCS11_CKM_GENERIC_SECRET_KEY_GEN:
+       case PKCS11_CKM_AES_KEY_GEN:
+               assert(check_attr_bval(proc_id, head, PKCS11_CKA_LOCAL, true));
+               break;
        default:
                TEE_Panic(proc_id);
                break;
        }
 
+       switch (proc_id) {
+       case PKCS11_CKM_GENERIC_SECRET_KEY_GEN:
+               assert(get_key_type(head) == PKCS11_CKK_GENERIC_SECRET);
+               break;
+       case PKCS11_CKM_AES_KEY_GEN:
+               assert(get_key_type(head) == PKCS11_CKK_AES);
+               break;
+       case PKCS11_PROCESSING_IMPORT:
+       default:
+               break;
+       }
+
        return PKCS11_CKR_OK;
 }
 
@@ -953,6 +1032,9 @@ static void get_key_min_max_sizes(enum pkcs11_key_type key_type,
        enum pkcs11_mechanism_id mechanism = PKCS11_CKM_UNDEFINED_ID;
 
        switch (key_type) {
+       case PKCS11_CKK_GENERIC_SECRET:
+               mechanism = PKCS11_CKM_GENERIC_SECRET_KEY_GEN;
+               break;
        case PKCS11_CKK_AES:
                mechanism = PKCS11_CKM_AES_KEY_GEN;
                break;
index d5b0d4b1403514ba9fe3214b8f5ec9d2ac3b1546..bd2a8ee548d9b4dff1f6f0549ca1c5c993943caa 100644 (file)
@@ -169,6 +169,7 @@ static const struct any_id __maybe_unused string_ta_cmd[] = {
        PKCS11_ID(PKCS11_CMD_VERIFY_FINAL),
        PKCS11_ID(PKCS11_CMD_SIGN_ONESHOT),
        PKCS11_ID(PKCS11_CMD_VERIFY_ONESHOT),
+       PKCS11_ID(PKCS11_CMD_GENERATE_KEY),
 };
 
 static const struct any_id __maybe_unused string_slot_flags[] = {
index 6fbeb1bb6e08519202b05e61d546ed8f7c0a8b1e..06ddbe4a5c9e2281659e8851de4027c5bb94dd38 100644 (file)
@@ -110,6 +110,178 @@ 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;
+
+       if (!*head)
+               return PKCS11_CKR_TEMPLATE_INCONSISTENT;
+
+       rc = get_attribute_ptr(*head, PKCS11_CKA_VALUE_LEN, &data, &data_size);
+       if (rc || data_size != sizeof(uint32_t)) {
+               DMSG("%s", rc ? "No attribute value_len found" :
+                    "Invalid size for attribute VALUE_LEN");
+
+               return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+       TEE_MemMove(&value_len, data, data_size);
+
+       if (get_key_type(*head) == PKCS11_CKK_GENERIC_SECRET)
+               value_len = (value_len + 7) / 8;
+
+       /* Remove the default empty value attribute if found */
+       rc = remove_empty_attribute(head, PKCS11_CKA_VALUE);
+       if (rc != PKCS11_CKR_OK && rc != PKCS11_RV_NOT_FOUND)
+               return PKCS11_CKR_GENERAL_ERROR;
+
+       value = TEE_Malloc(value_len, TEE_USER_MEM_HINT_NO_FILL_ZERO);
+       if (!value)
+               return PKCS11_CKR_DEVICE_MEMORY;
+
+       TEE_GenerateRandom(value, value_len);
+
+       rc = add_attribute(head, PKCS11_CKA_VALUE, value, value_len);
+
+       TEE_Free(value);
+
+       return rc;
+}
+
+enum pkcs11_rc entry_generate_secret(struct pkcs11_client *client,
+                                    uint32_t ptypes, TEE_Param *params)
+{
+       const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
+                                               TEE_PARAM_TYPE_NONE,
+                                               TEE_PARAM_TYPE_MEMREF_OUTPUT,
+                                               TEE_PARAM_TYPE_NONE);
+       TEE_Param *ctrl = params;
+       TEE_Param *out = params + 2;
+       enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
+       struct serialargs ctrlargs = { };
+       struct pkcs11_session *session = NULL;
+       struct pkcs11_attribute_head *proc_params = NULL;
+       struct obj_attrs *head = NULL;
+       struct pkcs11_object_head *template = NULL;
+       size_t template_size = 0;
+       uint32_t obj_handle = 0;
+
+       if (!client || ptypes != exp_pt ||
+           out->memref.size != sizeof(obj_handle))
+               return PKCS11_CKR_ARGUMENTS_BAD;
+
+       serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+       rc = serialargs_get_session_from_handle(&ctrlargs, client, &session);
+       if (rc)
+               return rc;
+
+       rc = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+       if (rc)
+               goto out;
+
+       rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
+       if (rc)
+               goto out;
+
+       if (serialargs_remaining_bytes(&ctrlargs)) {
+               rc = PKCS11_CKR_ARGUMENTS_BAD;
+               goto out;
+       }
+
+       rc = get_ready_session(session);
+       if (rc)
+               goto out;
+
+       template_size = sizeof(*template) + template->attrs_size;
+
+       rc = check_mechanism_against_processing(session, proc_params->id,
+                                               PKCS11_FUNCTION_GENERATE,
+                                               PKCS11_FUNC_STEP_INIT);
+       if (rc) {
+               DMSG("Invalid mechanism %#"PRIx32": %#x", proc_params->id, rc);
+               goto out;
+       }
+
+       /*
+        * Prepare a clean initial state for the requested object attributes.
+        * Free temporary template once done.
+        */
+       rc = create_attributes_from_template(&head, template, template_size,
+                                            NULL, PKCS11_FUNCTION_GENERATE,
+                                            proc_params->id);
+       if (rc)
+               goto out;
+
+       TEE_Free(template);
+       template = NULL;
+
+       rc = check_created_attrs(head, NULL);
+       if (rc)
+               goto out;
+
+       rc = check_created_attrs_against_processing(proc_params->id, head);
+       if (rc)
+               goto out;
+
+       rc = check_created_attrs_against_token(session, head);
+       if (rc)
+               goto out;
+
+       /*
+        * Execute target processing and add value as attribute
+        * PKCS11_CKA_VALUE. Symm key generation: depends on target
+        * processing to be used.
+        */
+       switch (proc_params->id) {
+       case PKCS11_CKM_GENERIC_SECRET_KEY_GEN:
+       case PKCS11_CKM_AES_KEY_GEN:
+               /* Generate random of size specified by attribute VALUE_LEN */
+               rc = generate_random_key_value(&head);
+               if (rc)
+                       goto out;
+               break;
+
+       default:
+               rc = PKCS11_CKR_MECHANISM_INVALID;
+               goto out;
+       }
+
+       TEE_Free(proc_params);
+       proc_params = NULL;
+
+       /*
+        * Object is ready, register it and return a handle.
+        */
+       rc = create_object(session, head, &obj_handle);
+       if (rc)
+               goto out;
+
+       /*
+        * Now obj_handle (through the related struct pkcs11_object instance)
+        * owns the serialized buffer that holds the object attributes.
+        * We reset head to NULL as it is no more the buffer owner and would
+        * be freed at function out.
+        */
+       head = NULL;
+
+       TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(obj_handle));
+       out->memref.size = sizeof(obj_handle);
+
+       DMSG("PKCS11 session %"PRIu32": generate secret %#"PRIx32,
+            session->handle, obj_handle);
+
+out:
+       TEE_Free(proc_params);
+       TEE_Free(template);
+       TEE_Free(head);
+
+       return rc;
+}
+
 /*
  * entry_processing_init - Generic entry for initializing a processing
  *
index d668b53e109ad0ed6b5d0336fae5ca6b14eb2ec7..afeaf2aae4d32df1f2c09bbba8eea0dec885fc50 100644 (file)
@@ -18,6 +18,9 @@ struct active_processing;
  * Entry points from PKCS11 TA invocation commands
  */
 
+enum pkcs11_rc entry_generate_secret(struct pkcs11_client *client,
+                                    uint32_t ptypes, TEE_Param *params);
+
 enum pkcs11_rc entry_processing_init(struct pkcs11_client *client,
                                     uint32_t ptypes, TEE_Param *params,
                                     enum processing_func function);
index 7d985fcebbef5f5920e756e070a949495981efb3..06f928919b0a431f724af09a66055dd1740d65ac 100644 (file)
@@ -78,6 +78,8 @@ static const struct pkcs11_mechachism_modes pkcs11_modes[] = {
        MECHANISM(PKCS11_CKM_AES_CBC_ENCRYPT_DATA, PKCS11_CKFM_DERIVE,
                  ANY_PART),
        MECHANISM(PKCS11_CKM_AES_KEY_GEN, PKCS11_CKFM_GENERATE, ANY_PART),
+       MECHANISM(PKCS11_CKM_GENERIC_SECRET_KEY_GEN, PKCS11_CKFM_GENERATE,
+                 ANY_PART),
        /* HMAC */
        MECHANISM(PKCS11_CKM_MD5_HMAC, CKFM_AUTH_NO_RECOVER, ANY_PART),
        MECHANISM(PKCS11_CKM_SHA_1_HMAC, CKFM_AUTH_NO_RECOVER, ANY_PART),
@@ -172,6 +174,8 @@ const struct pkcs11_mechachism_modes token_mechanism[] = {
        TA_MECHANISM(PKCS11_CKM_AES_CTS, CKFM_CIPHER),
        TA_MECHANISM(PKCS11_CKM_AES_ECB_ENCRYPT_DATA, PKCS11_CKFM_DERIVE),
        TA_MECHANISM(PKCS11_CKM_AES_CBC_ENCRYPT_DATA, PKCS11_CKFM_DERIVE),
+       TA_MECHANISM(PKCS11_CKM_AES_KEY_GEN, PKCS11_CKFM_GENERATE),
+       TA_MECHANISM(PKCS11_CKM_GENERIC_SECRET_KEY_GEN, PKCS11_CKFM_GENERATE),
        TA_MECHANISM(PKCS11_CKM_MD5_HMAC, CKFM_AUTH_NO_RECOVER),
        TA_MECHANISM(PKCS11_CKM_SHA_1_HMAC, CKFM_AUTH_NO_RECOVER),
        TA_MECHANISM(PKCS11_CKM_SHA224_HMAC, CKFM_AUTH_NO_RECOVER),
@@ -238,6 +242,11 @@ void mechanism_supported_key_sizes(uint32_t proc_id, uint32_t *min_key_size,
                                   uint32_t *max_key_size)
 {
        switch (proc_id) {
+       case PKCS11_CKM_GENERIC_SECRET_KEY_GEN:
+               /* This mechanism expects the keysize to be returned in bits */
+               *min_key_size = 1;              /* in bits */
+               *max_key_size = 4096;           /* in bits */
+               break;
        case PKCS11_CKM_MD5_HMAC:
                *min_key_size = 8;
                *max_key_size = 64;