How can I get the name of a Key Container that's in a smart card required for initialization of CspParameters?

CspParameters^ cspa = gcnew CspParameters(ProviderType, ProviderName, keyContainerName, cryptoSecurityKey, securityString);

RSACryptoServiceProvider^ csp = gcnew RSACryptoServiceProvider(cspa);

Since certificates from smart cards are automatically installed in a personal certificate store, I have tried looking for keyContainerName in X509Certificate2 and I couldn't find it there.

I have managed to find a container name of one of the keys outside of C++ using certutils.exe, and that way, I just entered that name and I managed to generate a digital signature using the aforementioned RSACryptoServiceProvider. It works beautifully. What can do I do with other certificates that the software might be used with? I can't ask the users to enter container name manually.

But, from what I understand, if I don't provide the container name (leave it empty), it doesn't work. So I need a way to find/get a key container name for any certificate in any smart card within the program code.

Unfortunately, most examples I've seen on the internet provide a constant predefined container name (like "example" or "test" - like here https://secpal.codeplex.com/discussions/13106 ), which is useless in real life.

migrated from crypto.stackexchange.com Feb 26 '15 at 12:43

This question came from our site for software developers, mathematicians and others interested in cryptography.


Is this what you're looking for? (sorry for messy code, I'm a Java guy thrown into VC++ code)

    DWORD status;

    if (FALSE == CryptAcquireContext(
        status = GetLastError();
    } else {
        PBYTE pbData = (PBYTE)Alloc(256);  // formally, you should check the max size
        DWORD tmp = 256;
        PDWORD pdwDataLen = &tmp;
        status = 0;
        bool is_first = TRUE;
        // PP_ENUMCONTAINERS does an enumeration over all containers available to the MS_SCARD_PROV crypto provider 
        // (which should be just all containers on the smartcard in case of single smartcard and single reader)
        while (status == 0) {
            if (FALSE == CryptGetProvParam(hProv, PP_ENUMCONTAINERS, pbData, pdwDataLen, (is_first ? CRYPT_FIRST : CRYPT_NEXT)))
                status = GetLastError();

            OutputDebugStringA((LPSTR)pbData); // or std::cout in a console application
            is_first = FALSE;

You'll have to know something about the certificate in question... subject name or issuer for example, get a handle on the X509Certificate2 object. From there, you can obtain the unique container name, generally located in C:\ProgramData\Microsoft\crypto\RSA\MachineKeys.

This is for c#, but can be adapted for C++ easily enough.

                RSACryptoServiceProvider rsa = cert.PrivateKey as RSACryptoServiceProvider;

                if (rsa != null)
                    string keyfilepath = FindKeyLocation(rsa.CspKeyContainerInfo.UniqueKeyContainerName);

                    string fullPrivateKeyPath = (keyfilepath + "\\" + rsa.CspKeyContainerInfo.UniqueKeyContainerName);

                    //Inform the user of the specific privatekey path.
            catch (Exception ex)
                Console.WriteLine("Exception occurred while trying to decrypt rsa key and find locaiton in file system:" + ex);

To get a handle, i generally search by subject name (if a known name):

X509Certificate2Collection CACerts = castore.Certificates.Find(X509FindType.FindBySubjectName, "Test-Certificate-Authority", true);
                        if (CACerts.Count <= 0)
                            MessageBox.Show("No existing Certificate Authority was found on this machine. Please either import one or select 'no' to generate a new one.");
                        ca2 = CACerts[0];

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy