RE: How to import certificate and PrK from PFX file to smart card



Thank you for your advice.

It really did help and I've moved a fair bit, but I've still got some
problems...

Even though my code runs without errors, it doesn't write the certificate
and key to the smart card.



Here is the source code:

----------------------------------
void MyClassDlg::importCertKeyToSmartCard(CString cardPIN, _CRYPTOAPI_BLOB
&pkcs12data, CString password)
{
HCERTSTORE hCS;

hCS = PFXImportCertStore(&pkcs12data, (LPCWSTR) password, CRYPT_EXPORTABLE
| CRYPT_USER_KEYSET );
if(hCS == NULL)
{
return;
}

PCCERT_CONTEXT pCC(NULL);

PBYTE pData(NULL);
DWORD sizeOfData(0);

BOOL success;
BOOL callerFree;

CRYPT_KEY_PROV_INFO* pKeyProvInfo(NULL);
HCRYPTPROV cryptoProvider(0), cardCryptoProvider(0);

DWORD cryptAcquireCertificatePrivateKeyFlags = AT_KEYEXCHANGE;

HCRYPTKEY cryptKeyHandle(0);
HCRYPTKEY sessionKeyHandle(0);
HCRYPTKEY importedKey(0);

BYTE* pPk(NULL);
DWORD pkSize;

DWORD err;

CString readerName = m_readers[m_cbReaders.GetCurSel()]->description;
if(readerName.GetLength() > 0) {
readerName.SetAt(readerName.GetLength()-1, ' ' );
readerName.TrimRight();
}

CString containerName(L"MyContainer");
CString containerNameFull;
containerNameFull.Format(L"\\\\.\\%s\\%s", readerName, containerName);

success = CryptAcquireContextW(&cardCryptoProvider,
(LPCTSTR)containerNameFull, L"Siemens Card API
CSP", PROV_RSA_FULL,CRYPT_NEWKEYSET// | CRYPT_SILENT );
if(!success) {
return;
}


// log in using PIN

char* pin;
long pinBufferLength = cardPIN.GetLength()+1;
pin = new char[pinBufferLength];

WideCharToMultiByte(GetACP(), 0, cardPIN, pinBufferLength-1, pin,
pinBufferLength, 0, 0);

pin[pinBufferLength-1] = 0;


success = CryptSetProvParam(cardCryptoProvider, PP_KEYEXCHANGE_PIN,
(BYTE*)pin, 0);
if(!success){
err = GetLastError();
return;
}

delete [] pin;

do
{
pCC = CertEnumCertificatesInStore(hCS, pCC);
if(pCC == NULL)
{
break;
}

CertGetCertificateContextProperty(pCC, CERT_KEY_PROV_INFO_PROP_ID, NULL,
&sizeOfData);
pData = new BYTE[sizeOfData];

success = CertGetCertificateContextProperty(pCC,
CERT_KEY_PROV_INFO_PROP_ID, (PVOID)pData, &sizeOfData);
if(!success) {
err = GetLastError();
break;
}

pKeyProvInfo = (CRYPT_KEY_PROV_INFO*) pData;

success = CryptAcquireCertificatePrivateKey(pCC,CRYPT_ACQUIRE_SILENT_FLAG,
NULL, &cryptoProvider, &cryptAcquireCertificatePrivateKeyFlags, &callerFree);
if(!success) {
err = GetLastError();
break;
}

success = CryptGetUserKey(cryptoProvider, AT_KEYEXCHANGE, &cryptKeyHandle);
if(!success){
err = GetLastError();
break;
}


// export key

success = CryptGenKey(cryptoProvider, CALG_3DES, CRYPT_EXPORTABLE,
&sessionKeyHandle);
if(!success){
err = GetLastError();
break;
}

CryptExportKey(cryptKeyHandle, sessionKeyHandle, PRIVATEKEYBLOB, 0, NULL,
&pkSize );
pPk = new BYTE[pkSize];

success = CryptExportKey(cryptKeyHandle, NULL, PRIVATEKEYBLOB, 0, pPk,
&pkSize );
if(!success){
err = GetLastError();
break;
}


// import key

success = CryptImportKey(cardCryptoProvider, pPk, pkSize,
sessionKeyHandle, 0, &importedKey);
if(!success){
err = GetLastError();
break;
}

// import certificate

success = CryptSetKeyParam(importedKey, KP_CERTIFICATE,
pCC->pbCertEncoded, 0);
if(!success){
err = GetLastError();
break;
}

}
while(false);

if(pCC) {
CertFreeCertificateContext(pCC);
}

if(pData) {
delete [] pData;
pData = NULL;
}

if(pPk) {
memset(pPk, 0, pkSize);
delete [] pPk;
pPk = NULL;
}

if(importedKey) {
CryptDestroyKey(importedKey);
}

if(cryptKeyHandle) {
CryptDestroyKey(cryptKeyHandle);
}

if(callerFree && cryptoProvider) {
CryptReleaseContext(cryptoProvider, NULL);
}

}

----------------------------------



"Mounir IDRASSI" wrote:

Hi,

Once you have the HCERTSTORE returned by PFXImportCertStore, you must
enumerate all the certificates on this store using
CertEnumCertificatesInStore. For each certificate found, do the following :

- Retrieve its CERT_KEY_PROV_INFO_PROP_ID property using
CertGetCertificateContextProperty. If it doesn't exists, then this is
certainly a standalone certificate with no associated key ( a root
certificate for example)
- Using the information from the property mentioned above, call the
function CryptAcquireCertificatePrivateKey to get a handle on the CSP context
of the key associated with this certificate.
- Call CryptGetUserKey to get a handle on the private key.
- Call CryptExportKey to export the private key as a PRIVATEKEYBLOB blob.
- Here you have all the needed information to import the certificate and
its private key into the smart card. You can for example create a new
container on the card using CryptAcquireContext , then import the private key
using CryptImportKey and finally put the certificate in the card by setting
the KP_CERTIFICATE property on the key you have just created.

I hope the above steps are clear enough to help you in what you intend to do.

Cheers,
--
Mounir IDRASSI
IDRIX
http://www.idrix.fr

.



Relevant Pages

  • Re: X.509 certificates and httpwebrequest
    ... > We retrieve data from a company called XYZ through httpwebrequest. ... > They have given a certificate to install. ... > we feel it is because of permission issue for the user ASPNET. ... > I have no success even after utilizing winhttpcertcfg. ...
    (microsoft.public.dotnet.security)
  • Re: Subject: [PATCH 01/16] Squashfs: inode operations
    ... None of the comments below are a reason against mainline inclusion, imo. ... No kernel code beside squashfs needs the headers ... Most linux functions return 0 on success and -ESOMETHING on error. ... err = squashfs_foo; ...
    (Linux-Kernel)
  • Re: unencrypting files that somehow got encrypted
    ... > imported into my certificate store, but still no success in unencrypting. ... Install the 128bit upgrade on his system. ...
    (microsoft.public.win2000.file_system)
  • [PATCH 004 of 4] md: Endian annotations for the bitmap superblock
    ... err = 0; ... switch { ...
    (Linux-Kernel)
  • how to setup SSL for IIS/OWA
    ... I have been following instruction cases below without success ... case 2 - Creating Certificate Hierarchies with MS Certificate Server Version ... The error code is 0x80092004. ...
    (microsoft.public.inetserver.iis.security)