How export all my certificates of software separately to a .pfx file?

て烟熏妆下的殇ゞ 提交于 2019-12-08 05:26:45

问题


I want export programatically of a computer all my certificates of software separately to .pfx file to sign 2 new softwares that already are in final step of building in another pc.

To make this i found a C++ code example (that after i translate to Delphi).

My Delphi version still not was tested but even so i think that is working fine.

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.

References:

  • ExportSert.cpp in Carberp
  • WinCrypt.pas
  • How can I access windows root certificate authorities certificates with Delphi?
  • How to export certificate from Windows certificate store via CryptoAPI as Base64 string

My trouble is that apparently my Delphi version (and also the C++ example), both exports ALL certificates to a unique .pfx file, and until where i know (fix me if i'm wrong) only is possible use 1 .pfx file/software, then how i can separate after all these certificates that this code exports to a unique .pfx file?

I belive that generating 1 .pfx file to each certificate found inCertEnumCertificatesInStore can solve this question, but not have sure about this. Someone could give me a suggestion please?


回答1:


Well, here is a possible solution based on suggestion of @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;


来源:https://stackoverflow.com/questions/51614210/how-export-all-my-certificates-of-software-separately-to-a-pfx-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!