{*******************************************************}
{                                                       }
{       Tocsg.Cert                                      }
{                                                       }
{       Copyright (C) 2025 kku                          }
{                                                       }
{*******************************************************}

unit Tocsg.Cert;

interface

uses
  Winapi.Windows;

//const
//  CERT_QUERY_OBJECT_FILE = $00000001;
//  CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = $00000020;
//  CERT_QUERY_FORMAT_FLAG_BINARY = $00000002;
//  CMSG_SIGNER_INFO_PARAM = 6;
//  CERT_NAME_SIMPLE_DISPLAY_TYPE = 4;
//  CERT_X500_NAME_STR = 3;
//  CERT_FIND_SUBJECT_CERT = $0000000B;
//
//  X509_ASN_ENCODING   = $00000001;  // X.509 인증서 인코딩
//  PKCS_7_ASN_ENCODING = $00010000;  // PKCS#7 서명 인코딩
//  ENCODING_TYPE = (X509_ASN_ENCODING or PKCS_7_ASN_ENCODING);
//
//type
//  HCERTSTORE = Pointer;
//  HCRYPTMSG = Pointer;
//  PCCERT_CONTEXT = ^CERT_CONTEXT;
//
//function CryptQueryObject(dwObjectType: DWORD; pvObject: PChar;
//  dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags: DWORD;
//  dwFlags: DWORD; var pdwMsgAndCertEncodingType, pdwContentType,
//  pdwFormatType: DWORD; var phCertStore: HCERTSTORE;
//  var phMsg: HCRYPTMSG; ppvContext: Pointer): BOOL; stdcall;
//  external 'Crypt32.dll';
//
//function CryptMsgGetParam(hCryptMsg: HCRYPTMSG; dwParamType, dwIndex: DWORD;
//  pvData: Pointer; var pcbData: DWORD): BOOL; stdcall;
//  external 'Crypt32.dll';
//
//function CertNameToStr(dwCertEncodingType: DWORD; pName: PCERT_NAME_BLOB;
//  dwStrType: DWORD; psz: PChar; csz: DWORD): DWORD; stdcall;
//  external 'Crypt32.dll' name 'CertNameToStrW';
//
//function CertFindCertificateInStore(hCertStore: HCERTSTORE;
//  dwCertEncodingType: DWORD; dwFindFlags: DWORD;
//  dwFindType: DWORD; pvFindPara: Pointer;
//  pPrevCertContext: PCCERT_CONTEXT): PCCERT_CONTEXT; stdcall;
//  external 'Crypt32.dll';
//
//function CertFreeCertificateContext(pCertContext: PCCERT_CONTEXT): BOOL; stdcall;
//  external 'Crypt32.dll';
//
//function CertCloseStore(hCertStore: HCERTSTORE; dwFlags: DWORD): BOOL; stdcall;
//  external 'Crypt32.dll';
//
//function CryptMsgClose(hCryptMsg: HCRYPTMSG): BOOL; stdcall;
//  external 'Crypt32.dll';

function IsFileSigned(const FileName: string): Boolean;

implementation

function IsFileSigned(const FileName: string): Boolean;
var
  WinTrustData: WINTRUST_DATA;
  WinTrustFileInfo: WINTRUST_FILE_INFO;
  GuidAction: TGUID;
begin
  Result := False;
  // GUID 설정 (WINTRUST_ACTION_GENERIC_VERIFY_V2)
  GuidAction := WINTRUST_ACTION_GENERIC_VERIFY_V2;
  // WINTRUST_FILE_INFO 초기화
  ZeroMemory(@WinTrustFileInfo, SizeOf(WinTrustFileInfo));
  WinTrustFileInfo.cbStruct := SizeOf(WinTrustFileInfo);
  WinTrustFileInfo.pcwszFilePath := PWideChar(WideString(FileName));
  WinTrustFileInfo.hFile := 0;
  WinTrustFileInfo.pgKnownSubject := nil;
  // WINTRUST_DATA 초기화
  ZeroMemory(@WinTrustData, SizeOf(WinTrustData));
  WinTrustData.cbStruct := SizeOf(WinTrustData);
  WinTrustData.dwUIChoice := WTD_UI_NONE;                   // UI 없음
  WinTrustData.fdwRevocationChecks := WTD_REVOKE_NONE;      // 인증서 폐기 목록(CRL) 체크 안 함
  WinTrustData.dwUnionChoice := WTD_CHOICE_FILE;            // 파일 검사
  WinTrustData.pFile := @WinTrustFileInfo;                 // 검사할 파일 정보
  WinTrustData.dwStateAction := 0;
  WinTrustData.hWVTStateData := 0;
  WinTrustData.pwszURLReference := nil;
  WinTrustData.dwProvFlags := WTD_SAFER_FLAG;
  // 서명 확인
  Result := WinVerifyTrust(0, GuidAction, @WinTrustData) = ERROR_SUCCESS;
end;

//function GetCertificateInfo(const FileName: string): string;
//var
//  hFile: THandle;
//  hFileMapping: THandle;
//  pbFile: Pointer;
//  hStore: HCERTSTORE;
//  hMsg: HCRYPTMSG;
//  CertContext: PCCERT_CONTEXT;
//  Encoding, ContentType, FormatType: DWORD;
//  SignerInfo: PCMSG_SIGNER_INFO;
//  dwSignerInfo: DWORD;
//  IssuerName, SubjectName: array[0..1023] of Char;
//begin
//  Result := '서명 정보 없음';
//
//  // 파일 열기
//  if not CryptQueryObject(CERT_QUERY_OBJECT_FILE, PChar(FileName),
//    CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
//    CERT_QUERY_FORMAT_FLAG_BINARY, 0, Encoding,
//    ContentType, FormatType, hStore, hMsg, nil) then
//  begin
//    Exit;
//  end;
//
//  // 서명자 정보 크기 확인
//  if not CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, nil, dwSignerInfo) then
//  begin
//    Exit;
//  end;
//
//  // 서명자 정보 가져오기
//  GetMem(SignerInfo, dwSignerInfo);
//  try
//    if not CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, SignerInfo, dwSignerInfo) then
//    begin
//      Exit;
//    end;
//
//    // 인증서 찾기
//    CertContext := CertFindCertificateInStore(hStore, ENCODING_TYPE,
//      0, CERT_FIND_SUBJECT_CERT, @SignerInfo^.Issuer, nil);
//
//    if Assigned(CertContext) then
//    begin
//      // 발급자 정보
//      CertNameToStr(CERT_X500_NAME_STR, @CertContext^.pCertInfo^.Issuer,
//        CERT_NAME_SIMPLE_DISPLAY_TYPE, IssuerName, SizeOf(IssuerName));
//
//      // 서명자 정보
//      CertNameToStr(CERT_X500_NAME_STR, @CertContext^.pCertInfo^.Subject,
//        CERT_NAME_SIMPLE_DISPLAY_TYPE, SubjectName, SizeOf(SubjectName));
//
//      Result := Format('발급자: %s' + sLineBreak + '서명자: %s', [IssuerName, SubjectName]);
//    end;
//  finally
//    FreeMem(SignerInfo);
//    if Assigned(CertContext) then
//      CertFreeCertificateContext(CertContext);
//    if hStore <> nil then
//      CertCloseStore(hStore, 0);
//    if hMsg <> nil then
//      CryptMsgClose(hMsg);
//  end;
//end;

end.
