|
@@ -20,26 +20,44 @@ interface
|
|
|
uses
|
|
|
System.Classes;
|
|
|
|
|
|
-function CheckFileTrust(const FileName: String; const CheckExists: Boolean = True; const KeepOpen: Boolean = False): TFileStream;
|
|
|
-function LoadTrustedLibrary(const FileName: String; const TrustAllOnDebug: Boolean = False): HMODULE;
|
|
|
+type
|
|
|
+ TCheckFileTrustOption = (cftoKeepOpen);
|
|
|
+ TCheckFileTrustOptions = set of TCheckFileTrustOption;
|
|
|
+ TLoadTrustedLibraryOption = (ltloTrustAllOnDebug);
|
|
|
+ TLoadTrustedLibraryOptions = set of TLoadTrustedLibraryOption;
|
|
|
+
|
|
|
+function CheckFileTrust(const FileName: String; const Options: TCheckFileTrustOptions): TFileStream;
|
|
|
+function LoadTrustedLibrary(const FileName: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
|
|
|
|
|
|
implementation
|
|
|
|
|
|
uses
|
|
|
Winapi.Windows, System.SysUtils {$IFNDEF TRUSTALL}, ECDSA, SHA256, ISSigFunc {$ENDIF};
|
|
|
|
|
|
-function CheckFileTrust(const FileName: String; const CheckExists, KeepOpen: Boolean): TFileStream;
|
|
|
+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 CheckFileTrust(const FileName: String; const Options: TCheckFileTrustOptions): TFileStream;
|
|
|
{$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;
|
|
|
+ var Attr := GetFileAttributes(PChar(FileName));
|
|
|
+ if (Attr = INVALID_FILE_ATTRIBUTES) or (Attr and faDirectory <> 0) then
|
|
|
+ raise Exception.Create(Win32ErrorString(ERROR_FILE_NOT_FOUND));
|
|
|
{$IFNDEF TRUSTALL}
|
|
|
var ExpectedFileSize: Int64;
|
|
|
var ExpectedFileHash: TSHA256Digest;
|
|
@@ -96,7 +114,7 @@ begin
|
|
|
FreeAndNil(F);
|
|
|
raise;
|
|
|
end;
|
|
|
- if not KeepOpen then
|
|
|
+ if not (cftoKeepOpen in Options) then
|
|
|
FreeAndNil(F);
|
|
|
|
|
|
Result := F;
|
|
@@ -105,21 +123,6 @@ begin
|
|
|
{$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);
|
|
@@ -127,19 +130,16 @@ begin
|
|
|
raise Exception.Create(Win32ErrorString(GetLastError));
|
|
|
end;
|
|
|
|
|
|
-function LoadTrustedLibrary(const FileName: String; const TrustAllOnDebug: Boolean): HMODULE;
|
|
|
+function LoadTrustedLibrary(const FileName: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
|
|
|
begin
|
|
|
{$IFDEF DEBUG}
|
|
|
- if TrustAllOnDebug then begin
|
|
|
+ if ltloTrustAllOnDebug in Options 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);
|
|
|
+ const F = CheckFileTrust(FileName, [cftoKeepOpen]);
|
|
|
try
|
|
|
- CheckFileTrust(FileName, False);
|
|
|
Result := DoLoadLibrary(FileName);
|
|
|
finally
|
|
|
F.Free;
|