Skip to content

Commit

Permalink
pkcs11: Add generic support for key pair generation
Browse files Browse the repository at this point in the history
This commit only adds common key pair generation support code.

Actual mechanism specific key pair generation codes are in their own
commits.

Specified in:
PKCS OP-TEE#11 Cryptographic Token Interface Base Specification Version 2.40 Plus
Errata 01

5.13 Key management functions
C_GenerateKeyPair

Co-developed-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Vesa Jääskeläinen <vesa.jaaskelainen@vaisala.com>
  • Loading branch information
vesajaaskelainen committed Dec 31, 2020
1 parent 98442a1 commit aa91f21
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 2 deletions.
3 changes: 3 additions & 0 deletions ta/pkcs11/src/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ TEE_Result TA_InvokeCommandEntryPoint(void *tee_session, uint32_t cmd,
case PKCS11_CMD_GET_OBJECT_SIZE:
rc = entry_get_object_size(client, ptypes, params);
break;
case PKCS11_CMD_GENERATE_KEY_PAIR:
rc = entry_generate_key_pair(client, ptypes, params);
break;
default:
EMSG("Command %#"PRIx32" is not supported", cmd);
return TEE_ERROR_NOT_SUPPORTED;
Expand Down
58 changes: 56 additions & 2 deletions ta/pkcs11/src/pkcs11_attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
trace_attributes_from_api_head("template", template, template_size);
switch (function) {
case PKCS11_FUNCTION_GENERATE:
case PKCS11_FUNCTION_GENERATE_PAIR:
case PKCS11_FUNCTION_IMPORT:
break;
default:
Expand Down Expand Up @@ -724,6 +725,19 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
}
}

/*
* For PKCS11_FUNCTION_GENERATE_PAIR, find the class and type
* based on the mechanism. These will be passed as hint
* sanitize_client_object() and added in temp if not
* already present
*/
if (function == PKCS11_FUNCTION_GENERATE_PAIR) {
switch (mecha) {
default:
TEE_Panic(TEE_ERROR_NOT_SUPPORTED);
}
}

rc = sanitize_client_object(&temp, template, template_size, class,
type);
if (rc)
Expand Down Expand Up @@ -794,6 +808,7 @@ create_attributes_from_template(struct obj_attrs **out, void *template,

switch (function) {
case PKCS11_FUNCTION_GENERATE:
case PKCS11_FUNCTION_GENERATE_PAIR:
local = PKCS11_TRUE;
break;
case PKCS11_FUNCTION_IMPORT:
Expand Down Expand Up @@ -1060,6 +1075,8 @@ enum pkcs11_rc check_created_attrs(struct obj_attrs *key1,
{
enum pkcs11_rc rc = PKCS11_CKR_OK;
struct obj_attrs *secret = NULL;
struct obj_attrs *private = NULL;
struct obj_attrs *public = NULL;
uint32_t max_key_size = 0;
uint32_t min_key_size = 0;
uint32_t key_length = 0;
Expand All @@ -1068,12 +1085,37 @@ enum pkcs11_rc check_created_attrs(struct obj_attrs *key1,
case PKCS11_CKO_SECRET_KEY:
secret = key1;
break;
case PKCS11_CKO_PUBLIC_KEY:
public = key1;
break;
case PKCS11_CKO_PRIVATE_KEY:
private = key1;
break;
default:
return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID;
}

if (key2)
return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID;
if (key2) {
switch (get_class(key2)) {
case PKCS11_CKO_PUBLIC_KEY:
public = key2;
if (private == key1)
break;

return PKCS11_CKR_TEMPLATE_INCONSISTENT;
case PKCS11_CKO_PRIVATE_KEY:
private = key2;
if (public == key1)
break;

return PKCS11_CKR_TEMPLATE_INCONSISTENT;
default:
return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID;
}

if (get_key_type(private) != get_key_type(public))
return PKCS11_CKR_TEMPLATE_INCONSISTENT;
}

if (secret) {
switch (get_key_type(secret)) {
Expand All @@ -1096,6 +1138,18 @@ enum pkcs11_rc check_created_attrs(struct obj_attrs *key1,
if (rc)
return PKCS11_CKR_TEMPLATE_INCOMPLETE;
}
if (public) {
switch (get_key_type(public)) {
default:
return PKCS11_CKR_TEMPLATE_INCONSISTENT;
}
}
if (private) {
switch (get_key_type(private)) {
default:
return PKCS11_CKR_TEMPLATE_INCONSISTENT;
}
}

get_key_min_max_sizes(get_key_type(key1), &min_key_size, &max_key_size);
if (key_length < min_key_size || key_length > max_key_size) {
Expand Down
2 changes: 2 additions & 0 deletions ta/pkcs11/src/pkcs11_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static const struct attr_size attr_ids[] = {
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_KEY_GEN_MECHANISM, 4),
PKCS11_ID_SZ(PKCS11_CKA_LABEL, 0),
PKCS11_ID_SZ(PKCS11_CKA_WRAP_TEMPLATE, 0),
PKCS11_ID_SZ(PKCS11_CKA_UNWRAP_TEMPLATE, 0),
Expand Down Expand Up @@ -175,6 +176,7 @@ static const struct any_id __maybe_unused string_ta_cmd[] = {
PKCS11_ID(PKCS11_CMD_FIND_OBJECTS_FINAL),
PKCS11_ID(PKCS11_CMD_GET_OBJECT_SIZE),
PKCS11_ID(PKCS11_CMD_GET_ATTRIBUTE_VALUE),
PKCS11_ID(PKCS11_CMD_GENERATE_KEY_PAIR),
};

static const struct any_id __maybe_unused string_slot_flags[] = {
Expand Down
219 changes: 219 additions & 0 deletions ta/pkcs11/src/processing.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,225 @@ enum pkcs11_rc entry_generate_secret(struct pkcs11_client *client,
return rc;
}

enum pkcs11_rc alloc_get_tee_attribute_data(TEE_ObjectHandle tee_obj,
uint32_t attribute,
void **data, size_t *size)
{
TEE_Result res = TEE_ERROR_GENERIC;
void *ptr = NULL;
uint32_t sz = 0;

res = TEE_GetObjectBufferAttribute(tee_obj, attribute, NULL, &sz);
if (res != TEE_ERROR_SHORT_BUFFER)
return PKCS11_CKR_FUNCTION_FAILED;

ptr = TEE_Malloc(sz, TEE_USER_MEM_HINT_NO_FILL_ZERO);
if (!ptr)
return PKCS11_CKR_DEVICE_MEMORY;

res = TEE_GetObjectBufferAttribute(tee_obj, attribute, ptr, &sz);
if (res) {
TEE_Free(ptr);
} else {
*data = ptr;
*size = sz;
}

return tee2pkcs_error(res);
}

enum pkcs11_rc tee2pkcs_add_attribute(struct obj_attrs **head,
uint32_t pkcs11_id,
TEE_ObjectHandle tee_obj,
uint32_t tee_id)
{
enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;
void *a_ptr = NULL;
size_t a_size = 0;

rc = alloc_get_tee_attribute_data(tee_obj, tee_id, &a_ptr, &a_size);
if (rc)
goto out;

rc = add_attribute(head, pkcs11_id, a_ptr, a_size);

TEE_Free(a_ptr);

out:
if (rc)
EMSG("Failed TEE attribute %#"PRIx32" for %#"PRIx32"/%s",
tee_id, pkcs11_id, id2str_attr(pkcs11_id));
return rc;
}

enum pkcs11_rc entry_generate_key_pair(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 *pub_head = NULL;
struct obj_attrs *priv_head = NULL;
struct pkcs11_object_head *template = NULL;
size_t template_size = 0;
uint32_t pubkey_handle = 0;
uint32_t privkey_handle = 0;
uint32_t *hdl_ptr = NULL;
size_t out_ref_size = sizeof(pubkey_handle) + sizeof(privkey_handle);

if (!client || ptypes != exp_pt || out->memref.size != out_ref_size)
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;

/* Get mechanism parameters */
rc = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
if (rc)
return rc;

/* Get and check public key attributes */
rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
if (rc)
goto out;

rc = get_ready_session(session);
if (rc)
goto out;

rc = check_mechanism_against_processing(session, proc_params->id,
PKCS11_FUNCTION_GENERATE_PAIR,
PKCS11_FUNC_STEP_INIT);
if (rc)
goto out;

template_size = sizeof(*template) + template->attrs_size;

rc = create_attributes_from_template(&pub_head,
template, template_size, NULL,
PKCS11_FUNCTION_GENERATE_PAIR,
proc_params->id,
PKCS11_CKO_PUBLIC_KEY);
if (rc)
goto out;

TEE_Free(template);
template = NULL;

rc = serialargs_alloc_get_attributes(&ctrlargs, &template);
if (rc)
goto out;

if (serialargs_remaining_bytes(&ctrlargs)) {
rc = PKCS11_CKR_ARGUMENTS_BAD;
goto out;
}

template_size = sizeof(*template) + template->attrs_size;

rc = create_attributes_from_template(&priv_head,
template, template_size, NULL,
PKCS11_FUNCTION_GENERATE_PAIR,
proc_params->id,
PKCS11_CKO_PRIVATE_KEY);
if (rc)
goto out;

TEE_Free(template);
template = NULL;

/* Generate CKA_ID for keys if not specified by the templates */
rc = add_missing_attribute_id(&pub_head, &priv_head);
if (rc)
goto out;

/* Check created object against processing and token state */
rc = check_created_attrs(pub_head, priv_head);
if (rc)
goto out;

rc = check_created_attrs_against_processing(proc_params->id, pub_head);
if (rc)
goto out;

rc = check_created_attrs_against_processing(proc_params->id, priv_head);
if (rc)
goto out;

rc = check_created_attrs_against_token(session, pub_head);
if (rc)
goto out;

rc = check_created_attrs_against_token(session, priv_head);
if (rc)
goto out;

/* Generate key pair */
switch (proc_params->id) {
default:
rc = PKCS11_CKR_MECHANISM_INVALID;
break;
}
if (rc)
goto out;

TEE_Free(proc_params);
proc_params = NULL;

/*
* Object is ready, register it and return a handle.
*/
rc = create_object(session, pub_head, &pubkey_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 local pub_head to NULL to mark that ownership has been
* transferred.
*/
pub_head = NULL;

rc = create_object(session, priv_head, &privkey_handle);
if (rc)
goto out;

/* Ownership has been transferred so mark it with NULL */
priv_head = NULL;

hdl_ptr = (uint32_t *)out->memref.buffer;

TEE_MemMove(hdl_ptr, &pubkey_handle, sizeof(pubkey_handle));
TEE_MemMove(hdl_ptr + 1, &privkey_handle, sizeof(privkey_handle));

pubkey_handle = 0;
privkey_handle = 0;

DMSG("PKCS11 session %"PRIu32": create key pair %#"PRIx32"/%#"PRIx32,
session->handle, privkey_handle, pubkey_handle);

out:
if (pubkey_handle)
destroy_object(session, pubkey_handle, false);
TEE_Free(priv_head);
TEE_Free(pub_head);
TEE_Free(template);
TEE_Free(proc_params);

return rc;
}

/*
* entry_processing_init - Generic entry for initializing a processing
*
Expand Down
12 changes: 12 additions & 0 deletions ta/pkcs11/src/processing.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ struct active_processing;
enum pkcs11_rc entry_generate_secret(struct pkcs11_client *client,
uint32_t ptypes, TEE_Param *params);

enum pkcs11_rc entry_generate_key_pair(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);
Expand All @@ -37,6 +40,15 @@ size_t get_object_key_bit_size(struct pkcs11_object *obj);

void release_active_processing(struct pkcs11_session *session);

enum pkcs11_rc alloc_get_tee_attribute_data(TEE_ObjectHandle tee_obj,
uint32_t attribute,
void **data, size_t *size);

enum pkcs11_rc tee2pkcs_add_attribute(struct obj_attrs **head,
uint32_t pkcs11_id,
TEE_ObjectHandle tee_obj,
uint32_t tee_id);

/*
* Symmetric crypto algorithm specific functions
*/
Expand Down

0 comments on commit aa91f21

Please sign in to comment.