3

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.

2 Answers 2

0

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

    HCRYPTPROV hProv = NULL;
    DWORD status;

    if (FALSE == CryptAcquireContext(
        &hProv, 
        NULL, 
        MS_SCARD_PROV, 
        PROV_RSA_FULL, 
        CRYPT_MACHINE_KEYSET | CRYPT_SILENT)
    ){
        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();
                //__leave;
            }

            OutputDebugStringA((LPSTR)pbData); // or std::cout in a console application
            OutputDebugStringA("\n");
            is_first = FALSE;
        }
    }
-1

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.

            try
            {
                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.
                    Console.WriteLine(fullPrivateKeyPath);
                }
            }
            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.");
                            return;
                        }
                        ca2 = CACerts[0];

You must log in to answer this question.