Przeglądaj źródła

Merge branch 'trustfunc'

Martijn Laan 5 miesięcy temu
rodzic
commit
823a86a588

+ 2 - 1
.github/workflows/build.yml

@@ -50,7 +50,8 @@ jobs:
             'tmp-unsigned\iscc /Sissigntool256="${{github.workspace}}\home\bin\run-signtool.bat $f" /DSIGNTOOL setup.iss'
             'tmp-unsigned\iscc /Sissigntool256="${{github.workspace}}\home\bin\run-signtool.bat $f" /DSIGNTOOL setup.iss'
       - name: build issrc
       - name: build issrc
         run: |
         run: |
-          "set DELPHIXEROOT=$env:DELPHIXEROOT" | Out-File -NoNewline -Encoding ascii compilesettings.bat
+          "set DELPHIXEROOT=$env:DELPHIXEROOT" | Out-File -Encoding ascii compilesettings.bat
+          "set ISSIGTOOL_KEY_FILE=${{github.workspace}}\home\bin\mykey.isprivatekey" | Out-File -NoNewline -Encoding ascii -Append compilesettings.bat
           "set DELPHIXEROOT=$env:DELPHIXEROOT" | Out-File -NoNewline -Encoding ascii ISHelp\ISHelpGen\compilesettings.bat
           "set DELPHIXEROOT=$env:DELPHIXEROOT" | Out-File -NoNewline -Encoding ascii ISHelp\ISHelpGen\compilesettings.bat
           "set HHCEXE=%ProgramFiles(x86)%\HTML Help Workshop\hhc.exe" | Out-File -NoNewline -Encoding ascii ISHelp\compilesettings.bat
           "set HHCEXE=%ProgramFiles(x86)%\HTML Help Workshop\hhc.exe" | Out-File -NoNewline -Encoding ascii ISHelp\compilesettings.bat
           .\build.bat
           .\build.bat

+ 2 - 2
Components/ScintEdit.pas

@@ -858,8 +858,8 @@ end;
 
 
 procedure TScintEdit.CreateWnd;
 procedure TScintEdit.CreateWnd;
 begin
 begin
-  if IsscintLibary = 0 then
-    Error('CreateWnd: IsscintLibary is 0');
+  if IsscintLibrary = 0 then
+    Error('CreateWnd: IsscintLibrary is 0');
   inherited;
   inherited;
   FDirectPtr := Pointer(SendMessage(Handle, SCI_GETDIRECTPOINTER, 0, 0));
   FDirectPtr := Pointer(SendMessage(Handle, SCI_GETDIRECTPOINTER, 0, 0));
   if FDirectPtr = nil then
   if FDirectPtr = nil then

+ 12 - 4
Components/ScintInt.pas

@@ -1353,15 +1353,23 @@ type
   SciFnDirectStatus = function(ptr: Pointer; iMessage: Cardinal;
   SciFnDirectStatus = function(ptr: Pointer; iMessage: Cardinal;
     wParam: WPARAM; lParam: LPARAM; var Status: Integer): LRESULT; cdecl;
     wParam: WPARAM; lParam: LPARAM; var Status: Integer): LRESULT; cdecl;
 
 
+const
+  IsscintDLL = 'isscint.dll';
+
 var
 var
-  IsscintLibary: HMODULE;
+  IsscintLibrary: HMODULE;
+
+procedure InitIsscintLibrary;
 
 
 implementation
 implementation
 
 
 uses
 uses
-  PathFunc;
+  PathFunc, TrustFunc;
 
 
-initialization
-  IsscintLibary := LoadLibrary(PChar(AddBackslash(PathExtractPath(ParamStr(0))) + 'isscint.dll'));
+procedure InitIsscintLibrary;
+begin
+  var FileName := AddBackslash(PathExtractPath(ParamStr(0))) + IsscintDLL;
+  IsscintLibrary := LoadTrustedLibrary(PChar(FileName));
+end;
 
 
 end.
 end.

+ 23 - 0
Components/TrustFunc.AllowedPublicKeys.inc

@@ -0,0 +1,23 @@
+{ Inno Setup build: the second key in this file should be replaced by your
+  own and this will happen automatically when using build.bat or build-ce.bat.
+  To ignore this change consider using Git's assume-unchanged or skip-worktree
+  functionality.
+  
+  Other builds: if you need only one key you can set AllowedPublicKey2Text To
+  an empty string and remove the '//end' marker. }
+
+AllowedPublicKey1Text := '''
+format issig-public-key
+key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
+public-x e3e943066aff8f28d2219fd71c9ffff4c8d1aa26bc4225434be67180ab5e242d
+public-y e419041c3f54551e86a1c47f387005cd535dfc9d64339b30d37f9a4f7866b650
+
+''';
+
+AllowedPublicKey2Text := '''
+format issig-public-key
+key-id def020edee3c4835fd54d85eff8b66d4d899b22a777353ca4a114b652e5e7a28
+public-x 515dc7d6c16d4a46272ceb3d158c5630a96466ab4d948e72c2029d737c823097
+public-y f3c21f6b5156c52a35f6f28016ee3e31a3ded60c325b81fb7b1f88c221081a61
+
+''';//end

+ 122 - 0
Components/TrustFunc.pas

@@ -0,0 +1,122 @@
+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 {$IFNDEF TRUSTALL}, System.Classes, ECDSA, SHA256, ISSigFunc {$ENDIF};
+
+procedure CheckFileTrust(const FileName: String; const CheckExists: Boolean);
+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;
+
+    var AllowedKeys: array of TECDSAKey;
+    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.

+ 6 - 0
Files/isbzip.dll.issig

@@ -0,0 +1,6 @@
+format issig-v1
+file-size 39200
+file-hash 8072e83385afc4a84006271a87a11fc0a22b149cbd77322669ca56c470d28ced
+key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
+sig-r c5d2720f9be49d87c4800bd8717066613173fae1e26ffb9f31f304a1be40e71e
+sig-s c68f97d069e34e7b2b410222032401254c35641d293ebf3fa0078d19b3478db4

+ 6 - 0
Files/islzma.dll.issig

@@ -0,0 +1,6 @@
+format issig-v1
+file-size 135816
+file-hash b252471e95f0853902b15ae71a90574f9b168f8d4a0c474b20537511f90220a5
+key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
+sig-r 63d9a298fdb44394705221a9e65d1fb459d20c73d26aa56cdacf8d0942896b64
+sig-s f7621fc374e28c22f21fcb0ce77acf8a6723c5d0934e6aa0f5a718afeea6cfb3

+ 6 - 0
Files/isscint.dll.issig

@@ -0,0 +1,6 @@
+format issig-v1
+file-size 795776
+file-hash 5ae5dcd47ae9cd0929e0d6b2591e2ecc14cb8dfe4e04fb37a6cef5f1896edd11
+key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
+sig-r dd7de5a0ea422c67375023d74c410973a8508a054d6675710a2e591d7b33abdd
+sig-s 0bd08ccdb7f69a97b3e390a28dfdda98a1cad50f11682567fa03b93c7c5fb285

+ 6 - 0
Files/iszlib.dll.issig

@@ -0,0 +1,6 @@
+format issig-v1
+file-size 34592
+file-hash 14c0d4a2a41572384f8309cdf03de5c6e7ed46bef64cce70d989b2665eff1a47
+key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
+sig-r e245c707db5d1f1d3f47226aa3923e0240e23abb8fa5077eb4fb7ffc776a89ff
+sig-s bf84dbda5c76cce509931aa05bdd9992f96154f9493345e7f1669e169f0b810c

+ 10 - 7
ISHelp/ISHelpGen/ISHelpGen.dpr

@@ -5,6 +5,7 @@ program ISHelpGen;
 uses
 uses
   Windows,
   Windows,
   SysUtils,
   SysUtils,
+  StrUtils,
   Classes,
   Classes,
   ActiveX,
   ActiveX,
   ComObj,
   ComObj,
@@ -331,7 +332,8 @@ begin
   Result := '';
   Result := '';
   Node := Node.FirstChild;
   Node := Node.FirstChild;
   while Assigned(Node) do begin
   while Assigned(Node) do begin
-    case ElementFromNode(Node) of
+    var Element := ElementFromNode(Node);
+    case Element of
       el_Text:
       el_Text:
         Result := Result + EscapeHTML(Node.Text, False);
         Result := Result + EscapeHTML(Node.Text, False);
       elA:
       elA:
@@ -354,12 +356,13 @@ begin
         Result := Result + '<dl>' + ParseFormattedText(Node) + '</dl>';
         Result := Result + '<dl>' + ParseFormattedText(Node) + '</dl>';
       elDT:
       elDT:
         Result := Result + '<dt>' + ParseFormattedText(Node) + '</dt>';
         Result := Result + '<dt>' + ParseFormattedText(Node) + '</dt>';
-      elExample:
-        Result := Result + '<div class="examplebox">' + SNewLine +
-          '<div class="exampleheader">Example:</div>' + ParseFormattedText(Node) + '</div>';
-      elExamples:
-        Result := Result + '<div class="examplebox">' + SNewLine +
-          '<div class="exampleheader">Examples:</div>' + ParseFormattedText(Node) + '</div>';
+      elExample, elExamples:
+        begin
+          Result := Result + '<div class="examplebox">' + SNewLine;
+          if Node.OptionalAttributes['noheader'] <> '1' then
+            Result := Result + '<div class="exampleheader">Example' + IfThen(Element = elExamples, 's', '') + ':</div>';
+          Result := Result + ParseFormattedText(Node) + '</div>';
+        end;
       elFlag:
       elFlag:
         begin
         begin
           S := Node.Attributes['name'];
           S := Node.Attributes['name'];

+ 2 - 0
ISHelp/isetup.dtd

@@ -65,7 +65,9 @@
 <!ELEMENT pre %Inline;>
 <!ELEMENT pre %Inline;>
 <!ELEMENT precode %Inline;>
 <!ELEMENT precode %Inline;>
 <!ELEMENT example %InlineOrBlock;>
 <!ELEMENT example %InlineOrBlock;>
+<!ATTLIST example noheader CDATA #IMPLIED>
 <!ELEMENT examples %InlineOrBlock;>
 <!ELEMENT examples %InlineOrBlock;>
+<!ATTLIST examples noheader CDATA #IMPLIED>
 <!ELEMENT indent %Block;>
 <!ELEMENT indent %Block;>
 
 
 <!-- Fancier block elements -->
 <!-- Fancier block elements -->

+ 95 - 4
ISHelp/isetup.xml

@@ -86,6 +86,7 @@
     <contentstopic title="Uninstaller Exit Codes" topic="uninstexitcodes" />
     <contentstopic title="Uninstaller Exit Codes" topic="uninstexitcodes" />
     <contentstopic title="Compiler IDE Keyboard And Mouse Commands" topic="compformshortcuts" />
     <contentstopic title="Compiler IDE Keyboard And Mouse Commands" topic="compformshortcuts" />
     <contentstopic title="Compiler IDE Regular Expressions" topic="compformregex" />
     <contentstopic title="Compiler IDE Regular Expressions" topic="compformregex" />
+    <contentstopic title="Inno Setup Signature Tool" topic="issigtool" />
     <contentstopic title="Miscellaneous Notes" topic="technotes" />
     <contentstopic title="Miscellaneous Notes" topic="technotes" />
     <contentstopic title="Example Scripts" topic="examples" />
     <contentstopic title="Example Scripts" topic="examples" />
     <contentstopic title="Frequently Asked Questions" topic="faq" />
     <contentstopic title="Frequently Asked Questions" topic="faq" />
@@ -102,7 +103,7 @@
 <body>
 <body>
 
 
 <p>
 <p>
-<b>Inno Setup version 6.4.2</b><br/>
+<b>Inno Setup version 6.4.3-dev</b><br/>
 <b>Copyright &copy; 1997-2025 Jordan Russell. All rights reserved.</b><br/>
 <b>Copyright &copy; 1997-2025 Jordan Russell. All rights reserved.</b><br/>
 <b>Portions Copyright &copy; 2000-2025 Martijn Laan. All rights reserved.</b><br/>
 <b>Portions Copyright &copy; 2000-2025 Martijn Laan. All rights reserved.</b><br/>
 <extlink href="https://jrsoftware.org/">Inno Setup home page</extlink>
 <extlink href="https://jrsoftware.org/">Inno Setup home page</extlink>
@@ -2955,7 +2956,7 @@ Shown by default, but can be disabled in some cases via <link topic="setup_disab
 
 
 <p>All entries are processed by the installer in the order they appear in a section.</p>
 <p>All entries are processed by the installer in the order they appear in a section.</p>
 
 
-<p>You can see the order yourself by loading a script into the Compiler IDE and pressing F7 (Step Into) repeatedly: each time Setup or Uninstall is about to process an entry the IDE will pause Setup or Uninstall and show you the entry.</p> 
+<p>You can see the order yourself by loading a script into the Compiler IDE and pressing F7 (Step Into) repeatedly: each time Setup or Uninstall is about to process an entry the IDE will pause Setup or Uninstall and show you the entry.</p>
 
 
 <p>Changes are undone by the uninstaller in the <i>opposite</i> order in which the installer made them. This is because the uninstall log is parsed from end to beginning.</p>
 <p>Changes are undone by the uninstaller in the <i>opposite</i> order in which the installer made them. This is because the uninstall log is parsed from end to beginning.</p>
 
 
@@ -3136,7 +3137,7 @@ Filename: "{win}\MYPROG.INI"; Section: "InstallSettings"; Key: "InstallPath"; St
 
 
 <p>A single dash (-) means there's no shortcut available for this command in the key map.</p>
 <p>A single dash (-) means there's no shortcut available for this command in the key map.</p>
 
 
-<p>Note: a few of the shortcuts below use string representations for special virtual keys. More precisely: ; for VK_OEM_1, . for VK_OEM_PERIOD, / for VK_OEM_2, [ for VK_OEM_4, \ for VK_OEM_5, and ] for VK_OEM_6. Different keyboard layouts usually reposition these special virtual keys or change the characters produced when they are pressed. In the <i>Edit</i> menu these shortcuts are shown using the current system's keyboard layout. For example, when using a French AZERTY keyboard layout the <i>Toggle Line Comment</i> shortcut is shown as Ctrl+: instead of Ctrl+/. If the keyboard layout doesn't support the virtual key then no shortcut will be shown.</p> 
+<p>Note: a few of the shortcuts below use string representations for special virtual keys. More precisely: ; for VK_OEM_1, . for VK_OEM_PERIOD, / for VK_OEM_2, [ for VK_OEM_4, \ for VK_OEM_5, and ] for VK_OEM_6. Different keyboard layouts usually reposition these special virtual keys or change the characters produced when they are pressed. In the <i>Edit</i> menu these shortcuts are shown using the current system's keyboard layout. For example, when using a French AZERTY keyboard layout the <i>Toggle Line Comment</i> shortcut is shown as Ctrl+: instead of Ctrl+/. If the keyboard layout doesn't support the virtual key then no shortcut will be shown.</p>
 
 
 <table>
 <table>
 <tr><td></td><td><u>Classic</u></td><td><u>Visual Studio Code</u></td></tr>
 <tr><td></td><td><u>Classic</u></td><td><u>Visual Studio Code</u></td></tr>
@@ -3492,6 +3493,96 @@ Filename: "{win}\MYPROG.INI"; Section: "InstallSettings"; Key: "InstallPath"; St
 
 
 
 
 
 
+<topic name="issigtool" title="Inno Setup Signature Tool">
+<keyword value="ISSigTool" />
+<body>
+
+<p>Inno Setup includes a command-line tool, ISSigTool.exe. This tool is designed to sign files using cryptographic signatures.</p>
+
+<p>Note: ISSigTool.exe does not replace Microsoft's signtool.exe in any way and is in fact not related to Authenticode Code Signing at all. If you are looking for more information about this topic see <link topic="setup_signtool">SignTool</link> instead.</p>
+
+<p>Command line usage is as follows:</p>
+
+<indent>
+<p>issigtool <i>[options]</i> <i>&lt;command&gt;</i> <i>&lt;arguments&gt;</i></p>
+</indent>
+
+<p>Available commands:</p>
+
+<indent>
+<table>
+<tr>
+<td>sign <i>&lt;file names&gt;</i></td>
+<td>Signs each specified file. Requires a private key.</td>
+</tr>
+<tr>
+<td>verify <i>&lt;file names&gt;</i></td>
+<td>Verifies the signature of each specified file against the key.</td>
+</tr>
+<tr>
+<td>export-public-key <i>&lt;file name&gt;</i></td>
+<td>Exports the public key used in the signing process to the specified file.</td>
+</tr>
+<tr>
+<td>generate-private-key</td>
+<td>Generates a new private key for signing operations.</td>
+</tr>
+</table>
+</indent>
+
+<p>Valid options are:</p>
+
+<indent>
+<table>
+<tr>
+<td>--key-file=&lt;filename&gt;</td>
+<td>Specifies the private key filename required for signing. This option overriddes the <tt>ISSIGTOOL_KEY_FILE</tt> environment variable which can also be used.</td>
+</tr>
+</table>
+</indent>
+
+<p>Examples:</p>
+
+<indent>
+<examples noheader="1">
+issigtool --key-file=MyKey.isprivatekey generate-private-key<br/>
+issigtool --key-file=MyKey.isprivatekey sign MyProg.dll<br/>
+issigtool --key-file=MyKey.isprivatekey export-public-key MyKey.ispublickey<br/>
+issigtool --key-file=MyKey.ispublickey verify MyProg.dll
+</examples>
+</indent>
+
+<p>Exit codes:</p>
+
+<indent>
+<table>
+<tr>
+<td>0</td>
+<td>Success</td>
+</tr>
+<tr>
+<td>1</td>
+<td>A signature verification failed</td>
+</tr>
+<tr>
+<td>2</td>
+<td>Command line parameters were invalid or a fatal error occurred</td>
+</tr>
+</table>
+</indent>
+
+<p>Notes:</p>
+
+<ul>
+<li>Filenames that include spaces must be enclosed in quotes.</li>
+<li>Ensure the private key file is secure, as its compromise can affect the validity of your signatures.</li>
+</ul>
+
+</body>
+</topic>
+
+
+
 <topic name="setupcmdline" title="Setup Command Line Parameters">
 <topic name="setupcmdline" title="Setup Command Line Parameters">
 <keyword value="Setup Command Line Parameters" />
 <keyword value="Setup Command Line Parameters" />
 <keyword value="command line parameters" />
 <keyword value="command line parameters" />
@@ -5665,7 +5756,7 @@ SignTool=mycustom sign /a /n $qMy Common Name$q /as /fd sha256 /td sha256 /tr ht
 <p>Note: for security reasons you should give a unique name to any Sign Tool set to <tt>$p</tt>, and not use a <tt>byparam</tt> name copied from this example. Consider what happens if you #include a third-party file that says:</p>
 <p>Note: for security reasons you should give a unique name to any Sign Tool set to <tt>$p</tt>, and not use a <tt>byparam</tt> name copied from this example. Consider what happens if you #include a third-party file that says:</p>
 <pre>
 <pre>
 [Setup]
 [Setup]
-SignTool=byparam format c: 
+SignTool=byparam format c:
 </pre>
 </pre>
 </example>
 </example>
 <p>Further details on obtaining signing certificates and using code-signing tools are beyond the scope of this documentation.</p>
 <p>Further details on obtaining signing certificates and using code-signing tools are beyond the scope of this documentation.</p>

+ 4 - 0
Projects/Bin/synch-isfiles.bat

@@ -7,9 +7,13 @@ echo - Synching files from Files to Projects\Bin
 copy ..\..\Files\Default.isl
 copy ..\..\Files\Default.isl
 copy ..\..\Files\ISPPBuiltins.iss
 copy ..\..\Files\ISPPBuiltins.iss
 copy ..\..\Files\is*zip.dll
 copy ..\..\Files\is*zip.dll
+copy ..\..\Files\isbzip.dll.issig
 copy ..\..\Files\is*zlib.dll
 copy ..\..\Files\is*zlib.dll
+copy ..\..\Files\iszlib.dll.issig
 copy ..\..\Files\isscint.dll
 copy ..\..\Files\isscint.dll
+copy ..\..\Files\isscint.dll.issig
 copy ..\..\Files\islzma.dll
 copy ..\..\Files\islzma.dll
+copy ..\..\Files\islzma.dll.issig
 copy ..\..\Files\islzma*.exe
 copy ..\..\Files\islzma*.exe
 copy ..\..\Files\ISetup.chm
 copy ..\..\Files\ISetup.chm
 copy ..\..\Files\ISetup-dark.chm
 copy ..\..\Files\ISetup-dark.chm

+ 28 - 1
Projects/Compil32.dpr

@@ -15,12 +15,14 @@ uses
   SysUtils,
   SysUtils,
   Forms,
   Forms,
   PathFunc in '..\Components\PathFunc.pas',
   PathFunc in '..\Components\PathFunc.pas',
+  TrustFunc in '..\Components\TrustFunc.pas',
   IDE.MainForm in 'Src\IDE.MainForm.pas' {MainForm},
   IDE.MainForm in 'Src\IDE.MainForm.pas' {MainForm},
   Shared.CommonFunc.Vcl in 'Src\Shared.CommonFunc.Vcl.pas',
   Shared.CommonFunc.Vcl in 'Src\Shared.CommonFunc.Vcl.pas',
   Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
   Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
   IDE.HelperFunc in 'Src\IDE.HelperFunc.pas',
   IDE.HelperFunc in 'Src\IDE.HelperFunc.pas',
   IDE.Messages in 'Src\IDE.Messages.pas',
   IDE.Messages in 'Src\IDE.Messages.pas',
   Shared.CompilerInt in 'Src\Shared.CompilerInt.pas',
   Shared.CompilerInt in 'Src\Shared.CompilerInt.pas',
+  Shared.CompilerInt.Struct in 'Src\Shared.CompilerInt.Struct.pas',
   IDE.OptionsForm in 'Src\IDE.OptionsForm.pas' {OptionsForm},
   IDE.OptionsForm in 'Src\IDE.OptionsForm.pas' {OptionsForm},
   IDE.StartupForm in 'Src\IDE.StartupForm.pas' {StartupForm},
   IDE.StartupForm in 'Src\IDE.StartupForm.pas' {StartupForm},
   IDE.Wizard.WizardForm in 'Src\IDE.Wizard.WizardForm.pas' {WizardForm},
   IDE.Wizard.WizardForm in 'Src\IDE.Wizard.WizardForm.pas' {WizardForm},
@@ -67,7 +69,10 @@ uses
   SHA256 in '..\Components\SHA256.pas',
   SHA256 in '..\Components\SHA256.pas',
   Shared.DotNetVersion in 'Src\Shared.DotNetVersion.pas',
   Shared.DotNetVersion in 'Src\Shared.DotNetVersion.pas',
   isxclasses_wordlists_generated in '..\ISHelp\isxclasses_wordlists_generated.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}
 {$SETPEOSVERSION 6.1}
 {$SETPESUBSYSVERSION 6.1}
 {$SETPESUBSYSVERSION 6.1}
@@ -200,6 +205,28 @@ begin
 end;
 end;
 
 
 begin
 begin
+  {$IFNDEF STATICCOMPILER}
+  try
+    InitISCmplrLibrary;
+  except
+    begin
+      MessageBox(0, PChar(Format('Could not load %s: %s' {$IFDEF DEBUG} + #13#10#13#10'Did you build the ISCmplr project?' {$ENDIF},
+        [ISCmplrDLL, GetExceptMessage])), nil, MB_OK or MB_ICONSTOP);
+      Halt(3);
+    end;
+  end;
+  {$ENDIF}
+
+  try
+    InitIsscintLibrary;
+  except
+    begin
+      MessageBox(0, PChar(Format('Could not load %s: %s' {$IFDEF DEBUG} + #13#10#13#10'Did you run Projects\Bin\synch-isfiles.bat as instructed in README.md?' {$ENDIF},
+        [IsscintDLL, GetExceptMessage])), nil, MB_OK or MB_ICONSTOP);
+      Halt(4);
+    end;
+  end;
+
   {$IFDEF DEBUG}
   {$IFDEF DEBUG}
   ReportMemoryLeaksOnShutdown := True;
   ReportMemoryLeaksOnShutdown := True;
   {$ENDIF}
   {$ENDIF}

+ 5 - 0
Projects/Compil32.dproj

@@ -78,6 +78,7 @@
         </DelphiCompile>
         </DelphiCompile>
         <DCCReference Include="..\Components\SafeDLLPath.pas"/>
         <DCCReference Include="..\Components\SafeDLLPath.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
+        <DCCReference Include="..\Components\TrustFunc.pas"/>
         <DCCReference Include="Src\IDE.MainForm.pas">
         <DCCReference Include="Src\IDE.MainForm.pas">
             <Form>MainForm</Form>
             <Form>MainForm</Form>
         </DCCReference>
         </DCCReference>
@@ -86,6 +87,7 @@
         <DCCReference Include="Src\IDE.HelperFunc.pas"/>
         <DCCReference Include="Src\IDE.HelperFunc.pas"/>
         <DCCReference Include="Src\IDE.Messages.pas"/>
         <DCCReference Include="Src\IDE.Messages.pas"/>
         <DCCReference Include="Src\Shared.CompilerInt.pas"/>
         <DCCReference Include="Src\Shared.CompilerInt.pas"/>
+        <DCCReference Include="Src\Shared.CompilerInt.Struct.pas"/>
         <DCCReference Include="Src\IDE.OptionsForm.pas">
         <DCCReference Include="Src\IDE.OptionsForm.pas">
             <Form>OptionsForm</Form>
             <Form>OptionsForm</Form>
         </DCCReference>
         </DCCReference>
@@ -153,6 +155,9 @@
             <FormType>dfm</FormType>
             <FormType>dfm</FormType>
             <DesignClass>TDataModule</DesignClass>
             <DesignClass>TDataModule</DesignClass>
         </DCCReference>
         </DCCReference>
+        <DCCReference Include="..\Components\ECDSA.pas"/>
+        <DCCReference Include="..\Components\ISSigFunc.pas"/>
+        <DCCReference Include="..\Components\StringScanner.pas"/>
         <BuildConfiguration Include="Base">
         <BuildConfiguration Include="Base">
             <Key>Base</Key>
             <Key>Base</Key>
         </BuildConfiguration>
         </BuildConfiguration>

+ 21 - 2
Projects/ISCC.dpr

@@ -23,12 +23,18 @@ uses
   Classes,
   Classes,
   {$IFDEF STATICCOMPILER} Compiler.Compile, {$ENDIF}
   {$IFDEF STATICCOMPILER} Compiler.Compile, {$ENDIF}
   PathFunc in '..\Components\PathFunc.pas',
   PathFunc in '..\Components\PathFunc.pas',
+  TrustFunc in '..\Components\TrustFunc.pas',
   Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
   Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
   Shared.CompilerInt in 'Src\Shared.CompilerInt.pas',
   Shared.CompilerInt in 'Src\Shared.CompilerInt.pas',
+  Shared.CompilerInt.Struct in 'Src\Shared.CompilerInt.Struct.pas',
   Shared.FileClass in 'Src\Shared.FileClass.pas',
   Shared.FileClass in 'Src\Shared.FileClass.pas',
   Shared.ConfigIniFile in 'Src\Shared.ConfigIniFile.pas',
   Shared.ConfigIniFile in 'Src\Shared.ConfigIniFile.pas',
   Shared.SignToolsFunc in 'Src\Shared.SignToolsFunc.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}
 {$SETPEOSVERSION 6.1}
 {$SETPESUBSYSVERSION 6.1}
 {$SETPESUBSYSVERSION 6.1}
@@ -559,6 +565,14 @@ begin
   end;
   end;
 
 
   {$IFNDEF STATICCOMPILER}
   {$IFNDEF STATICCOMPILER}
+  try
+    InitISCmplrLibrary;
+  except
+    begin
+      WriteStdErr(Format('Could not load %s: %s', [ISCmplrDLL, GetExceptMessage]), True);
+      Halt(1);
+    end;
+  end;
   Ver := ISDllGetVersion;
   Ver := ISDllGetVersion;
   {$ELSE}
   {$ELSE}
   Ver := ISGetVersion;
   Ver := ISGetVersion;
@@ -643,6 +657,11 @@ begin
     Halt(ExitCode);
     Halt(ExitCode);
 end;
 end;
 
 
+function ISPPInstalled: Boolean;
+begin
+  Result := NewFileExists(PathExtractPath(NewParamStr(0)) + 'ISPP.dll');
+end;
+
 begin
 begin
   SignTools := TStringList.Create;
   SignTools := TStringList.Create;
   try
   try
@@ -653,7 +672,7 @@ begin
     StdErrHandleIsConsole := GetConsoleMode(StdErrHandle, Mode);
     StdErrHandleIsConsole := GetConsoleMode(StdErrHandle, Mode);
     SetConsoleCtrlHandler(@ConsoleCtrlHandler, True);
     SetConsoleCtrlHandler(@ConsoleCtrlHandler, True);
     try
     try
-      IsppMode := FileExists(ExtractFilePath(NewParamStr(0)) + 'ispp.dll');
+      IsppMode := ISPPInstalled;
       ProcessCommandLine;
       ProcessCommandLine;
       Go;
       Go;
     except
     except

+ 6 - 0
Projects/ISCC.dproj

@@ -77,12 +77,18 @@
         </DelphiCompile>
         </DelphiCompile>
         <DCCReference Include="..\Components\SafeDLLPath.pas"/>
         <DCCReference Include="..\Components\SafeDLLPath.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
+        <DCCReference Include="..\Components\TrustFunc.pas"/>
         <DCCReference Include="Src\Shared.CommonFunc.pas"/>
         <DCCReference Include="Src\Shared.CommonFunc.pas"/>
         <DCCReference Include="Src\Shared.CompilerInt.pas"/>
         <DCCReference Include="Src\Shared.CompilerInt.pas"/>
+        <DCCReference Include="Src\Shared.CompilerInt.Struct.pas"/>
         <DCCReference Include="Src\Shared.FileClass.pas"/>
         <DCCReference Include="Src\Shared.FileClass.pas"/>
         <DCCReference Include="Src\Shared.ConfigIniFile.pas"/>
         <DCCReference Include="Src\Shared.ConfigIniFile.pas"/>
         <DCCReference Include="Src\Shared.SignToolsFunc.pas"/>
         <DCCReference Include="Src\Shared.SignToolsFunc.pas"/>
         <DCCReference Include="Src\Shared.Int64Em.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">
         <BuildConfiguration Include="Base">
             <Key>Base</Key>
             <Key>Base</Key>
         </BuildConfiguration>
         </BuildConfiguration>

+ 6 - 2
Projects/ISCmplr.dpr

@@ -12,7 +12,7 @@ library ISCmplr;
 uses
 uses
   SafeDLLPath in '..\Components\SafeDLLPath.pas',
   SafeDLLPath in '..\Components\SafeDLLPath.pas',
   SysUtils,
   SysUtils,
-  Shared.CompilerInt in 'Src\Shared.CompilerInt.pas',
+  Shared.CompilerInt.Struct in 'Src\Shared.CompilerInt.Struct.pas',
   Shared.PreprocInt in 'Src\Shared.PreprocInt.pas',
   Shared.PreprocInt in 'Src\Shared.PreprocInt.pas',
   Compiler.Compile in 'Src\Compiler.Compile.pas',
   Compiler.Compile in 'Src\Compiler.Compile.pas',
   Compiler.SetupCompiler in 'Src\Compiler.SetupCompiler.pas',
   Compiler.SetupCompiler in 'Src\Compiler.SetupCompiler.pas',
@@ -36,6 +36,7 @@ uses
   ChaCha20 in '..\Components\ChaCha20.pas',
   ChaCha20 in '..\Components\ChaCha20.pas',
   Shared.VerInfoFunc in 'Src\Shared.VerInfoFunc.pas',
   Shared.VerInfoFunc in 'Src\Shared.VerInfoFunc.pas',
   PathFunc in '..\Components\PathFunc.pas',
   PathFunc in '..\Components\PathFunc.pas',
+  TrustFunc in '..\Components\TrustFunc.pas',
   Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
   Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
   Shared.Int64Em in 'Src\Shared.Int64Em.pas',
   Shared.Int64Em in 'Src\Shared.Int64Em.pas',
   SHA256 in '..\Components\SHA256.pas',
   SHA256 in '..\Components\SHA256.pas',
@@ -48,7 +49,10 @@ uses
   Shared.SetupSteps in 'Src\Shared.SetupSteps.pas',
   Shared.SetupSteps in 'Src\Shared.SetupSteps.pas',
   SimpleExpression in '..\Components\SimpleExpression.pas',
   SimpleExpression in '..\Components\SimpleExpression.pas',
   Shared.DotNetVersion in 'Src\Shared.DotNetVersion.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}
 {$IMAGEBASE $00800000}
 {$SETPEOSVERSION 6.1}
 {$SETPEOSVERSION 6.1}

+ 5 - 1
Projects/ISCmplr.dproj

@@ -79,7 +79,7 @@
             <MainSource>MainSource</MainSource>
             <MainSource>MainSource</MainSource>
         </DelphiCompile>
         </DelphiCompile>
         <DCCReference Include="..\Components\SafeDLLPath.pas"/>
         <DCCReference Include="..\Components\SafeDLLPath.pas"/>
-        <DCCReference Include="Src\Shared.CompilerInt.pas"/>
+        <DCCReference Include="Src\Shared.CompilerInt.Struct.pas"/>
         <DCCReference Include="Src\Shared.PreprocInt.pas"/>
         <DCCReference Include="Src\Shared.PreprocInt.pas"/>
         <DCCReference Include="Src\Compiler.Compile.pas"/>
         <DCCReference Include="Src\Compiler.Compile.pas"/>
         <DCCReference Include="Src\Compiler.SetupCompiler.pas"/>
         <DCCReference Include="Src\Compiler.SetupCompiler.pas"/>
@@ -103,6 +103,7 @@
         <DCCReference Include="..\Components\ChaCha20.pas"/>
         <DCCReference Include="..\Components\ChaCha20.pas"/>
         <DCCReference Include="Src\Shared.VerInfoFunc.pas"/>
         <DCCReference Include="Src\Shared.VerInfoFunc.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
+        <DCCReference Include="..\Components\TrustFunc.pas"/>
         <DCCReference Include="Src\Shared.CommonFunc.pas"/>
         <DCCReference Include="Src\Shared.CommonFunc.pas"/>
         <DCCReference Include="Src\Shared.Int64Em.pas"/>
         <DCCReference Include="Src\Shared.Int64Em.pas"/>
         <DCCReference Include="..\Components\SHA256.pas"/>
         <DCCReference Include="..\Components\SHA256.pas"/>
@@ -116,6 +117,9 @@
         <DCCReference Include="..\Components\SimpleExpression.pas"/>
         <DCCReference Include="..\Components\SimpleExpression.pas"/>
         <DCCReference Include="Src\Shared.DotNetVersion.pas"/>
         <DCCReference Include="Src\Shared.DotNetVersion.pas"/>
         <DCCReference Include="..\Components\PBKDF2.pas"/>
         <DCCReference Include="..\Components\PBKDF2.pas"/>
+        <DCCReference Include="..\Components\ECDSA.pas"/>
+        <DCCReference Include="..\Components\ISSigFunc.pas"/>
+        <DCCReference Include="..\Components\StringScanner.pas"/>
         <BuildConfiguration Include="Base">
         <BuildConfiguration Include="Base">
             <Key>Base</Key>
             <Key>Base</Key>
         </BuildConfiguration>
         </BuildConfiguration>

+ 1 - 1
Projects/ISSigTool.dpr

@@ -232,7 +232,7 @@ end;
 
 
 procedure ShowBanner;
 procedure ShowBanner;
 begin
 begin
-  Writeln('Inno Setup Command-Line Signature Tool');
+  Writeln('Inno Setup Signature Tool');
   Writeln('Copyright (C) 1997-2025 Jordan Russell. All rights reserved.');
   Writeln('Copyright (C) 1997-2025 Jordan Russell. All rights reserved.');
   Writeln('Portions Copyright (C) 2000-2025 Martijn Laan. All rights reserved.');
   Writeln('Portions Copyright (C) 2000-2025 Martijn Laan. All rights reserved.');
   Writeln('https://www.innosetup.com');
   Writeln('https://www.innosetup.com');

BIN
Projects/Res/ISSigTool.versionandicon.res


+ 1 - 1
Projects/Src/Compiler.Compile.pas

@@ -12,7 +12,7 @@ unit Compiler.Compile;
 interface
 interface
 
 
 uses
 uses
-  Shared.CompilerInt;
+  Shared.CompilerInt.Struct;
 
 
 function ISCompileScript(const Params: TCompileScriptParamsEx;
 function ISCompileScript(const Params: TCompileScriptParamsEx;
   const PropagateExceptions: Boolean): Integer;
   const PropagateExceptions: Boolean): Integer;

+ 25 - 35
Projects/Src/Compiler.SetupCompiler.pas

@@ -20,7 +20,7 @@ interface
 uses
 uses
   Windows, SysUtils, Classes, Generics.Collections,
   Windows, SysUtils, Classes, Generics.Collections,
   SimpleExpression, SHA256, ChaCha20,
   SimpleExpression, SHA256, ChaCha20,
-  Shared.Struct, Shared.CompilerInt, Shared.PreprocInt, Shared.SetupMessageIDs,
+  Shared.Struct, Shared.CompilerInt.Struct, Shared.PreprocInt, Shared.SetupMessageIDs,
   Shared.SetupSectionDirectives, Shared.VerInfoFunc, Shared.Int64Em, Shared.DebugStruct,
   Shared.SetupSectionDirectives, Shared.VerInfoFunc, Shared.Int64Em, Shared.DebugStruct,
   Compiler.ScriptCompiler, Compiler.StringLists, Compression.LZMACompressor;
   Compiler.ScriptCompiler, Compiler.StringLists, Compression.LZMACompressor;
 
 
@@ -288,7 +288,7 @@ implementation
 
 
 uses
 uses
   Commctrl, TypInfo, AnsiStrings, Math, WideStrUtils,
   Commctrl, TypInfo, AnsiStrings, Math, WideStrUtils,
-  PathFunc, Shared.CommonFunc, Compiler.Messages, Shared.SetupEntFunc,
+  PathFunc, TrustFunc, Shared.CommonFunc, Compiler.Messages, Shared.SetupEntFunc,
   Shared.FileClass, Compression.Base, Compression.Zlib, Compression.bzlib,
   Shared.FileClass, Compression.Base, Compression.Zlib, Compression.bzlib,
   Shared.LangOptionsSectionDirectives, Shared.ResUpdateFunc, Compiler.ExeUpdateFunc,
   Shared.LangOptionsSectionDirectives, Shared.ResUpdateFunc, Compiler.ExeUpdateFunc,
 {$IFDEF STATICPREPROC}
 {$IFDEF STATICPREPROC}
@@ -502,31 +502,30 @@ begin
   end;
   end;
 end;
 end;
 
 
+function LoadCompilerDLL(const Filename: String; const TrustAllOnDebug: Boolean = False): HMODULE;
+begin
+  try
+    Result := LoadTrustedLibrary(FileName, TrustAllOnDebug);
+  except
+    begin
+      TSetupCompiler.AbortCompileFmt('Failed to load %s: %s', [PathExtractName(Filename), GetExceptMessage]);
+      Result := 0; //silence compiler
+    end;
+  end;
+end;
+
 procedure TSetupCompiler.InitPreprocessor;
 procedure TSetupCompiler.InitPreprocessor;
-{$IFNDEF STATICPREPROC}
-var
-  Filename: String;
-  Attr: DWORD;
-  M: HMODULE;
-{$ENDIF}
 begin
 begin
   if PreprocessorInitialized then
   if PreprocessorInitialized then
     Exit;
     Exit;
 {$IFNDEF STATICPREPROC}
 {$IFNDEF STATICPREPROC}
-  Filename := CompilerDir + 'ISPP.dll';
-  Attr := GetFileAttributes(PChar(Filename));
-  if (Attr = INVALID_FILE_ATTRIBUTES) and (GetLastError = ERROR_FILE_NOT_FOUND) then begin
-    { ISPP unavailable; fall back to built-in preprocessor }
-  end
-  else begin
-    M := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
-    if M = 0 then
-      AbortCompileFmt('Failed to load preprocessor DLL "%s" (%d)',
-        [Filename, GetLastError]);
+  var Filename := CompilerDir + 'ISPP.dll';
+  if NewFileExists(Filename) then begin
+    var M := LoadCompilerDLL(Filename, True);
     PreprocessScriptProc := GetProcAddress(M, 'ISPreprocessScriptW');
     PreprocessScriptProc := GetProcAddress(M, 'ISPreprocessScriptW');
     if not Assigned(PreprocessScriptProc) then
     if not Assigned(PreprocessScriptProc) then
-      AbortCompileFmt('Failed to get address of functions in "%s"', [Filename]);
-  end;
+      AbortCompile('Failed to get address of functions in ISPP.dll');
+  end; { else ISPP unavailable; fall back to built-in preprocessor }
 {$ELSE}
 {$ELSE}
   PreprocessScriptProc := ISPreprocessScript;
   PreprocessScriptProc := ISPreprocessScript;
 {$ENDIF}
 {$ENDIF}
@@ -534,42 +533,33 @@ begin
 end;
 end;
 
 
 procedure TSetupCompiler.InitZipDLL;
 procedure TSetupCompiler.InitZipDLL;
-var
-  M: HMODULE;
 begin
 begin
   if ZipInitialized then
   if ZipInitialized then
     Exit;
     Exit;
-  M := SafeLoadLibrary(CompilerDir + 'iszlib.dll', SEM_NOOPENFILEERRORBOX);
-  if M = 0 then
-    AbortCompileFmt('Failed to load iszlib.dll (%d)', [GetLastError]);
+  var Filename := CompilerDir + 'iszlib.dll';
+  var M := LoadCompilerDLL(Filename);
   if not ZlibInitCompressFunctions(M) then
   if not ZlibInitCompressFunctions(M) then
     AbortCompile('Failed to get address of functions in iszlib.dll');
     AbortCompile('Failed to get address of functions in iszlib.dll');
   ZipInitialized := True;
   ZipInitialized := True;
 end;
 end;
 
 
 procedure TSetupCompiler.InitBzipDLL;
 procedure TSetupCompiler.InitBzipDLL;
-var
-  M: HMODULE;
 begin
 begin
   if BzipInitialized then
   if BzipInitialized then
     Exit;
     Exit;
-  M := SafeLoadLibrary(CompilerDir + 'isbzip.dll', SEM_NOOPENFILEERRORBOX);
-  if M = 0 then
-    AbortCompileFmt('Failed to load isbzip.dll (%d)', [GetLastError]);
+  var Filename := CompilerDir + 'isbzip.dll';
+  var M := LoadCompilerDLL(Filename);
   if not BZInitCompressFunctions(M) then
   if not BZInitCompressFunctions(M) then
     AbortCompile('Failed to get address of functions in isbzip.dll');
     AbortCompile('Failed to get address of functions in isbzip.dll');
   BzipInitialized := True;
   BzipInitialized := True;
 end;
 end;
 
 
 procedure TSetupCompiler.InitLZMADLL;
 procedure TSetupCompiler.InitLZMADLL;
-var
-  M: HMODULE;
 begin
 begin
   if LZMAInitialized then
   if LZMAInitialized then
     Exit;
     Exit;
-  M := SafeLoadLibrary(CompilerDir + 'islzma.dll', SEM_NOOPENFILEERRORBOX);
-  if M = 0 then
-    AbortCompileFmt('Failed to load islzma.dll (%d)', [GetLastError]);
+  var Filename := CompilerDir + 'islzma.dll';
+  var M := LoadCompilerDLL(Filename);
   if not LZMAInitCompressFunctions(M) then
   if not LZMAInitCompressFunctions(M) then
     AbortCompile('Failed to get address of functions in islzma.dll');
     AbortCompile('Failed to get address of functions in islzma.dll');
   LZMAInitialized := True;
   LZMAInitialized := True;

+ 3 - 2
Projects/Src/IDE.MainForm.pas

@@ -25,7 +25,7 @@ uses
   Windows, Messages, SysUtils, Classes, Contnrs, Graphics, Controls, Forms, Dialogs, CommDlg,
   Windows, Messages, SysUtils, Classes, Contnrs, Graphics, Controls, Forms, Dialogs, CommDlg,
   Generics.Collections, UIStateForm, StdCtrls, ExtCtrls, Menus, Buttons, ComCtrls, CommCtrl,
   Generics.Collections, UIStateForm, StdCtrls, ExtCtrls, Menus, Buttons, ComCtrls, CommCtrl,
   ScintInt, ScintEdit, IDE.ScintStylerInnoSetup, NewTabSet, ModernColors, IDE.IDEScintEdit,
   ScintInt, ScintEdit, IDE.ScintStylerInnoSetup, NewTabSet, ModernColors, IDE.IDEScintEdit,
-  Shared.DebugStruct, Shared.CompilerInt, NewUxTheme, ImageList, ImgList, ToolWin, IDE.HelperFunc,
+  Shared.DebugStruct, Shared.CompilerInt.Struct, NewUxTheme, ImageList, ImgList, ToolWin, IDE.HelperFunc,
   VirtualImageList, BaseImageCollection;
   VirtualImageList, BaseImageCollection;
 
 
 const
 const
@@ -681,7 +681,8 @@ uses
   {$IFDEF STATICCOMPILER} Compiler.Compile, {$ENDIF}
   {$IFDEF STATICCOMPILER} Compiler.Compile, {$ENDIF}
   IDE.OptionsForm, IDE.StartupForm, IDE.Wizard.WizardForm, IDE.SignToolsForm,
   IDE.OptionsForm, IDE.StartupForm, IDE.Wizard.WizardForm, IDE.SignToolsForm,
   Shared.ConfigIniFile, Shared.SignToolsFunc, IDE.InputQueryComboForm, IDE.MsgBoxDesignerForm,
   Shared.ConfigIniFile, Shared.SignToolsFunc, IDE.InputQueryComboForm, IDE.MsgBoxDesignerForm,
-  IDE.FilesDesignerForm, IDE.RegistryDesignerForm, IDE.Wizard.WizardFormRegistryHelper;
+  IDE.FilesDesignerForm, IDE.RegistryDesignerForm, IDE.Wizard.WizardFormRegistryHelper,
+  Shared.CompilerInt;
 
 
 {$R *.DFM}
 {$R *.DFM}
 
 

+ 165 - 0
Projects/Src/Shared.CompilerInt.Struct.pas

@@ -0,0 +1,165 @@
+unit Shared.CompilerInt.Struct;
+
+{
+  Inno Setup
+  Copyright (C) 1997-2024 Jordan Russell
+  Portions by Martijn Laan
+  For conditions of distribution and use, see LICENSE.TXT.
+
+  Compiler interface records and other types
+}
+
+interface
+
+uses
+  Windows;
+
+const
+  { Constants passed in Code parameter of callback function }
+  iscbReadScript = 1;      { Sent when compiler needs the next script line }
+  iscbNotifyStatus = 2;    { Sent to notify the application of compiler status }
+  iscbNotifyIdle = 3;      { Sent at various intervals during the compilation }
+  iscbNotifySuccess = 4;   { Sent when compilation succeeds }
+  iscbNotifyError = 5;     { Sent when compilation fails or is aborted by the
+                             application }
+  iscbNotifyPreproc = 6;   { Sent to notify the application of preprocessor results }
+
+  { Return values for callback function }
+  iscrSuccess = 0;         { Return this for compiler to continue }
+  iscrRequestAbort = 1;    { Return this to abort compilation immediately.
+                             (When this value is returned, it is not necessary
+                             to set any of the "out" fields in the
+                             TCompilerCallbackData; the compiler will ignore
+                             them.) }
+
+  { Return values for ISDllCompileScript }
+  isceNoError = 0;         { Successful }
+  isceInvalidParam = 1;    { Bad parameters passed to function }
+  isceCompileFailure = 2;  { There was an error compiling or it was aborted
+                             by the application }
+
+type
+  { TCompilerCallbackData is a record passed to the callback function. The
+    fields which you may access vary depending on what Code was passed to the
+    callback function. }
+  TCompilerCallbackData = record
+    case Integer of
+      iscbReadScript: (
+        Reset: BOOL;          { [in] This field can be ignored in compiler
+                                versions 3.0.1 and later. (Previous versions
+                                of the compiler made multiple passes over the
+                                script, and set Reset to True when it needed
+                                to return to the beginning.) }
+        LineRead: PChar);     { [out] Application returns pointer to the next
+                                line it reads, or a NULL pointer if the end of
+                                file is reached. Application is responsible for
+                                allocating a buffer to hold the line; LineRead
+                                is initially NULL when the callback function
+                                is called. The pointer only needs to remain
+                                valid until the next time the callback function
+                                is called (i.e. the application may return the
+                                same pointer each time). }
+
+      iscbNotifyStatus: (
+        StatusMsg: PChar;     { [in] Contents of status message. }
+        Warning: BOOL);       { [in] Warning indicator (new in 6.0.0) }
+
+      iscbNotifyIdle: (
+        CompressProgress: Cardinal;     { [in] Amount compressed so far
+                                          (new in 4.1.6) }
+        CompressProgressMax: Cardinal;  { [in] Maximum value of CompressProgress
+                                          (new in 4.1.6) }
+        SecondsRemaining: Integer;      { [in] Estimated time remaining, or -1
+                                          if not known (new in 5.1.13) }
+        BytesCompressedPerSecond: Cardinal); { [in] Average bytes compressed
+                                               per second (new in 5.1.13) }
+
+      iscbNotifyPreproc: (
+        PreprocessedScript: PChar; { [in] Preprocessed script (new in 6.1.0) }
+        IncludedFilenames: PChar); { [in] Names of #included files. Each name is
+                                          a null-terminated string, and the final
+                                          name is followed by an additional null
+                                          character (new in 6.1.0) }
+
+      iscbNotifySuccess: (
+        OutputExeFilename: PChar;  { [in] The name of the resulting setup.exe,
+                                          or empty if output was disabled
+                                          (latter new in 5.5.5) }
+        DebugInfo: Pointer;        { [in] Debug info (new in 3.0.0.1) }
+        DebugInfoSize: Cardinal);  { [in] Size of debug info (new in 3.0.0.1) }
+
+      iscbNotifyError: (
+        ErrorMsg: PChar;      { [in] The error message, or NULL if compilation
+                                was aborted by the application. }
+        ErrorFilename: PChar; { [in] Filename in which the error occurred. This
+                                is NULL if the file is the main script. }
+        ErrorLine: Integer);  { [in] The line number the error occurred on.
+                                Zero if the error doesn't apply to any
+                                particular line. }
+  end;
+
+  TCompilerCallbackProc = function(Code: Integer;
+    var Data: TCompilerCallbackData; AppData: Longint): Integer; stdcall;
+
+  PCompileScriptParamsEx = ^TCompileScriptParamsEx;
+  TCompileScriptParamsEx = record
+    Size: Cardinal;       { [in] Set to SizeOf(TCompileScriptParamsEx). }
+    CompilerPath: PChar;  { [in] The "compiler:" directory. This is the
+                            directory which contains the *.e32 files. If this
+                            is set to NULL, the compiler will use the directory
+                            containing the compiler DLL/EXE. }
+    SourcePath: PChar;    { [in] The default source directory, and directory to
+                            look in for #include files. Normally, this is
+                            the directory containing the script file. This
+                            cannot be NULL. }
+    CallbackProc: TCompilerCallbackProc;
+                          { [in] The callback procedure which the compiler calls
+                            to read the script and for status notification. }
+    AppData: Longint;     { [in] Application-defined. AppData is passed to the
+                            callback function. }
+    Options: PChar;       { [in] Additional options. Each option is a
+                            null-terminated string, and the final option is
+                            followed by an additional null character.
+                            If you do not wish to specify any options, set this
+                            field to NULL or to point to a single null
+                            character.
+
+                            Currently supported options:
+
+                            Output=(0|no|false|1|yes|true)
+                              Enables or disables output.
+                            OutputBaseFilename=[filename]
+                              Overrides any OutputBaseFilename setting in the
+                              script; causes the compiler to use [filename]
+                              instead.
+                            OutputDir=[path]
+                              Overrides any output directory in the script;
+                              causes the compiler to use [path] instead.
+                            SignTool-[name]=[command]
+                              Configures a SignTool with name [name] and command
+                              [command].
+                            ISPP:[isppoption]
+                              Configures an ISPP option. }
+  end;
+
+  { The old TCompileScriptParams record. Use this in place of
+    TCompileScriptParamsEx if you need call ISCmplr.dll versions below
+    5.0.5. It's the same except it lacks an Options field. }
+  TCompileScriptParams = record
+    Size: Cardinal;       { [in] Set to SizeOf(TCompileScriptParams). }
+    CompilerPath: PChar;
+    SourcePath: PChar;
+    CallbackProc: TCompilerCallbackProc;
+    AppData: Longint;
+  end;
+
+  PCompilerVersionInfo = ^TCompilerVersionInfo;
+  TCompilerVersionInfo = record
+    Title: PAnsiChar;      { Name of compiler engine - 'Inno Setup' }
+    Version: PAnsiChar;    { Version number text }
+    BinVersion: Cardinal;  { Version number as an integer }
+  end;
+
+implementation
+
+end.

+ 29 - 150
Projects/Src/Shared.CompilerInt.pas

@@ -12,167 +12,46 @@ unit Shared.CompilerInt;
 interface
 interface
 
 
 uses
 uses
-  Windows;
-
-const
-  { Constants passed in Code parameter of callback function }
-  iscbReadScript = 1;      { Sent when compiler needs the next script line }
-  iscbNotifyStatus = 2;    { Sent to notify the application of compiler status }
-  iscbNotifyIdle = 3;      { Sent at various intervals during the compilation }
-  iscbNotifySuccess = 4;   { Sent when compilation succeeds }
-  iscbNotifyError = 5;     { Sent when compilation fails or is aborted by the
-                             application }
-  iscbNotifyPreproc = 6;   { Sent to notify the application of preprocessor results }
-
-  { Return values for callback function }
-  iscrSuccess = 0;         { Return this for compiler to continue }
-  iscrRequestAbort = 1;    { Return this to abort compilation immediately.
-                             (When this value is returned, it is not necessary
-                             to set any of the "out" fields in the
-                             TCompilerCallbackData; the compiler will ignore
-                             them.) }
-
-  { Return values for ISDllCompileScript }
-  isceNoError = 0;         { Successful }
-  isceInvalidParam = 1;    { Bad parameters passed to function }
-  isceCompileFailure = 2;  { There was an error compiling or it was aborted
-                             by the application }
-
-type
-  { TCompilerCallbackData is a record passed to the callback function. The
-    fields which you may access vary depending on what Code was passed to the
-    callback function. }
-  TCompilerCallbackData = record
-    case Integer of
-      iscbReadScript: (
-        Reset: BOOL;          { [in] This field can be ignored in compiler
-                                versions 3.0.1 and later. (Previous versions
-                                of the compiler made multiple passes over the
-                                script, and set Reset to True when it needed
-                                to return to the beginning.) }
-        LineRead: PChar);     { [out] Application returns pointer to the next
-                                line it reads, or a NULL pointer if the end of
-                                file is reached. Application is responsible for
-                                allocating a buffer to hold the line; LineRead
-                                is initially NULL when the callback function
-                                is called. The pointer only needs to remain
-                                valid until the next time the callback function
-                                is called (i.e. the application may return the
-                                same pointer each time). }
-
-      iscbNotifyStatus: (
-        StatusMsg: PChar;     { [in] Contents of status message. }
-        Warning: BOOL);       { [in] Warning indicator (new in 6.0.0) }
-
-      iscbNotifyIdle: (
-        CompressProgress: Cardinal;     { [in] Amount compressed so far
-                                          (new in 4.1.6) }
-        CompressProgressMax: Cardinal;  { [in] Maximum value of CompressProgress
-                                          (new in 4.1.6) }
-        SecondsRemaining: Integer;      { [in] Estimated time remaining, or -1
-                                          if not known (new in 5.1.13) }
-        BytesCompressedPerSecond: Cardinal); { [in] Average bytes compressed
-                                               per second (new in 5.1.13) }
-
-      iscbNotifyPreproc: (
-        PreprocessedScript: PChar; { [in] Preprocessed script (new in 6.1.0) }
-        IncludedFilenames: PChar); { [in] Names of #included files. Each name is
-                                          a null-terminated string, and the final
-                                          name is followed by an additional null
-                                          character (new in 6.1.0) }
-
-      iscbNotifySuccess: (
-        OutputExeFilename: PChar;  { [in] The name of the resulting setup.exe,
-                                          or empty if output was disabled
-                                          (latter new in 5.5.5) }
-        DebugInfo: Pointer;        { [in] Debug info (new in 3.0.0.1) }
-        DebugInfoSize: Cardinal);  { [in] Size of debug info (new in 3.0.0.1) }
-
-      iscbNotifyError: (
-        ErrorMsg: PChar;      { [in] The error message, or NULL if compilation
-                                was aborted by the application. }
-        ErrorFilename: PChar; { [in] Filename in which the error occurred. This
-                                is NULL if the file is the main script. }
-        ErrorLine: Integer);  { [in] The line number the error occurred on.
-                                Zero if the error doesn't apply to any
-                                particular line. }
-  end;
-
-  TCompilerCallbackProc = function(Code: Integer;
-    var Data: TCompilerCallbackData; AppData: Longint): Integer; stdcall;
-
-  PCompileScriptParamsEx = ^TCompileScriptParamsEx;
-  TCompileScriptParamsEx = record
-    Size: Cardinal;       { [in] Set to SizeOf(TCompileScriptParamsEx). }
-    CompilerPath: PChar;  { [in] The "compiler:" directory. This is the
-                            directory which contains the *.e32 files. If this
-                            is set to NULL, the compiler will use the directory
-                            containing the compiler DLL/EXE. }
-    SourcePath: PChar;    { [in] The default source directory, and directory to
-                            look in for #include files. Normally, this is
-                            the directory containing the script file. This
-                            cannot be NULL. }
-    CallbackProc: TCompilerCallbackProc;
-                          { [in] The callback procedure which the compiler calls
-                            to read the script and for status notification. }
-    AppData: Longint;     { [in] Application-defined. AppData is passed to the
-                            callback function. }
-    Options: PChar;       { [in] Additional options. Each option is a
-                            null-terminated string, and the final option is
-                            followed by an additional null character.
-                            If you do not wish to specify any options, set this
-                            field to NULL or to point to a single null
-                            character.
-
-                            Currently supported options:
-
-                            Output=(0|no|false|1|yes|true)
-                              Enables or disables output.
-                            OutputBaseFilename=[filename]
-                              Overrides any OutputBaseFilename setting in the
-                              script; causes the compiler to use [filename]
-                              instead.
-                            OutputDir=[path]
-                              Overrides any output directory in the script;
-                              causes the compiler to use [path] instead.
-                            SignTool-[name]=[command]
-                              Configures a SignTool with name [name] and command
-                              [command].
-                            ISPP:[isppoption]
-                              Configures an ISPP option. }
-  end;
-
-  { The old TCompileScriptParams record. Use this in place of
-    TCompileScriptParamsEx if you need call ISCmplr.dll versions below
-    5.0.5. It's the same except it lacks an Options field. }
-  TCompileScriptParams = record
-    Size: Cardinal;       { [in] Set to SizeOf(TCompileScriptParams). }
-    CompilerPath: PChar;
-    SourcePath: PChar;
-    CallbackProc: TCompilerCallbackProc;
-    AppData: Longint;
-  end;
-
-  PCompilerVersionInfo = ^TCompilerVersionInfo;
-  TCompilerVersionInfo = record
-    Title: PAnsiChar;      { Name of compiler engine - 'Inno Setup' }
-    Version: PAnsiChar;    { Version number text }
-    BinVersion: Cardinal;  { Version number as an integer }
-  end;
+  Shared.CompilerInt.Struct;
 
 
 const
 const
   ISCmplrDLL = 'ISCmplr.dll';
   ISCmplrDLL = 'ISCmplr.dll';
 
 
+var
+  ISCmplrLibrary: HMODULE;
+
 { The ISDllCompileScript function begins compilation of a script. See the above
 { The ISDllCompileScript function begins compilation of a script. See the above
   description of the TCompileScriptParams record. Return value is one of the
   description of the TCompileScriptParams record. Return value is one of the
   isce* constants. }
   isce* constants. }
-function ISDllCompileScript(const Params: TCompileScriptParamsEx): Integer;
-  stdcall; external ISCmplrDLL name 'ISDllCompileScriptW';
+  ISDllCompileScript: function(const Params: TCompileScriptParamsEx): Integer; stdcall;
 
 
 { The ISDllGetVersion returns a pointer to a TCompilerVersionInfo record which
 { The ISDllGetVersion returns a pointer to a TCompilerVersionInfo record which
   contains information about the compiler version. }
   contains information about the compiler version. }
-function ISDllGetVersion: PCompilerVersionInfo; stdcall; external ISCmplrDLL;
+  ISDllGetVersion: function: PCompilerVersionInfo; stdcall;
+
+procedure InitISCmplrLibrary;
 
 
 implementation
 implementation
 
 
+uses
+  Windows,
+  SysUtils,
+  PathFunc, TrustFunc;
+
+procedure InitISCmplrLibrary;
+begin
+  var FileName := AddBackslash(PathExtractPath(ParamStr(0))) + ISCmplrDLL;
+  ISCmplrLibrary := LoadTrustedLibrary(FileName, True);
+  if ISCmplrLibrary <> 0 then begin
+    ISDllCompileScript := GetProcAddress(ISCmplrLibrary, 'ISDllCompileScriptW');
+    ISDllGetVersion := GetProcAddress(ISCmplrLibrary, 'ISDllGetVersion');
+    if not Assigned(ISDllCompileScript) or not Assigned(ISDllGetVersion) then begin
+      FreeLibrary(ISCmplrLibrary);
+      ISCmplrLibrary := 0;
+      ISDllCompileScript := nil;
+      ISDllGetVersion := nil;
+    end;
+  end;
+end;
+
 end.
 end.

+ 2 - 2
Projects/Src/Shared.Struct.pas

@@ -17,8 +17,8 @@ uses
 
 
 const
 const
   SetupTitle = 'Inno Setup';
   SetupTitle = 'Inno Setup';
-  SetupVersion = '6.4.2';
-  SetupBinVersion = (6 shl 24) + (4 shl 16) + (2 shl 8) + 0;
+  SetupVersion = '6.4.3-dev';
+  SetupBinVersion = (6 shl 24) + (4 shl 16) + (3 shl 8) + 0;
 
 
 type
 type
   TSetupID = array[0..63] of AnsiChar;
   TSetupID = array[0..63] of AnsiChar;

+ 7 - 1
README.md

@@ -112,7 +112,7 @@ because they can function independently from Inno Setup.
 Overview
 Overview
 --------
 --------
 
 
-Inno Setup consists of six projects:
+Inno Setup consists of seven projects:
 
 
 **Compil32** - This is the GUI front-end for the compiler, also known as
 **Compil32** - This is the GUI front-end for the compiler, also known as
 the Compiler IDE. Compil32 does not do the actual compilation itself; it
 the Compiler IDE. Compil32 does not do the actual compilation itself; it
@@ -137,6 +137,12 @@ performs all (un)installation-related tasks.
 Setup program into the user's TEMP directory and runs it from there. It also
 Setup program into the user's TEMP directory and runs it from there. It also
 displays the "This will install..." and /HELP message boxes.
 displays the "This will install..." and /HELP message boxes.
 
 
+**ISSigTool** - This is a command-line tool which can be used to sign and verify
+any file. Compil32, ISCC, and ISCmplr use these signatures to verify the
+authenticity of a number of DLL files before loading them. Note: this tool does
+not replace Microsoft's signtool.exe in any way and is in fact not related to
+Authenticode Code Signing at all.
+
 How do the projects link together?
 How do the projects link together?
 
 
 - Compil32, ISCmplr, ISPP, Setup, and SetupLdr share the unit Shared.Struct.pas.
 - Compil32, ISCmplr, ISPP, Setup, and SetupLdr share the unit Shared.Struct.pas.

+ 27 - 3
build-ce.bat

@@ -7,7 +7,8 @@ rem  For conditions of distribution and use, see LICENSE.TXT.
 rem
 rem
 rem  Batch file to prepare a release
 rem  Batch file to prepare a release
 rem
 rem
-rem  Calls setup-sign.bat if it exists, else creates setup.exe without signing
+rem  Calls setup-sign.bat if it exists to create a signed build, otherwise creates setup.exe without signing
+rem  Signed builds also require a setup-presign.bat to exist which should sign all files passed to it
 rem
 rem
 rem  This batch files does the following things:
 rem  This batch files does the following things:
 rem  -Ask the user to compile Inno Setup including ISSigTool and ISHelpGen after clearing output first
 rem  -Ask the user to compile Inno Setup including ISSigTool and ISHelpGen after clearing output first
@@ -18,7 +19,7 @@ rem  Once done the installer can be found in Output
 
 
 setlocal
 setlocal
 
 
-set VER=6.4.2
+set VER=6.4.3-dev
 
 
 echo Building Inno Setup %VER%...
 echo Building Inno Setup %VER%...
 echo.
 echo.
@@ -28,6 +29,20 @@ cd /d %~dp0
 if "%1"=="setup" goto setup
 if "%1"=="setup" goto setup
 if not "%1"=="" goto failed
 if not "%1"=="" goto failed
 
 
+if not exist files\issigtool.exe (
+  echo Missing ISSigTool
+  echo Now open Projects\Projects.groupproj and build ISSigTool in Release mode
+
+  echo Waiting for file...
+  call :waitforfile files\issigtool.exe
+  echo Compiling ISSigTool done
+)
+
+call .\issig.bat embed
+if errorlevel 1 goto failed
+echo ISSigTool embed done
+
+echo.
 call :deletefile files\compil32.exe
 call :deletefile files\compil32.exe
 call :deletefile files\iscc.exe
 call :deletefile files\iscc.exe
 call :deletefile files\iscmplr.dll
 call :deletefile files\iscmplr.dll
@@ -37,7 +52,6 @@ call :deletefile files\setupldr.e32
 call :deletefile files\issigtool.exe
 call :deletefile files\issigtool.exe
 call :deletefile ishelp\ishelpgen\ishelpgen.exe
 call :deletefile ishelp\ishelpgen\ishelpgen.exe
 
 
-echo.
 echo Clearing compilation output done
 echo Clearing compilation output done
 echo Now open Projects\Projects.groupproj and build all projects in Release mode
 echo Now open Projects\Projects.groupproj and build all projects in Release mode
 
 
@@ -53,6 +67,16 @@ call :waitforfile ishelp\ishelpgen\ishelpgen.exe
 
 
 echo Found all, waiting 2 seconds more...
 echo Found all, waiting 2 seconds more...
 timeout /t 2 /nobreak >nul
 timeout /t 2 /nobreak >nul
+echo Compiling Inno Setup done
+
+if exist .\setup-presign.bat (
+  call .\setup-presign.bat Files\ISCmplr.dll Files\ISPP.dll
+)
+
+call .\issig.bat sign
+if errorlevel 1 goto failed
+echo ISSigTool sign done
+pause
 
 
 cd ishelp
 cd ishelp
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed

+ 22 - 2
build.bat

@@ -7,7 +7,8 @@ rem  For conditions of distribution and use, see LICENSE.TXT.
 rem
 rem
 rem  Batch file to prepare a release
 rem  Batch file to prepare a release
 rem
 rem
-rem  Calls setup-sign.bat if it exists, else creates setup.exe without signing
+rem  Calls setup-sign.bat if it exists to create a signed build, otherwise creates setup.exe without signing
+rem  Signed build also require a setup-presign.bat to exist which should sign all files passed to it
 rem
 rem
 rem  This batch files does the following things:
 rem  This batch files does the following things:
 rem  -Compile ISHelpGen
 rem  -Compile ISHelpGen
@@ -19,7 +20,7 @@ rem  Once done the installer can be found in Output
 
 
 setlocal
 setlocal
 
 
-set VER=6.4.2
+set VER=6.4.3-dev
 
 
 echo Building Inno Setup %VER%...
 echo Building Inno Setup %VER%...
 echo.
 echo.
@@ -47,9 +48,28 @@ if errorlevel 1 goto failed
 echo Compiling ISetup*.chm done
 echo Compiling ISetup*.chm done
 pause
 pause
 
 
+if not exist files\issigtool.exe (
+  echo Missing ISSigTool
+  call .\compile.bat issigtool
+  if errorlevel 1 goto failed
+  echo Compiling ISSigTool done
+)
+
+call .\issig.bat embed
+if errorlevel 1 goto failed
+echo ISSigTool embed done
+
 call .\compile.bat
 call .\compile.bat
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed
 echo Compiling Inno Setup done
 echo Compiling Inno Setup done
+
+if exist .\setup-presign.bat (
+  call .\setup-presign.bat Files\ISCmplr.dll Files\ISPP.dll
+) 
+
+call .\issig.bat sign
+if errorlevel 1 goto failed
+echo ISSigTool sign done
 pause
 pause
 
 
 :setup
 :setup

+ 13 - 7
compile.bat

@@ -13,8 +13,8 @@ cd /d %~dp0
 
 
 if exist compilesettings.bat goto compilesettingsfound
 if exist compilesettings.bat goto compilesettingsfound
 :compilesettingserror
 :compilesettingserror
-echo compilesettings.bat is missing or incomplete. It needs to be created
-echo with the following line, adjusted for your system:
+echo compilesettings.bat is missing or incomplete. It needs to contain
+echo the following line, adjusted for your system:
 echo.
 echo.
 echo   set DELPHIXEROOT=C:\Program Files\Embarcadero\RAD Studio\20.0 [Path to Delphi 10.4 Sydney (or later)]
 echo   set DELPHIXEROOT=C:\Program Files\Embarcadero\RAD Studio\20.0 [Path to Delphi 10.4 Sydney (or later)]
 goto failed2
 goto failed2
@@ -35,6 +35,9 @@ set DELPHIXEDISABLEDWARNINGS=-W-SYMBOL_DEPRECATED -W-SYMBOL_PLATFORM -W-UNSAFE_C
 cd Projects
 cd Projects
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed
 
 
+if "%1"=="issigtool" goto issigtool
+if not "%1"=="" goto failed
+
 echo - ISPP.dpr
 echo - ISPP.dpr
 mkdir Dcu\ISPP.dpr 2>nul
 mkdir Dcu\ISPP.dpr 2>nul
 "%DELPHIXEROOT%\bin\dcc32.exe" --no-config -NSSystem;System.Win;Winapi -Q -B -H -W %DELPHIXEDISABLEDWARNINGS% %1 -U"%DELPHIXEROOT%\lib\win32\release" -E..\Files -NUDcu\ISPP.dpr ISPP.dpr
 "%DELPHIXEROOT%\bin\dcc32.exe" --no-config -NSSystem;System.Win;Winapi -Q -B -H -W %DELPHIXEDISABLEDWARNINGS% %1 -U"%DELPHIXEROOT%\lib\win32\release" -E..\Files -NUDcu\ISPP.dpr ISPP.dpr
@@ -65,11 +68,6 @@ mkdir Dcu\Setup.dpr 2>nul
 "%DELPHIXEROOT%\bin\dcc32.exe" --no-config -NSSystem;System.Win;Winapi;Vcl -Q -B -W %DELPHIXEDISABLEDWARNINGS% %1 -U"%DELPHIXEROOT%\lib\win32\release;..\Components\UniPs\Source" -E..\Files -NUDcu\Setup.dpr -DSETUPPROJ;PS_MINIVCL;PS_NOGRAPHCONST;PS_PANSICHAR;PS_NOINTERFACEGUIDBRACKETS Setup.dpr
 "%DELPHIXEROOT%\bin\dcc32.exe" --no-config -NSSystem;System.Win;Winapi;Vcl -Q -B -W %DELPHIXEDISABLEDWARNINGS% %1 -U"%DELPHIXEROOT%\lib\win32\release;..\Components\UniPs\Source" -E..\Files -NUDcu\Setup.dpr -DSETUPPROJ;PS_MINIVCL;PS_NOGRAPHCONST;PS_PANSICHAR;PS_NOINTERFACEGUIDBRACKETS Setup.dpr
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed
 
 
-echo - ISSigTool.dpr
-mkdir Dcu\ISSigTool.dpr 2>nul
-"%DELPHIXEROOT%\bin\dcc32.exe" --no-config -NSSystem;System.Win;Winapi -Q -B -H -W %DELPHIXEDISABLEDWARNINGS% %1 -U"%DELPHIXEROOT%\lib\win32\release" -E..\Files -NUDcu\ISSigTool.dpr ISSigTool.dpr
-if errorlevel 1 goto failed
-
 echo - Renaming E32 files
 echo - Renaming E32 files
 cd ..\Files
 cd ..\Files
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed
@@ -77,6 +75,14 @@ move SetupLdr.exe SetupLdr.e32
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed
 move Setup.exe Setup.e32
 move Setup.exe Setup.e32
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed
+cd ..\Projects
+if errorlevel 1 goto failed
+
+:issigtool
+echo - ISSigTool.dpr
+mkdir Dcu\ISSigTool.dpr 2>nul
+"%DELPHIXEROOT%\bin\dcc32.exe" --no-config -NSSystem;System.Win;Winapi -Q -B -H -W %DELPHIXEDISABLEDWARNINGS% %1 -U"%DELPHIXEROOT%\lib\win32\release" -E..\Files -NUDcu\ISSigTool.dpr ISSigTool.dpr
+if errorlevel 1 goto failed
 
 
 cd ..
 cd ..
 if errorlevel 1 goto failed
 if errorlevel 1 goto failed

+ 77 - 0
issig.bat

@@ -0,0 +1,77 @@
+@echo off
+
+rem  Inno Setup
+rem  Copyright (C) 1997-2025 Jordan Russell
+rem  Portions by Martijn Laan
+rem  For conditions of distribution and use, see LICENSE.TXT.
+rem
+rem  Batch file to embed the public key in TrustFunc.AllowedPublicKeys.inc (before compilation) or to create ISCmplr.dll.issig and ISPP.dll.issig (after compilation)
+rem  Also generates a new private key if needed
+
+setlocal
+
+cd /d %~dp0
+
+if exist compilesettings.bat goto compilesettingsfound
+:compilesettingserror
+echo compilesettings.bat is missing or incomplete. It needs to contain
+echo the following line, adjusted for your system:
+echo.
+echo   set ISSIGTOOL_KEY_FILE=x:\path\MyKey.isprivatekey
+goto failed2
+
+:compilesettingsfound
+set ISSIGTOOL_KEY_FILE=
+call .\compilesettings.bat
+if "%ISSIGTOOL_KEY_FILE%"=="" goto compilesettingserror
+
+rem -------------------------------------------------------------------------
+
+cd Files
+if errorlevel 1 goto failed
+
+if not exist "%ISSIGTOOL_KEY_FILE%" (
+  echo Missing key file
+  ISSigTool.exe generate-private-key
+  if errorlevel 1 goto failed
+  if not exist "%ISSIGTOOL_KEY_FILE%" goto failed
+  echo Generating key file done - do not share with others!
+)
+
+if "%1"=="embed" goto embed
+if "%1"=="sign" goto sign
+if not "%1"=="" goto failed
+
+:embed
+set targetfile=..\Components\TrustFunc.AllowedPublicKeys.inc
+if not exist "%targetfile%" goto failed
+set publickeyfile=_temp.ispublickey
+ISSigTool.exe export-public-key "%publickeyfile%"
+if errorlevel 1 goto failed
+if not exist "%publickeyfile%" goto failed
+powershell.exe -NoProfile -Command "$filePath = '%targetfile%'; $replacementFilePath = '%publickeyfile%'; $startMarker = \"AllowedPublicKey2Text := '''\"; $endMarker = \"''';//end\"; try { $content = Get-Content -Raw -Path $filePath; $replacementText = Get-Content -Raw -Path $replacementFilePath; [string] $pattern = '(?s)' + [regex]::Escape($startMarker) + '.*?' + [regex]::Escape($endMarker); if ($content -match $pattern) { $replacement = $startMarker + \"`r`n\" + $replacementText + \"`r`n\" + $endMarker; $newContent = $content -replace $pattern, $replacement; $utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($false); [System.IO.File]::WriteAllText($filePath, $newContent, $utf8NoBomEncoding); Write-Host 'Embedded key.'; } else { Write-Host 'Markers not found.'; exit 1; } } catch { Write-Error ('Error: ' + $_.Exception.Message); exit 1; }"
+if errorlevel 1 goto failed
+del "%publickeyfile%"
+if errorlevel 1 goto failed
+cd ..
+if errorlevel 1 goto failed
+
+echo Success!
+goto exit
+
+:sign
+ISSigTool.exe sign ISCmplr.dll ISPP.dll
+if errorlevel 1 goto failed
+cd ..
+if errorlevel 1 goto failed
+
+echo Success!
+goto exit
+
+:failed
+echo *** FAILED ***
+cd ..
+:failed2
+exit /b 1
+
+:exit

+ 18 - 11
setup.iss

@@ -13,7 +13,7 @@
 [Setup]
 [Setup]
 AppName=Inno Setup
 AppName=Inno Setup
 AppId={code:GetAppId|Inno Setup 6}
 AppId={code:GetAppId|Inno Setup 6}
-AppVersion=6.4.2
+AppVersion=6.4.3-dev
 AppPublisher=jrsoftware.org
 AppPublisher=jrsoftware.org
 AppPublisherURL=https://www.innosetup.com/
 AppPublisherURL=https://www.innosetup.com/
 AppSupportURL=https://www.innosetup.com/
 AppSupportURL=https://www.innosetup.com/
@@ -117,7 +117,8 @@ Source: "license.txt"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\ISetup.chm"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\ISetup.chm"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\ISetup-dark.chm"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\ISetup-dark.chm"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\Compil32.exe"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 Source: "files\Compil32.exe"; DestDir: "{app}"; Flags: ignoreversion signonce touch
-Source: "files\isscint.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
+Source: "files\isscint.dll"; DestDir: "{app}"; Flags: ignoreversion signcheck touch
+Source: "files\isscint.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 #ifndef isccexe
 #ifndef isccexe
   #define isccexe "ISCC.exe"
   #define isccexe "ISCC.exe"
 #endif
 #endif
@@ -125,7 +126,8 @@ Source: "files\{#isccexe}"; DestName: "ISCC.exe"; DestDir: "{app}"; Flags: ignor
 #ifndef iscmplrdll
 #ifndef iscmplrdll
   #define iscmplrdll "ISCmplr.dll"
   #define iscmplrdll "ISCmplr.dll"
 #endif
 #endif
-Source: "files\{#iscmplrdll}"; DestName: "ISCmplr.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
+Source: "files\{#iscmplrdll}"; DestName: "ISCmplr.dll"; DestDir: "{app}"; Flags: ignoreversion signcheck touch
+Source: "files\ISCmplr.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\Setup.e32"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\Setup.e32"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\SetupLdr.e32"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\SetupLdr.e32"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\Default.isl"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\Default.isl"; DestDir: "{app}"; Flags: ignoreversion touch
@@ -135,16 +137,26 @@ Source: "files\WizClassicImage.bmp"; DestDir: "{app}"; Flags: ignoreversion touc
 Source: "files\WizClassicImage-IS.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\WizClassicImage-IS.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\WizClassicSmallImage.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\WizClassicSmallImage.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\WizClassicSmallImage-IS.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\WizClassicSmallImage-IS.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
-Source: "files\iszlib.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
+Source: "files\iszlib.dll"; DestDir: "{app}"; Flags: ignoreversion signcheck touch
+Source: "files\iszlib.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\isunzlib.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 Source: "files\isunzlib.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
-Source: "files\isbzip.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
+Source: "files\isbzip.dll"; DestDir: "{app}"; Flags: ignoreversion signcheck touch
+Source: "files\isbzip.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\isbunzip.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 Source: "files\isbunzip.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 #ifndef islzmadll
 #ifndef islzmadll
   #define islzmadll "islzma.dll"
   #define islzmadll "islzma.dll"
 #endif
 #endif
-Source: "files\{#islzmadll}"; DestName: "islzma.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
+Source: "files\{#islzmadll}"; DestName: "islzma.dll"; DestDir: "{app}"; Flags: ignoreversion signcheck touch
+Source: "files\islzma.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\islzma32.exe"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 Source: "files\islzma32.exe"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 Source: "files\islzma64.exe"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 Source: "files\islzma64.exe"; DestDir: "{app}"; Flags: ignoreversion signonce touch
+#ifndef isppdll
+  #define isppdll "ispp.dll"
+#endif
+Source: "files\{#isppdll}"; DestName: "ISPP.dll"; DestDir: "{app}"; Flags: ignoreversion signcheck touch
+Source: "files\ISPP.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
+Source: "files\ISPPBuiltins.iss"; DestDir: "{app}"; Flags: ignoreversion touch
+Source: "files\ISSigTool.exe"; DestDir: "{app}"; Flags: ignoreversion signonce touch
 Source: "whatsnew.htm"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "whatsnew.htm"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "Examples\64Bit.iss"; DestDir: "{app}\Examples"; Flags: ignoreversion touch
 Source: "Examples\64Bit.iss"; DestDir: "{app}\Examples"; Flags: ignoreversion touch
 Source: "Examples\64BitTwoArch.iss"; DestDir: "{app}\Examples"; Flags: ignoreversion touch
 Source: "Examples\64BitTwoArch.iss"; DestDir: "{app}\Examples"; Flags: ignoreversion touch
@@ -186,11 +198,6 @@ Source: "Examples\MyDll\C#\MyDll.sln"; DestDir: "{app}\Examples\MyDll\C#"; Flags
 Source: "Examples\MyDll\C#\packages.config"; DestDir: "{app}\Examples\MyDll\C#"; Flags: ignoreversion touch
 Source: "Examples\MyDll\C#\packages.config"; DestDir: "{app}\Examples\MyDll\C#"; Flags: ignoreversion touch
 Source: "Examples\MyDll\C#\Properties\AssemblyInfo.cs"; DestDir: "{app}\Examples\MyDll\C#\Properties"; Flags: ignoreversion touch
 Source: "Examples\MyDll\C#\Properties\AssemblyInfo.cs"; DestDir: "{app}\Examples\MyDll\C#\Properties"; Flags: ignoreversion touch
 Source: "Examples\MyDll\Delphi\MyDll.dpr"; DestDir: "{app}\Examples\MyDll\Delphi"; Flags: ignoreversion touch
 Source: "Examples\MyDll\Delphi\MyDll.dpr"; DestDir: "{app}\Examples\MyDll\Delphi"; Flags: ignoreversion touch
-#ifndef isppdll
-  #define isppdll "ispp.dll"
-#endif
-Source: "files\{#isppdll}"; DestName: "ISPP.dll"; DestDir: "{app}"; Flags: ignoreversion signonce touch
-Source: "files\ISPPBuiltins.iss"; DestDir: "{app}"; Flags: ignoreversion touch
 
 
 [INI]
 [INI]
 Filename: "{app}\isfaq.url"; Section: "InternetShortcut"; Key: "URL"; String: "https://jrsoftware.org/isfaq.php" 
 Filename: "{app}\isfaq.url"; Section: "InternetShortcut"; Key: "URL"; String: "https://jrsoftware.org/isfaq.php" 

+ 1 - 0
whatsnew.htm

@@ -32,6 +32,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
 <p><a name="6.4.3"></a><span class="ver">6.4.3-dev </span><span class="date">(?)</span></p>
 <p><a name="6.4.3"></a><span class="ver">6.4.3-dev </span><span class="date">(?)</span></p>
 <ul>
 <ul>
   <li>Compiler IDE change: The editor now restores selections on undo and redo.</li>
   <li>Compiler IDE change: The editor now restores selections on undo and redo.</li>
+  <li>Inno Setup now includes a new command-line tool, ISSigTool.exe. This tool is designed to sign files using cryptographic signatures. Compil32, ISCC, and ISCmplr use these signatures to verify a number of DLL files before loading them.<br />Note: ISSigTool.exe does not replace Microsoft's signtool.exe in any way and is in fact not related to Authenticode Code Signing at all.</li>
 </ul>
 </ul>
 
 
 <p><a name="6.4.2"></a><span class="ver">6.4.2 </span><span class="date">(2025-03-12)</span></p>
 <p><a name="6.4.2"></a><span class="ver">6.4.2 </span><span class="date">(2025-03-12)</span></p>