网上找到的代码貌似都不太靠谱,于是自己写了一个,下面只公布主要的函数
void CImportPFXDlg::ImportPFX(LPCTSTR PFX_FILE, LPCTSTR PFX_PASS)
{
//打开文件
HANDLE hFile = NULL;
hFile = ::CreateFile(PFX_FILE, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
::AfxMessageBox(_T("CreateFile Fail!"));
return;
}
//分配内存
DWORD dwSize = ::GetFileSize(hFile, NULL);
BYTE *pP12 = NULL;
if (!(pP12 = new BYTE[dwSize]))
{
::CloseHandle(hFile);
::AfxMessageBox(_T("new pP12 Fail!"));
return;
}
//读取证书内容
DWORD dwRead = 0;
if (!::ReadFile(hFile, pP12, dwSize, &dwRead, NULL))
{
::CloseHandle(hFile);
::AfxMessageBox(_T("ReadFile Fail!"));
return;
}
//关闭文件
::CloseHandle(hFile);
//生成结构体
CRYPT_DATA_BLOB CDB;
CDB.cbData = dwSize;
CDB.pbData = pP12;
//将证书导入临时证书库
HCERTSTORE hStore = NULL;
if (!(hStore = PFXImportCertStore(&CDB, PFX_PASS, CRYPT_EXPORTABLE)))
{
delete pP12; pP12 = NULL;
::AfxMessageBox(_T("PFXImportCertStore Fail!"));
return;
}
delete pP12; pP12 = NULL;
//枚举临时证书库中导入的证书
PCCERT_CONTEXT pCertContext = NULL;
HCRYPTPROV hCertProv = NULL;
HCRYPTKEY hKey = NULL;
BYTE *pPK = NULL;
HCRYPTKEY hPrvKey = NULL;
HCRYPTPROV hProv = NULL;
while (pCertContext = CertEnumCertificatesInStore(hStore, pCertContext))
{
//对比“颁发给”和“颁发者”是否一致(对于根证书是一致的,不要导入根证书)
//if (!CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
// &pCertContext->pCertInfo->Issuer,
// &pCertContext->pCertInfo->Subject))
{
//获取私钥临时 CSP 句柄
DWORD dwKeySpec = 0;
if (!CryptAcquireCertificatePrivateKey(pCertContext,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
NULL,
&hCertProv,
&dwKeySpec,
NULL))
{
DWORD dwRet = GetLastError();
::AfxMessageBox(_T("CryptAcquireCertificatePrivateKey Fail!"));
goto cleanup;
}
//获取密钥对
if (!CryptGetUserKey(hCertProv, ((m_cmbCertType.GetCurSel() == 0) ? AT_KEYEXCHANGE : AT_SIGNATURE), &hKey))
{
DWORD dwRet = GetLastError();
::AfxMessageBox(_T("CryptGetUserKey Fail!"));
goto cleanup;
}
//获取私钥长度
DWORD dwPKSize = 0;
if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwPKSize))
{
DWORD dwRet = GetLastError();
::AfxMessageBox(_T("CryptExportKey dwPKSize Fail!"));
goto cleanup;
}
//分配内存
if (!(pPK = new BYTE[dwPKSize]))
{
DWORD dwRet = GetLastError();
::AfxMessageBox(_T("new pPK Fail!"));
goto cleanup;
}
//导出私钥
if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pPK, &dwPKSize))
{
DWORD dwRet = GetLastError();
::AfxMessageBox(_T("CryptExportKey pPK Fail!"));
goto cleanup;
}
//获取 UKEY 的 CSP 句柄
//获取密钥容器名称
CString csContainer;
if (m_cmbContainer.GetCurSel() == 0) //新建密钥容器
{
m_edtContainer.GetWindowText(csContainer);
if (!CryptAcquireContext(&hProv, (LPCTSTR)csContainer, CSP_NAME, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
DWORD dwRst = ::GetLastError();
::AfxMessageBox(_T("CryptAcquireContext m_edtContainer Fail!"));
goto cleanup;
}
}
else //证书导入现有容器
{
m_cmbContainer.GetWindowText(csContainer);
if (!CryptAcquireContext(&hProv, (LPCTSTR)csContainer, CSP_NAME, PROV_RSA_FULL, 0))
{
DWORD dwRst = ::GetLastError();
::AfxMessageBox(_T("CryptAcquireContext m_cmbContainer Fail!"));
goto cleanup;
}
}
//将私钥导入到 CSP,并获取其句柄
if (!CryptImportKey(hProv, pPK, dwPKSize, NULL, 0, &hPrvKey))
{
DWORD dwRst = ::GetLastError();
::AfxMessageBox(_T("CryptImportKey Fail!"));
goto cleanup;
}
//将证书导入到密钥容器
if (!CryptSetKeyParam(hPrvKey, KP_CERTIFICATE, pCertContext->pbCertEncoded, 0))
{
DWORD dwRst = ::GetLastError();
::AfxMessageBox(_T("CryptSetKeyParam Fail!"));
goto cleanup;
}
break;
}
}
cleanup:
//销毁私钥句柄
CryptDestroyKey(hPrvKey);
//关闭 UKEY 的 CSP 句柄
CryptReleaseContext(hProv, 0);
//释放私钥内存
delete pPK; pPK = NULL;
//销毁密钥对句柄
CryptDestroyKey(hKey);
//释放证书句柄
CertFreeCertificateContext(pCertContext);
//关闭临时证书库
CertCloseStore(hStore, 0);
}