Вопрос, связанный с Lazarus или Delphi. Есть ли способ программно получить доступ к доверенным сертификатам корневых центров сертификации в Windows. Я знаю, что в Windows есть инструмент на основе графического интерфейса, который называется «mmc.exe», но мне нужно получить доступ к файлам сертификатов (таким как .crt или .cer или .pem и т. д.) с использованием синтаксиса Object Pascal. Может ли кто-нибудь помочь мне с этим?
Как я могу получить доступ к сертификатам корневых центров сертификации Windows с помощью Delphi?
Ответы (3)
В качестве альтернативы есть CAPICOM, который вы можете просто импортировать как библиотеку типов ActiveX, но есть и старый добрый Windows 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 (бесплатный паскаль).