diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index f4d545d7..e38c4d1a 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -20,6 +20,7 @@ #include "config.h" #include "libopensc/log.h" +#include "libopensc/asn1.h" #include #include @@ -807,13 +808,11 @@ pkcs15_bind_related_objects(struct pkcs15_fw_data *fw_data) } } -/* We deferred reading of the cert until needed, as it may be - * a private object, so we must wait till login to read - */ +/* We deferred reading of the cert until needed, as it may be + * a private object, so we must wait till login to read */ static int -check_cert_data_read(struct pkcs15_fw_data *fw_data, - struct pkcs15_cert_object *cert) +check_cert_data_read(struct pkcs15_fw_data *fw_data, struct pkcs15_cert_object *cert) { int rv; struct pkcs15_pubkey_object *obj2; @@ -823,8 +822,8 @@ check_cert_data_read(struct pkcs15_fw_data *fw_data, if (cert->cert_data) return 0; - if ((rv = sc_pkcs15_read_certificate(fw_data->p15_card, - cert->cert_info, &cert->cert_data) < 0)) + rv = sc_pkcs15_read_certificate(fw_data->p15_card, cert->cert_info, &cert->cert_data); + if (rv < 0) return rv; /* update the related public key object */ @@ -3014,6 +3013,8 @@ pkcs15_cert_get_attribute(struct sc_pkcs11_session *session, void *object, CK_AT } +#define ASN1_SET_TAG (SC_ASN1_SET | SC_ASN1_TAG_CONSTRUCTED) +#define ASN1_SEQ_TAG (SC_ASN1_SEQUENCE | SC_ASN1_TAG_CONSTRUCTED) static int pkcs15_cert_cmp_attribute(struct sc_pkcs11_session *session, void *object, CK_ATTRIBUTE_PTR attr) @@ -3021,38 +3022,43 @@ pkcs15_cert_cmp_attribute(struct sc_pkcs11_session *session, struct pkcs15_cert_object *cert = (struct pkcs15_cert_object*) object; struct sc_pkcs11_card *p11card = session->slot->card; struct pkcs15_fw_data *fw_data = NULL; - unsigned char *data = NULL; - size_t len; + unsigned char *data = NULL, *_data = NULL; + size_t len, _len; fw_data = (struct pkcs15_fw_data *) p11card->fws_data[session->slot->fw_data_idx]; if (!fw_data) return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue"); switch (attr->type) { - /* Check the issuer. Some pkcs11 callers (i.e. netscape) will pass - * in the ASN.1 encoded SEQUENCE OF SET ... while OpenSC just - * keeps the SET in the issuer field. */ + /* Check the issuer/subject. Some pkcs11 callers (i.e. netscape) will pass + * in the ASN.1 encoded SEQUENCE OF SET, + * while OpenSC just keeps the SET in the issuer/subject field. */ case CKA_ISSUER: if (check_cert_data_read(fw_data, cert) != 0) break; if (cert->cert_data->issuer_len == 0) break; - data = (u8 *) attr->pValue; - len = attr->ulValueLen; - /* SEQUENCE is tag 0x30, SET is 0x31 - * I know this code is icky, but hey... this is netscape - * we're dealing with :-) */ - if (cert->cert_data->issuer[0] == 0x31 - && data[0] == 0x30 && len >= 2) { - /* skip the length byte(s) */ - len = (data[1] & 0x80)? (data[1] & 0x7F) : 0; - if (attr->ulValueLen < len + 2) - break; - data += len + 2; - len = attr->ulValueLen - len - 2; - } - if (len == cert->cert_data->issuer_len - && !memcmp(cert->cert_data->issuer, data, len)) + + data = _data = (u8 *) attr->pValue; + len = _len = attr->ulValueLen; + if (cert->cert_data->issuer[0] == ASN1_SET_TAG && data[0] == ASN1_SEQ_TAG && len >= 2) + data = sc_asn1_skip_tag(context, &_data, &_len, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, &len); + + if (len == cert->cert_data->issuer_len && !memcmp(cert->cert_data->issuer, data, len)) + return 1; + break; + case CKA_SUBJECT: + if (check_cert_data_read(fw_data, cert) != 0) + break; + if (cert->cert_data->subject_len == 0) + break; + + data = _data = (u8 *) attr->pValue; + len = _len = attr->ulValueLen; + if (cert->cert_data->subject[0] == ASN1_SET_TAG && data[0] == ASN1_SEQ_TAG && len >= 2) + data = sc_asn1_skip_tag(context, &_data, &_len, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, &len); + + if (len == cert->cert_data->subject_len && !memcmp(cert->cert_data->subject, data, len)) return 1; break; default: diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index dbc5b996..94041fd0 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -72,6 +72,8 @@ enum { OPT_TOKEN_LABEL, OPT_APPLICATION_LABEL, OPT_APPLICATION_ID, + OPT_ISSUER, + OPT_SUBJECT, OPT_SO_PIN, OPT_INIT_TOKEN, OPT_INIT_PIN, @@ -123,6 +125,8 @@ static const struct option options[] = { { "delete-object", 0, NULL, 'b' }, { "application-label", 1, NULL, OPT_APPLICATION_LABEL }, { "application-id", 1, NULL, OPT_APPLICATION_ID }, + { "issuer", 1, NULL, OPT_ISSUER }, + { "subject", 1, NULL, OPT_SUBJECT }, { "type", 1, NULL, 'y' }, { "id", 1, NULL, 'd' }, { "label", 1, NULL, 'a' }, @@ -178,6 +182,8 @@ static const char *option_help[] = { "Delete an object", "Specify the application label of the data object (use with --type data)", "Specify the application ID of the data object (use with --type data)", + "Specify the issuer in hexadecimal format (use with --type cert)", + "Specify the subject in hexadecimal format (use with --type cert/privkey/pubkey)", "Specify the type of object (e.g. cert, privkey, pubkey, data)", "Specify the ID of the object", "Specify the label of the object", @@ -225,6 +231,8 @@ static char * opt_puk = NULL; static char * opt_new_pin = NULL; static char * opt_application_label = NULL; static char * opt_application_id = NULL; +static char * opt_issuer = NULL; +static char * opt_subject = NULL; static char * opt_key_type = NULL; static int opt_is_private = 0; static int opt_test_hotplug = 0; @@ -548,6 +556,12 @@ int main(int argc, char * argv[]) case OPT_APPLICATION_ID: opt_application_id = optarg; break; + case OPT_ISSUER: + opt_issuer = optarg; + break; + case OPT_SUBJECT: + opt_subject = optarg; + break; case OPT_NEW_PIN: opt_new_pin = optarg; break; @@ -787,7 +801,8 @@ int main(int argc, char * argv[]) if (opt_object_class_str == NULL) util_fatal("You should specify type of the object to read"); if (opt_object_id_len == 0 && opt_object_label == NULL && - opt_application_label == NULL && opt_application_id == NULL) + opt_application_label == NULL && opt_application_id == NULL && + opt_issuer == NULL && opt_subject == NULL) util_fatal("You should specify at least one of the " "object ID, object label, application label or application ID\n"); read_object(session); @@ -2794,6 +2809,7 @@ static int read_object(CK_SESSION_HANDLE session) CK_ULONG len = 0; FILE *out; struct sc_object_id oid; + unsigned char subject[0x400], issuer[0x400]; if (opt_object_class_str != NULL) { FILL_ATTR(attrs[nn_attrs], CKA_CLASS, @@ -2826,6 +2842,24 @@ static int read_object(CK_SESSION_HANDLE session) nn_attrs++; } + if (opt_issuer != NULL) { + size_t sz = sizeof(issuer); + + if (sc_hex_to_bin(opt_issuer, issuer, &sz)) + util_fatal("Invalid 'issuer' hexadecimal value"); + FILL_ATTR(attrs[nn_attrs], CKA_ISSUER, issuer, sz); + nn_attrs++; + } + + if (opt_subject != NULL) { + size_t sz = sizeof(subject); + + if (sc_hex_to_bin(opt_subject, subject, &sz)) + util_fatal("Invalid 'subject' hexadecimal value"); + FILL_ATTR(attrs[nn_attrs], CKA_SUBJECT, subject, sz); + nn_attrs++; + } + rv = find_object_with_attributes(session, &obj, attrs, nn_attrs, 0); if (rv != CKR_OK) p11_fatal("find_object_with_attributes()", rv);