windows delphi winapi digital-signature digital-certificate

windows - Comprobando la firma digital programáticamente desde Delphi



winapi digital-signature (2)

Aqui tienes:

// IsCodeSigned, which verifies that the exe hasn''t been modified, uses // WinVerifyTrust, so it''s NT only. IsCompanySigningCertificate works on Win9x, // but it only checks that the signing certificate hasn''t been replaced, which // keeps someone from re-signing a modified executable. // Imagehlp.dll const CERT_SECTION_TYPE_ANY = $FF; // Any Certificate type function ImageEnumerateCertificates(FileHandle: THandle; TypeFilter: WORD; out CertificateCount: DWORD; Indicies: PDWORD; IndexCount: Integer): BOOL; stdcall; external ''Imagehlp.dll''; function ImageGetCertificateHeader(FileHandle: THandle; CertificateIndex: Integer; var CertificateHeader: TWinCertificate): BOOL; stdcall; external ''Imagehlp.dll''; function ImageGetCertificateData(FileHandle: THandle; CertificateIndex: Integer; Certificate: PWinCertificate; var RequiredLength: DWORD): BOOL; stdcall; external ''Imagehlp.dll''; // Crypt32.dll const CERT_NAME_SIMPLE_DISPLAY_TYPE = 4; PKCS_7_ASN_ENCODING = $00010000; X509_ASN_ENCODING = $00000001; type PCCERT_CONTEXT = type Pointer; HCRYPTPROV_LEGACY = type Pointer; PFN_CRYPT_GET_SIGNER_CERTIFICATE = type Pointer; CRYPT_VERIFY_MESSAGE_PARA = record cbSize: DWORD; dwMsgAndCertEncodingType: DWORD; hCryptProv: HCRYPTPROV_LEGACY; pfnGetSignerCertificate: PFN_CRYPT_GET_SIGNER_CERTIFICATE; pvGetArg: Pointer; end; function CryptVerifyMessageSignature(const pVerifyPara: CRYPT_VERIFY_MESSAGE_PARA; dwSignerIndex: DWORD; pbSignedBlob: PByte; cbSignedBlob: DWORD; pbDecoded: PBYTE; pcbDecoded: PDWORD; ppSignerCert: PCCERT_CONTEXT): BOOL; stdcall; external ''Crypt32.dll''; function CertGetNameStringA(pCertContext: PCCERT_CONTEXT; dwType: DWORD; dwFlags: DWORD; pvTypePara: Pointer; pszNameString: PAnsiChar; cchNameString: DWORD): DWORD; stdcall; external ''Crypt32.dll''; function CertFreeCertificateContext(pCertContext: PCCERT_CONTEXT): BOOL; stdcall; external ''Crypt32.dll''; function CertCreateCertificateContext(dwCertEncodingType: DWORD; pbCertEncoded: PBYTE; cbCertEncoded: DWORD): PCCERT_CONTEXT; stdcall; external ''Crypt32.dll''; // WinTrust.dll const WINTRUST_ACTION_GENERIC_VERIFY_V2: TGUID = ''{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}''; WTD_CHOICE_FILE = 1; WTD_REVOKE_NONE = 0; WTD_UI_NONE = 2; type PWinTrustFileInfo = ^TWinTrustFileInfo; TWinTrustFileInfo = record cbStruct: DWORD; // = sizeof(WINTRUST_FILE_INFO) pcwszFilePath: PWideChar; // required, file name to be verified hFile: THandle; // optional, open handle to pcwszFilePath pgKnownSubject: PGUID; // optional: fill if the subject type is known end; PWinTrustData = ^TWinTrustData; TWinTrustData = record cbStruct: DWORD; pPolicyCallbackData: Pointer; pSIPClientData: Pointer; dwUIChoice: DWORD; fdwRevocationChecks: DWORD; dwUnionChoice: DWORD; pFile: PWinTrustFileInfo; dwStateAction: DWORD; hWVTStateData: THandle; pwszURLReference: PWideChar; dwProvFlags: DWORD; dwUIContext: DWORD; end; function WinVerifyTrust(hwnd: HWND; const ActionID: TGUID; ActionData: Pointer): Longint; stdcall; external wintrust; {-----------------------------------------------} function IsCodeSigned(const Filename: string): Boolean; var file_info: TWinTrustFileInfo; trust_data: TWinTrustData; begin // Verify that the exe is signed and the checksum matches FillChar(file_info, SizeOf(file_info), 0); file_info.cbStruct := sizeof(file_info); file_info.pcwszFilePath := PWideChar(WideString(Filename)); FillChar(trust_data, SizeOf(trust_data), 0); trust_data.cbStruct := sizeof(trust_data); trust_data.dwUIChoice := WTD_UI_NONE; trust_data.fdwRevocationChecks := WTD_REVOKE_NONE; trust_data.dwUnionChoice := WTD_CHOICE_FILE; trust_data.pFile := @file_info; Result := WinVerifyTrust(INVALID_HANDLE_VALUE, WINTRUST_ACTION_GENERIC_VERIFY_V2, @trust_data) = ERROR_SUCCESS end; {-----------------------------------------------} function IsCompanySigningCertificate(const Filename, CompanyName :string): Boolean; var hExe: HMODULE; Cert: PWinCertificate; CertContext: PCCERT_CONTEXT; CertCount: DWORD; CertName: AnsiString; CertNameLen: DWORD; VerifyParams: CRYPT_VERIFY_MESSAGE_PARA; begin // Returns TRUE if the SubjectName on the certificate used to sign the exe is // "Company Name". Should prevent a cracker from modifying the file and // re-signing it with their own certificate. // // Microsoft has an example that does this using CryptQueryObject and // CertFindCertificateInStore instead of CryptVerifyMessageSignature, but // CryptQueryObject is NT-only. Using CertCreateCertificateContext doesn''t work // either, though I don''t know why. Result := False; // Verify that the exe was signed by our private key hExe := CreateFile(PChar(Filename), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_RANDOM_ACCESS, 0); if hExe = INVALID_HANDLE_VALUE then Exit; try // There should only be one certificate associated with the exe if (not ImageEnumerateCertificates(hExe, CERT_SECTION_TYPE_ANY, CertCount, nil, 0)) or (CertCount <> 1) then Exit; // Read the certificate header so we can get the size needed for the full cert GetMem(Cert, SizeOf(TWinCertificate) + 3); // ImageGetCertificateHeader writes an DWORD at bCertificate for some reason try Cert.dwLength := 0; Cert.wRevision := WIN_CERT_REVISION_1_0; if not ImageGetCertificateHeader(hExe, 0, Cert^) then Exit; // Read the full certificate ReallocMem(Cert, SizeOf(TWinCertificate) + Cert.dwLength); if not ImageGetCertificateData(hExe, 0, Cert, Cert.dwLength) then Exit; // Get the certificate context. CryptVerifyMessageSignature has the // side effect of creating a context for the signing certificate. FillChar(VerifyParams, SizeOf(VerifyParams), 0); VerifyParams.cbSize := SizeOf(VerifyParams); VerifyParams.dwMsgAndCertEncodingType := X509_ASN_ENCODING or PKCS_7_ASN_ENCODING; if not CryptVerifyMessageSignature(VerifyParams, 0, @Cert.bCertificate, Cert.dwLength, nil, nil, @CertContext) then Exit; try // Extract and compare the certificate''s subject names. Don''t // compare the entire certificate or the public key as those will // change when the certificate is renewed. CertNameLen := CertGetNameStringA(CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, nil, 0); SetLength(CertName, CertNameLen - 1); CertGetNameStringA(CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, PAnsiChar(CertName), CertNameLen); if CertName <> CompanyName then Exit; finally CertFreeCertificateContext(CertContext) end; finally FreeMem(Cert); end; finally CloseHandle(hExe); end; Result := True; end;

Necesito una función en Delphi para verificar la firma digital de un EXE o DLL externo. En mi aplicación particular, voy a invocar ocasionalmente otros procesos, pero por razones de seguridad quiero asegurarme de que estos archivos ejecutables fueron creados por nuestra organización antes de ejecutarlos.

He visto el ejemplo de Microsoft en C , sin embargo, no quiero perder el tiempo traduciendo esto a Delphi si alguien más ya lo ha hecho.

Preferiría un fragmento o un ejemplo de código sobre una biblioteca de terceros. Gracias.


const WTD_UI_ALL = 1; WTD_UI_NONE = 2; WTD_UI_NOBAD = 3; WTD_UI_NOGOOD = 4; WTD_REVOKE_NONE = $00000000; WTD_REVOKE_WHOLECHAIN = $00000001; WTD_CHOICE_FILE = 1; WTD_CHOICE_CATALOG = 2; WTD_CHOICE_BLOB = 3; WTD_CHOICE_SIGNER = 4; WTD_CHOICE_CERT = 5; WTD_STATEACTION_IGNORE = $00000000; WTD_STATEACTION_VERIFY = $00000001; WTD_STATEACTION_CLOSE = $00000002; WTD_STATEACTION_AUTO_CACHE = $00000003; WTD_STATEACTION_AUTO_CACHE_FLUSH = $00000004; type PWinTrustFileInfo = ^TWinTrustFileInfo; TWinTrustFileInfo = record cbStruct: DWORD; pcwszFilePath: PWideChar; hFile: THandle; pgKnownSubject: PGUID; end; PWinTrustData = ^TWinTrustData; TWinTrustData = record cbStruct: DWORD; pPolicyCallbackData: Pointer; pSIPClientData: Pointer; dwUIChoice: DWORD; fdwRevocationChecks: DWORD; dwUnionChoice: DWORD; pUnionData: Pointer; dwStateAction: DWORD; hWVTStateData: THandle; pwszURLReference: PWideChar; dwProvFlags: DWORD; dwUIContext: DWORD; end; function VerifySignature(const FileName: WideString): Longint; var FileInfo: TWinTrustFileInfo; TrustData: TWinTrustData; begin FillChar(FileInfo, SizeOf(FileInfo), 0); FileInfo.cbStruct := SizeOf(FileInfo); FileInfo.pcwszFilePath := PWideChar(FileName); FillChar(TrustData, SizeOf(TrustData), 0); TrustData.cbStruct := SizeOf(TrustData); TrustData.dwUIChoice := WTD_UI_NONE; TrustData.fdwRevocationChecks := WTD_REVOKE_NONE; TrustData.dwUnionChoice := WTD_CHOICE_FILE; TrustData.pUnionData := @FileInfo; TrustData.dwStateAction := WTD_STATEACTION_IGNORE; TrustData.dwProvFlags := WTD_SAFER_FLAG; TrustData.dwUIContext := WTD_UICONTEXT_EXECUTE; Result := WinVerifyTrust(0, WINTRUST_ACTION_GENERIC_VERIFY_V2, @TrustData); end;

Hay más detalles en la WinVerifyTrust .

Alternativamente, puede usar CAPICOM . Importe la biblioteca de tipos CAPICOM desde capicom.dll y luego use la unidad CAPICOM_TLB generada:

procedure CodeSignVerify(const FileName: string; AllowUserPrompt: Boolean = False); var SignedCode: ISignedCode; begin SignedCode := CoSignedCode.Create; SignedCode.FileName := FileName; SignedCode.Verify(AllowUserPrompt); end;