我正在实现一个Delphi Windows服务作为服务器,并希望启用TLS/SSL进行安全通信。为此,我使用了TIdServerIOHandlerSSLOpenSSL组件,并且能够在客户端和服务器之间建立安全的通信。
我的问题与我如何加载证书和密钥有关。我已经写了以下代码来加载证书和密钥文件:
IOHandler.SSLOptions.CertFile := 'localhost.cert.pem'; // Certificate file
IOHandler.SSLOptions.KeyFile := 'localhost.key.pem'; // Key File
IOHandler.SSLOptions.RootCertFile := 'ca.cert.pem'; // Root certificate所有文件(证书和密钥)都放在应用程序目录中。但其中一个要求是从Windows证书库中读取证书。
如何从Delphi代码内部的Windows证书存储中读取证书并将这些证书分配给IOHandler.SSLOptions
发布于 2021-06-06 06:08:48
您可以使用WinCrypt函数将选定的证书及其链导出到一个PFX文件中,然后将该文件路径分配给CertFile、KeyFile和RootCertFile属性(是的,如果包含所有证书,则可以使用相同的文件)。
证书必须有"export“标志。
下一个示例是在Delphi2010中测试的,并使用JwaWinCrypt单元:
// Some declarations missing in JwaWinCrypt
function PFXExportCertStoreEx(hStore: HCERTSTORE;
var pPFX: CRYPT_DATA_BLOB;
szPassword: LPCWSTR;
pvPra: Pointer;
dwFlags: DWORD): BOOL; stdcall; external 'Crypt32.dll';
const
REPORT_NO_PRIVATE_KEY = $0001;
REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY = $0002;
EXPORT_PRIVATE_KEYS = $0004;
PKCS12_INCLUDE_EXTENDED_PROPERTIES = $0010;
// Password to protect PFX file
WidePass: WideString = '';
var
pStore, pStoreTmp: HCERTSTORE;
pCert: PCERT_CONTEXT;
PFX,
Hash: CRYPT_INTEGER_BLOB;
ChainPara: CERT_CHAIN_PARA;
EnhkeyUsage: CERT_ENHKEY_USAGE;
CertUsage: CERT_USAGE_MATCH;
pChainContext: PCCERT_CHAIN_CONTEXT;
ppCertSimpleChain: ^PCERT_SIMPLE_CHAIN;
ppCertChainElement: ^PCERT_CHAIN_ELEMENT;
i, j: Integer;
Buffer: RawByteString;
begin
pStore := nil;
pStoreTmp := nil;
pCert := nil;
PFX.pbData := nil;
PFX.cbData := 0;
// Open system certificate store
pStore := CertOpenSystemStore(0, 'MY');
// Open in-mem temporal certificate store
pStoreTmp := CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, nil);
// HEX SHA1 Hash of the certificate to find
Buffer := 'YourCertificateSHA1HashHEX9be0c6fef0600b';
Hash.cbData := Length(Buffer);
Hash.pbData := @Buffer[1];
// Find it
pCert := CertFindCertificateInStore(pStore,
X509_ASN_ENCODING,
0,
CERT_FIND_SHA1_HASH,
@Hash,
nil);
// Now let's get the certificate's chain context
EnhkeyUsage.cUsageIdentifier := 0;
EnhkeyUsage.rgpszUsageIdentifier := nil;
CertUsage.dwType := USAGE_MATCH_TYPE_AND;
CertUsage.Usage := EnhkeyUsage;
ChainPara.cbSize := SizeOf(CERT_CHAIN_PARA);
ChainPara.RequestedUsage := CertUsage;
CertGetCertificateChain(0, pCert, nil, nil,
@ChainPara, 0, nil, @pChainContext);
// Iterate the chain context and add every certificate to mem-store
ppCertSimpleChain := Pointer(pChainContext^.rgpChain);
for i := 1 to pChainContext.cChain do
begin
ppCertChainElement := Pointer(ppCertSimplechain^.rgpElement);
for j := 1 to ppCertSimpleChain^.cElement do
begin
CertAddCertificateLinkToStore(pStoreTmp,
ppCertChainElement^.pCertContext,
CERT_STORE_ADD_REPLACE_EXISTING,
nil);
Inc(ppCertChainElement);
end;
Inc(ppCertSimpleChain);
end;
// Save to PFX ...
PFX.pbData := nil;
PFX.cbData := 0;
// First a call with an empty BLOB to get the space needed
PFXExportCertStoreEx(pStoreTmp,
PFX,
PWideChar(WidePass),
nil,
EXPORT_PRIVATE_KEYS +
REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY +
REPORT_NO_PRIVATE_KEY +
PKCS12_INCLUDE_EXTENDED_PROPERTIES);
// OK, reserve the needed memory
GetMem(PFX.pbData, PFX.cbData);
// Fill data
PFXExportCertStoreEx(pStoreTmp,
PFX,
PWideChar(WidePass),
nil,
EXPORT_PRIVATE_KEYS +
REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY +
REPORT_NO_PRIVATE_KEY +
PKCS12_INCLUDE_EXTENDED_PROPERTIES);
// Now PFX.pbData points to PFX information of length PFX.cbData
// Write it to a temporary file that replaces your PEM files.
// Free memory used
// I deliberately did not check whether
// previous API calls returned an error.
// You should check.
// Take a look to Microsoft's documentation for functions results
// and GetLastError function for error code
CertFreeCertificateChain(pChainContext);
CertFreeCertificateContext(pCert);
CertCloseStore(pStoreTmp, 0);
CertCloseStore(pStore, 0);
FreeMem(PFX.pbData);
end.发布于 2021-06-09 00:17:44
您可以使用Delphi DLL CHILKAT。
https://www.example-code.com/delphidll/cert_load_from_windows_cert_store.asp
Cert Delphi DLL参考文档:
https://stackoverflow.com/questions/67816499
复制相似问题