| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- unit TrustFunc;
- {
- Inno Setup
- Copyright (C) 1997-2025 Jordan Russell
- Portions by Martijn Laan
- For conditions of distribution and use, see LICENSE.TXT.
- Trust support functions using ISSigFunc and key texts from TrustFunc.AllowedPublicKeys.inc
- }
- {.$DEFINE TRUSTALL}
- interface
- procedure CheckFileTrust(const FileName: String; const CheckExists: Boolean = True);
- function LoadTrustedLibrary(const FileName: String; const TrustAllOnDebug: Boolean = False): HMODULE;
- implementation
- uses
- Winapi.Windows, System.SysUtils, System.Classes {$IFNDEF TRUSTALL}, ECDSA, SHA256, ISSigFunc {$ENDIF};
- procedure CheckFileTrust(const FileName: String; const CheckExists: Boolean);
- {$IFNDEF TRUSTALL}
- var
- AllowedKeys: array of TECDSAKey;
- {$ENDIF}
- begin
- if CheckExists then begin
- var Attr := GetFileAttributes(PChar(FileName));
- if (Attr = INVALID_FILE_ATTRIBUTES) or (Attr and faDirectory <> 0) then
- raise Exception.CreateFmt('File "%s" does not exist.',
- [FileName]);
- end;
- {$IFNDEF TRUSTALL}
- var AllowedPublicKey1Text, AllowedPublicKey2Text: String;
- {$I TrustFunc.AllowedPublicKeys.inc}
- var Key1: TECDSAKey := nil;
- var Key2: TECDSAKey := nil;
- try
- Key1 := TECDSAKey.Create;
- if ISSigImportKeyText(Key1, AllowedPublicKey1Text, False) <> ikrSuccess then
- raise Exception.Create('ISSigImportKeyText failed');
- if AllowedPublicKey2Text <> '' then begin
- Key2 := TECDSAKey.Create;
- if ISSigImportKeyText(Key2, AllowedPublicKey2Text, False) <> ikrSuccess then
- raise Exception.Create('ISSigImportKeyText failed');
- end;
- if Key2 <> nil then
- AllowedKeys := [Key1, Key2]
- else
- AllowedKeys := [Key1];
- const SigFileName = FileName + '.issig';
- const SigText = ISSigLoadTextFromFile(SigFileName);
- var ExpectedFileSize: Int64;
- var ExpectedFileHash: TSHA256Digest;
- if ISSigVerifySignatureText(AllowedKeys, SigText, ExpectedFileSize,
- ExpectedFileHash) <> vsrSuccess then
- raise Exception.CreateFmt('Signature file "%s" is not valid',
- [SigFileName]);
- const F = TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
- try
- if F.Size <> ExpectedFileSize then
- raise Exception.CreateFmt('File "%s" is not trusted (incorrect size).',
- [FileName]);
- if not SHA256DigestsEqual(ISSigCalcStreamHash(F), ExpectedFileHash) then
- raise Exception.CreateFmt('File "%s" is not trusted (incorrect hash).',
- [FileName]);
- finally
- F.Free;
- end;
- finally
- Key2.Free;
- Key1.Free;
- end;
- {$ENDIF}
- end;
- function Win32ErrorString(ErrorCode: Integer): String;
- { Like SysErrorMessage but also passes the FORMAT_MESSAGE_IGNORE_INSERTS flag
- which allows the function to succeed on errors like 129 }
- var
- Len: Integer;
- Buffer: array[0..1023] of Char;
- begin
- Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
- FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY, nil,
- ErrorCode, 0, Buffer, SizeOf(Buffer) div SizeOf(Buffer[0]), nil);
- while (Len > 0) and ((Buffer[Len-1] <= ' ') or (Buffer[Len-1] = '.')) do
- Dec(Len);
- SetString(Result, Buffer, Len);
- end;
- function DoLoadLibrary(const FileName: String): HMODULE;
- begin
- Result := SafeLoadLibrary(PChar(FileName), SEM_NOOPENFILEERRORBOX);
- if Result = 0 then
- raise Exception.Create(Win32ErrorString(GetLastError));
- end;
- function LoadTrustedLibrary(const FileName: String; const TrustAllOnDebug: Boolean): HMODULE;
- begin
- {$IFDEF DEBUG}
- if TrustAllOnDebug then begin
- Result := DoLoadLibrary(FileName);
- Exit;
- end;
- {$ENDIF}
- { First open a temporary regular handle to the library to protect it from changes
- between the trust check and the load }
- const F = TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
- try
- CheckFileTrust(FileName, False);
- Result := DoLoadLibrary(FileName);
- finally
- F.Free;
- end;
- end;
- end.
|