none
How to determine whether an X509Certificate2 is exportable RRS feed

  • Question

  • I've studied the X509Certificate and X509Certificate2 .Net documentation and can't see how to determine whether a private key is exportable. I looked for a property or method that would work with X509KeyStorageFlags (used when you create one, I know) but couldn't find anything.

    Can anyone tell me how to do this in a .net program using a framework class?

    Thanks.

    wip

    Sunday, January 22, 2012 5:30 PM

Answers

  • I'm not so familiar with the .net classes; but you could try to call the Export() method using Pkcs12 on the X509Certificate2 class. If it fails then I guess that means it is not exportable with the private key.  This could happen if the private key is not exportable, or not there, or some other error. The one downside I can think of about this is that it is possible the csp/ksp will pop up ui when accessing the private key. I don't think the Export() method allows you to say that you want a silent export.

    Andrew

    • Marked as answer by wcfWIP Monday, January 23, 2012 6:46 PM
    Monday, January 23, 2012 5:19 AM
  • Here is a possible approach:

    X509Certificate2.PrivateKey                Gets the AsymmetricAlgorithm object that represents the private key associated with a certificate.

    The RSACryptoServiceProvider class is a AsymmetricAlgorithm

    Then get the RSACryptoServiceProvider.CspKeyContainerInfo  which is a   CspKeyContainerInfo object that has a

    Exportable

    property that:   Gets a value indicating whether a key can be exported from a key container.

    • Marked as answer by wcfWIP Monday, January 23, 2012 6:46 PM
    Monday, January 23, 2012 3:11 PM

All replies

  • I'm not so familiar with the .net classes; but you could try to call the Export() method using Pkcs12 on the X509Certificate2 class. If it fails then I guess that means it is not exportable with the private key.  This could happen if the private key is not exportable, or not there, or some other error. The one downside I can think of about this is that it is possible the csp/ksp will pop up ui when accessing the private key. I don't think the Export() method allows you to say that you want a silent export.

    Andrew

    • Marked as answer by wcfWIP Monday, January 23, 2012 6:46 PM
    Monday, January 23, 2012 5:19 AM
  • Here is a possible approach:

    X509Certificate2.PrivateKey                Gets the AsymmetricAlgorithm object that represents the private key associated with a certificate.

    The RSACryptoServiceProvider class is a AsymmetricAlgorithm

    Then get the RSACryptoServiceProvider.CspKeyContainerInfo  which is a   CspKeyContainerInfo object that has a

    Exportable

    property that:   Gets a value indicating whether a key can be exported from a key container.

    • Marked as answer by wcfWIP Monday, January 23, 2012 6:46 PM
    Monday, January 23, 2012 3:11 PM
  • Thanks for the suggestion Andrew. I bet that solution would work, although it may not be appropriate for the situation I'm in.

    What are the odds of getting two replies from two Andrews? Andrew7Webb suggests another approach that might be what I'm looking for.

    Thanks again.

    Monday, January 23, 2012 6:43 PM
  • Got it in one - thanks very much. I was probing around AsymmetricAlgorithm but gave up too easily.

     

    You da man.

    Monday, January 23, 2012 6:45 PM
  • Again, I'm not familiar with the .net api. But how do you know your AsymmetricAlgorithm will be for an rsa key? Isn't there also dsa? ecdsa? ecdh? or something else?

    Andrew

    Tuesday, January 24, 2012 4:00 AM
  • I guess I won't take the rest of the week off after all. Rats.

    You may not be familiar with the .Net api but you seem more than a little familiar with the win32 crypto api. And I take your point about the AsymmetricAlgorithm object being other than an RSACryptoProvider; of course I don't know what the AsymmetricAlgorithm implementation will be.

    I went back and re-read your first post and then took a look at the MSDN documentation. I came across an entry that says

    "Classes that extend the AsymmetricAlgorithm class should implement the ICspAsymmetricAlgorithm interface to enumerate key container information using a CspKeyContainerInfo object, and to import and export Microsoft Cryptographic API (CAPI)–compatible key blobs."

    I'm not sure what happens if you ask it for a private key - whether it silently fails and returns a byte array with a zero length or maybe partially filled in. Hopefully there's some way to answer the question about exporting the private key base on the contents of the array. And I'll need to cruft up a series of objects that implement the other providers and check it on them.

    The entry for ExportCspBlob() doesn't mention an exception so perhaps it won't display a dialog box either. I looked at this late last night and seem to remember a call on one interface or another that you can make to tell the object not to display a UI during its lifetime; this morning I couldn't find it. Maybe it was a dream.

    Anyway, kudos to you and thanks for following up. I'll look into X509Certificate(2)::Export and ICspAsymmetricAlgorithm::ExportCspBlob.

    wip

    ps

    Calling X509Certificate(2)::Export on an RSACryptotoServiceProvider that doesn't export its private key results in the same exception as calling ICspAsymmetricAlgorithm.ExportCspBlob, where you're indicating they should export the private key.  The HRESULT and message is 0x8009000B: Key not valid for use in specified state.

    I didn't receive a dialog box in either case.

     

    • Edited by wcfWIP Tuesday, January 24, 2012 11:28 PM
    Tuesday, January 24, 2012 10:41 PM
  • Here is one way to get the "dialog" box to come up when you are exporting the key.

    You will need to create a key that requires "strong protection". Either high or medium level will do. You can do this using certreq by using the following inf file:

    [NewRequest]
        Subject = "CN=Test"
        Exportable = true
        KeySpec = AT_KEYEXCHANGE
        ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0"
        RequestType =Cert
        KeyProtection = NCRYPT_UI_FORCE_HIGH_PROTECTION_FLAG

    And then running certreq -new <inf file> out.cer

    This will create a cert/key for you where the key is protected by UI. Now, try to export that key and you should always have a pop-up.

    I think if you set up the requirements such that you only accept rsa/dsa keys that are not ui protected then you can limit the scope of this problem and stick with the RSACryptoServiceProvider and the DSACryptoServiceProvider.

    Andrew

     

    Andrew

    Tuesday, January 24, 2012 11:51 PM
  • I'll give this a try. It appears this is accessible programmatically through the CNG library only - the older crypto api doesn't give you access to it.

     

    Thanks for pointing this out, Andrew.

     

    wip

    Wednesday, January 25, 2012 6:42 PM
  • "But how do you know your AsymmetricAlgorithm will be for an rsa key? Isn't there also dsa? ecdsa? ecdh? or something else?"

    The answer is ICspAsymmetricAlgorithm .

    MSDN: "Classes that extend the AsymmetricAlgorithm class should implement the ICspAsymmetricAlgorithm interface to enumerate key container information using a CspKeyContainerInfo object, and to import and export Microsoft Cryptographic API (CAPI)–compatible key blobs."

    and

    MSDN: AsymmetricAlgorithm "...Represents the abstract base class from which all implementations of asymmetric algorithms must inherit..."

    My mistake was in using the AsymmetricAlgorithm rather than ICspAsymmetricAlgorithm. Things work pretty well, at least with 3.5sp1 and the latest codeplex CLR security release.

    I did learn a few interesting things while down in the rabbit hole. I tried out your Strong encryption and found that if you cancel the dialog box when exporting from the Windows store it exports the certificate sans the private key (I think - you get a byte array but fewer bytes. I believe I tried re-importing it but am not certain.) It acts a little differently if you create the certificate using AD Cert Server but I"m not sure why.

    I'd love to find a way to prevent the popup.  It's not necessary for what I'm trying to do and things would work more smoothly.

    I had one bad actor - a certificate in LocalMachine personal that gave me this error when I used ICspAsymmetricAlgorithm:

    The requested key container was not found 0x80131430 at System.Security.Cryptography.CspKeyContainerInfo.get_Exportable()

    The certificate looks like this:

    Crypto API
    Microsoft Enhanced Cryptographic Provider v1.0
    RSACryptoServiceProvider

    Similar certificates in the same store worked fine with it. However the certificate Export() method worked fine so there you go. I'd recommend people use the interface first because the Export method throws exceptions which, as you pointed out - may be caused by a private key that can't be exported or maybe something else.

    Thanks Andrew.

    wip

     

    Friday, January 27, 2012 10:40 PM