Getting Information about an X509Certificate’s Key Container


One of the more common things a lot of people want to do with their X509Certificate2 is figure out what key container its keys are stored in.  You can access this information relatively trivially via the PublicKey property of the X509Certificate2 object:



/// <summary>
/// Get information about the key container a certificate is stored in
/// </summary>
public static CspKeyContainerInfo GetKeyConatinerInformation(X509Certificate2 certificate)
{
    if (certificate == null)
        throw new ArgumentNullException(“certificate”);

    ICspAsymmetricAlgorithm key = certificate.PublicKey.Key as ICspAsymmetricAlgorithm;
    if (key == null)
        throw new InvalidOperationException(“Unknown key type”);

    return key.CspKeyContainerInfo;
}

Here we get the ICspAsymmetricAlgorithm representing the key from the public key, which should work for both RSA and DSS certificates.  From there we can simply pull the CspKeyContainerInfo object and get basically anything we want to know about the key container.  Specifically, the KeyContainerName, KeyNumber, ProviderName, ProviderType, HardwareDevice, and Exportable properties tend to be the most interesting.


Note that this trick will not work with the PrivateKey property of the X509Certificate2, since the private key returned is actually a copy of the key associated with the certificate.

Comments (8)

  1. Rui Fiske says:

    **Apologies if this is not strictly related to your post, but it is related – honest!**

    I’ve been looking into the System.Security.Cryptography.X509Certificates namespace today to look at upgrading our existing 1.1 code to 2.0.

    Currently we have to use CAPICOM to manage our certificate validation. I remember getting quite excited about the new X509 libraries that were shipping with Whidbey, as they seemed to immensely simplify some of the processes.

    However, one thing I need to able to do is retrieve certificates from the Active Directory, where many of the certificates are stored.

    CAPICOM had an enumerated value for accessing the Active Directory store. However, the X509Store.StoreLocation Enumeration has only the Local (file-based) stores.

    Is this an oversight? By me, I mean?

    How am I supposed to retrieve a certificate from the Active Directory store with the new X509 APIs?

    Thanks for your attention. There are many interesting entries on this blog.

  2. shawnfa says:

    Hi Rui,

    How did you open an AD cert with CAPICOM?

  3. Rui Fiske says:

    Hi Shawn,

    Thanks for the response.

    I’m trying to find a certificate from the AD, by Issuer DN and Serial Number, which MUST be a unique combination. Not all certificates exist on the local user’s machine, of course.

    Here is the (1.1) code:

    <code>

    using CAPICOM;

    //create store

    store m_Store = new store();

    String subjectCN = "";

    m_Store.Open(CAPICOM_STORE_LOCATION.CAPICOM_ACTIVE_DIRECTORY_USER_STORE, subjectCN, CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_READ_ONLY);

    //Get all the certificates from the store

    Certificates MatchingCerts = m_Store.Certificates;

    //Find those with matching Issuer

    MatchingCerts = MatchingCerts.Find(CAPICOM_CERTIFICATE_FIND_TYPE.CAPICOM_CERTIFICATE_FIND_ISSUER_NAME, IssuerCN, False);

    //then iterate through the certificates to find the matching certificate.

    </code>

    Although this is not the most efficient way to do it, it seemed the most obvious way in .NET 1.1 (though COM really!)

    Which brings me on to my point:

    CAPICOM had 5 (five) enumerated values for StoreLocation:

    CAPICOM_ACTIVE_DIRECTORY_USER_STORE

    CAPICOM_CURRENT_USER_STORE

    CAPICOM_LOCAL_MACHINE_STORE

    CAPICOM_MEMORY_STORE

    CAPICOM_SMART_CARD_USER_STORE

    However, the X509Store in System.Security.Cryptography.X509Certificates has only 2 (two) enumerated values:

    CurrentUser

    LocalMachine

    Is this by design? Am I missing something?

    Surely in enterprise architecture, it is better to have the certificates managed by the AD, rather than having to push them to individual clients. It means also that a new certificate issued by the (Windows) CA is automatically available to all users, as it is published to the AD.

    As a side note, it would be possible to use LDAP to retrieve the certificates, but it would be far simpler if the new CryptoAPI libraries would do it for me!

    Any help or guidance on this topic would be much appreciated.

  4. shawnfa says:

    CAPICOM is actually doing some AD stuff itself it looks like, and is not exposing a feature of the native X509 APIs.  Since the X509Certificate2 class is a wrapper over the native APIs and not CAPICOM, there’s unfortunately no solution for your problem in the current runtime.

    However, if you would like us to consider it for inclusion into a future framework, please file it in the MSDN Product Feedback Center.

    Sorry that I don’t have better news for you 🙁

    -Shawn

  5. Harris says:

    Shawn,

    Great post!  I have a similar need, but I’m on .NET 1.1; here’s what I’d like to accomplish:

    Is there a way to determine if a cert came from hardware or software?  Specifically, I’m interested in knowing if the cert came from the operating system or if it came off a more secure device, such as a smart card.  Is this possible?

    Oh…there’s a bit of a catch…The cert’s coming over the HTTPS and into ASP.NET.  I’m hoping that the cert may/not have that information that can be retrieved via the GetRawData() method and can be processed by the CAPICOM and other crypto APIs.

    I appreciate any insight you can provide.

    Thanks,

    H

  6. shawnfa says:

    So you want to find out if the server side certificate was pulled from a hardware device?  The certificate is unlikely to have that information in it if its coming over the wire.

    -Shawn

  7. Harris says:

    Shawn,

    Thanks for your reply.  I tried the code you provided above, adapted slightly to read-in the raw bytes from the HttpClientCertificate object, and found the HardwareDevice property to be, in fact, FALSE.

    After thinking about this, and reviewing the other data returned by the CspKeyContainerInfo object, it actually makes sense: how would the server receive information about the CSP Key Container over HTTP[S]?  Moreover, that would seem like it could expose some rather sensitive information…

    Also, a rather interesting find, I discovered that the KeyContainerName property returned a container named "CLR{GUID}"…Any light you can shed on what’s going on under the covers there?

    Always appreciated,

    H