Przeglądaj źródła

Cleanup duplicate ISSig verification code.

Martijn Laan 3 miesięcy temu
rodzic
commit
faf859c14a

+ 65 - 0
Components/ISSigFunc.pas

@@ -19,6 +19,9 @@ type
   TISSigVerifySignatureResult = (vsrSuccess, vsrMalformed, vsrKeyNotFound,
   TISSigVerifySignatureResult = (vsrSuccess, vsrMalformed, vsrKeyNotFound,
     vsrBadSignature);
     vsrBadSignature);
   TISSigImportKeyResult = (ikrSuccess, ikrMalformed, ikrNotPrivateKey);
   TISSigImportKeyResult = (ikrSuccess, ikrMalformed, ikrNotPrivateKey);
+  TISSigVerifySignatureFileMissingErrorProc = reference to procedure(const Filename: String);
+  TISSigVerifySignatureSigFileMissingErrorProc = reference to procedure(const Filename, SigFilename: String);
+  TISSigVerifySignatureVerificationFailedErrorProc = reference to procedure(const SigFilename: String; const VerifyResult: TISSigVerifySignatureResult);
 
 
 { Preferred, hardened functions for loading/saving .issig and key file text }
 { Preferred, hardened functions for loading/saving .issig and key file text }
 function ISSigLoadTextFromFile(const AFilename: String): String;
 function ISSigLoadTextFromFile(const AFilename: String): String;
@@ -33,6 +36,17 @@ function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
   const AText: String; out AFileSize: Int64;
   const AText: String; out AFileSize: Int64;
   out AFileHash: TSHA256Digest; out AKeyUsedID: String): TISSigVerifySignatureResult; overload;
   out AFileHash: TSHA256Digest; out AKeyUsedID: String): TISSigVerifySignatureResult; overload;
 
 
+function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
+  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest; out AKeyUsedID: String;
+  const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
+  const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
+  const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean; overload;
+function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
+  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
+  const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
+  const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
+  const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean; overload;
+
 procedure ISSigExportPrivateKeyText(const AKey: TECDSAKey;
 procedure ISSigExportPrivateKeyText(const AKey: TECDSAKey;
   var APrivateKeyText: String);
   var APrivateKeyText: String);
 procedure ISSigExportPublicKeyText(const AKey: TECDSAKey;
 procedure ISSigExportPublicKeyText(const AKey: TECDSAKey;
@@ -54,6 +68,9 @@ function ISSigIsValidKeyIDForPublicXY(const AKeyID, APublicX, APublicY: String):
 
 
 function ISSigCalcStreamHash(const AStream: TStream): TSHA256Digest;
 function ISSigCalcStreamHash(const AStream: TStream): TSHA256Digest;
 
 
+var
+  ISSigExt: String = '.issig';
+
 implementation
 implementation
 
 
 uses
 uses
@@ -247,6 +264,54 @@ begin
   Result := ISSigVerifySignatureText(AAllowedKeys, AText, AFileSize, AFileHash, KeyUsedID);
   Result := ISSigVerifySignatureText(AAllowedKeys, AText, AFileSize, AFileHash, KeyUsedID);
 end;
 end;
 
 
+function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
+  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest; out AKeyUsedID: String;
+  const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
+  const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
+  const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean;
+  
+  function NewFileExists(const Name: String): Boolean;
+  { Returns True if the specified file exists.
+    This function is better than Delphi's FileExists function because it works
+    on files in directories that don't have "list" permission. There is, however,
+    one other difference: FileExists allows wildcards, but this function does
+    not. }
+  begin
+    var Attr := GetFileAttributes(PChar(Name));
+    Result := (Attr <> INVALID_FILE_ATTRIBUTES) and (Attr and faDirectory = 0);
+  end;
+
+begin
+  if Assigned(AFileMissingErrorProc) and not NewFileExists(AFilename) then begin
+    AFileMissingErrorProc(AFilename);
+    Exit(False);
+  end;
+  const SigFilename = AFilename + ISSigExt;
+  if not NewFileExists(SigFilename) then begin
+    if Assigned(ASigFileMissingErrorProc) then
+      ASigFileMissingErrorProc(AFilename, SigFilename);
+    Exit(False);
+  end;
+  const SigText = ISSigLoadTextFromFile(SigFilename);
+  const VerifyResult = ISSigVerifySignatureText(AAllowedKeys, SigText,
+    AExpectedFileSize, AExpectedFileHash, AKeyUsedID);
+  Result := VerifyResult = vsrSuccess;
+  if not Result and Assigned(AVerificationFailedErrorProc) then
+    AVerificationFailedErrorProc(SigFilename, VerifyResult);
+end;
+
+function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
+  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
+  const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
+  const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
+  const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean;
+begin
+  var KeyUsedID: String;
+  Result := ISSigVerifySignature(AFilename, AAllowedKeys, AExpectedFileSize,
+    AExpectedFileHash, KeyUsedID, AFileMissingErrorProc, ASigFileMissingErrorProc,
+    AVerificationFailedErrorProc);
+end;
+
 procedure ISSigExportPrivateKeyText(const AKey: TECDSAKey;
 procedure ISSigExportPrivateKeyText(const AKey: TECDSAKey;
   var APrivateKeyText: String);
   var APrivateKeyText: String);
 begin
 begin

+ 21 - 21
Components/TrustFunc.pas

@@ -34,6 +34,9 @@ begin
         [FileName]);
         [FileName]);
   end;
   end;
 {$IFNDEF TRUSTALL}
 {$IFNDEF TRUSTALL}
+  var ExpectedFileSize: Int64;
+  var ExpectedFileHash: TSHA256Digest;
+
   var AllowedPublicKey1Text, AllowedPublicKey2Text: String;
   var AllowedPublicKey1Text, AllowedPublicKey2Text: String;
   {$I TrustFunc.AllowedPublicKeys.inc}
   {$I TrustFunc.AllowedPublicKeys.inc}
   var Key1: TECDSAKey := nil;
   var Key1: TECDSAKey := nil;
@@ -53,31 +56,28 @@ begin
     else
     else
       AllowedKeys := [Key1];
       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;
+    ISSigVerifySignature(Filename, AllowedKeys, ExpectedFileSize, ExpectedFileHash, nil, nil,
+      procedure(const SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
+      begin
+        if VerifyResult <> vsrSuccess then
+          raise Exception.CreateFmt('Signature file "%s" is not valid', [SigFileName]);
+      end);
   finally
   finally
     Key2.Free;
     Key2.Free;
     Key1.Free;
     Key1.Free;
   end;
   end;
+  
+  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;
 {$ENDIF}
 {$ENDIF}
 end;
 end;
 
 

+ 31 - 39
Projects/ISSigTool.dpr

@@ -147,30 +147,25 @@ begin
     F.Free;
     F.Free;
   end;
   end;
 
 
-  const SigFilename = AFilename + '.issig';
-
   { ECDSA signature output is non-deterministic: signing the same hash with
   { ECDSA signature output is non-deterministic: signing the same hash with
     the same key produces a totally different signature each time. To avoid
     the same key produces a totally different signature each time. To avoid
     unnecessary alterations to the "sig-r" and "sig-s" values when a file is
     unnecessary alterations to the "sig-r" and "sig-s" values when a file is
     being re-signed but its contents haven't changed, we attempt to load and
     being re-signed but its contents haven't changed, we attempt to load and
     verify the existing .issig file. If the key, file size, and file hash are
     verify the existing .issig file. If the key, file size, and file hash are
     all up to date, then we skip creation of a new .issig file. }
     all up to date, then we skip creation of a new .issig file. }
-  if NewFileExists(SigFilename) then begin
-    const ExistingSigText = ISSigLoadTextFromFile(SigFilename);
-    var ExistingFileSizeValue: Int64;
-    var ExistingFileHashValue: TSHA256Digest;
-    if ISSigVerifySignatureText([AKey], ExistingSigText, ExistingFileSizeValue,
-       ExistingFileHashValue) = vsrSuccess then begin
-      if (FileSize = ExistingFileSizeValue) and
-         SHA256DigestsEqual(FileHash, ExistingFileHashValue) then begin
-        PrintUnlessQuiet('signature unchanged');
-        Exit;
-      end;
-    end;
+  var ExistingFileSizeValue: Int64;
+  var ExistingFileHashValue: TSHA256Digest;
+  var Verified := ISSigVerifySignature(AFilename, [AKey],
+    ExistingFileSizeValue, ExistingFileHashValue, nil, nil, nil);
+
+  if Verified and (FileSize = ExistingFileSizeValue) and
+     SHA256DigestsEqual(FileHash, ExistingFileHashValue) then begin
+    PrintUnlessQuiet('signature unchanged');
+    Exit;
   end;
   end;
 
 
   const SigText = ISSigCreateSignatureText(AKey, FileSize, FileHash);
   const SigText = ISSigCreateSignatureText(AKey, FileSize, FileHash);
-  ISSigSaveTextToFile(SigFilename, SigText);
+  ISSigSaveTextToFile(AFilename + ISSigExt, SigText);
   PrintUnlessQuiet('signature written');
   PrintUnlessQuiet('signature written');
 end;
 end;
 
 
@@ -192,33 +187,30 @@ begin
   Result := False;
   Result := False;
   PrintFmtUnlessQuiet('%s: ', [AFilename], False);
   PrintFmtUnlessQuiet('%s: ', [AFilename], False);
 
 
-  if not NewFileExists(AFilename) then begin
-    PrintUnlessQuiet('MISSINGFILE (File does not exist)');
-    Exit;
-  end;
-
-  const SigFilename = AFilename + '.issig';
-  if not NewFileExists(SigFilename) then begin
-    PrintUnlessQuiet('MISSINGSIGFILE (Signature file does not exist)');
-    Exit;
-  end;
-
-  const SigText = ISSigLoadTextFromFile(SigFilename);
   var ExpectedFileSize: Int64;
   var ExpectedFileSize: Int64;
   var ExpectedFileHash: TSHA256Digest;
   var ExpectedFileHash: TSHA256Digest;
-  const VerifyResult = ISSigVerifySignatureText([AKey], SigText,
-    ExpectedFileSize, ExpectedFileHash);
-  if VerifyResult <> vsrSuccess then begin
-    case VerifyResult of
-      vsrMalformed, vsrBadSignature:
-        PrintUnlessQuiet('BADSIGFILE (Signature file is not valid)');
-      vsrKeyNotFound:
-        PrintUnlessQuiet('UNKNOWNKEY (Incorrect key ID)');
-    else
-      RaiseFatalError('Unknown verify result');
-    end;
+  if not ISSigVerifySignature(AFilename, [AKey], ExpectedFileSize, ExpectedFileHash,
+    procedure(const Filename: String)
+    begin
+      PrintUnlessQuiet('MISSINGFILE (File does not exist)');
+    end,
+    procedure(const Filename, SigFilename: String)
+    begin
+      PrintUnlessQuiet('MISSINGSIGFILE (Signature file does not exist)');
+    end,
+    procedure(const SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
+    begin
+      case VerifyResult of
+        vsrMalformed, vsrBadSignature:
+          PrintUnlessQuiet('BADSIGFILE (Signature file is not valid)');
+        vsrKeyNotFound:
+          PrintUnlessQuiet('UNKNOWNKEY (Incorrect key ID)');
+      else
+        RaiseFatalError('Unknown verify result');
+      end;
+    end
+  ) then
     Exit;
     Exit;
-  end;
 
 
   const F = TFile.Create(AFilename, fdOpenExisting, faRead, fsRead);
   const F = TFile.Create(AFilename, fdOpenExisting, faRead, fsRead);
   try
   try

+ 2 - 1
Projects/Src/Compiler.Messages.pas

@@ -86,7 +86,8 @@ const
   SCompilerSourceFileDoesntExist = 'Source file "%s" does not exist';
   SCompilerSourceFileDoesntExist = 'Source file "%s" does not exist';
   SCompilerSourceFileNotSigned = 'Source file "%s" is not signed';
   SCompilerSourceFileNotSigned = 'Source file "%s" is not signed';
   SCompilerSourceFileISSigMissingFile = 'Signature file does not exist for source file "%s"';
   SCompilerSourceFileISSigMissingFile = 'Signature file does not exist for source file "%s"';
-  SCompilerSourceFileISSigInvalidSignature = 'Signature is not valid for source file "%s": %s';
+  SCompilerSourceFileISSigInvalidSignature1 = 'Signature file "%s" is not valid: %s';
+  SCompilerSourceFileISSigInvalidSignature2 = 'Signature for source file "%s" is not valid: %s';
   SCompilerSourceFileISSigMalformedOrBadSignature = 'malformed or bad signature';
   SCompilerSourceFileISSigMalformedOrBadSignature = 'malformed or bad signature';
   SCompilerSourceFileISSigKeyNotFound = 'no matching key found';
   SCompilerSourceFileISSigKeyNotFound = 'no matching key found';
   SCompilerSourceFileISSigUnknownVerifyResult = 'unknown verify result';
   SCompilerSourceFileISSigUnknownVerifyResult = 'unknown verify result';

+ 23 - 20
Projects/Src/Compiler.SetupCompiler.pas

@@ -7044,27 +7044,30 @@ var
             { See Setup.Install's CopySourceFileToDestFile for similar code }
             { See Setup.Install's CopySourceFileToDestFile for similar code }
             if Length(ISSigAvailableKeys) = 0 then { shouldn't fail: flag stripped already }
             if Length(ISSigAvailableKeys) = 0 then { shouldn't fail: flag stripped already }
               AbortCompileFmt(SCompilerCompressInternalError, ['Length(ISSigAvailableKeys) = 0']);
               AbortCompileFmt(SCompilerCompressInternalError, ['Length(ISSigAvailableKeys) = 0']);
-            const SigFilename = FileLocationEntryFilenames[I] + '.issig';
-            if not NewFileExists(SigFilename) then
-              AbortCompileFmt(SCompilerSourceFileISSigMissingFile, [FileLocationEntryFilenames[I]]);
-            const SigText = ISSigLoadTextFromFile(SigFilename);
             var ExpectedFileSize: Int64;
             var ExpectedFileSize: Int64;
-            const VerifyResult = ISSigVerifySignatureText(
-              GetISSigAllowedKeys(ISSigAvailableKeys, FLExtraInfo.ISSigAllowedKeys), SigText,
-              ExpectedFileSize, ExpectedFileHash, FLExtraInfo.ISSigKeyUsedID);
-            if VerifyResult <> vsrSuccess then begin
-              var VerifyResultAsString: String;
-              case VerifyResult of
-                vsrMalformed, vsrBadSignature: VerifyResultAsString := SCompilerSourceFileISSigMalformedOrBadSignature;
-                vsrKeyNotFound: VerifyResultAsString := SCompilerSourceFileISSigKeyNotFound;
-              else
-                VerifyResultAsString := SCompilerSourceFileISSigUnknownVerifyResult;
-              end;
-              AbortCompileFmt(SCompilerSourceFileISSigInvalidSignature,
-                [FileLocationEntryFilenames[I], VerifyResultAsString]);
-            end;
+            ISSigVerifySignature(FileLocationEntryFilenames[I],
+              GetISSigAllowedKeys(ISSigAvailableKeys, FLExtraInfo.ISSigAllowedKeys),
+              ExpectedFileSize, ExpectedFileHash, FLExtraInfo.ISSigKeyUsedID,
+              nil,
+              procedure(const Filename, SigFilename: String)
+              begin
+                AbortCompileFmt(SCompilerSourceFileISSigMissingFile, [Filename]);
+              end,
+              procedure(const SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
+              begin
+                var VerifyResultAsString: String;
+                case VerifyResult of
+                  vsrMalformed, vsrBadSignature: VerifyResultAsString := SCompilerSourceFileISSigMalformedOrBadSignature;
+                  vsrKeyNotFound: VerifyResultAsString := SCompilerSourceFileISSigKeyNotFound;
+                else
+                  VerifyResultAsString := SCompilerSourceFileISSigUnknownVerifyResult;
+                end;
+                AbortCompileFmt(SCompilerSourceFileISSigInvalidSignature1,
+                  [SigFilename, VerifyResultAsString]);
+              end
+            );
             if Int64(SourceFile.Size) <> ExpectedFileSize then
             if Int64(SourceFile.Size) <> ExpectedFileSize then
-              AbortCompileFmt(SCompilerSourceFileISSigInvalidSignature,
+              AbortCompileFmt(SCompilerSourceFileISSigInvalidSignature2,
                 [FileLocationEntryFilenames[I], SCompilerSourceFileISSigFileSizeIncorrect]);
                 [FileLocationEntryFilenames[I], SCompilerSourceFileISSigFileSizeIncorrect]);
             { ExpectedFileHash checked below after compression }
             { ExpectedFileHash checked below after compression }
           end;
           end;
@@ -7117,7 +7120,7 @@ var
 
 
           if floISSigVerify in FLExtraInfo.Flags then begin
           if floISSigVerify in FLExtraInfo.Flags then begin
             if not SHA256DigestsEqual(FL.SHA256Sum, ExpectedFileHash) then
             if not SHA256DigestsEqual(FL.SHA256Sum, ExpectedFileHash) then
-              AbortCompileFmt(SCompilerSourceFileISSigInvalidSignature,
+              AbortCompileFmt(SCompilerSourceFileISSigInvalidSignature2,
                 [FileLocationEntryFilenames[I], SCompilerSourceFileISSigFileHashIncorrect]);
                 [FileLocationEntryFilenames[I], SCompilerSourceFileISSigFileHashIncorrect]);
             AddStatus(SCompilerStatusFilesISSigVerified);
             AddStatus(SCompilerStatusFilesISSigVerified);
           end;
           end;

+ 22 - 19
Projects/Src/Setup.Install.pas

@@ -258,7 +258,7 @@ end;
 
 
 procedure CopySourceFileToDestFile(const SourceF, DestF: TFile;
 procedure CopySourceFileToDestFile(const SourceF, DestF: TFile;
   const ISSigVerify: Boolean; [Ref] const ISSigAvailableKeys: TArrayOfECDSAKey;
   const ISSigVerify: Boolean; [Ref] const ISSigAvailableKeys: TArrayOfECDSAKey;
-  const ISSigAllowedKeys: AnsiString; const ISSigFilename: String; AMaxProgress: Integer64);
+  const ISSigAllowedKeys: AnsiString; const ISSigSourceFilename: String; AMaxProgress: Integer64);
 { Copies all bytes from SourceF to DestF, incrementing process meter as it
 { Copies all bytes from SourceF to DestF, incrementing process meter as it
   goes. Assumes file pointers of both are 0. }
   goes. Assumes file pointers of both are 0. }
 const
 const
@@ -277,24 +277,27 @@ var
 begin
 begin
   var ExpectedFileHash: TSHA256Digest;
   var ExpectedFileHash: TSHA256Digest;
   if ISSigVerify then begin
   if ISSigVerify then begin
-    { See Compiler.SetupCompiler's TSetupCompiler.Compile for similar code }
-    if not NewFileExists(ISSigFilename) then
-      ISSigVerifyError(ISSigMissingFile, FmtSetupMessage1(msgSourceDoesntExist, ISSigFilename));
-    const SigText = ISSigLoadTextFromFile(ISSigFilename);
     var ExpectedFileSize: Int64;
     var ExpectedFileSize: Int64;
-    const VerifyResult = ISSigVerifySignatureText(
-      GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys), SigText,
-      ExpectedFileSize, ExpectedFileHash);
-    if VerifyResult <> vsrSuccess then begin
-      var VerifyResultAsString: String;
-      case VerifyResult of
-        vsrMalformed, vsrBadSignature: VerifyResultAsString := ISSigMalformedOrBadSignature;
-        vsrKeyNotFound: VerifyResultAsString := ISSigKeyNotFound;
-      else
-        VerifyResultAsString := ISSigUnknownVerifyResult;
-      end;
-      ISSigVerifyError(VerifyResultAsString, SetupMessages[msgSourceIsCorrupted]);
-    end;
+    ISSigVerifySignature(ISSigSourceFilename,
+      GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
+      ExpectedFileSize, ExpectedFileHash,
+      nil,
+      procedure(const Filename, SigFilename: String)
+      begin
+        ISSigVerifyError(ISSigMissingFile, FmtSetupMessage1(msgSourceDoesntExist, SigFilename));
+      end,
+      procedure(const SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
+      begin
+        var VerifyResultAsString: String;
+        case VerifyResult of
+          vsrMalformed, vsrBadSignature: VerifyResultAsString := ISSigMalformedOrBadSignature;
+          vsrKeyNotFound: VerifyResultAsString := ISSigKeyNotFound;
+        else
+          VerifyResultAsString := ISSigUnknownVerifyResult;
+        end;
+        ISSigVerifyError(VerifyResultAsString, SetupMessages[msgSourceIsCorrupted]);
+      end
+    );
     if Int64(SourceF.Size) <> ExpectedFileSize then
     if Int64(SourceF.Size) <> ExpectedFileSize then
       ISSigVerifyError(ISSigFileSizeIncorrect, SetupMessages[msgSourceIsCorrupted]);
       ISSigVerifyError(ISSigFileSizeIncorrect, SetupMessages[msgSourceIsCorrupted]);
     { ExpectedFileHash checked below after copy }
     { ExpectedFileHash checked below after copy }
@@ -1498,7 +1501,7 @@ var
                     [], '', '', CurFileLocation^.OriginalSize)
                     [], '', '', CurFileLocation^.OriginalSize)
                 else
                 else
                   CopySourceFileToDestFile(SourceF, DestF, foISSigVerify in CurFile^.Options,
                   CopySourceFileToDestFile(SourceF, DestF, foISSigVerify in CurFile^.Options,
-                    ISSigAvailableKeys, CurFile^.ISSigAllowedKeys, SourceFile + '.issig', AExternalSize);
+                    ISSigAvailableKeys, CurFile^.ISSigAllowedKeys, SourceFile, AExternalSize);
               finally
               finally
                 SourceF.Free;
                 SourceF.Free;
               end;
               end;

+ 39 - 40
Projects/Src/Setup.ScriptFunc.pas

@@ -1818,20 +1818,12 @@ var
       const Filename = Stack.GetString(PStart-2);
       const Filename = Stack.GetString(PStart-2);
       const KeepOpen = Stack.GetBool(PStart-3);
       const KeepOpen = Stack.GetBool(PStart-3);
 
 
-      { Following is same as ISSigTool's VerifySingleFile but uses TFileStream
-        instead of TFile because we want to return one and scripts don't known TFile }
-
-      if not NewFileExists(Filename) then
-        raise Exception.Create('File does not exist');
-
-      const SigFilename = Filename + '.issig';
-      if not NewFileExists(SigFilename) then
-        raise Exception.Create('Signature file does not exist');
+      var ExpectedFileSize: Int64;
+      var ExpectedFileHash: TSHA256Digest;
 
 
       var AllowedKeys: TArrayOfECDSAKey;
       var AllowedKeys: TArrayOfECDSAKey;
       const NAllowedKeys = Length(AllowedKeysTexts);
       const NAllowedKeys = Length(AllowedKeysTexts);
       SetLength(AllowedKeys, NAllowedKeys);
       SetLength(AllowedKeys, NAllowedKeys);
-      var F: TFileStream;
       try
       try
         { Import keys }
         { Import keys }
         for var I := 0 to NAllowedKeys-1 do begin
         for var I := 0 to NAllowedKeys-1 do begin
@@ -1844,40 +1836,47 @@ var
         end;
         end;
 
 
         { Verify signature }
         { Verify signature }
-        const SigText = ISSigLoadTextFromFile(SigFilename);
-        var ExpectedFileSize: Int64;
-        var ExpectedFileHash: TSHA256Digest;
-        const VerifyResult = ISSigVerifySignatureText(AllowedKeys, SigText,
-          ExpectedFileSize, ExpectedFileHash);
-        if VerifyResult <> vsrSuccess then begin
-          case VerifyResult of
-            vsrMalformed, vsrBadSignature:
-              raise Exception.Create('Signature file is not valid');
-            vsrKeyNotFound:
-              raise Exception.Create('Incorrect key ID');
-          else
-            InternalError('Unknown verify result');
-          end;
-        end;
-
-        { Verify file, keeping open afterwards if requested }
-        F := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
-        try
-          if Int64(F.Size) <> ExpectedFileSize then
-            raise Exception.Create('File size is incorrect');
-          const ActualFileHash = ISSigCalcStreamHash(F);
-          if not SHA256DigestsEqual(ActualFileHash, ExpectedFileHash) then
-            raise Exception.Create('File hash is incorrect');
-        except
-          FreeAndNil(F);
-          raise;
-        end;
-        if not KeepOpen then
-          FreeAndNil(F);
+        ISSigVerifySignature(Filename, AllowedKeys, ExpectedFileSize, ExpectedFileHash,
+          procedure(const Filename: String)
+          begin
+            raise Exception.Create('File does not exist');
+          end,
+          procedure(const Filename, SigFilename: String)
+          begin
+            raise Exception.Create('Signature file does not exist');
+          end,
+          procedure(const SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
+          begin
+            case VerifyResult of
+              vsrMalformed, vsrBadSignature:
+                raise Exception.Create('Signature file is not valid');
+              vsrKeyNotFound:
+                raise Exception.Create('Incorrect key ID');
+            else
+              InternalError('Unknown verify result');
+            end;
+          end
+        );
       finally
       finally
         for var I := 0 to NAllowedKeys-1 do
         for var I := 0 to NAllowedKeys-1 do
           AllowedKeys[I].Free;
           AllowedKeys[I].Free;
       end;
       end;
+
+      { Verify file, keeping open afterwards if requested }
+      var F := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
+      try
+        if Int64(F.Size) <> ExpectedFileSize then
+          raise Exception.Create('File size is incorrect');
+        const ActualFileHash = ISSigCalcStreamHash(F);
+        if not SHA256DigestsEqual(ActualFileHash, ExpectedFileHash) then
+          raise Exception.Create('File hash is incorrect');
+      except
+        FreeAndNil(F);
+        raise;
+      end;
+      if not KeepOpen then
+        FreeAndNil(F);
+
       Stack.SetClass(PStart, F);
       Stack.SetClass(PStart, F);
     end);
     end);
   end;
   end;