Как экспортировать все мои сертификаты программного обеспечения отдельно в файл.pfx?
Я хочу, чтобы программно экспортировать все свои сертификаты программного обеспечения компьютера в файл .pfx, чтобы подписать 2 новых программного обеспечения, которые уже находятся на последнем этапе сборки на другом компьютере.
Чтобы сделать это, я нашел пример кода C++ (после перевода на Delphi).
Моя версия Delphi еще не была протестирована, но я думаю, что она работает нормально.
program CertToPFX;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
WinCrypt,
Classes,
SysUtils;
var
CertContext: PCCERT_CONTEXT;
CertPropId: DWORD;
Data: array [0 .. 511] of Char;
DataLen: DWORD;
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
RaiseLastOSError;
Writeln('Subject CERT_NAME_EMAIL_TYPE: ', CertName);
if CertGetNameString(CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil,
CertName, 256) = 0 then
RaiseLastOSError;
Writeln('Subject CERT_NAME_SIMPLE_DISPLAY_TYPE: ', CertName);
if CertGetNameString(CertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, nil,
CertName, 256) = 0 then
RaiseLastOSError;
Writeln('Subject CERT_NAME_FRIENDLY_DISPLAY_TYPE: ', CertName);
if CertGetNameString(CertContext, CERT_NAME_EMAIL_TYPE, CERT_NAME_ISSUER_FLAG,
nil, CertName, 256) = 0 then
RaiseLastOSError;
Writeln('Issuer CERT_NAME_EMAIL_TYPE: ', CertName);
if CertGetNameString(CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG, nil, CertName, 256) = 0 then
RaiseLastOSError;
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
RaiseLastOSError;
Writeln('Issuer CERT_NAME_FRIENDLY_DISPLAY_TYPE: ', CertName);
end;
procedure ExportCertToPFX(NameStore, Password: string);
var
TmpPFX: CRYPT_DATA_BLOB;
hStore: HCERTSTORE;
Mem: TMemoryStream;
i, J: Integer;
begin
hStore := CertOpenSystemStore(0, PChar(NameStore));
if (hStore = nil) then
RaiseLastOSError;
Mem := TMemoryStream.Create;
J := 0;
try
try
CertContext := CertEnumCertificatesInStore(hStore, nil);
while (CertContext <> nil) do
begin
DisplayCertContext(CertContext);
CertPropId := CertEnumCertificateContextProperties(CertContext, 0);
while CertPropId <> 0 do
begin
DataLen := 512;
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', [cProvParam]));
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;
Inc(J);
CertContext := CertEnumCertificatesInStore(hStore, CertContext);
end;
if (J = 0) then
Exit;
Writeln(Format('CertificatesInStore = [%d]', [J]));
Writeln('');
TmpPFX.cbData := 0;
TmpPFX.pbData := nil;
if (PFXExportCertStoreEx(hStore, @TmpPFX, PChar(Password), nil,
EXPORT_PRIVATE_KEYS)) then
TmpPFX.pbData := CryptMemAlloc(SizeOf(BYTE) * TmpPFX.cbData);
if (TmpPFX.pbData <> nil) then
begin
if (PFXExportCertStoreEx(hStore, @TmpPFX, PChar(Password), nil,
EXPORT_PRIVATE_KEYS)) then
begin
Mem.WriteBuffer(TmpPFX.pbData^, TmpPFX.cbData);
Mem.SaveToFile(NameStore + '_' + IntToStr(J) + '_' + Format('%08x',
[GetTickCount]) + '.pfx');
end;
CryptMemFree(TmpPFX.pbData);
end;
except
on E: Exception do
Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
end;
finally
CertCloseStore(hStore, 0);
Mem.Free;
end;
end;
begin
try
ExportCertToPFX('MY', '123');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Рекомендации:
- ExportSert.cpp в Карберп
- WinCrypt.pas
- Как я могу получить доступ к сертификатам корневых центров сертификации Windows с помощью Delphi?
- Как экспортировать сертификат из хранилища сертификатов Windows через CryptoAPI в виде строки Base64
Моя проблема в том, что, очевидно, моя версия Delphi (а также пример C++) экспортирует ВСЕ сертификаты в уникальный файл.pfx, и до тех пор, пока я не узнаю (исправлю меня, если я ошибаюсь), возможно использование только 1 файла.pfx / программное обеспечение, то как я могу отделить после всех этих сертификатов, что этот код экспортирует в уникальный файл.pfx?
Я верю, что создание 1.pfx файла для каждого сертификата, найденного в CertEnumCertificatesInStore
Можно решить этот вопрос, но не уверен в этом. Кто-нибудь может дать мне предложение, пожалуйста?
1 ответ
Ну, вот возможное решение, основанное на предложении @bartonjs
var
CertContext: PCCERT_CONTEXT;
procedure ExportCertToPFX(NameStore, Password: string);
var
TmpPFX: CRYPT_DATA_BLOB;
hTempStore: HCERTSTORE;
begin
hTempStore := CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
CERT_STORE_CREATE_NEW_FLAG, nil);
if (hTempStore = nil) then
RaiseLastOSError;
try
CertContext := CertEnumCertificatesInStore(hStore, nil);
while (CertContext <> nil) do
begin
if not CertAddCertificateContextToStore(hTempStore, CertContext,
CERT_STORE_ADD_NEW, nil) then
Continue;
TmpPFX.cbData := 0;
TmpPFX.pbData := nil;
if (PFXExportCertStoreEx(hTempStore, @TmpPFX, PChar(Password), nil,
EXPORT_PRIVATE_KEYS)) then
TmpPFX.pbData := CryptMemAlloc(SizeOf(BYTE) * TmpPFX.cbData);
if (TmpPFX.pbData <> nil) then
begin
if (PFXExportCertStoreEx(hTempStore, @TmpPFX, PChar(Password), nil,
EXPORT_PRIVATE_KEYS)) then
begin
// Save to .pfx file
end;
CryptMemFree(TmpPFX.pbData);
end;
if not CertDeleteCertificateFromStore
(CertDuplicateCertificateContext(CertContext)) then
if (GetLastError = Cardinal(E_ACCESSDENIED)) then
Continue;
CertContext := CertEnumCertificatesInStore(hStore, CertContext);
end;
except
on E: Exception do
Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
CertCloseStore(hTempStore, 0);
end;
CertCloseStore(hTempStore, 0);
end;