【问题标题】:How can I access windows root certificate authorities certificates with Delphi?如何使用 Delphi 访问 Windows 根证书颁发机构证书?
【发布时间】:2011-12-31 09:52:15
【问题描述】:

关于 Lazarus 或 Delphi 的问题。有没有办法以编程方式访问 Windows 中受信任的根证书颁发机构证书。我知道 Windows 中有一个名为“mmc.exe”的基于 GUI 的工具,但我需要使用 Object Pascal 语法访问证书文件(如 .crt 或 .cer 或 .pem 等)。谁能帮我解决这个问题?

【问题讨论】:

    标签: delphi certificate-store


    【解决方案1】:

    您可以使用 EldoS 的 SecureBlackBox 做任何事情。 http://www.eldos.com/sbb/

    这个软件让它看起来很简单。这并不容易。

    【讨论】:

    • 我同意 Chris 的观点,我有幸使用早期版本,这非常好。但是,我不再可以访问它。如果你的预算允许,买这个,让你的生活更轻松。他们的多个包裹也变得复杂,因此请与他们交谈以确切了解您需要哪一个。它带有一个 fpc 版本。
    • PKIBlackBox 包正是您所需要的。但是,您应该继续获得完整的 SecureBlackBox Professional 鳄梨酱。它并不便宜(超过一千美元),但值得每一分钱。
    【解决方案2】:

    作为替代方案,您可以将 CAPICOM 简单地导入为 ActiveX 类型库,但也有普通的旧 Windows Cryptography API

    举个例子,这是我的一个非常古老的测试项目(我最近没试过)。您将需要 WinCryptJwaWinCrypt 单元以及相关 API 翻译,这些翻译应在 JEDI 上提供:

    program lstore;
    
    {$APPTYPE CONSOLE}
    
    uses
      Windows,
      SysUtils,
      WinCrypt;
    
    var
      StoreName: array[0..255] of Char;
      hStore: HCERTSTORE;
      CertContext: PCertContext;
      CertPropId: DWORD;
      Data: array[0..511] of Char;
      DataLen: DWORD;
      i: Integer;
    
    procedure DisplayCertContext(Cert: PCertContext);
    var
      CertName: array[0..255] of Char;
    begin
      if CertGetNameString(CertContext, CERT_NAME_EMAIL_TYPE, 0, nil,
        CertName, 256) = 0 then
        RaiseLastWin32Error;
      Writeln('Subject CERT_NAME_EMAIL_TYPE: ', CertName);
      if CertGetNameString(CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil,
        CertName, 256) = 0 then
        RaiseLastWin32Error;
      Writeln('Subject CERT_NAME_SIMPLE_DISPLAY_TYPE: ', CertName);
      if CertGetNameString(CertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, nil,
        CertName, 256) = 0 then
        RaiseLastWin32Error;
      Writeln('Subject CERT_NAME_FRIENDLY_DISPLAY_TYPE: ', CertName);
    
      if CertGetNameString(CertContext, CERT_NAME_EMAIL_TYPE, CERT_NAME_ISSUER_FLAG, nil,
        CertName, 256) = 0 then
        RaiseLastWin32Error;
      Writeln('Issuer CERT_NAME_EMAIL_TYPE: ', CertName);
      if CertGetNameString(CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, nil,
        CertName, 256) = 0 then
        RaiseLastWin32Error;
      Writeln('Issuer CERT_NAME_SIMPLE_DISPLAY_TYPE: ', CertName);
      if CertGetNameString(CertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, nil,
        CertName, 256) = 0 then
        RaiseLastWin32Error;
      Writeln('Issuer CERT_NAME_FRIENDLY_DISPLAY_TYPE: ', CertName);
    end;
    
    begin
      try
        Write('Enter name of store to be listed: ');
        Readln(StoreName);
        hStore := CertOpenSystemStore(0, StoreName);
        if hStore = nil then
          RaiseLastWin32Error;
        try
          CertContext := CertEnumCertificatesInStore(hStore, nil);
          while CertContext <> nil do
          begin
            DisplayCertContext(CertContext);
            CertPropId := CertEnumCertificateContextProperties(CertContext, 0);
            while CertPropId <> 0 do
            begin
              DataLen := 512;
      //        Writeln(Format('CertPropId: %d', [CertPropId]));
              case CertPropId of
              CERT_KEY_PROV_HANDLE_PROP_ID:
              begin
                CertGetCertificateContextProperty(CertContext, CertPropId,
                  @Data[0], DataLen);
                Writeln(Format('KEY_PROV_HANDLE: $%.8x', [PDWORD(@Data[0])^]));
              end;
              CERT_KEY_PROV_INFO_PROP_ID:
              begin
                CertGetCertificateContextProperty(CertContext, CertPropId,
                  @Data[0], DataLen);
                with PCryptKeyProvInfo(@Data[0])^ do
                begin
                  Writeln(Format('pwszContainerName = %s', [pwszContainerName]));
                  Writeln(Format('pwszProvName = %s', [pwszProvName]));
                  Writeln(Format('dwFlags = %d', [dwFlags]));
                  Writeln(Format('cProvParams = %d', [cProvParams]));
                  //Writeln(Format('rgProvParam', [rgProvParam]));
                  Writeln(Format('dwKeySpec = %d', [dwKeySpec]));
                end;
                Writeln(Format('KEY_PROV_INFO: %d', [@Data[0]]));
              end;
              CERT_FRIENDLY_NAME_PROP_ID:
              begin
                CertGetCertificateContextProperty(CertContext, CertPropId,
                  @Data[0], DataLen);
                Writeln(Format('FRIENDLY_NAME: %s', [PChar(@Data[0])]));
              end;
              CERT_KEY_IDENTIFIER_PROP_ID:
              begin
                CertGetCertificateContextProperty(CertContext, CertPropId,
                  @Data[0], DataLen);
                Write('KEY_IDENTIFIER: ');
                for i := 1 to DataLen do
                  Write(Format('%.2x ', [PBYTE(@Data[i - 1])^]));
                Writeln;
              end;
              CERT_SHA1_HASH_PROP_ID:
              begin
                CertGetCertificateContextProperty(CertContext, CertPropId,
                  @Data[0], DataLen);
                Write('SHA1_HASH: ');
                for i := 1 to DataLen do
                  Write(Format('%.2x ', [PBYTE(@Data[i - 1])^]));
                Writeln;
              end;
              CERT_MD5_HASH_PROP_ID:
              begin
                CertGetCertificateContextProperty(CertContext, CertPropId,
                  @Data[0], DataLen);
                Write('MD5_HASH: ');
                for i := 1 to DataLen do
                  Write(Format('%.2x ', [PBYTE(@Data[i - 1])^]));
                Writeln;
              end;
              else
              end;
              CertPropId := CertEnumCertificateContextProperties(CertContext,
                CertPropId);
            end;
            CertContext := CertEnumCertificatesInStore(hStore, CertContext);
          end;
    //      if GetLastError <> CRYPT_E_NOT_FOUND then
    //        RaiseLastWin32Error;
        finally
          CertCloseStore(hStore, 0);
        end;
      except
        on E: Exception do
        begin
          ExitCode := 1;
          Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
        end;
      end;
    end.
    

    【讨论】:

      【解决方案3】:

      我推荐Eldos SecureBlackBox,但有一个免费的替代方案。

      您还可以使用 OpenSSL 库。您需要一个完整的 OpenSSL 端口,因为 Indy OpenSSL 标头不完整。您还需要编译来自证书颁发机构的公共证书数据库,因为它不包括在内。

      使用 OpenSSL,您将无法直接访问 Windows 证书存储。您可以从 Windows 或 Firefox 导出证书并导入它们。

      Eldos SecureBlackBox 提供对 Windows 证书存储的访问,包括验证程序代码签名签名的方法。

      您可以在您的 Windows 产品中包含 OpenSSL 二进制文件,并且 OpenSSL 已经安装并在 Mac OS 上可用。因此,OpenSSL 对于 FireMonkey 或 Lazarus 是可行的。

      OpenSSL 有很好的文档记录,您可以在网上找到很多示例,但主要是使用 C 或 C++ 编写的。我很幸运用它实现了我需要的任何东西。它有很多读取和写入PEM文件的功能。

      SecureBlackBox 还没有 FireMonkey 版本,但他们说他们明年会有一个(根据他们的论坛)。他们确实有 fpc(免费帕斯卡)版本。

      【讨论】:

        猜你喜欢
        • 2018-06-19
        • 2018-10-08
        • 2012-10-31
        • 2014-12-26
        • 2012-04-18
        • 1970-01-01
        • 2016-01-01
        • 2017-10-01
        相关资源
        最近更新 更多