diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 18c89cab..a005df5c 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -126,6 +126,12 @@ struct pkcs15_data_object { #define data_p15obj base.p15_object #define is_data(obj) (__p15_type(obj) == SC_PKCS15_TYPE_DATA_OBJECT) +struct pkcs15_profile_object { + struct pkcs15_any_object base; + + unsigned long profile_id; +}; + struct pkcs15_skey_object { struct pkcs15_any_object base; @@ -142,6 +148,7 @@ extern struct sc_pkcs11_object_ops pkcs15_cert_ops; extern struct sc_pkcs11_object_ops pkcs15_prkey_ops; extern struct sc_pkcs11_object_ops pkcs15_pubkey_ops; extern struct sc_pkcs11_object_ops pkcs15_dobj_ops; +extern struct sc_pkcs11_object_ops pkcs15_profile_ops; extern struct sc_pkcs11_object_ops pkcs15_skey_ops; const CK_BYTE gostr3410_paramset_A_encoded_oid[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 }; @@ -811,6 +818,32 @@ __pkcs15_create_data_object(struct pkcs15_fw_data *fw_data, return rv; } +/* Note, that this is not actuall PKCS #15 object, but just bogus + * structure to create PKCS #11 object. There is no corresponding + * PKCS #15 object. */ +static int +__pkcs15_create_profile_object(struct pkcs15_fw_data *fw_data, + int public_certificates, struct pkcs15_any_object **profile_object) +{ + struct pkcs15_profile_object *pobj = NULL; + struct sc_pkcs15_object *obj = NULL; + int rv; + + obj = calloc(1, sizeof(struct sc_pkcs15_object)); + + rv = __pkcs15_create_object(fw_data, (struct pkcs15_any_object **) &pobj, + obj, &pkcs15_profile_ops, sizeof(struct pkcs15_profile_object)); + if (rv >= 0) { + pobj->profile_id = public_certificates ? CKP_PUBLIC_CERTIFICATES_TOKEN : CKP_AUTHENTICATION_TOKEN; + } + + if (profile_object != NULL) + *profile_object = (struct pkcs15_any_object *) pobj; + + return rv; +} + + static int __pkcs15_create_secret_key_object(struct pkcs15_fw_data *fw_data, @@ -1430,6 +1463,10 @@ _add_pin_related_objects(struct sc_pkcs11_slot *slot, struct sc_pkcs15_object *p static void _add_public_objects(struct sc_pkcs11_slot *slot, struct pkcs15_fw_data *fw_data) { + /* Public Certificates Token in PKCS #11 3.0 */ + struct pkcs15_any_object *pobj = NULL; + int public_certificates = 1; + CK_RV rv; unsigned i; if (slot == NULL || fw_data == NULL) @@ -1446,8 +1483,15 @@ _add_public_objects(struct sc_pkcs11_slot *slot, struct pkcs15_fw_data *fw_data) if (obj->base.flags & SC_PKCS11_OBJECT_SEEN) continue; /* Ignore 'private' object */ - if (obj->p15_object->flags & SC_PKCS15_CO_FLAG_PRIVATE) + if (obj->p15_object->flags & SC_PKCS15_CO_FLAG_PRIVATE) { + /* If we found some non-accessible public object, + * we can no longer claim Public Ceritificate Token conformance */ + if (obj->p15_object->type & SC_PKCS15_TYPE_PUBKEY || + obj->p15_object->type & SC_PKCS15_TYPE_CERT) { + public_certificates = 0; + } continue; + } /* PKCS#15 4.1.3 is a little vague, but implies if not PRIVATE it is readable * even if there is an auth_id to allow writing for example. * See bug issue #291 @@ -1456,9 +1500,20 @@ _add_public_objects(struct sc_pkcs11_slot *slot, struct pkcs15_fw_data *fw_data) if (obj->p15_object->auth_id.len && !(is_pubkey(obj) || is_cert(obj))) continue; - sc_log(context, "Add public object(%p,%.*s,%x)", obj, (int) sizeof obj->p15_object->label, obj->p15_object->label, obj->p15_object->type); + sc_log(context, "Add public object(%p,%.*s,%x)", obj, + (int) sizeof obj->p15_object->label, obj->p15_object->label, + obj->p15_object->type); pkcs15_add_object(slot, obj, NULL); } + + /* If all certificates and public keys are visible, we can claim conformance + * to Public Certificate Token profile, making life easier for many applications + * saying, they do not need to login to see all keys available */ + rv = __pkcs15_create_profile_object(fw_data, public_certificates, &pobj); + if (rv != CKR_OK || pobj == NULL) { + return; + } + pkcs15_add_object(slot, pobj, NULL); } @@ -4949,6 +5004,66 @@ struct sc_pkcs11_object_ops pkcs15_dobj_ops = { NULL /* wrap_key */ }; +/* PKCS#15 Data Object*/ +static void +pkcs15_profile_release(void *object) +{ + __pkcs15_release_object((struct pkcs15_any_object *) object); +} + + +static CK_RV +pkcs15_profile_set_attribute(struct sc_pkcs11_session *session, + void *object, CK_ATTRIBUTE_PTR attr) +{ + /* Profile object is not writable */ + return CKR_ACTION_PROHIBITED; +} + +static CK_RV +pkcs15_profile_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ATTRIBUTE_PTR attr) +{ + struct pkcs15_profile_object *pobj = (struct pkcs15_profile_object*) object; + + sc_log(context, "pkcs15_profile_get_attribute() called"); + switch (attr->type) { + case CKA_CLASS: + check_attribute_buffer(attr, sizeof(CK_OBJECT_CLASS)); + *(CK_OBJECT_CLASS*)attr->pValue = CKO_PROFILE; + break; + case CKA_PRIVATE: + /* This is needed internally for the object to be visible */ + check_attribute_buffer(attr, sizeof(CK_BBOOL)); + *(CK_BBOOL*)attr->pValue = CK_FALSE; + break; + case CKA_PROFILE_ID: + /* TODO */ + check_attribute_buffer(attr, sizeof(CK_ULONG)); + *(CK_ULONG*)attr->pValue = pobj->profile_id; + break; + default: + return CKR_ATTRIBUTE_TYPE_INVALID; + } + + return CKR_OK; +} +struct sc_pkcs11_object_ops pkcs15_profile_ops = { + pkcs15_profile_release, + pkcs15_profile_set_attribute, + pkcs15_profile_get_attribute, + sc_pkcs11_any_cmp_attribute, + pkcs15_any_destroy, + NULL, /* get_size */ + NULL, /* sign */ + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ + NULL, /* can_do */ + NULL, /* init_params */ + NULL /* wrap_key */ +}; + + /* PKCS#15 Secret Key Objects */ /* TODO Currently only session objects */ diff --git a/src/pkcs11/pkcs11-display.c b/src/pkcs11/pkcs11-display.c index 66e33d65..095a2ce0 100644 --- a/src/pkcs11/pkcs11-display.c +++ b/src/pkcs11/pkcs11-display.c @@ -250,6 +250,7 @@ static enum_specs ck_cls_s[] = { { CKO_PUBLIC_KEY , "CKO_PUBLIC_KEY " }, { CKO_PRIVATE_KEY , "CKO_PRIVATE_KEY " }, { CKO_SECRET_KEY , "CKO_SECRET_KEY " }, + { CKO_PROFILE , "CKO_PROFILE " }, { CKO_HW_FEATURE , "CKO_HW_FEATURE " }, { CKO_DOMAIN_PARAMETERS, "CKO_DOMAIN_PARAMETERS" }, { CKO_NETSCAPE_CRL, "CKO_NETSCAPE_CRL " }, @@ -259,6 +260,15 @@ static enum_specs ck_cls_s[] = { { CKO_VENDOR_DEFINED , "CKO_VENDOR_DEFINED " } }; +enum_specs ck_profile_s[] = { + { CKP_INVALID_ID , "CKP_INVALID_ID " }, + { CKP_BASELINE_PROVIDER , "CKP_BASELINE_PROVIDER " }, + { CKP_EXTENDED_PROVIDER , "CKP_EXTENDED_PROVIDER " }, + { CKP_AUTHENTICATION_TOKEN , "CKP_AUTHENTICATION_TOKEN " }, + { CKP_PUBLIC_CERTIFICATES_TOKEN, "CKP_PUBLIC_CERTIFICATES_TOKEN" }, + { CKP_VENDOR_DEFINED , "CKP_VENDOR_DEFINED " } +}; + static enum_specs ck_crt_s[] = { { CKC_X_509, "CKC_X_509" }, { CKC_X_509_ATTR_CERT, "CKC_X_509_ATTR_CERT" }, @@ -657,6 +667,7 @@ static enum_specs ck_ckd_s[] = { enum_spec ck_types[] = { { OBJ_T, ck_cls_s, sizeof(ck_cls_s) / SZ_SPECS, "CK_OBJECT_CLASS" }, + { PROFILE_T, ck_profile_s, sizeof(ck_profile_s)/SZ_SPECS, "CK_PROFILE"}, { KEY_T, ck_key_s, sizeof(ck_key_s) / SZ_SPECS, "CK_KEY_TYPE" }, { CRT_T, ck_crt_s, sizeof(ck_crt_s) / SZ_SPECS, "CK_CERTIFICATE_TYPE" }, { MEC_T, ck_mec_s, sizeof(ck_mec_s) / SZ_SPECS, "CK_MECHANISM_TYPE" }, @@ -670,6 +681,7 @@ enum_spec ck_types[] = { static enum_spec ck_key_t[] = { { KEY_T, ck_key_s, sizeof(ck_key_s) / SZ_SPECS, "CK_KEY_TYPE" } }; static enum_spec ck_cls_t[] = { { OBJ_T, ck_cls_s, sizeof(ck_cls_s) / SZ_SPECS, "CK_OBJECT_CLASS" } }; static enum_spec ck_crt_t[] = { { CRT_T, ck_crt_s, sizeof(ck_crt_s) / SZ_SPECS, "CK_CERTIFICATE_TYPE" } }; +static enum_spec ck_profile_t[] = { { PROFILE_T, ck_profile_s, sizeof(ck_profile_s) / SZ_SPECS, "CK_PROFILE" } }; type_spec ck_attribute_specs[] = { { CKA_CLASS , "CKA_CLASS ", print_enum, ck_cls_t }, @@ -781,6 +793,7 @@ type_spec ck_attribute_specs[] = { { CKA_ENCODING_METHODS , "CKA_ENCODING_METHODS ", print_generic, NULL }, { CKA_MIME_TYPES , "CKA_MIME_TYPES ", print_generic, NULL }, { CKA_MECHANISM_TYPE , "CKA_MECHANISM_TYPE ", print_generic, NULL }, + { CKA_PROFILE_ID , "CKA_PROFILE_ID ", print_enum, ck_profile_t }, { CKA_REQUIRED_CMS_ATTRIBUTES, "CKA_REQUIRED_CMS_ATTRIBUTES ", print_generic, NULL }, { CKA_DEFAULT_CMS_ATTRIBUTES, "CKA_DEFAULT_CMS_ATTRIBUTES ", print_generic, NULL }, { CKA_SUPPORTED_CMS_ATTRIBUTES, "CKA_SUPPORTED_CMS_ATTRIBUTES ", print_generic, NULL }, diff --git a/src/pkcs11/pkcs11-display.h b/src/pkcs11/pkcs11-display.h index 88f3bff8..5e315302 100644 --- a/src/pkcs11/pkcs11-display.h +++ b/src/pkcs11/pkcs11-display.h @@ -53,6 +53,7 @@ typedef struct { enum ck_type{ OBJ_T, + PROFILE_T, KEY_T, CRT_T, MEC_T, diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h index 11f09f5b..02612bf8 100644 --- a/src/pkcs11/pkcs11.h +++ b/src/pkcs11/pkcs11.h @@ -321,8 +321,16 @@ typedef unsigned long ck_object_class_t; #define CKO_HW_FEATURE (5UL) #define CKO_DOMAIN_PARAMETERS (6UL) #define CKO_MECHANISM (7UL) +#define CKO_OTP_KEY (8UL) +#define CKO_PROFILE (9UL) #define CKO_VENDOR_DEFINED (1UL << 31) +#define CKP_INVALID_ID (0UL) +#define CKP_BASELINE_PROVIDER (1UL) +#define CKP_EXTENDED_PROVIDER (2UL) +#define CKP_AUTHENTICATION_TOKEN (3UL) +#define CKP_PUBLIC_CERTIFICATES_TOKEN (4UL) +#define CKP_VENDOR_DEFINED (1UL << 31) typedef unsigned long ck_hw_feature_type_t; @@ -482,6 +490,7 @@ typedef unsigned long ck_attribute_type_t; #define CKA_OTP_COUNTER (0x22EUL) #define CKA_OTP_TIME (0x22FUL) #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600UL) +#define CKA_PROFILE_ID (0x601UL) #define CKA_VENDOR_DEFINED (1UL << 31) @@ -1506,6 +1515,7 @@ struct ck_c_initialize_args #define CKR_ATTRIBUTE_SENSITIVE (0x11UL) #define CKR_ATTRIBUTE_TYPE_INVALID (0x12UL) #define CKR_ATTRIBUTE_VALUE_INVALID (0x13UL) +#define CKR_ACTION_PROHIBITED (0x1BUL) #define CKR_DATA_INVALID (0x20UL) #define CKR_DATA_LEN_RANGE (0x21UL) #define CKR_DEVICE_ERROR (0x30UL) diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index fbeb0c9d..e8e244fe 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -437,6 +437,7 @@ static void show_object(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void show_key(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void show_cert(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj); +static void show_profile(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj); static void sign_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void verify_signature(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); static void decrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); @@ -554,6 +555,7 @@ ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE); /* getKEY_TYPE */ ATTR_METHOD(CERTIFICATE_TYPE, CK_CERTIFICATE_TYPE); /* getCERTIFICATE_TYPE */ ATTR_METHOD(MODULUS_BITS, CK_ULONG); /* getMODULUS_BITS */ ATTR_METHOD(VALUE_LEN, CK_ULONG); /* getVALUE_LEN */ +ATTR_METHOD(PROFILE_ID, CK_ULONG); /* getPROFILE_ID */ VARATTR_METHOD(LABEL, char); /* getLABEL */ VARATTR_METHOD(APPLICATION, char); /* getAPPLICATION */ VARATTR_METHOD(ID, unsigned char); /* getID */ @@ -3740,6 +3742,9 @@ static void show_object(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) case CKO_DATA: show_dobj(sess, obj); break; + case CKO_PROFILE: + show_profile(sess, obj); + break; default: printf("Object %u, type %u\n", (unsigned int) obj, @@ -4303,6 +4308,20 @@ static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) } +static void show_profile(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) +{ + CK_ULONG id = 0; + + printf("Profile object %u\n", (unsigned int) obj); + printf(" profile_id: "); + if ((id = getPROFILE_ID(sess, obj)) != 0) { + printf("'%lu'\n", id); + } else { + printf("\n"); + } +} + + static void get_token_info(CK_SLOT_ID slot, CK_TOKEN_INFO_PTR info) {