5

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

4

3 回答 3

6

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

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

于 2011-11-17T14:35:26.027 回答
6

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

例如,这是我的一个非常古老的测试项目(我最近没有尝试过)。您将需要WinCryptor单元以及JEDIJwaWinCrypt上应该可用的相关 API 翻译:

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.
于 2011-11-17T15:38:18.367 回答
4

我推荐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(免费帕斯卡)版本。

于 2011-11-17T15:07:23.527 回答