pkcs11: #439: 'SEQUENCE' of 'SET' issue when comparing cert attributes

Thanks to 'crank'.
https://www.opensc-project.org/opensc/ticket/439

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.
This commit is contained in:
Viktor Tarasov 2012-08-15 19:59:09 +02:00
parent 16b4cb6a3f
commit dfbc3996bf
2 changed files with 69 additions and 29 deletions

View File

@ -20,6 +20,7 @@
#include "config.h"
#include "libopensc/log.h"
#include "libopensc/asn1.h"
#include <stdlib.h>
#include <string.h>
@ -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:

View File

@ -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);