The logic in the current PKCS#11 library could not handle more advanced cards where it would incorrectly group objects into slots. This patch fixes two such issues:
- A key pair can be used for multiple certificates, but a certificate can never use more than one key pair. Unfortunately the code was designed for the completely opposite scenario (most likely out of convenience). I.e. the code would only put the first certificate it found together with its private key. Any later certificates with the same key would end up in the wrong slot. - Some PKCS#15 object have an auth_id even though they are not private. The current code always uses the auth_id though, which can result in incorrect grouping. The code removes the connection priv_key->cert and sets up cert->priv_key instead. The pkcs15_prkey_get_attribute() routine needs access to one of the associated certs though, but the new code iterates rather than maintaining the priv_key->cert link as keeping the link could trick people into reintroducing some of the buggy behaviour. --- =================================================================== --- src/pkcs11/framework-pkcs15.c (revision 18006) +++ src/pkcs11/framework-pkcs15.c (working copy) @@ -82,6 +82,7 @@ #define cert_p15obj base.p15_object #define cert_pubkey base.related_pubkey #define cert_issuer base.related_cert +#define cert_prvkey base.related_privkey struct pkcs15_prkey_object { struct pkcs15_any_object base; @@ -91,7 +92,6 @@ #define prv_flags base.base.flags #define prv_p15obj base.p15_object #define prv_pubkey base.related_pubkey -#define prv_cert base.related_cert #define prv_next base.related_privkey struct pkcs15_pubkey_object { @@ -102,7 +102,7 @@ }; #define pub_flags base.base.flags #define pub_p15obj base.p15_object -#define pub_cert base.related_cert +#define pub_genfrom base.related_cert #define __p15_type(obj) (((obj) && (obj)->p15_object)? ((obj)->p15_object->type) : (unsigned int)-1) #define is_privkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PRKEY_RSA) @@ -343,7 +343,7 @@ } else obj2->pub_data = NULL; /* will copy from cert when cert is read */ - obj2->pub_cert = object; + obj2->pub_genfrom = object; object->cert_pubkey = obj2; if (cert_object != NULL) @@ -481,18 +481,12 @@ *pp = (struct pkcs15_prkey_object *) obj; } } else - if (is_cert(obj) && !pk->prv_cert) { - struct pkcs15_cert_object *cert; - - cert = (struct pkcs15_cert_object *) obj; - if (sc_pkcs15_compare_id(&cert->cert_info->id, id)) - pk->prv_cert = cert; - } else if (is_pubkey(obj) && !pk->prv_pubkey) { struct pkcs15_pubkey_object *pubkey; pubkey = (struct pkcs15_pubkey_object *) obj; if (sc_pkcs15_compare_id(&pubkey->pub_info->id, id)) { + sc_debug(context, "Associating object %d as public key", i); pk->prv_pubkey = pubkey; if (pk->prv_info->modulus_length == 0) pk->prv_info->modulus_length = pubkey->pub_info->modulus_length; @@ -504,25 +498,37 @@ static void __pkcs15_cert_bind_related(struct pkcs15_fw_data *fw_data, struct pkcs15_cert_object *cert) { - struct sc_pkcs15_cert *c1 = cert->cert_data, *c2; + struct sc_pkcs15_cert *c1 = cert->cert_data; + sc_pkcs15_id_t *id = &cert->cert_info->id; unsigned int i; - /* Loop over all certificates see if we find the certificate of - * the issuer */ + /* Loop over all objects to see if we find the certificate of + * the issuer and the associated private key */ for (i = 0; i < fw_data->num_objects; i++) { struct pkcs15_any_object *obj = fw_data->objects[i]; - if (!is_cert(obj) || obj == (struct pkcs15_any_object *) cert) - continue; + if (is_cert(obj) && obj != (struct pkcs15_any_object *) cert) { + struct sc_pkcs15_cert *c2; - c2 = ((struct pkcs15_cert_object *) obj)->cert_data; + c2 = ((struct pkcs15_cert_object *) obj)->cert_data; - if (!c1 || !c2 || !c1->issuer_len || !c2->subject_len) - continue; - if (c1->issuer_len == c2->subject_len - && !memcmp(c1->issuer, c2->subject, c1->issuer_len)) { - cert->cert_issuer = (struct pkcs15_cert_object *) obj; - return; + if (!c1 || !c2 || !c1->issuer_len || !c2->subject_len) + continue; + if (c1->issuer_len == c2->subject_len + && !memcmp(c1->issuer, c2->subject, c1->issuer_len)) { + sc_debug(context, "Associating object %d as issuer", i); + cert->cert_issuer = (struct pkcs15_cert_object *) obj; + return; + } + } else + if (is_privkey(obj) && !cert->cert_prvkey) { + struct pkcs15_prkey_object *pk; + + pk = (struct pkcs15_prkey_object *) obj; + if (sc_pkcs15_compare_id(&pk->prv_info->id, id)) { + sc_debug(context, "Associating object %d as private key", i); + cert->cert_prvkey = pk; + } } } } @@ -540,6 +546,9 @@ if (obj->base.flags & SC_PKCS11_OBJECT_HIDDEN) continue; + + sc_debug(context, "Looking for objects related to object %d", i); + if (is_privkey(obj)) { __pkcs15_prkey_bind_related(fw_data, (struct pkcs15_prkey_object *) obj); } else if (is_cert(obj)) { @@ -606,6 +615,9 @@ struct pkcs15_any_object *obj, CK_OBJECT_HANDLE_PTR pHandle) { + int i; + struct pkcs15_fw_data *card_fw_data; + if (obj == NULL || (obj->base.flags & (SC_PKCS11_OBJECT_HIDDEN | SC_PKCS11_OBJECT_RECURS))) return; @@ -630,9 +642,22 @@ switch (__p15_type(obj)) { case SC_PKCS15_TYPE_PRKEY_RSA: - if (obj->related_cert == NULL) - pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL); - pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_cert, NULL); + pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL); + card_fw_data = (struct pkcs15_fw_data *) slot->card->fw_data; + for (i = 0; i < card_fw_data->num_objects; i++) { + struct pkcs15_any_object *obj2 = card_fw_data->objects[i]; + struct pkcs15_cert_object *cert; + + if (!is_cert(obj2)) + continue; + + cert = (struct pkcs15_cert_object*) obj2; + + if (cert->cert_prvkey != obj) + continue; + + pkcs15_add_object(slot, obj2, NULL); + } break; case SC_PKCS15_TYPE_CERT_X509: pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_pubkey, NULL); @@ -788,10 +813,15 @@ for (j=0; j < fw_data->num_objects; j++) { struct pkcs15_any_object *obj = fw_data->objects[j]; + /* "Fake" objects we've generated */ if (__p15_type(obj) == (unsigned int)-1) continue; - else if (!sc_pkcs15_compare_id(&pin_info->auth_id, &obj->p15_object->auth_id)) + /* Some objects have an auth_id even though they are + * not private. Just ignore those... */ + if (!(obj->p15_object->flags & SC_PKCS15_CO_FLAG_PRIVATE)) continue; + if (!sc_pkcs15_compare_id(&pin_info->auth_id, &obj->p15_object->auth_id)) + continue; if (is_privkey(obj)) { sc_debug(context, "Adding private key %d to PIN %d\n", j, i); @@ -1924,25 +1954,43 @@ unsigned int usage; size_t len; - /* will use modulus from cert, or pubkey if possible */ - if (prkey->prv_cert && prkey->prv_cert->cert_pubkey) { - /* make sure we have read the cert to get modulus etc but only if needed. */ - switch(attr->type) { - case CKA_MODULUS: - case CKA_PUBLIC_EXPONENT: - case CKA_MODULUS_BITS: - if (check_cert_data_read(fw_data, prkey->prv_cert) != 0) { - /* no cert found, maybe we have a pub_key */ - if (prkey->prv_pubkey && prkey->prv_pubkey->pub_data) - key = prkey->prv_pubkey->pub_data; /* may be NULL */ - } else - key = prkey->prv_cert->cert_pubkey->pub_data; - break; - default: - key = prkey->prv_cert->cert_pubkey->pub_data; + /* PKCS#11 requires us to supply CKA_MODULUS for private keys, + * although that is not generally available from a smart card + * (the key is supposed to be safely locked away after all). + * + * To work around this, we hope that we either have an associated + * public key, or we try to find a certificate with the + * corresponding public key. + * + * Note: We do the same thing for CKA_PUBLIC_EXPONENT as some + * applications assume they can get that from the private + * key, something PKCS#11 doesn't guarantee. + */ + if ((attr->type == CKA_MODULUS) || (attr->type == CKA_PUBLIC_EXPONENT)) { + /* First see if we have a associated public key */ + if (prkey->prv_pubkey) + key = prkey->prv_pubkey->pub_data; + else { + /* Try to find a certificate with the public key */ + unsigned int i; + + for (i = 0; i < fw_data->num_objects; i++) { + struct pkcs15_any_object *obj = fw_data->objects[i]; + struct pkcs15_cert_object *cert; + + if (!is_cert(obj)) + continue; + + cert = (struct pkcs15_cert_object*) obj; + + if (cert->cert_prvkey != prkey) + continue; + + if (check_cert_data_read(fw_data, cert) == 0) + key = cert->cert_pubkey->pub_data; + } } - } else if (prkey->prv_pubkey) - key = prkey->prv_pubkey->pub_data; + } switch (attr->type) { case CKA_CLASS: @@ -2259,7 +2307,7 @@ CK_ATTRIBUTE_PTR attr) { struct pkcs15_pubkey_object *pubkey = (struct pkcs15_pubkey_object*) object; - struct pkcs15_cert_object *cert = pubkey->pub_cert; + struct pkcs15_cert_object *cert = pubkey->pub_genfrom; struct pkcs15_fw_data *fw_data = (struct pkcs15_fw_data *) session->slot->card->fw_data; size_t len; Rgds -- Pierre Ossman OpenSource-based Thin Client Technology System Developer Telephone: +46-13-21 46 00 Cendio AB Web: http://www.cendio.com
signature.asc
Description: PGP signature
_______________________________________________ opensc-devel mailing list opensc-devel@lists.opensc-project.org http://www.opensc-project.org/mailman/listinfo/opensc-devel