Ken
If you already have a CSP, you can easily write a certificate store provider
that gets called when "MY" store is opened. You can then add the
certificate in the smartcard/token in the store that is given to you by the
callback function. You also have to set the private key for an application
to call CryptAcquireContext on your CSP.
The following code is a skeleton for implementing a quick and dirty cert
store provider. Add your code to CertDllOpenStoreProv. You want to add
your certificate to the hCertStore that is passed to you and set the private
key information on the certificate context.
thanks
Carlos
#include <windows.h>
#include <WinCrypt.h>
#include <objbase.h>
#include <stdio.h>
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpRes)
{
return TRUE;
}
BOOL WINAPI CertDllOpenStoreProv(
IN LPCSTR lpszStoreProvider,
IN DWORD dwEncodingType,
IN HCRYPTPROV hCryptProv,
IN DWORD dwFlags,
IN const void *pvPara,
IN HCERTSTORE hCertStore,
IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
)
{
// Add your certificate to hCertStore and application
// will see it everytime someone opens "MY" store
// To associate a private key (CSP) call
// CertSetCertificateContextProperty with
// CERT_KEY_PROV_INFO_PROP_ID
return TRUE;
}
STDAPI DllRegisterServer(void)
{
BOOL fResult;
CHAR szError[256];
MessageBox(NULL, "Calling CryptRegisterOIDFunction", "", MB_OK);
fResult = CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC,
"MyProvider", L"MyCertOpenStore.dll",
CRYPT_OID_OPEN_STORE_PROV_FUNC);
if (!fResult)
{
wsprintf(szError, "CryptRegisterOIDFunction failed with %x",
GetLastError());
MessageBox(NULL, szError, "Failure", MB_OK);
return E_FAIL;
}
else
{
CERT_PHYSICAL_STORE_INFO PhysicalStore;
ZeroMemory(&PhysicalStore, sizeof(PhysicalStore));
PhysicalStore.cbSize = sizeof(PhysicalStore);
PhysicalStore.pszOpenStoreProvider = "MyProvider";
PhysicalStore.dwFlags = CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG;
PhysicalStore.dwFlags |= CERT_PHYSICAL_STORE_REMOTE_OPEN_DISABLE_FLAG;
fResult = CertRegisterPhysicalStore(L"MY",
CERT_STORE_CREATE_NEW_FLAG|CERT_SYSTEM_STORE_CURRENT_USER,
L"MyStore",
&PhysicalStore,
NULL);
if (!fResult)
{
wsprintf(szError, "CertRegisterPhysicalStore failed with %x",
GetLastError());
MessageBox(NULL, szError, "Failure", MB_OK);
return E_FAIL;
}
else
{
MessageBox(NULL, "Registration succeeded!", "Success", MB_OK);
return S_OK;
}
}
}
// The DllUnregisterServer Entry Point
STDAPI DllUnregisterServer(void)
{
HRESULT hr = S_OK;
BOOL fResult;
CHAR szError[256];
fResult = CertUnregisterPhysicalStore(L"MY",
CERT_STORE_DELETE_FLAG|CERT_SYSTEM_STORE_CURRENT_USER,
L"MyStore");
if (!fResult)
{
wsprintf(szError, "CertUnregisterPhysicalStore failed with %x",
GetLastError());
MessageBox(NULL, szError, "Failure", MB_OK);
hr = E_FAIL;
}
else
{
fResult = CryptUnregisterOIDFunction(0,
CRYPT_OID_OPEN_STORE_PROV_FUNC,
"MyProvider");
if (!fResult)
{
if(ERROR_FILE_NOT_FOUND != GetLastError())
{
wsprintf(szError, "CryptUnregisterOIDFunction failed with %x",
GetLastError());
MessageBox(NULL, szError, "Failure", MB_OK);
hr = E_FAIL;
}
}
else
{
MessageBox(NULL, "Deregistration completed successfully!",
"Success", MB_OK);
}
}
return hr;
}
Now lets say I use brand X to place a certificate/key pair on the token. It
works well also. But I now want to make that certificate known to all the
Microsoft programs, and retain the private key on the token. This is what I
mean my "register". Perhaps poor wording.
And of course I would like to have the reverse. If I have a certificate/key
pair is known only to the default CSP, how would I move the
certificate/private key to the token, and make it available to all of the
Microsoft programs, as well as any brand x programs. I know I can export
the certificate/key pair and import into the token (and that works), but how
do I delete the private key from the default store, and yet have the
required "links" to the private key on the token.
Ken
"Carlos Lopez" <nospam...@microsoft.com> wrote in message
news:#R66XWi7AHA.1496@tkmsftngp03...
The code I pasted in my previous reply doesn't require the certificate to be
placed in the system store. Any application who opens "MY" store will cause
the CertDllOpenStoreProv function to get called. You then place the
certificate in the hCertStore that was passed as a parameter. This is
something that is never really done.
The more common scenario is to copy the certificate in the token to the
certificate store. In this case, since you directly place the certificate
in the store and associated a private key with it, the application sees it.
It can then get the certificate, get the private key information, call
CryptAcquireContext on the token's CSP and things work fine.
I have a sample that copies the certificate from a smartcard to the user's
personal store. The private key always stays in the smartcard/token.
thanks
Carlos
// PropSmartCardCert.cpp
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
void PrintUsage(void);
void main(int argc, char *argv[])
{
int n;
BOOL fProvider = FALSE;
DWORD dwProvider;
CHAR szStore[16];
DWORD dwOpenFlag = CERT_SYSTEM_STORE_CURRENT_USER;
DWORD dwProvType, dwSize, dwImpType;
DWORD dwKeySpec, dwCertificate;
CHAR szProvider[256];
CHAR szContainer[256];
WCHAR szwProvider[256];
WCHAR szwContainer[256];
BYTE pbCertificate[4096];
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCERTSTORE hCertStore = 0;
PCCERT_CONTEXT pCertContext = NULL;
CRYPT_KEY_PROV_INFO KeyProvInfo;
BOOL fResult;
if (argc == 1)
{
PrintUsage();
return;
}
__try
{
n = 1;
lstrcpyA(szStore, "MY");
while (n < argc)
{
if (lstrcmpi(argv[n], "-p") == 0)
{
if ((n + 1) < argc)
{
fProvider = TRUE;
dwProvider = atol(argv[++n]);
n++;
}
else
{
PrintUsage();
return;
}
}
else if (lstrcmpi(argv[n], "-s") == 0)
{
if ((n + 1) < argc)
{
lstrcpyA(szStore, argv[++n]);
n++;
}
else
{
PrintUsage();
return;
}
}
else if (lstrcmpi(argv[n], "-l") == 0)
{
if ((n + 1) < argc)
{
if (lstrcmpi(argv[++n], "m") == 0)
{
dwOpenFlag = CERT_SYSTEM_STORE_LOCAL_MACHINE;
}
else if (lstrcmpi(argv[++n], "u") != 0)
{
PrintUsage();
return;
}
n++;
}
else
{
PrintUsage();
return;
}
}
else
{
PrintUsage();
return;
}
}
if (!fProvider)
{
printf("\nYou must choose a provider.\n");
return;
}
dwSize = 160;
if (!CryptEnumProviders(dwProvider, NULL, 0, &dwProvType, szProvider,
&dwSize))
{
printf("\nUnable to get provider.\n");
}
fResult = CryptAcquireContext(&hProv, NULL, szProvider, dwProvType,
CRYPT_VERIFYCONTEXT);
if (!fResult)
{
printf("CryptAcquireContext failed with %x\n", GetLastError());
__leave;
}
dwSize = sizeof(DWORD);
fResult = CryptGetProvParam(hProv, PP_IMPTYPE, (LPBYTE)&dwImpType,
&dwSize, 0);
if (!fResult)
{
printf("CryptGetProvParam(PP_IMPTYPE) failed with %x\n",
GetLastError());
__leave;
}
if ((dwImpType & CRYPT_IMPL_REMOVABLE) != CRYPT_IMPL_REMOVABLE)
{
printf("This is not a Smart Card Provider.\n");
__leave;
}
CryptReleaseContext(hProv, 0);
hProv = 0;
fResult = CryptAcquireContext(&hProv, NULL, szProvider, dwProvType,
0);
if (!fResult)
{
printf("CryptAcquireContext failed with %x\n", GetLastError());
__leave;
}
dwSize = 256;
fResult = CryptGetProvParam(hProv, PP_CONTAINER, (LPBYTE)szContainer,
&dwSize, 0);
if (!fResult)
{
printf("CryptGetProvParam(PP_CONTAINER) failed with %x\n",
GetLastError());
__leave;
}
printf("Container = %s\n", szContainer);
fResult = CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKey);
if (!fResult)
{
fResult = CryptGetUserKey(hProv, AT_SIGNATURE, &hKey);
if (!fResult)
{
printf("CryptGetUserKey failed with %x\n", GetLastError());
__leave;
}
else
{
dwKeySpec = AT_SIGNATURE;
}
}
else
{
dwKeySpec = AT_KEYEXCHANGE;
}
printf("Key handle retrieved\n");
dwCertificate = 4096;
fResult = CryptGetKeyParam(hKey, KP_CERTIFICATE, pbCertificate,
&dwCertificate, 0);
if (!fResult)
{
printf("CryptGetKeyParam failed with %x\n", GetLastError());
__leave;
}
printf("Certificate retrieved\n");
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A,
ENCODING,
0,
dwOpenFlag,
szStore);
if (!hCertStore)
{
printf("CertOpenStore failed with %x\n", GetLastError());
__leave;
}
fResult = CertAddEncodedCertificateToStore(hCertStore,
ENCODING,
pbCertificate,
dwCertificate,
CERT_STORE_ADD_REPLACE_EXISTING,
&pCertContext);
if (!fResult)
{
printf("CertAddEncodedCertificateToStore failed with %x\n",
GetLastError());
__leave;
}
if (mbstowcs(szwProvider, szProvider, 256) == -1)
{
printf("Could not convert provider to unicode string.\n");
__leave;
}
if (mbstowcs(szwContainer, szContainer, 256) == -1)
{
printf("Could not convert container to unicode string.\n");
__leave;
}
ZeroMemory(&KeyProvInfo, sizeof(KeyProvInfo));
KeyProvInfo.pwszProvName = szwProvider;
KeyProvInfo.pwszContainerName = szwContainer;
KeyProvInfo.dwKeySpec = dwKeySpec;
KeyProvInfo.dwProvType = dwProvType;
fResult = CertSetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
0,
&KeyProvInfo);
if (!fResult)
{
printf("CertSetCertificateContextProperty failed with %x\n",
GetLastError());
__leave;
}
printf("Certificate moved to store\n");
}
__finally
{
if (pCertContext) CertFreeCertificateContext(pCertContext);
if (hCertStore) CertCloseStore(hCertStore, 0);
if (hKey) CryptDestroyKey(hKey);
if (hProv) CryptReleaseContext(hProv, 0);
}
}
void PrintUsage(void)
{
DWORD nIndex = 0;
DWORD dwProvType, dwSize;
CHAR szProvider[160];
HCRYPTPROV hProv = 0;
BOOL fResult;
printf("\nUsage: PropSmartCardCert <options>\n");
printf("<options>\n");
printf("-p <provider number>\n");
printf("-s <store to place certificate>\n");
printf("-l <location> - location can be u(user) or m(machine)\n");
printf("\nCertificate are normally placed in the MY user store\n");
printf("\nProviders:\n");
dwSize = 160;
while (CryptEnumProviders(nIndex, NULL, 0, &dwProvType, szProvider,
&dwSize))
{
fResult = CryptAcquireContext(&hProv, NULL, szProvider, dwProvType,
CRYPT_VERIFYCONTEXT);
if (fResult)
{
DWORD dwType;
DWORD dwDWORDSize = sizeof(DWORD);
fResult = CryptGetProvParam(hProv, PP_IMPTYPE, (LPBYTE)&dwType,
&dwDWORDSize, 0);
if (fResult)
{
if (dwType & CRYPT_IMPL_REMOVABLE == CRYPT_IMPL_REMOVABLE)
{
printf("\t%d : %s\n", nIndex, szProvider);
}
}
CryptReleaseContext(hProv, 0);
}
dwSize = 160;
nIndex++;
}
}
Thanks Carlos, excellent support.
Ken
"Carlos Lopez" <nospam...@microsoft.com> wrote in message
news:OJhQXbq7AHA.996@tkmsftngp05...
However, it appears as if the token only knows about containers that have
been placed on the USB token using the Microsoft CAPI interface.
How do I define or make known containers for those private keys/certificates
that have been placed on the USB token using brand x software?
Example, I have a USB token that has five valid private key/certificate
pairs, in which two were placed on the token using the Microsoft Internet
Explorer 5.5. The other three were placed on the token with brand x
software. All five are valid certificates. However when I enumerate the
containers, only two are returned.
Ken