如何使用Delphi访问Windows根证书颁发机构证书?
拉撒路或德尔福相关的问题。有没有办法在Windows中以编程方式访问受信任的根证书颁发机构证书。我知道Windows中有基于GUI的工具叫'mmc.exe',但我需要使用Object Pascal语法访问证书文件(如.crt或.cer或.pem等)。任何人都可以帮助我吗?如何使用Delphi访问Windows根证书颁发机构证书?
作为替代方案,有CAPICOM,您可以简单地导入为ActiveX类型库,但也有简单的旧的Windows Cryptography API。作为一个例子,这里有一个很老的我的测试项目(我最近没试过)。你将需要WinCrypt
或JwaWinCrypt
单位与有关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.
我推荐Eldos SecureBlackBox,但有一个免费的替代方案。
您也可以使用OpenSSL库。由于Indy OpenSSL头文件不完整,您将需要一个完整的OpenSSL端口。您还需要从证书颁发机构编译公用证书的数据库,因为它不包含在内。
使用OpenSSL,您将无法直接访问Windows证书存储。您可以从Windows或Firefox导出证书并导入它们。
Eldos SecureBlackBox提供对Windows证书存储的访问,包括验证程序的代码签名签名的方法。
您可以在您的Windows产品中包含OpenSSL二进制文件,并且已经在Mac OS上安装并提供了OpenSSL。所以,OpenSSL对于FireMonkey或Lazarus是可行的。
OpenSSL有很好的文档记录,你可以在网上找到很多例子,尽管大多数是C或C++。我已经有很好的运气来实现我需要的任何东西。它具有很多读写PEM文件的功能。
SecureBlackBox还没有FireMonkey版本,但他们表示他们明年会有一个(每个论坛)。他们有一个fpc(免费pascal)版本。
我与克里斯同意,我已经受够了早期版本的工作的特权,这是非常不错。但是,我无法再访问它。如果你的预算允许,购买这个,让你的生活变得轻松。它们的多个软件包也变得复杂起来,所以要和他们交谈,找出你需要的是哪一个。它带有一个fpc版本。 –
PKIBlackBox包是你需要的。但是,您应该继续并获得完整的SecureBlackBox Professional鳄梨酱。它并不便宜(超过一千美元),但它值得每一分钱。 –