首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用Delphi从windows证书库中读取SSL证书

如何用Delphi从windows证书库中读取SSL证书
EN

Stack Overflow用户
提问于 2021-06-03 14:35:12
回答 2查看 622关注 0票数 1

我正在实现一个Delphi Windows服务作为服务器,并希望启用TLS/SSL进行安全通信。为此,我使用了TIdServerIOHandlerSSLOpenSSL组件,并且能够在客户端和服务器之间建立安全的通信。

我的问题与我如何加载证书和密钥有关。我已经写了以下代码来加载证书和密钥文件:

代码语言:javascript
复制
  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

EN

回答 2

Stack Overflow用户

发布于 2021-06-06 06:08:48

您可以使用WinCrypt函数将选定的证书及其链导出到一个PFX文件中,然后将该文件路径分配给CertFile、KeyFile和RootCertFile属性(是的,如果包含所有证书,则可以使用相同的文件)。

证书必须有"export“标志。

下一个示例是在Delphi2010中测试的,并使用JwaWinCrypt单元:

代码语言:javascript
复制
// 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.
票数 0
EN

Stack Overflow用户

发布于 2021-06-09 00:17:44

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67816499

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档