如何解决PFXExportCertStoreEx API 未将私钥导出到 PFX 文件
我正在尝试使用 PFXExportCertStoreEx API 为自签名证书及其相应的私钥创建 pfx 文件。
自签名证书导出到 pfx,但私钥不导出到 pfx 文件。我将私钥的导出策略设置如下。
export_policy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
我尝试了如下不同的方法,在两种情况下 PFXExportCertStoreEx API 都失败,错误代码为 0x80090016。
方法 1: 调用 API CertSetCertificateContextProperty 和 CERT_KEY_PROV_INFO_PROP_ID 作为提到的 here
方法 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",NULL,nameBlob.pbData,&nameBlob.cbData,NULL))
{
printf("\nFailed CertStrToNameW 1");
goto fail;
}
nameBlob.pbData = malloc(nameBlob.cbData);
if (!CertStrToNameW(X509_ASN_ENCODING,NULL))
{
printf("\nFailed CertStrToNameW 2");
goto fail;
}
SYSTEMTIME EndTime;
SYSTEMTIME StartTime;
GetSystemTime(&StartTime);
GetSystemTime(&EndTime);
EndTime.wYear += 10;
certContext = CertCreateSelfSignCertificate(
keyHandle,&nameBlob,&keyProvInfo,&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,&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,(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,(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",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(),Blob.cbData);
if(!Blob.pbData)
{
printf("Error allocating data blob: %d\n",GetLastError());
goto fail;
}
if(!PFXExportCertStoreEx(hMemStore,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,CREATE_ALWAYS,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(),Blob.pbData);
return result;
}
让我知道如何将私钥与自签名证书一起导出到 pfx 文件。
提前致谢。
解决方法
把上面的代码改成下面这样,私钥和证书就成功导出到pfx文件了。
调用 NCryptOpenStorageProvider 之前。
memset(&keyProvInfo,sizeof(keyProvInfo));
keyProvInfo.pwszContainerName = L"Label_key1";;
keyProvInfo.pwszProvName = MS_KEY_STORAGE_PROVIDER;
keyProvInfo.dwProvType = 0;
keyProvInfo.dwKeySpec = 0;
调用 CertCreateSelfSignCertificate 后添加以下代码
if(CertSetCertificateContextProperty(certContext,CERT_NCRYPT_KEY_HANDLE_PROP_ID,(const void *)&keyHandle))
{
printf("Key set.\n");
}
else
{
printf("Key set faile\n");
goto fail;
}
查看下面的完整代码。
#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;
memset(&keyProvInfo,sizeof(keyProvInfo));
keyProvInfo.pwszContainerName = L"Label_key1";;
keyProvInfo.pwszProvName = MS_KEY_STORAGE_PROVIDER;
keyProvInfo.dwProvType = 0;
keyProvInfo.dwKeySpec = 0;
if (NCryptOpenStorageProvider(&providerHandle,MS_KEY_STORAGE_PROVIDER,0) != 0)
{
printf("\nFailed NCryptOpenStorageProvider");
goto fail;
}
if (NCryptCreatePersistedKey(providerHandle,&keyHandle,BCRYPT_RSA_ALGORITHM,keyProvInfo.pwszContainerName,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",NULL,nameBlob.pbData,&nameBlob.cbData,NULL))
{
printf("\nFailed CertStrToNameW 1");
goto fail;
}
nameBlob.pbData = malloc(nameBlob.cbData);
if (!CertStrToNameW(X509_ASN_ENCODING,NULL))
{
printf("\nFailed CertStrToNameW 2");
goto fail;
}
SYSTEMTIME EndTime;
SYSTEMTIME StartTime;
GetSystemTime(&StartTime);
GetSystemTime(&EndTime);
EndTime.wYear += 10;
certContext = CertCreateSelfSignCertificate(
keyHandle,&nameBlob,&keyProvInfo,&StartTime,&EndTime,&certExtensions
);
if (!certContext)
{
printf("\nFailed CertCreateSelfSignCertificate");
goto fail;
}
if(CertSetCertificateContextProperty(certContext,(const void *)&keyHandle))
{
printf("Key set.\n");
}
else
{
printf("Key set faile\n");
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,&Friendly_Name_Blob))
{
printf("A name has been set.\n");
}
else
{
printf("The display name was not set.\n");
}
PCCERT_CONTEXT pCertContext = NULL;
HCERTSTORE hMemStore = NULL;
CRYPT_DATA_BLOB Blob;
hMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY,(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",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(),Blob.cbData);
if(!Blob.pbData)
{
printf("Error allocating data blob: %d\n",GetLastError());
goto fail;
}
if(!PFXExportCertStoreEx(hMemStore,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,CREATE_ALWAYS,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(),Blob.pbData);
return result;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。