views:

136

answers:

2

I am using certificate based authentication between my server and client. I have generated Root Certificate. My client at the time of installation will generate a new Certificate and use the Root Certificate to sign it. I need to use Windows API. Cannot use any windows tools like makecert.

Till now I have been able to Install the Root certificate in store. Below code

X509Certificate2 ^ certificate = gcnew X509Certificate2("C:\\rootcert.pfx","test123");
X509Store ^ store = gcnew X509Store( "teststore",StoreLocation::CurrentUser );
store->Open( OpenFlags::ReadWrite );
store->Add( certificate );
store->Close();

Then open the installed root certificate to get the context

GetRootCertKeyInfo(){
  HCERTSTORE hCertStore;
  PCCERT_CONTEXT pSignerCertContext=NULL;
  DWORD dwSize = NULL; 
  CRYPT_KEY_PROV_INFO* pKeyInfo = NULL; 
  DWORD dwKeySpec;
  if ( !( hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL,  CERT_SYSTEM_STORE_CURRENT_USER,L"teststore")))
  {
    _tprintf(_T("Error 0x%x\n"), GetLastError());
  }
  pSignerCertContext = CertFindCertificateInStore(hCertStore,MY_ENCODING_TYPE,0,CERT_FIND_ANY,NULL,NULL);

if(NULL == pSignerCertContext)
{
    _tprintf(_T("Error 0x%x\n"), GetLastError());
}

if(!(CertGetCertificateContextProperty( pSignerCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwSize))) 
{ 
    _tprintf(_T("Error 0x%x\n"), GetLastError());
} 

if(pKeyInfo) 
   free(pKeyInfo); 
if(!(pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize))) 
{ 
    _tprintf(_T("Error 0x%x\n"), GetLastError());
} 


if(!(CertGetCertificateContextProperty( pSignerCertContext, CERT_KEY_PROV_INFO_PROP_ID, pKeyInfo, &dwSize))) 
{    
    _tprintf(_T("Error 0x%x\n"), GetLastError());
}
return pKeyInfo;
}

Then finally created the certificate and signed with the pKeyInfo

    // Acquire key container
if (!CryptAcquireContext(&hCryptProv, _T("trykeycon"), NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) 
{
  _tprintf(_T("Error 0x%x\n"), GetLastError());

  // Try to create a new key container
  _tprintf(_T("CryptAcquireContext... "));
  if (!CryptAcquireContext(&hCryptProv, _T("trykeycon"), NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
  {
    _tprintf(_T("Error 0x%x\n"), GetLastError());
    return 0;
  }
  else 
  {
    _tprintf(_T("Success\n"));
  }
}
else
{
  _tprintf(_T("Success\n"));
}

// Generate new key pair
_tprintf(_T("CryptGenKey... "));
if (!CryptGenKey(hCryptProv, AT_SIGNATURE, 0x08000000 /*RSA-2048-BIT_KEY*/, &hKey))
{
  _tprintf(_T("Error 0x%x\n"), GetLastError());
  return 0;
}
else
{
  _tprintf(_T("Success\n"));
}
//some code
    CERT_NAME_BLOB SubjectIssuerBlob;
memset(&SubjectIssuerBlob, 0, sizeof(SubjectIssuerBlob));
SubjectIssuerBlob.cbData = cbEncoded;
SubjectIssuerBlob.pbData = pbEncoded;

// Prepare algorithm structure for self-signed certificate
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
memset(&SignatureAlgorithm, 0, sizeof(SignatureAlgorithm));
SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;

// Prepare Expiration date for self-signed certificate
SYSTEMTIME EndTime;
GetSystemTime(&EndTime);
EndTime.wYear += 5;

// Create self-signed certificate
_tprintf(_T("CertCreateSelfSignCertificate... "));

CRYPT_KEY_PROV_INFO* aKeyInfo;
aKeyInfo = GetRootCertKeyInfo();
pCertContext = CertCreateSelfSignCertificate(NULL, &SubjectIssuerBlob, 0, aKeyInfo, &SignatureAlgorithm, 0, &EndTime, 0);

With the above code I am able to create the certificate but it does not looks be signed by the root certificate. I am unable to figure what I did is right or not.. Any help with be greatly appreciated..

Thanks Asif

A: 

I don't think a self-signed certificate is what you need here. You want to create a new "client" certificate that is signed by your "root" certificate, correct? I think you need to use CryptSignAndEncodeCertificate to do this.

Luke
yes..I need to sign it by the root certificate..looking at the certcreateselfsigncertificate() description, it looks it can also be used to sign with my root certificate..However I am still confused..how does a signing a with a root certificate different from certificate chain..I mean if I sign my certificate with the root certificate, then will my certificate will have path like this.. Root certificate___ | | ----- My certificate..Thanks a lotAsif
Asif Alam
Asif Alam
I'm not sure how CertCreateSelfSignCertificate works exactly, but generally speaking when you create a self-signed certificate it is a certificate that is signed by itself. The only self-signed certificate that could be signed by your root certificate is your root certificate. I don't know how CryptSignAndEncodeCertificate works, either, but it sounds like a reasonable candidate for what you are trying to do. Here is some code that exports it to a file:http://hi.baidu.com/mingyuejingque/blog/item/8982f1ee5d00b22f2df53498.html
Luke
A: 

First of all some years ago I wrote some product which contain also the full code what you asked for: creating of a new certificate and signing it with respect of other root certificate. This code use only Microsoft CryptoAPI. But before I give you detailed answer or post some code I want to know, whether your problem is actual: your question is one and half months old.

In general to do what you want, one should not use CertCreateSelfSignCertificate() function, but create a certificate with respect of other CryptoAPIs. CertCreateSelfSignCertificate() function can only be used to create and to sign a self-signed certificate. It can not sign a certificate with other certificate which you created. Moreover CertCreateSelfSignCertificate() function have (or at least had some years before) a hard restriction to the length of created private key. Thus one have to make the same things which CertCreateSelfSignCertificate() function do manually. The last API in the chain of API what one do is CryptSignAndEncodeCertificate() like wrote in another answer Luke on your question.

Moreover I have a large suspect, that for your purpose creating a certificate chain is not correct way. If you need to do this only for authentication, you don't need create a certificate on the client side. It seems to me, that it will be enough working with singed messages. One use certificates instead of key pair is cases where you need features like key revocation or key restriction for usage for some purpose only (for example only for code signing and not for data encryption).

If you really needs implement certificated based authentication, then at least you have to create a certificate of the client computer, send it to the server computer and sing client certificate on the server computer, because only server computer could hold a private key of root certificate.

It can be also that you can implement your requirement with respect of the Certificate Enrollment API? It will be not exactly what you asked for, but it can solve your main problem.

Answer on additional questions (comments): Either I don't understand the construct which you plan to realize as "2 way authentication" or the concept is wrong.

  1. I don't understand how and when you plan transport root client certificate from all clients to server.
  2. You want to sign client certificate with clients root CA, so you have to hold on the client the private key of the client's root CA certificate (!!!???).
  3. If server don't have any verified information about the client like its root CA certificate, than you can not really use client certificate for client's authorization. Any client with a certificate will be "authorized".
  4. With the standard SSL without client certificate you can be sure that you communicate all the time with the same client. So if you don't solve the problem of clients root CA transport to the server you will be not able to achieve more security as in the standard (without client certificate) SSL.
  5. What you wrote seems like you try not to use a standard communication protocol between server and client. Instead of that you try to introduce a new own protocol. It is VERY dangerous! If you not a cryptography expert, you will realize a protocol which only looks like safe and not be so. "SMALL" problems like holding of private key and safe transport of public key from client to server or back are very important cryptographic subjects. There are different cryptographic protocols to solve there. So don't try to implement something new in this area!
  6. Think one more about why you really want use client certificate. Are you really implement client authentication with the way? In standard SSL, for example, one can be sure that one communicate all time with the same client and use for this only a random nonces and a symmetric key generated for the session. Do you want generate a certificate per client or per session?

I can write more my questions. If you implement his own certificate based communication protocol I have large problems to give my recommendation before I understand you concept.

Oleg
thanks.. for giving some insight into this. what are we trying to achieve: We have to set certificate based authentication between the server and client. Upon SSL setup, the server shall send its certificate (signed by private CA or Root Certificate) and also expect the client to send its certificate.Now both the server and the client shall have the private CA installed as trusted certificate. What I need to do is at the installation time of the server and client, I have to create a new certificate and sign it with the private trusted CA.
Asif Alam
We intend to 2 way authentication with encryption using the asymmetric key pair. As you suggested we would like to create the client certificate on the fly, send it to the server, sign it and then use it for SSL handshake. However I am sure how should take this model if we looking at 2 way authentication.It would be great if you can give me hints on using the MS Crypto Api, to much with my dislike to Windows, I still have to get this done on windows
Asif Alam