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

Reply via email to