我们的应用程序使用OpenSSL来保护客户端设备和服务器之间的通信。证书由客户CA生成,我们必须将服务器证书和私钥上传到基于Windows操作系统的计算机。
到目前为止,我们指导客户在服务器文件系统的特定目录中保存包含服务器证书和私钥的PEM文件,我们的应用程序从那里上传它。最近,客户要求我们从本地Windows证书商店阅读PFX证书。
我可以想到两个选项,它们结合使用CAPI库从WCS导出PFX文件(根据友好名称),序列化然后使用OpenSSL API上传。
第一个选项将其保存为服务器文件系统上的临时文件,然后像以前一样使用OpenSSL API读取。
第二个选项使用内存,即传递指针而不是使用临时文件。
我的团队花了很多时间在网上搜索(主要是Stack Overflow)并尝试使用代码段,但没有找到可行的解决方案。我知道在将文件导入WCS时,私钥应该是可导出的。
当我在下面的代码中尝试简单导出证书并将其保存到文件(基于MS示例代码的选项#1的前半部分)时,它只将一个字符写入文件。
我在这里想念什么?我需要重新格式化证书吗?
任何关于什么是错的想法以及做正确的方法是什么?
可以通过这种方式提取私钥吗?
提前感谢任何评论
//-----------------------------------------
#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