Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

USB Token Support

13 views
Skip to first unread message

Kenneth R. Robinette

unread,
Jun 4, 2001, 9:09:39 AM6/4/01
to
Has anyone been able to "register" a certificate/private key located on a
USB Token/Smart Card that is not currently in the registry
(SystemCertificates\My\Certificates, SystemCertificates\My\Keys, and the
reverse, to place the required certificate data on the USB Token/Smart Card
that is currently known to Windows, but not the token? The tokens/smart
cards support both PKCS-11 and the Microsoft CSP.

Ken

Carlos Lopez

unread,
Jun 5, 2001, 9:10:57 PM6/5/01
to
You can register a certificate store. To provide access to the private key
on the USB Token/SmartCard you would also need to write your own CSP. The
way that CryptoAPI use certificates is usually to get them from a
certificate store and then see if they have a private key associated with
them by calling CryptGetCertificateContextProperty with the
CERT_KEY_PROV_INFO_PROP_ID flag or by calling
CryptAcquireCertificatePrivateKey.

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;
}

Kenneth R. Robinette

unread,
Jun 6, 2001, 7:05:14 AM6/6/01
to
Perhaps I asked the question wrong. The USB token does have a CSP and it
also has support for PKCS#11. If I use xEnroll to create a pkcs#10, and
request the private key be place on the USB token, then when the certificate
is installed everything works as expected. I can see an entry in the
HKEY_CURRENT_USER MY/Certificates and MY/Keys. If I display the objects
contained on the token, I can see the certificate along with the
private/public keys. All is well and works as it should. Whenever access
to the private key is needed, the private key located on the token is
accessed as it should be.

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...

Carlos Lopez

unread,
Jun 6, 2001, 12:36:28 PM6/6/01
to
Actually, my response wasn't too far off. If you want MS applications to
see the certificate, you can write a certificate store provider. You can
also place the public certificate in a system store such as "MY" store and
set the private key property to point to the CSP.

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++;
}
}


Kenneth R. Robinette

unread,
Jun 6, 2001, 9:22:46 PM6/6/01
to
Brilliant, works like a charm.

Thanks Carlos, excellent support.

Ken

"Carlos Lopez" <nospam...@microsoft.com> wrote in message

news:OJhQXbq7AHA.996@tkmsftngp05...

Kenneth R. Robinette

unread,
Jun 7, 2001, 1:56:26 PM6/7/01
to
I have been successful in "registering" a certificate contained on a USB
Token and it works quite well. I have also been able to use
CryptGetProvParam to enumerate the containers on the token, to select the
container that has the private key/certificate I wish to register.

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

0 new messages