我正在尝试使用 PFXExportCertStoreEx API 为自签名证书及其相应的私钥创建一个 pfx 文件。
自签名证书导出到 pfx 但私钥未导出到 pfx 文件。我为私钥设置了导出策略,如下所示。
export_policy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
我尝试了以下不同的方法,在这两种情况下,PFXExportCertStoreEx API 都失败,错误代码为 0x80090016。
方法 1:使用此处 提到的 CERT_KEY_PROV_INFO_PROP_ID 调用 API CertSetCertificateContextProperty
方法 2: 使用 CERT_NCRYPT_KEY_HANDLE_PROP_ID 和 keyHandle 调用 API CertSetCertificateContextProperty
我正在使用以下代码创建私钥、自签名证书并导出到 pfx 文件。
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <strsafe.h>
#include<ncrypt.h>
#pragma comment (lib, "crypt32")
#pragma comment(lib, "ncrypt.lib")
int main()
{
CreateCert();
return 0;
}
int CreateCert(void)
{
int result = 0;
CERT_NAME_BLOB nameBlob = {0, NULL};
CERT_EXTENSIONS certExtensions = { 0 };
NCRYPT_PROV_HANDLE providerHandle = { 0 };
NCRYPT_KEY_HANDLE keyHandle = { 0 };
PCCERT_CONTEXT certContext = NULL;
ZeroMemory(&certExtensions,sizeof(certExtensions));
CRYPT_KEY_PROV_INFO keyProvInfo;
ZeroMemory(&keyProvInfo,sizeof(keyProvInfo));
keyProvInfo.pwszContainerName = L"Label1_Key";
keyProvInfo.dwProvType = PROV_RSA_FULL;
keyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
keyProvInfo.dwKeySpec = AT_SIGNATURE;
if (NCryptOpenStorageProvider(&providerHandle,
MS_KEY_STORAGE_PROVIDER,
0) != 0)
{
printf("\nFailed NCryptOpenStorageProvider");
goto fail;
}
if (NCryptCreatePersistedKey(providerHandle,
&keyHandle,
BCRYPT_RSA_ALGORITHM,
L"Label1_Key",
AT_SIGNATURE,
NCRYPT_OVERWRITE_KEY_FLAG) != 0)
{
printf("\nFailed NCryptCreatePersistedKey");
goto fail;
}
NTSTATUS status = -1;
DWORD dwBits = 2048;
status = NCryptSetProperty(
keyHandle,
NCRYPT_LENGTH_PROPERTY,
(PBYTE) &dwBits,
sizeof(dwBits),
NCRYPT_PERSIST_FLAG
);
if( status )
{
printf("\nFailed NCryptSetProperty to key size");
goto fail;
}
DWORD export_policy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
if (NCryptSetProperty(
keyHandle,
NCRYPT_EXPORT_POLICY_PROPERTY,
(PBYTE)&export_policy,
sizeof(export_policy),
NCRYPT_PERSIST_FLAG))
{
printf("\nFailed NCryptSetProperty to export policy");
goto fail;
}
if (NCryptFinalizeKey(keyHandle,
NCRYPT_SILENT_FLAG) != 0)
{
printf("\nFailed NCryptFinalizeKey");
goto fail;
}
if (!CertStrToNameW(X509_ASN_ENCODING,
L"CN=Label1",
0,
NULL,
nameBlob.pbData,
&nameBlob.cbData,
NULL))
{
printf("\nFailed CertStrToNameW 1");
goto fail;
}
nameBlob.pbData = malloc(nameBlob.cbData);
if (!CertStrToNameW(X509_ASN_ENCODING,
L"CN=Label1",
0,
NULL,
nameBlob.pbData,
&nameBlob.cbData, NULL))
{
printf("\nFailed CertStrToNameW 2");
goto fail;
}
SYSTEMTIME EndTime;
SYSTEMTIME StartTime;
GetSystemTime(&StartTime);
GetSystemTime(&EndTime);
EndTime.wYear += 10;
certContext = CertCreateSelfSignCertificate(
keyHandle,
&nameBlob,
0,
&keyProvInfo,
NULL,
&StartTime,
&EndTime,
&certExtensions
);
if (!certContext)
{
printf("\nFailed CertCreateSelfSignCertificate");
goto fail;
}
CRYPT_DATA_BLOB Friendly_Name_Blob;
ZeroMemory( &Friendly_Name_Blob, sizeof(Friendly_Name_Blob) );
Friendly_Name_Blob.pbData = (BYTE *)L"Temp Name";
Friendly_Name_Blob.cbData = (wcslen((LPWSTR)Friendly_Name_Blob.pbData)+1) * sizeof(WCHAR);;
if(CertSetCertificateContextProperty(
certContext,
CERT_FRIENDLY_NAME_PROP_ID,
0,
&Friendly_Name_Blob))
{
printf("A name has been set.\n");
}
else
{
printf("The display name was not set.\n");
}
CRYPT_KEY_PROV_INFO kpi;
ZeroMemory(&kpi, sizeof(kpi) );
kpi.pwszContainerName = L"Label1_Key";
kpi.dwProvType = PROV_RSA_FULL;
kpi.dwKeySpec = AT_KEYEXCHANGE;
kpi.dwFlags = CRYPT_MACHINE_KEYSET;
if(CertSetCertificateContextProperty(certContext,
CERT_KEY_PROV_INFO_PROP_ID,
0,
(const void *)&kpi))
{
printf("Key set.\n");
}
else
{
printf("Key set faile\n");
goto fail;
}
// if(CertSetCertificateContextProperty(certContext,
// CERT_NCRYPT_KEY_HANDLE_PROP_ID,
// 0,
// (const void *)&keyHandle))
// {
// printf("Key set.\n");
// }
// else
// {
// printf("Key set faile\n");
// goto fail;
// }
PCCERT_CONTEXT pCertContext = NULL;
HCERTSTORE hMemStore = NULL;
CRYPT_DATA_BLOB Blob;
hMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
0,
(HCRYPTPROV_LEGACY)NULL,
CERT_STORE_CREATE_NEW_FLAG,
NULL);
if(!hMemStore)
{
printf("Error creating memory certificate store: %d\n",GetLastError());
goto fail;
}
if(!CertAddCertificateContextToStore(hMemStore,
certContext,
CERT_STORE_ADD_ALWAYS,
NULL))
{
printf("Error adding certificate to memory certificate store: %d\n",GetLastError());
goto fail;
}
ZeroMemory(&Blob,sizeof(CRYPT_DATA_BLOB));
if (!PFXExportCertStoreEx(hMemStore,
&Blob,
L"mypassword",
NULL,
EXPORT_PRIVATE_KEYS |
REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY |
PKCS12_INCLUDE_EXTENDED_PROPERTIES |
REPORT_NO_PRIVATE_KEY))
{
printf("Error sizing blob: 0x%x \n", GetLastError());
goto fail;
}
Blob.pbData = (PBYTE)HeapAlloc(GetProcessHeap(),0,Blob.cbData);
if(!Blob.pbData)
{
printf("Error allocating data blob: %d\n", GetLastError());
goto fail;
}
if(!PFXExportCertStoreEx(hMemStore,
&Blob,
L"mypassword",
NULL,
EXPORT_PRIVATE_KEYS |
REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY |
PKCS12_INCLUDE_EXTENDED_PROPERTIES |
REPORT_NO_PRIVATE_KEY))
{
printf("Error exporting certificates: %d\n",GetLastError());
goto fail;
}
HANDLE hFile = NULL;
DWORD dwBytesWritten = 0;
hFile = CreateFile("Certificate.pfx",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,0);
if(hFile == INVALID_HANDLE_VALUE) {
printf("Error creating output file: %d\n", GetLastError());
goto fail;
}
if(!WriteFile(hFile,Blob.pbData,Blob.cbData,&dwBytesWritten,0)) {
printf("Error writing to file: %d\n", GetLastError());
goto fail;
}
if (dwBytesWritten != Blob.cbData) {
printf("Number of bytes written does not match requested!\n");
goto fail;
}
printf("\nCertificate Created Successfully");
fail:
free(nameBlob.pbData);
if (providerHandle)
NCryptFreeObject(providerHandle);
if (certContext)
CertFreeCertificateContext(certContext);
if(hMemStore)
CertCloseStore(hMemStore, 0);
if(pCertContext)
CertFreeCertificateContext(pCertContext);
if(hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
if(Blob.pbData) HeapFree(GetProcessHeap(),0,Blob.pbData);
return result;
}
让我知道如何将私钥与自签名证书一起导出到 pfx 文件。
提前致谢。