Use ISSigFunc to check trust. Works while debugging from Delphi as well. Defining TRUSTALL would only be needed while debugging isscint.dll from VS for example.

AllowedPublicKeyText is formatted as a Delphi 12 multiline string literal since I plan to make ISSigTool embed it automatically from issig.bat to avoid complicating the build for others.
This commit is contained in:
Martijn Laan 2025-04-16 21:13:14 +02:00
parent 155cb989fc
commit ec81524172
No known key found for this signature in database
GPG Key ID: E2DD568CF6098F6A
7 changed files with 69 additions and 30 deletions

View File

@ -7,9 +7,7 @@ unit TrustFunc;
For conditions of distribution and use, see LICENSE.TXT.
}
{$IFDEF DEBUG}
{$DEFINE TRUSTALL}
{$ENDIF}
{.$DEFINE TRUSTALL}
interface
@ -18,35 +16,56 @@ function TrustedFileExists(const FileName: String): Boolean;
implementation
uses
Winapi.Windows {$IFDEF TRUSTALL}, System.SysUtils {$ENDIF};
Winapi.Windows, System.SysUtils {$IFNDEF TRUSTALL}, System.Classes, ECDSA, SHA256, ISSigFunc {$ENDIF};
function TrustedFileExists(const FileName: String): Boolean;
begin
{$IFNDEF TRUSTALL}
var FileInfo: TWinTrustFileInfo;
ZeroMemory(@FileInfo, SizeOf(FileInfo));
FileInfo.cbStruct := SizeOf(FileInfo);
FileInfo.pcwszFilePath := PChar(FileName);
var WinTrustData: TWinTrustData;
ZeroMemory(@WinTrustData, SizeOf(WinTrustData));
WinTrustData.cbStruct := SizeOf(WinTrustData);
WinTrustData.dwUIChoice := WTD_UI_NONE;
WinTrustData.fdwRevocationChecks := WTD_REVOKE_NONE;
WinTrustData.dwUnionChoice := WTD_CHOICE_FILE;
WinTrustData.pFile := @FileInfo;
WinTrustData.dwStateAction := WTD_STATEACTION_VERIFY;
WinTrustData.dwProvFlags := WTD_REVOCATION_CHECK_NONE;
var PolicyGUID := WINTRUST_ACTION_GENERIC_VERIFY_V2;
Result := WinVerifyTrust(0, PolicyGUID, @WinTrustData) = 0;
WinTrustData.dwStateAction := WTD_STATEACTION_CLOSE;
WinVerifyTrust(0, PolicyGUID, @WinTrustData);
{$ELSE}
var Attr := GetFileAttributes(PChar(FileName));
Result := (Attr <> INVALID_FILE_ATTRIBUTES) and (Attr and faDirectory = 0);
{$IFNDEF TRUSTALL}
if Result then begin
try
const
AllowedPublicKeyText = '''
format issig-public-key
key-id c2587f3885b12463bafdadb799f23435f26c03944c1afc1716aabc6a43f2426f
public-x f9a30c72189077370a8846015ac3ec1e9a1cf425d2996d34dc25bd4f4923dd1b
public-y f754897b7819da5bbbc5ac568311eee922fbea492578748e07f453dc1289c532
''';
const Key = TECDSAKey.Create;
try
if ISSigImportKeyText(Key, AllowedPublicKeyText, False) <> ikrSuccess then
raise Exception.Create('ISSigImportKeyText failed');
const SigFileName = FileName + '.issig';
const SigText = ISSigLoadTextFromFile(SigFileName);
var ExpectedFileSize: Int64;
var ExpectedFileHash: TSHA256Digest;
if ISSigVerifySignatureText([Key], 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
Key.Free;
end;
except
Result := False;
end;
end;
{$ENDIF}
end;

View File

@ -69,7 +69,10 @@ uses
SHA256 in '..\Components\SHA256.pas',
Shared.DotNetVersion in 'Src\Shared.DotNetVersion.pas',
isxclasses_wordlists_generated in '..\ISHelp\isxclasses_wordlists_generated.pas',
IDE.ImagesModule in 'Src\IDE.ImagesModule.pas' {ImagesModule: TDataModule};
IDE.ImagesModule in 'Src\IDE.ImagesModule.pas' {ImagesModule: TDataModule},
ECDSA in '..\Components\ECDSA.pas',
ISSigFunc in '..\Components\ISSigFunc.pas',
StringScanner in '..\Components\StringScanner.pas';
{$SETPEOSVERSION 6.1}
{$SETPESUBSYSVERSION 6.1}

View File

@ -155,6 +155,9 @@
<FormType>dfm</FormType>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="..\Components\ECDSA.pas"/>
<DCCReference Include="..\Components\ISSigFunc.pas"/>
<DCCReference Include="..\Components\StringScanner.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>

View File

@ -30,7 +30,11 @@ uses
Shared.FileClass in 'Src\Shared.FileClass.pas',
Shared.ConfigIniFile in 'Src\Shared.ConfigIniFile.pas',
Shared.SignToolsFunc in 'Src\Shared.SignToolsFunc.pas',
Shared.Int64Em in 'Src\Shared.Int64Em.pas';
Shared.Int64Em in 'Src\Shared.Int64Em.pas',
SHA256 in '..\Components\SHA256.pas',
ECDSA in '..\Components\ECDSA.pas',
ISSigFunc in '..\Components\ISSigFunc.pas',
StringScanner in '..\Components\StringScanner.pas';
{$SETPEOSVERSION 6.1}
{$SETPESUBSYSVERSION 6.1}

View File

@ -85,6 +85,10 @@
<DCCReference Include="Src\Shared.ConfigIniFile.pas"/>
<DCCReference Include="Src\Shared.SignToolsFunc.pas"/>
<DCCReference Include="Src\Shared.Int64Em.pas"/>
<DCCReference Include="..\Components\SHA256.pas"/>
<DCCReference Include="..\Components\ECDSA.pas"/>
<DCCReference Include="..\Components\ISSigFunc.pas"/>
<DCCReference Include="..\Components\StringScanner.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>

View File

@ -49,7 +49,10 @@ uses
Shared.SetupSteps in 'Src\Shared.SetupSteps.pas',
SimpleExpression in '..\Components\SimpleExpression.pas',
Shared.DotNetVersion in 'Src\Shared.DotNetVersion.pas',
PBKDF2 in '..\Components\PBKDF2.pas';
PBKDF2 in '..\Components\PBKDF2.pas',
ECDSA in '..\Components\ECDSA.pas',
ISSigFunc in '..\Components\ISSigFunc.pas',
StringScanner in '..\Components\StringScanner.pas';
{$IMAGEBASE $00800000}
{$SETPEOSVERSION 6.1}

View File

@ -119,6 +119,9 @@ $(PostBuildEvent)]]></PostBuildEvent>
<DCCReference Include="..\Components\SimpleExpression.pas"/>
<DCCReference Include="Src\Shared.DotNetVersion.pas"/>
<DCCReference Include="..\Components\PBKDF2.pas"/>
<DCCReference Include="..\Components\ECDSA.pas"/>
<DCCReference Include="..\Components\ISSigFunc.pas"/>
<DCCReference Include="..\Components\StringScanner.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>