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

Attachment: signature.asc
Description: PGP signature

_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to