Question:
I’m attempting to work with an X509 certificate that was originally imported into the CurrentUser keystore on a Windows 10 computer using the “Certificates” snap-in of an MMC. The same procedure has been tested on a Windows 8.1 computer with the same result.
Using the standard PowerShell PKI module, I’m getting an X509Certificate2 object using Get-Item:
1 2 |
$my_cert = Get-Item Cert:\CurrentUser\My\ADAA82188A17THUMBPRINTXXXXXXXXXXX |
The output of $my_cert | fl *
is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
PSPath : Microsoft.PowerShell.Security\Certificate::CurrentUser\My\XXXXXXXXXXXXXXXXXXX PSParentPath : Microsoft.PowerShell.Security\Certificate::CurrentUser\My PSChildName : XXXXXXXXXXXXXXXXXXX PSDrive : Cert PSProvider : Microsoft.PowerShell.Security\Certificate PSIsContainer : False EnhancedKeyUsageList : {Secure Email (1.3.6.1.5.5.7.3.4), IP security user (1.3.6.1.5.5.7.3.7), Encrypting File System (1.3.6.1.4.1.311.10.3.4), Document Signing (1.3.6.1.4.1.311.10.3.12)...} DnsNameList : {My Name} SendAsTrustedIssuer : False EnrollmentPolicyEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty EnrollmentServerEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty PolicyId : {D52C406F-C279-4BF2-B7C2-EE704290DB3E} Archived : False Extensions : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid...} FriendlyName : IssuerName : System.Security.Cryptography.X509Certificates.X500DistinguishedName NotAfter : 4/15/2017 2:15:16 PM NotBefore : 4/15/2016 2:15:16 PM HasPrivateKey : True PrivateKey : PublicKey : System.Security.Cryptography.X509Certificates.PublicKey RawData : {56, 130, 19, 252...} SerialNumber : 4F0000002F700000000000000000000000 SubjectName : System.Security.Cryptography.X509Certificates.X500DistinguishedName SignatureAlgorithm : System.Security.Cryptography.Oid Thumbprint : XXXXXXXXXXXXXXXXXXX Version : 3 Handle : 2241663016272 Issuer : CN=Issuing CA, DC=My, DC=Domain, DC=us Subject : E=my.name@my.domain.us, CN=My Name |
So HasPrivateKey == True, but PrivateKey == null. I’ve been trying to figure out how to gain access to the private key to perform encryption and decryption. The examples I’ve seen online all seem to indicate the PrivateKey property of the X509Certificate2 class should be readily available, but apparently I’ve missed something.
I’ve read similar questions here, such as Empty PrivateKey in x509certificate2, but none seem to resolve my issue. I’ve also read Eight tips for working with X.509 certificates in .NET by Paul Stovell, which was very enlightening, but ultimately didn’t help. It did help me verify that the Private Key exists in the correct place and, as far as I can tell, with the correct permissions to be referenced by the x509Certificate2 class:
1 2 |
C:\Users\My.Name\AppData\Roaming\Microsoft\SystemCertificates\My\Keys |
The name of the key file matches to the Subject Key Identifier on the certificate.
Edit:
The output of certutil -user -store my "Serial Number"
is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Serial Number: 4f000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Issuer: CN=Issuing CA, DC=My, DC=Domain, DC=us NotBefore: 4/15/2016 2:15 PM NotAfter: 4/15/2017 2:15 PM Subject: E=my.name@my.domain.us, CN=My Name Non-root Certificate Template: Userv1, User v1 Cert Hash(sha1): ad ab 82 18 8a 17 4d 75 11 04 48 7c 43 43 d4 05 b9 74 c8 4c Key Container = te-Userv1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Unique container name: fcbba1aa0xxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Provider = Microsoft Software Key Storage Provider Encryption test passed CertUtil: -store command completed successfully. |
What “key” piece of information am I missing here? Why isn’t the private key conveniently referenced from the X509Certificate2 object? How do I gain access to it?
Answer:
This may indicate one of the following:
1) the private key is stored in the Key Storage Provider (rather than legacy crypto service provider) which is poorly supported by .NET and not supported by PrivateKey
property of X509Certificate2
class at all. You can check this by running the following command:
1 2 |
certutil -user -store my " |
2) the private key is missing.
HasPrivateKey
property doesn’t necessary reflect the actual picture and may True
for non-existent keys or False
for existing keys. Run the certutil command above to make sure if the key is presented.
In the case if private key is presented, but the bindings are broken, you can try to restore bindings by running the following command:
1 2 |
certutil -user -repairstore my " |