Discussion:
How associate private key to certificate?
(too old to reply)
n***@email.com
2005-09-10 20:41:36 UTC
Permalink
Hi,

i have some problems with certificates, my code is heavily based on
certificate creation example from MS SDK and i'm not sure about way how
private key asociated with my certificate is inserted into system... my
code goes about this way:

#define MY_PROVNAME MS_ENHANCED_PROV
#define MY_PROVTYPE PROV_RSA_FULL
#define MY_ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)

// create crypto context
if(!CryptAcquireContext(&hCryptProv, szContainer, MY_PROVNAME,
MY_PROVTYPE, CRYPT_NEWKEYSET | dwCertContainer))
break;

// generate public/private key pair
if(!CryptGenKey(hCryptProv, dwKeyType, CRYPT_EXPORTABLE,
&hPubPrivKeyPair))
break;

... here goes code about filling CERT_INFO structure and adding some
important extensions to certificate...


// finally, crypt, sign & encode certificate
if(!CryptSignAndEncodeCertificate(hIssuerCryptProv, dwIssuerKeyType,
MY_ENCODING, X509_CERT_TO_BE_SIGNED, (LPVOID)&stCertInfo,
&(stIssuerCert->pCertInfo->SignatureAlgorithm), NULL, NULL, &dwSize))
break;

if(!(pEncodedCert = (LPBYTE)HeapAlloc(hHeap, 0, dwSize)))
break;

if(!CryptSignAndEncodeCertificate(hIssuerCryptProv, dwIssuerKeyType,
MY_ENCODING, X509_CERT_TO_BE_SIGNED,
(LPVOID)&stCertInfo, &(stIssuerCert->pCertInfo->SignatureAlgorithm),
NULL, pEncodedCert, &dwSize))
break;

// open specified certificate store
if(!(hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, MY_ENCODING,
NULL, dwCertLocation, A2W(szCertStore))))
break;

// insert encoded certificate into store
if(!CertAddEncodedCertificateToStore(hCertStore, MY_ENCODING,
pEncodedCert, dwSize, CERT_STORE_ADD_REPLACE_EXISTING, &pCertContext))
break;

// get private key blob
LPBYTE pPrivateKey = NULL;
if(!CryptExportKey(hPubPrivKeyPair, NULL, PRIVATEKEYBLOB, 0, NULL,
&dwSize))
break;

if(!(pPrivateKey = (LPBYTE)HeapAlloc(hHeap, 0, dwSize)))
break;

if(!CryptExportKey(hPubPrivKeyPair, NULL, PRIVATEKEYBLOB, 0,
pPrivateKey, &dwSize))
break;

// import key
HCRYPTKEY outKey = NULL;
if(!CryptImportKey(hCryptProv, pPrivateKey, dwSize, 0,
CRYPT_EXPORTABLE, &outKey))
break;

// initialize CRYPT_KEY_PROV_INFO structure
ZeroMemory(&stCryptKeyProvInfo, sizeof(stCryptKeyProvInfo));
stCryptKeyProvInfo.pwszContainerName = A2W(szContainer);
stCryptKeyProvInfo.pwszProvName = A2W(MY_PROVNAME);
stCryptKeyProvInfo.dwProvType = MY_PROVTYPE;
stCryptKeyProvInfo.dwKeySpec = dwKeyType;

// set certificate's key provider info
if(!CertSetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID, 0, (LPVOID)&stCryptKeyProvInfo))
break;


certificate imported to store in this 2-way manner (first certificate,
then key) and opened in mmc/certificates have private key asociated
with it (as i'm told by certificate) but this certificate didn't worked
in IIS when i tried to use HTTPS (and SSL Diagnostics told me that
CryptAcquireCertificatePrivateKey has failed).

Any advice about what's wrong with my code or how works association of
private key to certificate would be greatly appreciated, any included
code is welcomed also.

NonSuch
lelteto
2005-09-11 17:03:03 UTC
Permalink
I don't know WHY do you need to export the private key then re-import it.
It's already in your container, you can just reference / use it. (It would
have the added benefit of security: you don't have to set the key type to
exportable, ie. the private key would always stay in the system.) And I don't
see the export of the PUBLIC key before you are creating the certificate.
What public key are you using in your cert?

As for IIS you have to create MACHINE keyset, ie have to specify
CRYPT_MACHINE_KEYSET in your first CryptAcquireContext.

Laszlo Elteto
SafeNet, Inc.
Post by n***@email.com
Hi,
i have some problems with certificates, my code is heavily based on
certificate creation example from MS SDK and i'm not sure about way how
private key asociated with my certificate is inserted into system... my
#define MY_PROVNAME MS_ENHANCED_PROV
#define MY_PROVTYPE PROV_RSA_FULL
#define MY_ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
// create crypto context
if(!CryptAcquireContext(&hCryptProv, szContainer, MY_PROVNAME,
MY_PROVTYPE, CRYPT_NEWKEYSET | dwCertContainer))
break;
// generate public/private key pair
if(!CryptGenKey(hCryptProv, dwKeyType, CRYPT_EXPORTABLE,
&hPubPrivKeyPair))
break;
.... here goes code about filling CERT_INFO structure and adding some
important extensions to certificate...
// finally, crypt, sign & encode certificate
if(!CryptSignAndEncodeCertificate(hIssuerCryptProv, dwIssuerKeyType,
MY_ENCODING, X509_CERT_TO_BE_SIGNED, (LPVOID)&stCertInfo,
&(stIssuerCert->pCertInfo->SignatureAlgorithm), NULL, NULL, &dwSize))
break;
if(!(pEncodedCert = (LPBYTE)HeapAlloc(hHeap, 0, dwSize)))
break;
if(!CryptSignAndEncodeCertificate(hIssuerCryptProv, dwIssuerKeyType,
MY_ENCODING, X509_CERT_TO_BE_SIGNED,
(LPVOID)&stCertInfo, &(stIssuerCert->pCertInfo->SignatureAlgorithm),
NULL, pEncodedCert, &dwSize))
break;
// open specified certificate store
if(!(hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, MY_ENCODING,
NULL, dwCertLocation, A2W(szCertStore))))
break;
// insert encoded certificate into store
if(!CertAddEncodedCertificateToStore(hCertStore, MY_ENCODING,
pEncodedCert, dwSize, CERT_STORE_ADD_REPLACE_EXISTING, &pCertContext))
break;
// get private key blob
LPBYTE pPrivateKey = NULL;
if(!CryptExportKey(hPubPrivKeyPair, NULL, PRIVATEKEYBLOB, 0, NULL,
&dwSize))
break;
if(!(pPrivateKey = (LPBYTE)HeapAlloc(hHeap, 0, dwSize)))
break;
if(!CryptExportKey(hPubPrivKeyPair, NULL, PRIVATEKEYBLOB, 0,
pPrivateKey, &dwSize))
break;
// import key
HCRYPTKEY outKey = NULL;
if(!CryptImportKey(hCryptProv, pPrivateKey, dwSize, 0,
CRYPT_EXPORTABLE, &outKey))
break;
// initialize CRYPT_KEY_PROV_INFO structure
ZeroMemory(&stCryptKeyProvInfo, sizeof(stCryptKeyProvInfo));
stCryptKeyProvInfo.pwszContainerName = A2W(szContainer);
stCryptKeyProvInfo.pwszProvName = A2W(MY_PROVNAME);
stCryptKeyProvInfo.dwProvType = MY_PROVTYPE;
stCryptKeyProvInfo.dwKeySpec = dwKeyType;
// set certificate's key provider info
if(!CertSetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID, 0, (LPVOID)&stCryptKeyProvInfo))
break;
certificate imported to store in this 2-way manner (first certificate,
then key) and opened in mmc/certificates have private key asociated
with it (as i'm told by certificate) but this certificate didn't worked
in IIS when i tried to use HTTPS (and SSL Diagnostics told me that
CryptAcquireCertificatePrivateKey has failed).
Any advice about what's wrong with my code or how works association of
private key to certificate would be greatly appreciated, any included
code is welcomed also.
NonSuch
n***@email.com
2005-09-11 18:58:29 UTC
Permalink
Hello,

first of all, thank you for your help. I know this export/import thing
look terrible, but it was added in misery of unability to get things
moving, if you saying this export/import thing is uselles i agree, but
i don't know where is the private key in the first place, if it is in
CSP's container in pair with public key after i call CryptGenKey(...),
then i don't understand how can i get this private key into system
because it's not part of the certificate (which contains only public
key).

I found in MSDN that machine's private keys associated with
certificates are stored in "\Documents and Settings\All
Users\Application Data\Microsoft\Crypto\RSA" but i don't understand the
way they get in there. I know how to export my private key and save it
into file but that's not very helping.

When you look on my CryptAcquireContext(...) you can see parameter
dwCertContainer which is already set to CRYPT_MACHINE_KEYSET, if this
parameter isn't set to this constant you can't install certificate to
IIS at all.

Export of my public key is done in part where i'm filling CERT_INFO
structure and it looks like this:


// get public key info
if(!CryptExportPublicKeyInfo(hCryptProv, dwKeyType, MY_ENCODING, NULL,
&dwSize))
break;
if(!(stPubKeyInfo = (PCERT_PUBLIC_KEY_INFO)HeapAlloc(hHeap, 0,
dwSize)))
break;
if(!CryptExportPublicKeyInfo(hCryptProv, dwKeyType, MY_ENCODING,
stPubKeyInfo, &dwSize))
break;

// CERT_INFO: set public key info
stCertInfo.SubjectPublicKeyInfo = *stPubKeyInfo;


stPubKeyInfo contains both algorithm (RSA) and public key. So
basically, my cert is in store and it looks like it have asociated
private key but HTTPS in IIS doesn't work and i don't know what's up
with private key.

I hope i answered all of your questions.

With kind regards, NonSuch
lelteto
2005-09-12 16:20:10 UTC
Permalink
The private key is never part of the certificate. You need the private key on
on THAT system which you generated the key - and it's just there (Microsoft
stores it in the system - you should not care where, it's just available via
the proper calls). Exporting the private key is needed only if you intend to
transfer it onto other system(s) eg. if you have redundant servers and want
to use the same cert on all. If you have only one server than you are OK.
BTW I don't know why you are going into this much of problem if the only
thing you need is IIS server certificate. IIS has the proper utility / tool
to generate the key pair, output the cert request then import it back ready
for SSL. I forgot the exact steps - did that several years ago and my memory
is not that good - but any IIS admin could tell you how to accomplish that
w/o any programming on your part.

Laszlo Elteto
SafeNet, Inc.
Post by n***@email.com
Hello,
first of all, thank you for your help. I know this export/import thing
look terrible, but it was added in misery of unability to get things
moving, if you saying this export/import thing is uselles i agree, but
i don't know where is the private key in the first place, if it is in
CSP's container in pair with public key after i call CryptGenKey(...),
then i don't understand how can i get this private key into system
because it's not part of the certificate (which contains only public
key).
I found in MSDN that machine's private keys associated with
certificates are stored in "\Documents and Settings\All
Users\Application Data\Microsoft\Crypto\RSA" but i don't understand the
way they get in there. I know how to export my private key and save it
into file but that's not very helping.
When you look on my CryptAcquireContext(...) you can see parameter
dwCertContainer which is already set to CRYPT_MACHINE_KEYSET, if this
parameter isn't set to this constant you can't install certificate to
IIS at all.
Export of my public key is done in part where i'm filling CERT_INFO
// get public key info
if(!CryptExportPublicKeyInfo(hCryptProv, dwKeyType, MY_ENCODING, NULL,
&dwSize))
break;
if(!(stPubKeyInfo = (PCERT_PUBLIC_KEY_INFO)HeapAlloc(hHeap, 0,
dwSize)))
break;
if(!CryptExportPublicKeyInfo(hCryptProv, dwKeyType, MY_ENCODING,
stPubKeyInfo, &dwSize))
break;
// CERT_INFO: set public key info
stCertInfo.SubjectPublicKeyInfo = *stPubKeyInfo;
stPubKeyInfo contains both algorithm (RSA) and public key. So
basically, my cert is in store and it looks like it have asociated
private key but HTTPS in IIS doesn't work and i don't know what's up
with private key.
I hope i answered all of your questions.
With kind regards, NonSuch
n***@email.com
2005-09-12 17:59:52 UTC
Permalink
I don't want to export private key, if i wanted this i would export
cert along with private key associated with it into PFX format. All a
want is to install CA cert and server cert (signed by this CA of mine)
into store. You said i don't need to care about private key because by
installing cert into store, system take care of proper placement of
it's associated private key, if i uderstood you correctly. But this is
not happening, my cert is installed into store,
CERT_KEY_PROV_INFO_PROP_ID is set, cert tells me that i have private
key but when i try to export this cert with his private key into PFX
format (and i set EXPORT_PRIVATE_KEYS), it's not there (as i found out
after reimporting it into store).

And no, i can't use MS Certificate Services on Windows Server because
whole point of this work is to write my own CA, this is part of my
project. That's why i can't use MakeCert or MS Certificate services.

If you just take a look on my code and tell me if i'm missing
something, i've already red whole CryptoApi section of MSDN and
searched various mailing lists but every tip i tried didn't help me.
HTTPS is still not working and CryptAcquireCertificatePrivateKey(...)
is returning error "keyset does not exist".

And about IIS, i've created CA cert and site cert on Windows Server
2003 in theirs built-in Certificate Services (which is build ONLY into
server series), exported them into PFX, installed on my machine (WXP)
and HTTPS works just fine, i've even tried to imitate this MS site cert
in my code (by adding some extensions that MS cert contains) but with
no luck. Sign my site certificate with MS generated CA didn't work
either.

NonSuch
n***@email.com
2005-09-16 11:43:32 UTC
Permalink
Nevermind, i found it already myself, problem was in the
CRYPT_KEY_PROV_INFO_PROP_ID structure. I didn't specified dwFlags, it
has to be set to CRYPT_MACHINE_KEYSET like in CryptAcquireContext(...).
Loading...