David, Responses inline.
----- Original Message ----- > It certainly makes sense to add a new function which can locate objects > *purely* by their PKCS#11 URI. And if I can spend a little time trying > to properly understand the reasons you currently eschew > PK11_FindCertsFromNickname(), perhaps we can make sure that > PK11_FindCertsFromUri() doesn't have the same problems for you. The problem really stems from the design of NSS, specifically the CERTCertificate*, which maps to a unique DER encoded cert, but not to a single PKCS#11 object in a single token. Since the same cert can exist in multiple tokens, but there can only be one CERTCertificate* pointer for all of them, the only way to resolve the issue would be for the lookup function to return something other than just CERTCertificate* alone. PK11_ListCerts does that. > Some applications use PK11_FindCertFromNickname, and others don't. > The API call is really treacherous in what it does, and the results are > really not well-defined in ambiguous cases - for example, if a cert and > key exists in multiple tokens. >Hm, purely for finding the *cert*, why doesn't the token: prefix >resolve that? The token: prefix is only used as a starting point for the lookup. But if the same DER cert exists in multiple tokens, then the value of CERTCertificate->slot pointer is unpredictable. It may or may not match what was used during the lookup. Same issue for the nickname field. >Hm. I see you making an explicit attempt to find a private key in the >*same* token that the cert came from, and I understand the need for >that. What I'm missing though, is the reason you can't use >PK11_FindCertsFromNickname() to find the *cert*. I'm missing the >difference in behaviour that your servnss_get_cert_from_nickname() has. The difference that servnss_get_cert_from_nickname has is that it uses PK11_ListCerts, and checks the nickname against the certlist's entry's appData field. PK11_FindsCertsFromNickname doesn't work the same way. Also, the optional arguments to servnss_get_cert_from_nickname let it determine whether to search for user certs or non-user certs, and whether to pass in a pre-existing cert list or not, as PK11_ListCerts is an expensive call. Even if the cert lookup function ultimately returns a CERTCertificate in this case, you still need to find the corresponding key. It's possible for the cert and key to live in different tokens. That wouldn't be the intended usage, so we forbid it. If you use PK11_FindKeyByCert Basically, what it comes down to, is that if you use the following sequence : cert = PK11_FindCertFromNickname("token:subject") key PK11_FindKeyByCert(cert); Your cert and key may not match the "token" in the original lookup string. cert->slot and key->slot may not match. And both of these slots could differ from the PK11SlotInfo that matches the "token" of the original lookup. The goal of the code I wrote was to ensure that the cert and key in the intended device were used, even when multiple copies existed. Even if you use the alternate sequence : cert = PK11_FindCertFromNickname("token:subject") slot = cert->slot key PK11_FindKeyByCertInSlot(cert, cert->slot); It's no better, since cert->slot may not match "token". The code I wrote properly allows, for example the use of multiple HSMs or SSL accelerators from different vendors within one process, for different virtual servers, in combination with the softoken. It may be convoluted, but this was actually tested. I believe the code is also used as part of the admin UI that manages among other things, trust flags for certs. Ultimately, when you are searching for a user cert, usually you want to locate the private key at the same time. It makes sense to combine the lookup for both. Some generic (non-PKCS#11 specific) lookup function to uniquely identify a cert and key could look like : bool FindCertAndKey(Cert** outCert, Key** outKey, const char* reqdSubject, const char* optionalIssuer, const char* optionalSerial); And if you want to make it PKCS#11 specific, add some sort of identifier for the module and/or token. >(Well, there's the TPM, and GnuTLS has a 'tpm:…' identifier string >which references objects there. And TPM really *doesn't* fit well into >the PKCS#11 model. So yeah, perhaps I might one day find myself trying >to standardise a 'TPM URI' and ensure that it's supported consistently. >But that day isn't imminent :) I plead ignorance with TPMs. Is there a technical reasons why you couldn't manipulate TPM objects as PKCS#11 objects ? >The scope of what I'm doing here, across GnuTLS, OpenSSL and NSS, is >"where objects are identified in a PKCS#11 store, they can be >identified by a RFC7512 identifier string instead of just some random >home-grown application-specific or crypto-library-specific form." I'm pretty sure the PKCS#11 support in OpenSSL is optional, and many apps don't use it. NSS is the one that stands out in terms of requiring it - something that wasn't always true. In a world where many vendors no longer provide PKCS#11 libraries for their devices, the value of PKCS#11 has diminished. And of course, there are other kinds of keystores like JKS, etc. Julien -- dev-tech-crypto mailing list dev-tech-crypto@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-tech-crypto