diff --git a/ta/pkcs11/include/pkcs11_ta.h b/ta/pkcs11/include/pkcs11_ta.h index bbe73b108da..6c093756250 100644 --- a/ta/pkcs11/include/pkcs11_ta.h +++ b/ta/pkcs11/include/pkcs11_ta.h @@ -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, +}; + /* * Valid values for mechanism IDs * PKCS11_CKM_ reflects CryptoKi client API mechanism IDs CKM_. diff --git a/ta/pkcs11/src/attributes.h b/ta/pkcs11/src/attributes.h index ae9241ebbe2..c5da0bbfcc0 100644 --- a/ta/pkcs11/src/attributes.h +++ b/ta/pkcs11/src/attributes.h @@ -262,6 +262,25 @@ 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_CKM_UNDEFINED_ID on error. + */ +static inline +enum pkcs11_certificate_type get_certificate_type(struct obj_attrs *head) +{ + uint32_t type = 0; + uint32_t size = sizeof(type); + + if (get_attribute(head, PKCS11_CKA_CERTIFICATE_TYPE, &type, &size)) + return PKCS11_CKC_UNDEFINED_ID; + + return type; +} + /* * get_mechanism_type() - Get the mechanism type of an object * @head: Pointer to serialized attributes diff --git a/ta/pkcs11/src/object.c b/ta/pkcs11/src/object.c index 4c8c4c274ec..093024170d2 100644 --- a/ta/pkcs11/src/object.c +++ b/ta/pkcs11/src/object.c @@ -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", diff --git a/ta/pkcs11/src/pkcs11_attributes.c b/ta/pkcs11/src/pkcs11_attributes.c index 89ef6c75ad9..ef9cde8343f 100644 --- a/ta/pkcs11/src/pkcs11_attributes.c +++ b/ta/pkcs11/src/pkcs11_attributes.c @@ -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, @@ -567,6 +596,119 @@ 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; + 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 = NULL; + 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, + &cert_category, &attr_size); + if (rc == PKCS11_CKR_OK && attr_size == sizeof(uint32_t)) { + /* Sanitize certificate 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"/%s", + *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) @@ -940,6 +1082,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) @@ -1134,6 +1279,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: @@ -1792,6 +1938,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: + 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, @@ -1840,6 +2040,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; } diff --git a/ta/pkcs11/src/pkcs11_helpers.c b/ta/pkcs11/src/pkcs11_helpers.c index 0c9cadff1c1..d2139645bf6 100644 --- a/ta/pkcs11/src/pkcs11_helpers.c +++ b/ta/pkcs11/src/pkcs11_helpers.c @@ -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), @@ -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(). @@ -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"; diff --git a/ta/pkcs11/src/pkcs11_helpers.h b/ta/pkcs11/src/pkcs11_helpers.h index 8713829dcec..41b9b579252 100644 --- a/ta/pkcs11/src/pkcs11_helpers.h +++ b/ta/pkcs11/src/pkcs11_helpers.h @@ -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); diff --git a/ta/pkcs11/src/sanitize_object.c b/ta/pkcs11/src/sanitize_object.c index 977482c3cf0..d39302c945f 100644 --- a/ta/pkcs11/src/sanitize_object.c +++ b/ta/pkcs11/src/sanitize_object.c @@ -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)); @@ -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: