1

Our application uses OpenSSL for securing communication between client device and server. The certificates are generated by customers CA and we had to upload server certificate and private key to Windows OS based machine.

Until now we guide our customers to save a PEM files which include server certificate and private key at specific directory on server file system and our application upload it from there. Lately, we were asked by customer to read a PFX certificate from local windows certificate store.

I can think of 2 options which both combines use of CAPI library for exporting the PFX file from WCS (according to friendly name), serializing it and then uploading it using OpenSSL API.

The first option save it as temporary file on server file system then read as before with OpenSSL API.

The 2nd option uses memory i.e. pass pointers instead of using temporary file.

My team spent a lot of time searching the web (mainly Stack Overflow) and trying code snippets but didn't found working solution. I understood that the private key should be exportable marked during importing the file to WCS.

When I tried below code for simple exporting certificate and saving it to file (first half of option #1 based on MS example code) it writes only one character to file.

What do I miss here? Do I need to reformat certificate?

Any Idea of what is wrong and what is the right way to do it?

Can the private key be extract this way?

Thanks in advance for any comment

//-----------------------------------------

#pragma comment(lib, "crypt32.lib")

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);

void main(void)
{
//-------------------------------------------------------------------
// Declare and initialize variables.
HCERTSTORE         hSystemStore;
PCCERT_CONTEXT     pCertContext = NULL;
Char pszStoreName[256] = "root";
char               pszNameString[256] = "CARootTest"; 
BYTE              pbElement[3000];
DWORD              cbElement;
//-------------------------------------------------------------------
// Open a system certificate store.
if(hSystemStore = CertOpenSystemStore(
    0,
    pszStoreName))
{
  printf("The %s system store is open. Continue.\n", pszStoreName );
}
else
{
  MyHandleError("The first system store did not open.");
}
//-------------------------------------------------------------------
// Get a certificate that has the desired friendly name. 
if(pCertContext=CertFindCertificateInStore(
      hSystemStore,
      MY_ENCODING_TYPE,             // Use X509_ASN_ENCODING
      0,                            // No dwFlags needed 
      CERT_NAME_FRIENDLY_DISPLAY_TYPE,        // Find a certificate
      pszNameString, // The Unicode string to be found
                                    // in a certificate's subject
      NULL))                        // NULL for the first call 
{
  printf("The %s certificate was found. \n", pszNameString);
}
else
{
   MyHandleError("Could not find the %s certificate.");
}
//-------------------------------------------------------------------
// Find out how much memory to allocate for the serialized element.

if(CertSerializeCertificateStoreElement(
    pCertContext,      // The existing certificate.
    0,                 // Accept default for dwFlags, 
    NULL,              // NULL for the first function call.
    &cbElement))       // Address where the length of the 
                       // serialized element will be placed.
{
     printf("The length of the serialized string is %d.\n",
         cbElement);
}
else
{
     MyHandleError("Finding the length of the serialized "
         "element failed.");
}
//-------------------------------------------------------------------
// Allocate memory for the serialized element.

if(pbElement = (BYTE*)malloc(cbElement+1))
{
     printf("Memory has been allocated. Continue.\n");
}
else
{
     MyHandleError("The allocation of memory failed.");
}
//-------------------------------------------------------------------
// Create the serialized element from a certificate context.

if(CertSerializeCertificateStoreElement(
    pCertContext,        // The certificate context source for the 
                         // serialized element.
    0,                   // dwFlags. Accept the default.
    pbElement,           // A pointer to where the new element will
                         // be stored.
    &cbElement))         // The length of the serialized element,
{
     printf("The encoded element has been serialized. \n");
}
else
{
     MyHandleError("The element could not be serialized.");
}
//-------------------------------------------------------------------
//  pbElement could be written to a file ??

FILE *fp;
errno_t err;
if ((err = fopen_s(&fp, "cert.p12", "wb")) != 0)
    printf("File was not opened\n");
else
    fprintf(fp, "%s", pbElement);
fclose(fp);

//-------------------------------------------------------------------
// Free memory.

free(pbElement);
CertCloseStore(hSystemStore,0);
printf("The program ran without error to the end.\n");
} // End of main

//-------------------------------------------------------------------
void MyHandleError(char *s)
{
    fprintf(stderr,"An error occurred in running the program. \n");
    fprintf(stderr,"%s\n",s);
    fprintf(stderr, "Error number %x.\n", GetLastError());
    fprintf(stderr, "Program terminating. \n");
    exit(1);
} // End of MyHandleError
jww
  • 97,681
  • 90
  • 411
  • 885
yes
  • 71
  • 8
  • why not use `PFXExportCertStoreEx` for save cert in pfx file ? – RbMm Jul 09 '17 at 13:54
  • Our application runs as service and using PFXExportCertStore required password "The PFX BLOB created by this function is protected by a password.". We don't want user input and hard coded password shall be sequrity breech. – yes Jul 09 '17 at 14:53
  • Moreover, if I correctly understand this command exports all certificates in the store and not just the required certificate. – yes Jul 09 '17 at 14:54
  • 2
    yes, this function really export all certificates in the strore, but you need first create in memory temporary store by `HCERTSTORE hMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, 0 )` then add selected cert in this store `CertAddCertificateContextToStore(hMemStore, pCertContext, CERT_STORE_ADD_NEW, 0)` and finally `PFXExportCertStoreEx(hMemStore, &db, szPassword, 0, EXPORT_PRIVATE_KEYS|REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)` – RbMm Jul 09 '17 at 17:04
  • and about password - it optional parameter - you can set it *szPassword* and to 0 if not want use password protected pfx (here will be private key). – RbMm Jul 09 '17 at 17:23
  • Thanks RbMm. 2 more questions regarding passing the certificate + private key. 1) After serialization of the certificate I noticed that I probably should convert it to base64 encoding if I want to save it into pfx file. This is the reason that I got before only 1 character in the file. But I need to separate the certificate and the private key and add for each of the sections header and trailer. How can I do it from the blob? 2) If instead of using file I shall pass it via memory? How can I import (which commands should I use) the certificate and private key to openSll? – yes Jul 11 '17 at 15:05

0 Answers0