Problem with ENGINE_load_private_key and PKCS#11 - pkcs#11

Being stuck with signing (Authenticode) using PKCS#11 tokens, and given the amazingly poor driver support from the vendor (SafeNet), we're signing Windows code on Linux.
All of this is working fine using all of our tokens on several build servers. However, I have one token that fails, depending on the mechanism being used. From Java, using Jsign and the SunPKCS11 provider, everything works fine with this token.
However, from osslsigncode, signing fails with this token:
Unable to enumerate certificates
PKCS11_get_private_key returned NULL
Failed to load private key 9df65894eb084ba3140555614123992:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:eng_pkey.c:124:
Failed
The difference between the working token and the non-working token is that the non-working token includes not just the certificate, but also its trust chain:
# pkcs11-tool --module libeToken.so --list-objects
Using slot 0 with a present token (0x0)
Certificate Object, type = X.509 cert
label: te-69f298db-2f32-4a94-82ea-3e11829b26cd
ID: 9df65894eb084ba3
Certificate Object, type = X.509 cert
label:
Certificate Object, type = X.509 cert
label:
Using p11tool, the two empty-looking certs above show as:
Type: X.509 Certificate
Label:
Flags: CKA_CERTIFICATE_CATEGORY=CA;
ID:
My other tokens, all of which work fine, do not include these CA certs. This token was created recently, so it may be that either the token firmware is different from my others, or the token installation process has changed since I created the other, working tokens. The certificate is the same on all of them, working and non-working.
I've confirmed (via gdb) that the correct key ID is being passed into ENGINE_load_private_key.
I'm not sure who owns the ENGINE API in this case - is it a token driver issue? (SafeNet) Is it a problem with OpenSC? etc. It would be helpful to find some other tool that uses the API in the same way so I could confirm whether the problem somehow lies with osslsigncode (which isn't actively supported) or one of the lower layers in this tower of cards.
P.S. I used PKCS#11 Spy, and it shows enumeration of all of the certs in the chain, so it's finding the key pair (by ID), but then fails - no errors in PKCS#11 Spy - all CKR_OK.
P.P.S. To address the question of whether this token also has a private key...
Using slot 0 with a present token (0x0)
Logging in to "Code Signing Token 11".
Please enter User PIN:
Private Key Object; RSA
label:
ID: 9df65894eb084ba3
Usage: decrypt, sign, unwrap
Certificate Object, type = X.509 cert
label: te-69f298db-2f32-4a94-82ea-3e11829b26cd
ID: 9df65894eb084ba3
Certificate Object, type = X.509 cert
label:
Certificate Object, type = X.509 cert
label:

The solution, at least for now, seems to be just deleting the CA certs from the token (via SAC Tools on Windows). Once done, osslsigncode (via the PKCS#11 stack) has no problem finding the token. The CA certs aren't needed for signing, so deleting them presents no problem.

It seems that you did NOT login to the token. In pkcs11-tool, use --login --pin <your-pin-code> if you want to retrieve private objects.
It should be noted that the signing process needs an appropriate private key (not certificate).

Related

iOS Alamofire SSL Pinning with both certificate about to expire and a new certificate

My application implements SSLPining with leaf certificate. And it's about to expire.
I researched and got the answer:
Some time before the certificate expires, release a new version of your app with a replacement cert in the pin list, as well as the original cert
How can i add both replacement cert and original cert to my project?
I just need to add a new certificate with any name and Will Alamofire go through all the certificate files I declare and if any match will it allow the connection?
Thanks
Yes, that will work. Alamofire's PinnedCertificatesTrustEvaluator gathers all certificates from the main bundle by default and checks to see whether the certificate received is within that set. So as long as both certificates are within that set, either of them should work.

How to check if a digital signature token has signing and encryption

I have a dsc token, im aware that they can be only signing, or they can be signing and encryption. How do i check?
KeyUsageFlag for X509 certificate is a bitwise flag.
Please refer: X509KeyUsageFlags Enum
There can be a single certificate with both the flag set (addation of values for DigitalSignature and KeyEncipherment) i.e. 128 + 32 or two different certificates. This depends on how Certifying Authority choses to issue the certificate.
How do i check?
Method 1: You must have Smartcard or USB Token driver installed which pushesh Certificates in token to Windows Certificate Store on inserting the token. Then run certmgr.msc to open Certificate Manager; go to Personal Certificates, double click the required certificate to open the Certificate Details and check Key Usage property in Details tab. Values displayed here are in Hex. like: Digital Signature (80)
Method 2:
You may filter on key values and check as above.
Install Signer.Digital Browser Extension as described here
Once Extension is installed and available in the browser, open any site so that browser loads extension script and execute below commands from the console of the browser
SignerDigital.getSelectedCertificate("", 32) - to list only Encryption Certificates
SignerDigital.getSelectedCertificate("", 128) - to list only DigitalSignature Certificates.
Here 32 and 128 are X509KeyUsageFilter values as discussed above.

Is Self-Signed IdentityServer4 signing credential good enough in production?

We are using IdentityServer4 and our version loads the signing key from a PFX file in file system or from the windows certificate store. Using the certificate works. The question is - which certificate issuer should be used in production?
Is a certificate from a public CA recommended? Or is it enough to have a self-signed certificate (without a CA at all) such as it can be created with IIS Manager?
In our tests we have found that the client could still validate the signature in the access token, even if the signing certificate would not have a valid CA chain on the client.
In the docs, it says that you can also use raw key material instead of a certificate:
http://docs.identityserver.io/en/latest/topics/crypto.html#token-signing-and-validation
In this scenario there would be no CA chain whatsoever.
That leads me to the assumption, that when the client loads the public signing key (via the HTTP(s) endpoint), the CA chain information might not be passed anyways. Is that right? Through the loading mechanism via HTTPs you also have a combined security mechanism.
So my conclusion is that for the signing credential a self-signed cert is just as safe as one from VeriSign. Can this be confirmed?
There is no certificate involved in signing and verifying the tokens. Only a private and public key (RSA or ECDSA key).
However a certificate can be useful to "import/transport" the keys into .NET. So, because of that we don't care about who issued the certificate.
When importing the key, one approach is to bundle the certificate that holds the public key + the private key and store it in a PKCE#12 file (.pfx/.p12 extension). Then load that file into .NET. Before .NET 5 working with keys was a bit hard.
The more important thing is that you can manage and deploy the private key in a secure way and that it is persisted over time.
Optionally, you can add support for key-rotation.

ADFS Export Default Token Signing Certificate Private Key

How can I export the Token Signing Certificate that is created when ADFS 3.0 is installed? When I open up the certificate MMC, I am able to see the certificate however the message 'You have a private key that corresponds to this certificate' is missing and I am unable to export the private key. I read in the article ADFS deep dive: Certificate Planning that I can find it in Active Directory in the following container:
CN=ADFS,CN=Microsoft,CN=Program Data,DC=domain,DC=com
However, although I can get to that container, all I see is a GUID inside and do not know how to export the private key out of Active Directory.
How can I get the private key?
******************************************** EDIT ********************************************
In case anyone comes to this later, the certs are actually in the personal cert store of the ADFS service account but they are NOT exportable. You almost certainly want the SSL cert private key NOT the token signing cert private key. The documentation
I was following to set up ADFS for SharePoint was a little confusing. The private key had to exported for the SSL cert, however the thumbprint of the token signing cert had to be placed in the web config. I was incorrectly trying to export the private key of the token signing cert.
******************************************** EDIT ********************************************
You mean the self-signed ones you get with automatic rollover?
If so, where do you see these with mmc?
They are stored in a combination of an AD container and the ADFS DB.
So you can't export in the normal manner.
For a very good reason - security. If you have the private key you can send / hack anything and it will be accepted as coming from ADFS.
The public key is available in the metadata.
If you have to do this, turn off automatic rollover and use your own certificates.

When .net says "certificate valid", what is it checking?

I'm using the SignedXml.CheckSignature(X509Certificate2, boolean) method. I would like to know what checks are performed when deciding the validity of the certificate. I have verified that the Current User/Not Trusted list is checked. The documentation says it will use the "address book" store, searching by subject key identifier, to build the certificate chain. I imagine this means the Local Machine and Current User certificate stores?
Am I right to think that certificate revocation and signature timestamp are not checked? To do an OCSP check for certificate revocation, am I obliged to use Bouncy Castle?
In the remarks in the msdn article you link to one finds:
In version 1.1 of the .NET Framework, the X.509 certificate is not verified.
In version 2.0 and later, the X.509 certificate is verified.
In version 2.0 and later of the .NET Framework, the CheckSignature method will search the "AddressBook" store for certificates suitable for the verification. For example, if the certificate is referenced by a Subject Key Identifier (SKI), the CheckSignature method will select certificates with this SKI and try them one after another until it can verify the certificate.
Thus, first of all the behavior of that method has changed in different .NET framework versions. So for reproducible results, you had better not count on that method even check the certificate at all.
Furthermore, the formulation try them one after another until it can verify the certificate sounds like there just might be the mathematical test whether or not the certificate is signed by its alleged issuer.
https://referencesource.microsoft.com/#System.Security/system/security/cryptography/xml/signedxml.cs,b9518cc2212419a2
It checks
The certificate has no Key Usage extension, or the Key Usage extension has either Digital Signature or Non Repudiation usages enabled
The certificate chains up to a trusted root authority
The certificate has not been revoked
The certificate was not expired when you called this method
It doesn't know when the document was signed, so it doesn't answer that question.
That none of the certificates in the chain are explicitly prohibited by the user or system configuration.