Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ta: pkcs11: Add certificate object support #4797

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions ta/pkcs11/include/pkcs11_ta.h
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,27 @@ enum pkcs11_key_type {
PKCS11_CKK_UNDEFINED_ID = PKCS11_UNDEFINED_ID,
};

/*
* Valid values for attribute PKCS11_CKA_CERTIFICATE_TYPE
*/
enum pkcs11_certificate_type {
PKCS11_CKC_X_509 = 0x00000000UL,
PKCS11_CKC_X_509_ATTR_CERT = 0x00000001UL,
PKCS11_CKC_WTLS = 0x00000002UL,
/* Vendor extension: reserved for undefined ID (~0U) */
PKCS11_CKC_UNDEFINED_ID = PKCS11_UNDEFINED_ID,
};

/*
* Valid values for attribute PKCS11_CKA_CERTIFICATE_CATEGORY
*/
enum pkcs11_certificate_category {
PKCS11_CK_CERTIFICATE_CATEGORY_UNSPECIFIED = 0UL,
PKCS11_CK_CERTIFICATE_CATEGORY_TOKEN_USER = 1UL,
PKCS11_CK_CERTIFICATE_CATEGORY_AUTHORITY = 2UL,
PKCS11_CK_CERTIFICATE_CATEGORY_OTHER_ENTITY = 3UL,
vesajaaskelainen marked this conversation as resolved.
Show resolved Hide resolved
};

/*
* Valid values for mechanism IDs
* PKCS11_CKM_<x> reflects CryptoKi client API mechanism IDs CKM_<x>.
Expand Down
18 changes: 18 additions & 0 deletions ta/pkcs11/src/attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,24 @@ static inline enum pkcs11_key_type get_key_type(struct obj_attrs *head)
return type;
}

/*
* get_certificate_type() - Get the certificate type of an object
* @head: Pointer to serialized attributes
*
* Returns the certificate type of an object on success or returns
* PKCS11_CKC_UNDEFINED_ID on error.
*/
static inline
enum pkcs11_certificate_type get_certificate_type(struct obj_attrs *head)
{
uint32_t type = 0;

if (get_u32_attribute(head, PKCS11_CKA_CERTIFICATE_TYPE, &type))
return PKCS11_CKC_UNDEFINED_ID;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: assert(size == sizeof(uint32_t));
or I think you could even drop fetching size.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel better if we fetch it ;) ... but will add the assert

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh -- none of the other methods with the same construct have it -- should we add assert to those too?

Copy link
Contributor Author

@vesajaaskelainen vesajaaskelainen Oct 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_u32_attribute() would have sanity check embedded -- shall we use this and no assert?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, get_u32_attribute() and no extra assertions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the PR with that.

return type;
}

/*
* get_mechanism_type() - Get the mechanism type of an object
* @head: Pointer to serialized attributes
Expand Down
1 change: 1 addition & 0 deletions ta/pkcs11/src/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ enum pkcs11_rc entry_find_objects_init(struct pkcs11_client *client,
case PKCS11_CKO_PUBLIC_KEY:
case PKCS11_CKO_PRIVATE_KEY:
case PKCS11_CKO_DATA:
case PKCS11_CKO_CERTIFICATE:
break;
default:
EMSG("Find object of class %s (%"PRIu32") is not supported",
Expand Down
205 changes: 205 additions & 0 deletions ta/pkcs11/src/pkcs11_attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,35 @@ const uint32_t raw_data_opt_or_null[] = {
PKCS11_CKA_OBJECT_ID, PKCS11_CKA_APPLICATION, PKCS11_CKA_VALUE,
};

/* PKCS#11 specification for certificate object (+pkcs11_any_object_xxx) */
static const uint32_t pkcs11_certificate_mandated[] = {
PKCS11_CKA_CERTIFICATE_TYPE,
};

static const uint32_t pkcs11_certificate_boolprops[] = {
PKCS11_CKA_TRUSTED,
};

static const uint32_t pkcs11_certificate_optional[] = {
PKCS11_CKA_CERTIFICATE_CATEGORY, PKCS11_CKA_CHECK_VALUE,
PKCS11_CKA_START_DATE, PKCS11_CKA_END_DATE, PKCS11_CKA_PUBLIC_KEY_INFO,
};

/*
* PKCS#11 specification for X.509 certificate object (+pkcs11_certificate_xxx)
*/
static const uint32_t pkcs11_x509_certificate_mandated[] = {
PKCS11_CKA_SUBJECT,
};

static const uint32_t pkcs11_x509_certificate_optional[] = {
PKCS11_CKA_ID, PKCS11_CKA_ISSUER, PKCS11_CKA_SERIAL_NUMBER,
PKCS11_CKA_VALUE, PKCS11_CKA_URL,
PKCS11_CKA_HASH_OF_SUBJECT_PUBLIC_KEY,
PKCS11_CKA_HASH_OF_ISSUER_PUBLIC_KEY,
PKCS11_CKA_JAVA_MIDP_SECURITY_DOMAIN, PKCS11_CKA_NAME_HASH_ALGORITHM,
};

/* PKCS#11 specification for any key object (+any_object_xxx) */
static const uint32_t any_key_boolprops[] = {
PKCS11_CKA_DERIVE,
Expand Down Expand Up @@ -567,6 +596,122 @@ static enum pkcs11_rc create_data_attributes(struct obj_attrs **out,
ARRAY_SIZE(raw_data_opt_or_null));
}

static enum pkcs11_rc create_certificate_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;
void *attr_value = NULL;
uint32_t attr_size = 0;
uint32_t default_cert_category =
PKCS11_CK_CERTIFICATE_CATEGORY_UNSPECIFIED;
uint32_t default_name_hash_alg = PKCS11_CKM_SHA_1;
uint32_t cert_category = 0;
enum pkcs11_rc rc = PKCS11_CKR_OK;

assert(get_class(temp) == PKCS11_CKO_CERTIFICATE);

rc = create_storage_attributes(out, temp);
if (rc)
return rc;

assert(get_class(*out) == PKCS11_CKO_CERTIFICATE);

rc = set_mandatory_boolprops(out, temp, pkcs11_certificate_boolprops,
ARRAY_SIZE(pkcs11_certificate_boolprops));
if (rc)
return rc;

rc = set_mandatory_attributes(out, temp, pkcs11_certificate_mandated,
ARRAY_SIZE(pkcs11_certificate_mandated));
if (rc)
return rc;

rc = set_optional_attributes(out, temp, pkcs11_certificate_optional,
ARRAY_SIZE(pkcs11_certificate_optional));
if (rc)
return rc;

switch (get_certificate_type(*out)) {
case PKCS11_CKC_X_509:
mandated = pkcs11_x509_certificate_mandated;
optional = pkcs11_x509_certificate_optional;
mandated_count = ARRAY_SIZE(pkcs11_x509_certificate_mandated);
optional_count = ARRAY_SIZE(pkcs11_x509_certificate_optional);
break;
default:
EMSG("Invalid certificate type %#"PRIx32"/%s",
get_certificate_type(*out),
id2str_certificate_type(get_certificate_type(*out)));

return PKCS11_CKR_TEMPLATE_INCONSISTENT;
}

rc = set_mandatory_attributes(out, temp, mandated, mandated_count);
if (rc)
return rc;

rc = set_optional_attributes(out, temp, optional, optional_count);
if (rc)
return rc;

attr_size = 0;
rc = get_attribute_ptr(*out, PKCS11_CKA_CERTIFICATE_CATEGORY,
&attr_value, &attr_size);
if (rc == PKCS11_CKR_OK && attr_size == sizeof(cert_category)) {
/* Sanitize certificate category */
TEE_MemMove(&cert_category, attr_value, sizeof(cert_category));

switch (cert_category) {
case PKCS11_CK_CERTIFICATE_CATEGORY_UNSPECIFIED:
case PKCS11_CK_CERTIFICATE_CATEGORY_TOKEN_USER:
case PKCS11_CK_CERTIFICATE_CATEGORY_AUTHORITY:
case PKCS11_CK_CERTIFICATE_CATEGORY_OTHER_ENTITY:
break;
default:
EMSG("Invalid certificate category %#"PRIx32,
cert_category);

return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID;
}
} else if (rc == PKCS11_RV_NOT_FOUND) {
/* Set default category when missing */
rc = set_attribute(out, PKCS11_CKA_CERTIFICATE_CATEGORY,
&default_cert_category,
sizeof(default_cert_category));
if (rc)
return rc;
} else {
/* All other cases are errors */
EMSG("Invalid certificate category");

return PKCS11_CKR_TEMPLATE_INCONSISTENT;
}

attr_size = 0;
rc = get_attribute_ptr(*out, PKCS11_CKA_NAME_HASH_ALGORITHM, NULL,
&attr_size);
if (rc == PKCS11_CKR_OK && attr_size == sizeof(uint32_t)) {
/* We accept any algorithm what caller wanted to specify */
} else if (rc == PKCS11_RV_NOT_FOUND) {
/* Set default hash algorithm when missing */
rc = set_attribute(out, PKCS11_CKA_NAME_HASH_ALGORITHM,
&default_name_hash_alg,
sizeof(default_name_hash_alg));
if (rc)
return rc;
} else {
/* All other cases are errors */
EMSG("Invalid name hash algorithm");

return PKCS11_CKR_TEMPLATE_INCONSISTENT;
}

return rc;
}

static enum pkcs11_rc create_pub_key_attributes(struct obj_attrs **out,
struct obj_attrs *temp,
enum processing_func function)
Expand Down Expand Up @@ -940,6 +1085,9 @@ create_attributes_from_template(struct obj_attrs **out, void *template,
case PKCS11_CKO_DATA:
rc = create_data_attributes(&attrs, temp);
break;
case PKCS11_CKO_CERTIFICATE:
rc = create_certificate_attributes(&attrs, temp);
break;
case PKCS11_CKO_SECRET_KEY:
rc = sanitize_symm_key_attributes(&temp, function);
if (rc)
Expand Down Expand Up @@ -1134,6 +1282,7 @@ enum pkcs11_rc check_access_attrs_against_token(struct pkcs11_session *session,
case PKCS11_CKO_PRIVATE_KEY:
case PKCS11_CKO_PUBLIC_KEY:
case PKCS11_CKO_DATA:
case PKCS11_CKO_CERTIFICATE:
private = object_is_private(head);
break;
default:
Expand Down Expand Up @@ -1792,6 +1941,60 @@ static bool attr_is_modifiable_private_key(struct pkcs11_attribute_head *attr,
}
}

static bool attr_is_modifiable_certificate(struct pkcs11_attribute_head *attr,
struct pkcs11_session *session,
struct pkcs11_object *obj)
{
uint8_t boolval = 0;
uint32_t boolsize = 0;
enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR;

/* Trusted certificates cannot be modified. */
rc = get_attribute(obj->attributes, PKCS11_CKA_TRUSTED,
&boolval, &boolsize);
if (rc || boolval == PKCS11_TRUE)
return false;

/* Common certificate attributes */
switch (attr->id) {
case PKCS11_CKA_TRUSTED:
/*
* The CKA_TRUSTED attribute cannot be set to CK_TRUE by an
* application. It MUST be set by a token initialization
* application or by the token’s SO.
*/
return pkcs11_session_is_so(session);
case PKCS11_CKA_CERTIFICATE_TYPE:
case PKCS11_CKA_CERTIFICATE_CATEGORY:
return false;
default:
break;
}

/* Certificate type specific attributes */
switch (get_certificate_type(obj->attributes)) {
case PKCS11_CKC_X_509:
/*
* Only the CKA_ID, CKA_ISSUER, and CKA_SERIAL_NUMBER
* attributes may be modified after the object is created.
*/
switch (attr->id) {
case PKCS11_CKA_ID:
case PKCS11_CKA_ISSUER:
case PKCS11_CKA_SERIAL_NUMBER:
return true;
default:
vesajaaskelainen marked this conversation as resolved.
Show resolved Hide resolved
break;
}
break;
default:
/* Unsupported certificate type */
break;
}

return false;
}

static bool attribute_is_modifiable(struct pkcs11_session *session,
struct pkcs11_attribute_head *req_attr,
struct pkcs11_object *obj,
Expand Down Expand Up @@ -1840,6 +2043,8 @@ static bool attribute_is_modifiable(struct pkcs11_session *session,
case PKCS11_CKO_DATA:
/* None of the data object attributes are modifiable */
return false;
case PKCS11_CKO_CERTIFICATE:
return attr_is_modifiable_certificate(req_attr, session, obj);
default:
break;
}
Expand Down
22 changes: 22 additions & 0 deletions ta/pkcs11/src/pkcs11_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ static const struct attr_size attr_ids[] = {
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_CERTIFICATE_TYPE, 4),
PKCS11_ID_SZ(PKCS11_CKA_ISSUER, 0),
PKCS11_ID_SZ(PKCS11_CKA_SERIAL_NUMBER, 0),
PKCS11_ID_SZ(PKCS11_CKA_CERTIFICATE_CATEGORY, 4),
PKCS11_ID_SZ(PKCS11_CKA_URL, 0),
PKCS11_ID_SZ(PKCS11_CKA_HASH_OF_SUBJECT_PUBLIC_KEY, 0),
PKCS11_ID_SZ(PKCS11_CKA_HASH_OF_ISSUER_PUBLIC_KEY, 0),
PKCS11_ID_SZ(PKCS11_CKA_JAVA_MIDP_SECURITY_DOMAIN, 4),
PKCS11_ID_SZ(PKCS11_CKA_NAME_HASH_ALGORITHM, 4),
PKCS11_ID_SZ(PKCS11_CKA_CHECK_VALUE, 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),
Expand Down Expand Up @@ -330,6 +340,13 @@ static const struct any_id __maybe_unused string_key_type[] = {
PKCS11_ID(PKCS11_CKK_UNDEFINED_ID)
};

static const struct any_id __maybe_unused string_certificate_type[] = {
PKCS11_ID(PKCS11_CKC_X_509),
PKCS11_ID(PKCS11_CKC_X_509_ATTR_CERT),
PKCS11_ID(PKCS11_CKC_WTLS),
PKCS11_ID(PKCS11_CKC_UNDEFINED_ID)
};

/*
* Processing IDs not exported in the TA API.
* PKCS11_CKM_* mechanism IDs are looked up from mechanism_string_id().
Expand Down Expand Up @@ -760,6 +777,11 @@ const char *id2str_key_type(uint32_t id)
return ID2STR(id, string_key_type, "PKCS11_CKK_");
}

const char *id2str_certificate_type(uint32_t id)
{
return ID2STR(id, string_certificate_type, "PKCS11_CKC_");
}

const char *id2str_attr_value(uint32_t id, size_t size, void *value)
{
static const char str_true[] = "TRUE";
Expand Down
1 change: 1 addition & 0 deletions ta/pkcs11/src/pkcs11_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ 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_certificate_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);
Expand Down
2 changes: 1 addition & 1 deletion ta/pkcs11/src/sanitize_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ bool sanitize_consistent_class_and_type(struct obj_attrs *attrs)
{
switch (get_class(attrs)) {
case PKCS11_CKO_DATA:
case PKCS11_CKO_CERTIFICATE:
return true;
case PKCS11_CKO_SECRET_KEY:
return key_type_is_symm_key(get_key_type(attrs));
Expand All @@ -37,7 +38,6 @@ bool sanitize_consistent_class_and_type(struct obj_attrs *attrs)
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:
Expand Down