Как я могу получить доступ к сертификатам корневых центров сертификации Windows с помощью Delphi?
Вопрос, связанный с Lazarus или Delphi. Есть ли способ для программного доступа к доверенным сертификатам корневых центров сертификации в Windows. Я знаю, что в Windows есть инструмент с графическим интерфейсом, называемый mmc.exe, но мне нужен доступ к файлам сертификатов (например,.crt или.cer или.pem и т. Д.) С использованием синтаксиса Object Pascal. Кто-нибудь может мне помочь с этим?
3 ответа
В качестве альтернативы есть 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.
Вы можете сделать что угодно с SecureBlackBox от EldoS. http://www.eldos.com/sbb/
Это программное обеспечение делает это простым. Это не просто.
Я рекомендую Eldos SecureBlackBox, но есть бесплатная альтернатива.
Вы также можете использовать библиотеки OpenSSL. Вам понадобится полный порт OpenSSL, так как заголовки Indy OpenSSL неполные. Вам также нужно будет скомпилировать базу данных открытых сертификатов из центров сертификации, поскольку она не включена.
С OpenSSL у вас не будет доступа к хранилищу сертификатов Windows напрямую. Вы можете экспортировать сертификаты из Windows или Firefox и импортировать их.
Eldos SecureBlackBox предоставляет доступ к хранилищу сертификатов Windows, включая методы проверки подписи кода для подписи программы.
Вы можете включить двоичные файлы OpenSSL в свой продукт Windows, и OpenSSL уже установлен и доступен в Mac OS. Итак, OpenSSL жизнеспособен для FireMonkey или Lazarus.
OpenSSL довольно хорошо документирован, и вы можете найти много примеров в Интернете, хотя в основном на C или C++. Мне повезло, что я реализовал все, что мне было нужно. Он имеет много функций для чтения и записи в файлы PEM.
SecureBlackBox еще не имеет версию FireMonkey, но они говорят, что у них будет одна в следующем году (согласно их форуму). У них есть fpc (бесплатная версия на паскале).