Ver Fonte

Add SHA256 verification in all places where it can do ISSig verification, using new [Files] parameter Hash.

Didn't test anything yet. Want to do a small refactor first.
Martijn Laan há 3 meses atrás
pai
commit
41e4b363cd

+ 1 - 0
Components/SHA256.pas

@@ -15,6 +15,7 @@ type
   TSHA256Context = record
   TSHA256Context = record
     hash: THashSHA2;
     hash: THashSHA2;
   end;
   end;
+  PSHA256Digest = ^TSHA256Digest;
   TSHA256Digest = array[0..31] of Byte;
   TSHA256Digest = array[0..31] of Byte;
 
 
 procedure SHA256Init(var ctx: TSHA256Context);
 procedure SHA256Init(var ctx: TSHA256Context);

+ 0 - 2
Files/Default.isl

@@ -219,8 +219,6 @@ StopDownload=Are you sure you want to stop the download?
 ErrorDownloadAborted=Download aborted
 ErrorDownloadAborted=Download aborted
 ErrorDownloadFailed=Download failed: %1 %2
 ErrorDownloadFailed=Download failed: %1 %2
 ErrorDownloadSizeFailed=Getting size failed: %1 %2
 ErrorDownloadSizeFailed=Getting size failed: %1 %2
-ErrorFileHash1=File hash failed: %1
-ErrorFileHash2=Invalid file hash: expected %1, found %2
 ErrorProgress=Invalid progress: %1 of %2
 ErrorProgress=Invalid progress: %1 of %2
 ErrorFileSize=Invalid file size: expected %1, found %2
 ErrorFileSize=Invalid file size: expected %1, found %2
 
 

+ 6 - 4
Projects/Src/Compiler.Messages.pas

@@ -53,7 +53,7 @@ const
   SCompilerStatusFilesCompressingVersion = '   Compressing: %s   (%u.%u.%u.%u)';
   SCompilerStatusFilesCompressingVersion = '   Compressing: %s   (%u.%u.%u.%u)';
   SCompilerStatusFilesStoring = '   Storing: %s';
   SCompilerStatusFilesStoring = '   Storing: %s';
   SCompilerStatusFilesStoringVersion = '   Storing: %s   (%u.%u.%u.%u)';
   SCompilerStatusFilesStoringVersion = '   Storing: %s   (%u.%u.%u.%u)';
-  SCompilerStatusFilesISSigVerified = '      ISSig verification successful.';
+  SCompilerStatusFilesVerified = '      File verification successful.';
   SCompilerStatusCompressingSetupExe = '   Compressing Setup program executable';
   SCompilerStatusCompressingSetupExe = '   Compressing Setup program executable';
   SCompilerStatusUpdatingVersionInfo = '   Updating version info (%s)';
   SCompilerStatusUpdatingVersionInfo = '   Updating version info (%s)';
   SCompilerStatusUpdatingManifest = '   Updating manifest (%s)';
   SCompilerStatusUpdatingManifest = '   Updating manifest (%s)';
@@ -291,8 +291,10 @@ const
   SCompilerFilesWildcardNotMatched = 'No files found matching "%s"';
   SCompilerFilesWildcardNotMatched = 'No files found matching "%s"';
   SCompilerFilesDestNameCantBeSpecified = 'Parameter "DestName" cannot be specified if ' +
   SCompilerFilesDestNameCantBeSpecified = 'Parameter "DestName" cannot be specified if ' +
     'the "Source" parameter contains wildcards or flag "extractarchive" is used';
     'the "Source" parameter contains wildcards or flag "extractarchive" is used';
-  SCompilerFilesCantHaveNonExternalExternalSize = 'Parameter "ExternalSize" may only be used when ' +
-    'the "external" flag is used';
+  SCompilerFilesParamRequiresFlag = 'Parameter "%s" may only be used when ' +
+    'the "%s" flag is used';
+  SCompilerFilesParamFlagConflict = 'Parameter "%s" may not be used when ' +
+    'the "%s" flag is used';
   SCompilerFilesExcludeTooLong = 'Parameter "Excludes" contains a pattern that is too long';
   SCompilerFilesExcludeTooLong = 'Parameter "Excludes" contains a pattern that is too long';
   SCompilerFilesUnsafeFile = 'Unsafe file detected: %s.' + SNewLine2 +
   SCompilerFilesUnsafeFile = 'Unsafe file detected: %s.' + SNewLine2 +
     'See the "Unsafe Files" topic in the help file for more information';
     'See the "Unsafe Files" topic in the help file for more information';
@@ -312,7 +314,7 @@ const
     'documentation in the help file for details.';
     'documentation in the help file for details.';
   SCompilerFilesISSigVerifyMissingISSigKeys = 'Flag "issigverify" may not be used when the "ISSigKeys" section doesn''t exist or is empty.';
   SCompilerFilesISSigVerifyMissingISSigKeys = 'Flag "issigverify" may not be used when the "ISSigKeys" section doesn''t exist or is empty.';
   SCompilerFilesISSigAllowedKeysMissingISSigVerify = 'Flag "issigverify" must be used when the "ISSigAllowedKeys" parameter is used.';
   SCompilerFilesISSigAllowedKeysMissingISSigVerify = 'Flag "issigverify" must be used when the "ISSigAllowedKeys" parameter is used.';
-  SCompilerFilesISSigAllowedKeysConflict = 'Parameter "ISSigAllowedKeys" cannot allow different keys on the same source file';
+  SCompilerFilesValueConflict = 'Parameter "%s" cannot allow different values on the same source file';
   SCompilerFilesUnkownISSigKeyNameOrGroupName = 'Parameter "%s" includes an unknown name or group name.';
   SCompilerFilesUnkownISSigKeyNameOrGroupName = 'Parameter "%s" includes an unknown name or group name.';
 
 
   { [Icons] }
   { [Icons] }

+ 41 - 17
Projects/Src/Compiler.SetupCompiler.pas

@@ -256,7 +256,7 @@ type
     procedure WriteCompiledCodeDebugInfo(const CompiledCodeDebugInfo: AnsiString);
     procedure WriteCompiledCodeDebugInfo(const CompiledCodeDebugInfo: AnsiString);
     function CreateMemoryStreamsFromFiles(const ADirectiveName, AFiles: String): TObjectList<TCustomMemoryStream>;
     function CreateMemoryStreamsFromFiles(const ADirectiveName, AFiles: String): TObjectList<TCustomMemoryStream>;
     function CreateMemoryStreamsFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TObjectList<TCustomMemoryStream>;
     function CreateMemoryStreamsFromResources(const AResourceNamesPrefixes, AResourceNamesPostfixes: array of String): TObjectList<TCustomMemoryStream>;
-    procedure ISSigVerifyError(const AError: TISSigVerifySignatureError;
+    procedure VerificationError(const AError: TVerificationError;
       const AFilename: String; const ASigFilename: String = '');
       const AFilename: String; const ASigFilename: String = '');
   public
   public
     AppData: Longint;
     AppData: Longint;
@@ -324,8 +324,9 @@ type
   PFileLocationEntryExtraInfo = ^TFileLocationEntryExtraInfo;
   PFileLocationEntryExtraInfo = ^TFileLocationEntryExtraInfo;
   TFileLocationEntryExtraInfo = record
   TFileLocationEntryExtraInfo = record
     Flags: set of (floVersionInfoNotValid, floIsUninstExe, floApplyTouchDateTime,
     Flags: set of (floVersionInfoNotValid, floIsUninstExe, floApplyTouchDateTime,
-      floSolidBreak, floISSigVerify);
+      floSolidBreak, floHashVerify, floISSigVerify);
     Sign: TFileLocationSign;
     Sign: TFileLocationSign;
+    Hash: TSHA256Digest;
     ISSigAllowedKeys: AnsiString;
     ISSigAllowedKeys: AnsiString;
     ISSigKeyUsedID: String;
     ISSigKeyUsedID: String;
   end;
   end;
@@ -4668,7 +4669,7 @@ procedure TSetupCompiler.EnumFilesProc(const Line: PChar; const Ext: Integer);
 type
 type
   TParam = (paFlags, paSource, paDestDir, paDestName, paCopyMode, paAttribs,
   TParam = (paFlags, paSource, paDestDir, paDestName, paCopyMode, paAttribs,
     paPermissions, paFontInstall, paExcludes, paExternalSize, paExtractArchivePassword,
     paPermissions, paFontInstall, paExcludes, paExternalSize, paExtractArchivePassword,
-    paStrongAssemblyName, paISSigAllowedKeys, paDownloadISSigSource, paDownloadUserName,
+    paStrongAssemblyName, paHash, paISSigAllowedKeys, paDownloadISSigSource, paDownloadUserName,
     paDownloadPassword, paComponents, paTasks, paLanguages, paCheck, paBeforeInstall,
     paDownloadPassword, paComponents, paTasks, paLanguages, paCheck, paBeforeInstall,
     paAfterInstall, paMinVersion, paOnlyBelowVersion);
     paAfterInstall, paMinVersion, paOnlyBelowVersion);
 const
 const
@@ -4683,6 +4684,7 @@ const
   ParamFilesExternalSize = 'ExternalSize';
   ParamFilesExternalSize = 'ExternalSize';
   ParamFilesExtractArchivePassword = 'ExtractArchivePassword';
   ParamFilesExtractArchivePassword = 'ExtractArchivePassword';
   ParamFilesStrongAssemblyName = 'StrongAssemblyName';
   ParamFilesStrongAssemblyName = 'StrongAssemblyName';
+  ParamFilesHash = 'Hash';
   ParamFilesISSigAllowedKeys = 'ISSigAllowedKeys';
   ParamFilesISSigAllowedKeys = 'ISSigAllowedKeys';
   ParamFilesDownloadISSigSource = 'DownloadISSigSource';
   ParamFilesDownloadISSigSource = 'DownloadISSigSource';
   ParamFilesDownloadUserName = 'DownloadUserName';
   ParamFilesDownloadUserName = 'DownloadUserName';
@@ -4700,6 +4702,7 @@ const
     (Name: ParamFilesExternalSize; Flags: []),
     (Name: ParamFilesExternalSize; Flags: []),
     (Name: ParamFilesExtractArchivePassword; Flags: []),
     (Name: ParamFilesExtractArchivePassword; Flags: []),
     (Name: ParamFilesStrongAssemblyName; Flags: [piNoEmpty]),
     (Name: ParamFilesStrongAssemblyName; Flags: [piNoEmpty]),
+    (Name: ParamFilesHash; Flags: [piNoEmpty]),
     (Name: ParamFilesISSigAllowedKeys; Flags: [piNoEmpty]),
     (Name: ParamFilesISSigAllowedKeys; Flags: [piNoEmpty]),
     (Name: ParamFilesDownloadISSigSource; Flags: []),
     (Name: ParamFilesDownloadISSigSource; Flags: []),
     (Name: ParamFilesDownloadUserName; Flags: [piNoEmpty]),
     (Name: ParamFilesDownloadUserName; Flags: [piNoEmpty]),
@@ -4982,11 +4985,18 @@ type
               to compressing the first one }
               to compressing the first one }
             SolidBreak := False;
             SolidBreak := False;
           end;
           end;
+          NewFileLocationEntryExtraInfo^.Hash := NewFileEntry^.Hash;
           NewFileLocationEntryExtraInfo^.ISSigAllowedKeys := NewFileEntry^.ISSigAllowedKeys;
           NewFileLocationEntryExtraInfo^.ISSigAllowedKeys := NewFileEntry^.ISSigAllowedKeys;
-        end else if NewFileLocationEntryExtraInfo^.ISSigAllowedKeys <> NewFileEntry^.ISSigAllowedKeys then
-          AbortCompile(SCompilerFilesISSigAllowedKeysConflict);
+        end else begin
+          if not CompareMem(@NewFileLocationEntryExtraInfo^.Hash[0], @NewFileEntry^.Hash[0], SizeOf(TSHA256Digest)) then
+            AbortCompileFmt(SCompilerFilesValueConflict, ['Hash']);
+          if NewFileLocationEntryExtraInfo^.ISSigAllowedKeys <> NewFileEntry^.ISSigAllowedKeys then
+            AbortCompileFmt(SCompilerFilesValueConflict, ['ISSigAllowedKeys']);
+        end;
         if Touch then
         if Touch then
           Include(NewFileLocationEntryExtraInfo^.Flags, floApplyTouchDateTime);
           Include(NewFileLocationEntryExtraInfo^.Flags, floApplyTouchDateTime);
+        if foHashVerify in NewFileEntry^.Options then
+          Include(NewFileLocationEntryExtraInfo^.Flags, floHashVerify);
         if foISSigVerify in NewFileEntry^.Options then
         if foISSigVerify in NewFileEntry^.Options then
           Include(NewFileLocationEntryExtraInfo^.Flags, floISSigVerify);
           Include(NewFileLocationEntryExtraInfo^.Flags, floISSigVerify);
         { Note: "nocompression"/"noencryption" on one file makes all merged
         { Note: "nocompression"/"noencryption" on one file makes all merged
@@ -5345,7 +5355,7 @@ begin
                { ExternalSize }
                { ExternalSize }
                if Values[paExternalSize].Found then begin
                if Values[paExternalSize].Found then begin
                  if not ExternalFile then
                  if not ExternalFile then
-                   AbortCompile(SCompilerFilesCantHaveNonExternalExternalSize);
+                   AbortCompileFmt(SCompilerFilesParamRequiresFlag, ['ExternalSize', 'external']);
                  if not StrToInteger64(Values[paExternalSize].Data, ExternalSize) then
                  if not StrToInteger64(Values[paExternalSize].Data, ExternalSize) then
                    AbortCompileParamError(SCompilerParamInvalid2, ParamFilesExternalSize);
                    AbortCompileParamError(SCompilerParamInvalid2, ParamFilesExternalSize);
                  Include(Options, foExternalSizePreset);
                  Include(Options, foExternalSizePreset);
@@ -5363,6 +5373,12 @@ begin
                { ExtractArchivePassword }
                { ExtractArchivePassword }
                ExtractArchivePassword := Values[paExtractArchivePassword].Data;
                ExtractArchivePassword := Values[paExtractArchivePassword].Data;
 
 
+               { Hash }
+               if Values[paHash].Found then begin
+                 Hash := SHA256DigestFromString(Values[paHash].Data);
+                 Include(Options, foHashVerify);
+               end;
+
                { ISSigAllowedKeys }
                { ISSigAllowedKeys }
                var S := Values[paISSigAllowedKeys].Data;
                var S := Values[paISSigAllowedKeys].Data;
                while True do begin
                while True do begin
@@ -5483,7 +5499,13 @@ begin
         if (ISSigAllowedKeys <> '') and not (foISSigVerify in Options) then
         if (ISSigAllowedKeys <> '') and not (foISSigVerify in Options) then
           AbortCompile(SCompilerFilesISSigAllowedKeysMissingISSigVerify);
           AbortCompile(SCompilerFilesISSigAllowedKeysMissingISSigVerify);
 
 
+        if (foHashVerify in Options) and (foISSigVerify in Options) then
+          AbortCompileFmt(SCompilerFilesParamRequiresFlag, ['Hash', 'issigverify']);
+
         if Sign in [fsYes, fsOnce] then begin
         if Sign in [fsYes, fsOnce] then begin
+          if foHashVerify in Options then
+            AbortCompileFmt(SCompilerParamErrorBadCombo2,
+              [ParamCommonFlags, SignFlags[Sign], 'hashverify']);
           if foISSigVerify in Options then
           if foISSigVerify in Options then
             AbortCompileFmt(SCompilerParamErrorBadCombo2,
             AbortCompileFmt(SCompilerParamErrorBadCombo2,
               [ParamCommonFlags, SignFlags[Sign], 'issigverify']);
               [ParamCommonFlags, SignFlags[Sign], 'issigverify']);
@@ -6643,10 +6665,10 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TSetupCompiler.ISSigVerifyError(const AError: TISSigVerifySignatureError;
+procedure TSetupCompiler.VerificationError(const AError: TVerificationError;
   const AFilename, ASigFilename: String);
   const AFilename, ASigFilename: String);
 const
 const
-  Messages: array[TISSigVerifySignatureError] of String =
+  Messages: array[TVerificationError] of String =
     (SCompilerVerificationSignatureDoesntExist, SCompilerVerificationSignatureMalformed,
     (SCompilerVerificationSignatureDoesntExist, SCompilerVerificationSignatureMalformed,
      SCompilerVerificationKeyNotFound, SCompilerVerificationSignatureBad,
      SCompilerVerificationKeyNotFound, SCompilerVerificationSignatureBad,
      SCompilerVerificationFileSizeIncorrect, SCompilerVerificationFileHashIncorrect);
      SCompilerVerificationFileSizeIncorrect, SCompilerVerificationFileHashIncorrect);
@@ -7149,7 +7171,9 @@ var
           fdOpenExisting, faRead, fsRead);
           fdOpenExisting, faRead, fsRead);
         try
         try
           var ExpectedFileHash: TSHA256Digest;
           var ExpectedFileHash: TSHA256Digest;
-          if floISSigVerify in FLExtraInfo.Flags then begin
+          if floHashVerify in FLExtraInfo.Flags then
+            ExpectedFileHash := FLExtraInfo.Hash
+          else if floISSigVerify in FLExtraInfo.Flags then begin
             { 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']);
@@ -7160,15 +7184,15 @@ var
               nil,
               nil,
               procedure(const Filename, SigFilename: String)
               procedure(const Filename, SigFilename: String)
               begin
               begin
-                ISSigVerifyError(vseSignatureMissing, Filename, SigFilename);
+                VerificationError(veSignatureMissing, Filename, SigFilename);
               end,
               end,
               procedure(const Filename, SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
               procedure(const Filename, SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
               begin
               begin
                 var VerifyResultAsString: String;
                 var VerifyResultAsString: String;
                 case VerifyResult of
                 case VerifyResult of
-                  vsrMalformed: ISSigVerifyError(vseSignatureMalformed, Filename, SigFilename);
-                  vsrBad: ISSigVerifyError(vseSignatureBad, Filename, SigFilename);
-                  vsrKeyNotFound: ISSigVerifyError(vseKeyNotFound, Filename, SigFilename);
+                  vsrMalformed: VerificationError(veSignatureMalformed, Filename, SigFilename);
+                  vsrBad: VerificationError(veSignatureBad, Filename, SigFilename);
+                  vsrKeyNotFound: VerificationError(veKeyNotFound, Filename, SigFilename);
                 else
                 else
                   AbortCompileFmt(SCompilerCompressInternalError, ['Unknown ISSigVerifySignature result'])
                   AbortCompileFmt(SCompilerCompressInternalError, ['Unknown ISSigVerifySignature result'])
                 end;
                 end;
@@ -7176,7 +7200,7 @@ var
             ) then
             ) then
               AbortCompileFmt(SCompilerCompressInternalError, ['Unexpected ISSigVerifySignature result']);
               AbortCompileFmt(SCompilerCompressInternalError, ['Unexpected ISSigVerifySignature result']);
             if Int64(SourceFile.Size) <> ExpectedFileSize then
             if Int64(SourceFile.Size) <> ExpectedFileSize then
-              ISSigVerifyError(vseFileSizeIncorrect, FileLocationEntryFilenames[I]);
+              VerificationError(veFileSizeIncorrect, FileLocationEntryFilenames[I]);
             { ExpectedFileHash checked below after compression }
             { ExpectedFileHash checked below after compression }
           end;
           end;
 
 
@@ -7226,10 +7250,10 @@ var
           CH.CompressFile(SourceFile, FL.OriginalSize,
           CH.CompressFile(SourceFile, FL.OriginalSize,
             floCallInstructionOptimized in FL.Flags, FL.SHA256Sum);
             floCallInstructionOptimized in FL.Flags, FL.SHA256Sum);
 
 
-          if floISSigVerify in FLExtraInfo.Flags then begin
+          if (floHashVerify in FLExtraInfo.Flags) or (floISSigVerify in FLExtraInfo.Flags) then begin
             if not SHA256DigestsEqual(FL.SHA256Sum, ExpectedFileHash) then
             if not SHA256DigestsEqual(FL.SHA256Sum, ExpectedFileHash) then
-              ISSigVerifyError(vseFileHashIncorrect, FileLocationEntryFilenames[I]);
-            AddStatus(SCompilerStatusFilesISSigVerified);
+              VerificationError(veFileHashIncorrect, FileLocationEntryFilenames[I]);
+            AddStatus(SCompilerStatusFilesVerified);
           end;
           end;
         finally
         finally
           SourceFile.Free;
           SourceFile.Free;

+ 74 - 65
Projects/Src/Setup.Install.pas

@@ -14,7 +14,7 @@ interface
 uses
 uses
   Classes, SHA256, Shared.FileClass, Shared.SetupTypes, Shared.Int64Em;
   Classes, SHA256, Shared.FileClass, Shared.SetupTypes, Shared.Int64Em;
 
 
-procedure ISSigVerifyError(const AError: TISSigVerifySignatureError;
+procedure VerificationError(const AError: TVerificationError;
   const ASigFilename: String = '');
   const ASigFilename: String = '');
 
 
 procedure DoISSigVerify(const SourceF: TFile; const SourceFS: TFileStream;
 procedure DoISSigVerify(const SourceF: TFile; const SourceFS: TFileStream;
@@ -31,13 +31,13 @@ type
 procedure ExtractTemporaryFile(const BaseName: String);
 procedure ExtractTemporaryFile(const BaseName: String);
 function ExtractTemporaryFiles(const Pattern: String): Integer;
 function ExtractTemporaryFiles(const Pattern: String): Integer;
 function DownloadFile(const Url, CustomUserName, CustomPassword: String;
 function DownloadFile(const Url, CustomUserName, CustomPassword: String;
-  const DestF: TFile; const ISSigVerify: Boolean; const ISSigAllowedKeys: AnsiString;
-  const ISSigSourceFilename: String;
+  const DestF: TFile; const HashVerify, ISSigVerify: Boolean; const ExpectedHash: PSHA256Digest;
+  const ISSigAllowedKeys: AnsiString; const ISSigSourceFilename: String;
   const OnSimpleDownloadProgress: TOnSimpleDownloadProgress;
   const OnSimpleDownloadProgress: TOnSimpleDownloadProgress;
   const OnSimpleDownloadProgressParam: Integer64): Int64;
   const OnSimpleDownloadProgressParam: Integer64): Int64;
-function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String;
-  const ISSigVerify: Boolean; const ISSigAllowedKeys: AnsiString;
-  const OnDownloadProgress: TOnDownloadProgress): Int64;
+function DownloadTemporaryFile(const Url, BaseName: String;
+  const HashVerify, ISSigVerify: Boolean; const ExpectedHash: PSHA256Digest;
+  const ISSigAllowedKeys: AnsiString; const OnDownloadProgress: TOnDownloadProgress): Int64;
 function DownloadTemporaryFileSize(const Url: String): Int64;
 function DownloadTemporaryFileSize(const Url: String): Int64;
 function DownloadTemporaryFileDate(const Url: String): String;
 function DownloadTemporaryFileDate(const Url: String): String;
 procedure SetDownloadTemporaryFileCredentials(const User, Pass: String);
 procedure SetDownloadTemporaryFileCredentials(const User, Pass: String);
@@ -287,18 +287,18 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure ISSigVerifyError(const AError: TISSigVerifySignatureError;
+procedure VerificationError(const AError: TVerificationError;
   const ASigFilename: String);
   const ASigFilename: String);
 const
 const
-  LogMessages: array[TISSigVerifySignatureError] of String =
+  LogMessages: array[TVerificationError] of String =
     ('Signature file does not exist', 'Signature is malformed', 'No matching key found',
     ('Signature file does not exist', 'Signature is malformed', 'No matching key found',
      'Signature is bad', 'File size is incorrect', 'File hash is incorrect');
      'Signature is bad', 'File size is incorrect', 'File hash is incorrect');
-  SetupMessageIDs: array[TISSigVerifySignatureError] of TSetupMessageID =
+  SetupMessageIDs: array[TVerificationError] of TSetupMessageID =
     (msgVerificationSignatureDoesntExist, msgVerificationSignatureInvalid, msgVerificationKeyNotFound,
     (msgVerificationSignatureDoesntExist, msgVerificationSignatureInvalid, msgVerificationKeyNotFound,
      msgVerificationSignatureInvalid, msgVerificationFileSizeIncorrect, msgVerificationFileHashIncorrect);
      msgVerificationSignatureInvalid, msgVerificationFileSizeIncorrect, msgVerificationFileHashIncorrect);
 begin
 begin
   { Also see Compiler.SetupCompiler for a similar function }
   { Also see Compiler.SetupCompiler for a similar function }
-  Log('ISSig verification error: ' + AddPeriod(LogMessages[AError]));
+  Log('Verification error: ' + AddPeriod(LogMessages[AError]));
   raise Exception.Create(FmtSetupMessage1(msgSourceVerificationFailed,
   raise Exception.Create(FmtSetupMessage1(msgSourceVerificationFailed,
     FmtSetupMessage1(SetupMessageIDs[AError], PathExtractName(ASigFilename)))); { Not all messages actually have a %1 parameter but that's OK }
     FmtSetupMessage1(SetupMessageIDs[AError], PathExtractName(ASigFilename)))); { Not all messages actually have a %1 parameter but that's OK }
 end;
 end;
@@ -319,14 +319,14 @@ begin
     nil,
     nil,
     procedure(const Filename, SigFilename: String)
     procedure(const Filename, SigFilename: String)
     begin
     begin
-      ISSigVerifyError(vseSignatureMissing, SigFilename);
+      VerificationError(veSignatureMissing, SigFilename);
     end,
     end,
     procedure(const Filename, SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
     procedure(const Filename, SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
     begin
     begin
       case VerifyResult of
       case VerifyResult of
-        vsrMalformed:  ISSigVerifyError(vseSignatureMalformed, SigFilename);
-        vsrBad: ISSigVerifyError(vseSignatureBad, SigFilename);
-        vsrKeyNotFound: ISSigVerifyError(vseKeyNotFound, SigFilename);
+        vsrMalformed:  VerificationError(veSignatureMalformed, SigFilename);
+        vsrBad: VerificationError(veSignatureBad, SigFilename);
+        vsrKeyNotFound: VerificationError(veKeyNotFound, SigFilename);
       else
       else
         InternalError('Unknown ISSigVerifySignature result');
         InternalError('Unknown ISSigVerifySignature result');
       end;
       end;
@@ -339,15 +339,16 @@ begin
   else
   else
     FileSize := SourceFS.Size;
     FileSize := SourceFS.Size;
   if FileSize <> ExpectedFileSize then
   if FileSize <> ExpectedFileSize then
-    ISSigVerifyError(vseFileSizeIncorrect);
+    VerificationError(veFileSizeIncorrect);
   { Caller must check ExpectedFileHash }
   { Caller must check ExpectedFileHash }
 end;
 end;
 
 
 const
 const
-  ISSigVerificationSuccessfulLogMessage = 'ISSig verification successful.';
+  VerificationSuccessfulLogMessage = 'Verification successful.';
 
 
 procedure CopySourceFileToDestFile(const SourceF, DestF: TFile;
 procedure CopySourceFileToDestFile(const SourceF, DestF: TFile;
-  const ISSigVerify: Boolean; const ISSigAllowedKeys: AnsiString; const ISSigSourceFilename: String;
+  const HashVerify, ISSigVerify: Boolean; const HashExpectedHash: PSHA256Digest;
+  const ISSigAllowedKeys: AnsiString; const ISSigSourceFilename: String;
   const AExpectedSize: Integer64);
   const AExpectedSize: 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. }
@@ -358,8 +359,11 @@ var
   Context: TSHA256Context;
   Context: TSHA256Context;
 begin
 begin
   var ExpectedFileHash: TSHA256Digest;
   var ExpectedFileHash: TSHA256Digest;
-  if ISSigVerify then begin
-    DoISSigVerify(SourceF, nil, ISSigSourceFilename, ISSigAllowedKeys, ExpectedFileHash);
+  if HashVerify or ISSigVerify then begin
+    if HashVerify then
+      ExpectedFileHash := HashExpectedHash^
+    else
+      DoISSigVerify(SourceF, nil, ISSigSourceFilename, ISSigAllowedKeys, ExpectedFileHash);
     { ExpectedFileHash checked below after copy }
     { ExpectedFileHash checked below after copy }
     SHA256Init(Context);
     SHA256Init(Context);
   end;
   end;
@@ -391,10 +395,10 @@ begin
     ExternalProgressProc64(To64(BufSize), MaxProgress);
     ExternalProgressProc64(To64(BufSize), MaxProgress);
   end;
   end;
 
 
-  if ISSigVerify then begin
+  if HashVerify or ISSigVerify then begin
     if not SHA256DigestsEqual(SHA256Final(Context), ExpectedFileHash) then
     if not SHA256DigestsEqual(SHA256Final(Context), ExpectedFileHash) then
-      ISSigVerifyError(vseFileHashIncorrect);
-    Log(ISSigVerificationSuccessfulLogMessage);
+      VerificationError(veFileHashIncorrect);
+    Log(VerificationSuccessfulLogMessage);
   end;
   end;
 
 
   { In case the source file was shorter than we thought it was, bump the
   { In case the source file was shorter than we thought it was, bump the
@@ -1196,7 +1200,6 @@ var
     CurFileVersionInfoValid: Boolean;
     CurFileVersionInfoValid: Boolean;
     CurFileVersionInfo, ExistingVersionInfo: TFileVersionNumbers;
     CurFileVersionInfo, ExistingVersionInfo: TFileVersionNumbers;
     CurFileDateValid, ExistingFileDateValid: Boolean;
     CurFileDateValid, ExistingFileDateValid: Boolean;
-    CurFileHash, ExistingFileHash: TSHA256Digest;
     IsProtectedFile, AllowTimeStampComparison: Boolean;
     IsProtectedFile, AllowTimeStampComparison: Boolean;
     DeleteFlags: Longint;
     DeleteFlags: Longint;
     CurFileDate, ExistingFileDate: TFileTime;
     CurFileDate, ExistingFileDate: TFileTime;
@@ -1386,7 +1389,9 @@ var
                    not(foOverwriteSameVersion in CurFile^.Options) then begin
                    not(foOverwriteSameVersion in CurFile^.Options) then begin
                   if foReplaceSameVersionIfContentsDiffer in CurFile^.Options then begin
                   if foReplaceSameVersionIfContentsDiffer in CurFile^.Options then begin
                     { Get the two files' SHA-256 hashes and compare them }
                     { Get the two files' SHA-256 hashes and compare them }
+                    var ExistingFileHash: TSHA256Digest;
                     if TryToGetSHA256OfFile(DisableFsRedir, DestFile, ExistingFileHash) then begin
                     if TryToGetSHA256OfFile(DisableFsRedir, DestFile, ExistingFileHash) then begin
+                      var CurFileHash: TSHA256Digest;
                       if Assigned(CurFileLocation) then
                       if Assigned(CurFileLocation) then
                         CurFileHash := CurFileLocation^.SHA256Sum
                         CurFileHash := CurFileLocation^.SHA256Sum
                       else begin
                       else begin
@@ -1592,11 +1597,11 @@ var
                   { Download the .issig file }
                   { Download the .issig file }
                   const ISSigUrl = GetISSigUrl(SourceFile, ExpandConst(CurFile^.DownloadISSigSource));
                   const ISSigUrl = GetISSigUrl(SourceFile, ExpandConst(CurFile^.DownloadISSigSource));
                   DownloadFile(ISSigUrl, DownloadUserName, DownloadPassword,
                   DownloadFile(ISSigUrl, DownloadUserName, DownloadPassword,
-                    ISSigDestF, False, '', '', JustProcessEventsProc64, To64(0));
+                    ISSigDestF, False, False, nil, '', '', JustProcessEventsProc64, To64(0));
                   FreeAndNil(ISSigDestF);
                   FreeAndNil(ISSigDestF);
                   { Download and verify the actual file }
                   { Download and verify the actual file }
                   DownloadFile(SourceFile, DownloadUserName, DownloadPassword,
                   DownloadFile(SourceFile, DownloadUserName, DownloadPassword,
-                    DestF, True, CurFile^.ISSigAllowedKeys, TempFile, ExternalProgressProc64, MaxProgress);
+                    DestF, False, True, nil, CurFile^.ISSigAllowedKeys, TempFile, ExternalProgressProc64, MaxProgress);
                 finally
                 finally
                   ISSigDestF.Free;
                   ISSigDestF.Free;
                   { Delete the .issig file }
                   { Delete the .issig file }
@@ -1604,7 +1609,8 @@ var
                 end;
                 end;
               end else
               end else
                 DownloadFile(SourceFile, DownloadUserName, DownloadPassword,
                 DownloadFile(SourceFile, DownloadUserName, DownloadPassword,
-                  DestF, False, '', '', ExternalProgressProc64, MaxProgress);
+                  DestF, foHashVerify in CurFile^.Options, False, @CurFile^.Hash[0],
+                    '', '', ExternalProgressProc64, MaxProgress);
             end
             end
             else begin
             else begin
               { Copy a duplicated non-external file, or an external file }
               { Copy a duplicated non-external file, or an external file }
@@ -1612,11 +1618,12 @@ var
               try
               try
                 LastOperation := SetupMessages[msgErrorCopying];
                 LastOperation := SetupMessages[msgErrorCopying];
                 if Assigned(CurFileLocation) then
                 if Assigned(CurFileLocation) then
-                  CopySourceFileToDestFile(SourceF, DestF, False,
+                  CopySourceFileToDestFile(SourceF, DestF, False, False, nil,
                     '', '', CurFileLocation^.OriginalSize)
                     '', '', CurFileLocation^.OriginalSize)
                 else
                 else
-                  CopySourceFileToDestFile(SourceF, DestF, foISSigVerify in CurFile^.Options,
-                    CurFile^.ISSigAllowedKeys, SourceFile, AExternalSize);
+                  CopySourceFileToDestFile(SourceF, DestF, foHashVerify in CurFile^.Options,
+                    foISSigVerify in CurFile^.Options, @CurFile^.Hash[0], CurFile^.ISSigAllowedKeys,
+                    SourceFile, AExternalSize);
               finally
               finally
                 SourceF.Free;
                 SourceF.Free;
               end;
               end;
@@ -2030,17 +2037,21 @@ var
         var Failed: String;
         var Failed: String;
         repeat
         repeat
           try
           try
-            if foISSigVerify in CurFile^.Options then begin
-              if ISSigVerifySourceF = nil then
-                ISSigVerifySourceF := TFileRedir.Create(DisableFsRedir, ArchiveFilename, fdOpenExisting, faRead, fsRead);
+            if  (foHashVerify in CurFile^.Options) or (foISSigVerify in CurFile^.Options) then begin
               var ExpectedFileHash: TSHA256Digest;
               var ExpectedFileHash: TSHA256Digest;
-              DoISSigVerify(ISSigVerifySourceF, nil, ArchiveFilename, CurFile^.ISSigAllowedKeys,
+              if foHashVerify in CurFile^.Options then
+                ExpectedFileHash := CurFile^.Hash
+              else begin
+                if ISSigVerifySourceF = nil then
+                  ISSigVerifySourceF := TFileRedir.Create(DisableFsRedir, ArchiveFilename, fdOpenExisting, faRead, fsRead);
+                DoISSigVerify(ISSigVerifySourceF, nil, ArchiveFilename, CurFile^.ISSigAllowedKeys,
                 ExpectedFileHash);
                 ExpectedFileHash);
+              end;
               { Can't get the SHA-256 while extracting so need to get and check it now }
               { Can't get the SHA-256 while extracting so need to get and check it now }
               const ActualFileHash = GetSHA256OfFile(ISSigVerifySourceF);
               const ActualFileHash = GetSHA256OfFile(ISSigVerifySourceF);
               if not SHA256DigestsEqual(ActualFileHash, ExpectedFileHash) then
               if not SHA256DigestsEqual(ActualFileHash, ExpectedFileHash) then
-                ISSigVerifyError(vseFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
-              Log(ISSigVerificationSuccessfulLogMessage);
+                VerificationError(veFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
+              Log(VerificationSuccessfulLogMessage);
               { Keeping ISSigVerifySourceF open until extraction has completed }
               { Keeping ISSigVerifySourceF open until extraction has completed }
             end;
             end;
 
 
@@ -3799,8 +3810,8 @@ begin
 end;
 end;
 
 
 function DownloadFile(const Url, CustomUserName, CustomPassword: String;
 function DownloadFile(const Url, CustomUserName, CustomPassword: String;
-  const DestF: TFile; const ISSigVerify: Boolean; const ISSigAllowedKeys: AnsiString;
-  const ISSigSourceFilename: String;
+  const DestF: TFile; const HashVerify, ISSigVerify: Boolean; const ExpectedHash: PSHA256Digest;
+  const ISSigAllowedKeys: AnsiString; const ISSigSourceFilename: String;
   const OnSimpleDownloadProgress: TOnSimpleDownloadProgress;
   const OnSimpleDownloadProgress: TOnSimpleDownloadProgress;
   const OnSimpleDownloadProgressParam: Integer64): Int64;
   const OnSimpleDownloadProgressParam: Integer64): Int64;
 var
 var
@@ -3856,13 +3867,16 @@ begin
       FreeAndNil(HandleStream);
       FreeAndNil(HandleStream);
 
 
       { Check .issig if specified, otherwise check everything else we can check }
       { Check .issig if specified, otherwise check everything else we can check }
-      if ISSigVerify then begin
+      if HashVerify or ISSigVerify then begin
         var ExpectedFileHash: TSHA256Digest;
         var ExpectedFileHash: TSHA256Digest;
-        DoISSigVerify(DestF, nil, ISSigSourceFilename, ISSigAllowedKeys, ExpectedFileHash);
+        if HashVerify then
+          ExpectedFileHash := ExpectedHash^
+        else
+          DoISSigVerify(DestF, nil, ISSigSourceFilename, ISSigAllowedKeys, ExpectedFileHash);
         const FileHash = GetSHA256OfFile(DestF);
         const FileHash = GetSHA256OfFile(DestF);
         if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
         if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
-          ISSigVerifyError(vseFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
-        Log(ISSigVerificationSuccessfulLogMessage);
+          VerificationError(veFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
+        Log(VerificationSuccessfulLogMessage);
       end else begin
       end else begin
         if HTTPDataReceiver.ProgressMax > 0 then begin
         if HTTPDataReceiver.ProgressMax > 0 then begin
           if HTTPDataReceiver.Progress <> HTTPDataReceiver.ProgressMax then
           if HTTPDataReceiver.Progress <> HTTPDataReceiver.ProgressMax then
@@ -3879,9 +3893,9 @@ begin
   end;
   end;
 end;
 end;
 
 
-function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String;
-  const ISSigVerify: Boolean; const ISSigAllowedKeys: AnsiString;
-  const OnDownloadProgress: TOnDownloadProgress): Int64;
+function DownloadTemporaryFile(const Url, BaseName: String;
+  const HashVerify, ISSigVerify: Boolean; const ExpectedHash: PSHA256Digest;
+  const ISSigAllowedKeys: AnsiString; const OnDownloadProgress: TOnDownloadProgress): Int64;
 var
 var
   DestFile, TempFile: String;
   DestFile, TempFile: String;
   TempF: TFile;
   TempF: TFile;
@@ -3890,7 +3904,6 @@ var
   HTTPDataReceiver: THTTPDataReceiver;
   HTTPDataReceiver: THTTPDataReceiver;
   HTTPClient: THTTPClient;
   HTTPClient: THTTPClient;
   HTTPResponse: IHTTPResponse;
   HTTPResponse: IHTTPResponse;
-  SHA256OfFile: String;
   RetriesLeft: Integer;
   RetriesLeft: Integer;
   LastError: DWORD;
   LastError: DWORD;
   User, Pass, CleanUrl: String;
   User, Pass, CleanUrl: String;
@@ -3909,7 +3922,13 @@ begin
 
 
   { Prepare directory }
   { Prepare directory }
   if NewFileExists(DestFile) then begin
   if NewFileExists(DestFile) then begin
-    if ISSigVerify then begin
+    if HashVerify then begin
+      if SHA256DigestsEqual(GetSHA256OfFile(False, DestFile), ExpectedHash^) then begin
+        Log('  File already downloaded.');
+        Result := 0;
+        Exit;
+      end;
+    end else if ISSigVerify then begin
       var ExistingFileSize: Int64;
       var ExistingFileSize: Int64;
       var ExistingFileHash: TSHA256Digest;
       var ExistingFileHash: TSHA256Digest;
       if ISSigVerifySignature(DestFile, GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
       if ISSigVerifySignature(DestFile, GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
@@ -3926,11 +3945,6 @@ begin
           DestF.Free;
           DestF.Free;
         end;
         end;
       end;
       end;
-    end else if (RequiredSHA256OfFile <> '') and
-                SameText(RequiredSHA256OfFile, SHA256DigestToString(GetSHA256OfFile(False, DestFile))) then begin
-      Log('  File already downloaded.');
-      Result := 0;
-      Exit;
     end;
     end;
 
 
     SetFileAttributes(PChar(DestFile), GetFileAttributes(PChar(DestFile)) and not FILE_ATTRIBUTE_READONLY);
     SetFileAttributes(PChar(DestFile), GetFileAttributes(PChar(DestFile)) and not FILE_ATTRIBUTE_READONLY);
@@ -3991,26 +4005,21 @@ begin
       Result := HandleStream.Size;
       Result := HandleStream.Size;
       FreeAndNil(HandleStream);
       FreeAndNil(HandleStream);
 
 
-      { Check .issig or hash if specified, otherwise check everything else we can check }
-      if ISSigVerify then begin
+      { Check hash or .issig if specified, otherwise check everything else we can check }
+      if HashVerify or ISSigVerify then begin
         var ExpectedFileHash: TSHA256Digest;
         var ExpectedFileHash: TSHA256Digest;
-        DoISSigVerify(TempF, nil, DestFile, ISSigAllowedKeys, ExpectedFileHash);
+        if HashVerify then
+          ExpectedFileHash := ExpectedHash^
+        else
+          DoISSigVerify(TempF, nil, DestFile, ISSigAllowedKeys, ExpectedFileHash);
         FreeAndNil(TempF);
         FreeAndNil(TempF);
         const FileHash = GetSHA256OfFile(False, TempFile);
         const FileHash = GetSHA256OfFile(False, TempFile);
         if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
         if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
-          ISSigVerifyError(vseFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
-        Log(ISSigVerificationSuccessfulLogMessage);
+          VerificationError(veFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
+        Log(VerificationSuccessfulLogMessage);
       end else begin
       end else begin
         FreeAndNil(TempF);
         FreeAndNil(TempF);
-        if RequiredSHA256OfFile <> '' then begin
-          try
-            SHA256OfFile := SHA256DigestToString(GetSHA256OfFile(False, TempFile));
-          except on E: Exception do
-            raise Exception.Create(FmtSetupMessage(msgErrorFileHash1, [E.Message]));
-          end;
-          if not SameText(RequiredSHA256OfFile, SHA256OfFile) then
-            raise Exception.Create(FmtSetupMessage(msgErrorFileHash2, [RequiredSHA256OfFile, SHA256OfFile]));
-        end else if HTTPDataReceiver.ProgressMax > 0 then begin
+        if HTTPDataReceiver.ProgressMax > 0 then begin
           if HTTPDataReceiver.Progress <> HTTPDataReceiver.ProgressMax then
           if HTTPDataReceiver.Progress <> HTTPDataReceiver.ProgressMax then
             raise Exception.Create(FmtSetupMessage(msgErrorProgress, [IntToStr(HTTPDataReceiver.Progress), IntToStr(HTTPDataReceiver.ProgressMax)]))
             raise Exception.Create(FmtSetupMessage(msgErrorProgress, [IntToStr(HTTPDataReceiver.Progress), IntToStr(HTTPDataReceiver.ProgressMax)]))
           else if HTTPDataReceiver.ProgressMax <> Result then
           else if HTTPDataReceiver.ProgressMax <> Result then

+ 11 - 6
Projects/Src/Setup.ScriptDlg.pas

@@ -13,7 +13,7 @@ interface
 
 
 uses
 uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, Contnrs, Generics.Collections,
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, Contnrs, Generics.Collections,
-  Setup.WizardForm, Setup.Install, Compression.SevenZipDecoder,
+  SHA256, Setup.WizardForm, Setup.Install, Compression.SevenZipDecoder,
   NewCheckListBox, NewStaticText, NewProgressBar, PasswordEdit, RichEditViewer,
   NewCheckListBox, NewStaticText, NewProgressBar, PasswordEdit, RichEditViewer,
   BidiCtrls, TaskbarProgressFunc;
   BidiCtrls, TaskbarProgressFunc;
 
 
@@ -173,8 +173,9 @@ type
   end;
   end;
 
 
   TDownloadFile = class
   TDownloadFile = class
-    Url, BaseName, RequiredSHA256OfFile, UserName, Password: String;
-    ISSigVerify: Boolean;
+    Url, BaseName, UserName, Password: String;
+    HashVerify, ISSigVerify: Boolean;
+    Hash: TSHA256Digest;
     ISSigAllowedKeys: AnsiString;
     ISSigAllowedKeys: AnsiString;
   end;
   end;
   TDownloadFiles = TObjectList<TDownloadFile>;
   TDownloadFiles = TObjectList<TDownloadFile>;
@@ -1063,9 +1064,13 @@ begin
   var F := TDownloadFile.Create;
   var F := TDownloadFile.Create;
   F.Url := Url;
   F.Url := Url;
   F.BaseName := BaseName;
   F.BaseName := BaseName;
-  F.RequiredSHA256OfFile := RequiredSHA256OfFile;
   F.UserName := UserName;
   F.UserName := UserName;
   F.Password := Password;
   F.Password := Password;
+  F.HashVerify := RequiredSHA256OfFile <> '';
+  if F.HashVerify then
+    F.Hash := SHA256DigestFromString(RequiredSHA256OfFile)
+  else
+    ZeroMemory(@F.Hash[0], SizeOf(F.Hash)); { not really necessary }
   F.ISSigVerify := ISSigVerify;
   F.ISSigVerify := ISSigVerify;
   F.ISSigAllowedKeys := ISSigAllowedKeys;
   F.ISSigAllowedKeys := ISSigAllowedKeys;
   Result := FFiles.Add(F);
   Result := FFiles.Add(F);
@@ -1132,8 +1137,8 @@ begin
   for var F in FFiles do begin
   for var F in FFiles do begin
     { Don't need to set DownloadTemporaryFileOrExtractArchiveProcessMessages before downloading since we already process messages ourselves }
     { Don't need to set DownloadTemporaryFileOrExtractArchiveProcessMessages before downloading since we already process messages ourselves }
     SetDownloadTemporaryFileCredentials(F.UserName, F.Password);
     SetDownloadTemporaryFileCredentials(F.UserName, F.Password);
-    Result := Result + DownloadTemporaryFile(F.Url, F.BaseName, F.RequiredSHA256OfFile,
-      F.ISSigVerify, F.ISSigAllowedKeys, InternalOnDownloadProgress);
+    Result := Result + DownloadTemporaryFile(F.Url, F.BaseName, F.HashVerify, F.ISSigVerify,
+      @F.Hash[0], F.ISSigAllowedKeys, InternalOnDownloadProgress);
   end;
   end;
   SetDownloadTemporaryFileCredentials('', '');
   SetDownloadTemporaryFileCredentials('', '');
 end;
 end;

+ 10 - 3
Projects/Src/Setup.ScriptFunc.pas

@@ -822,10 +822,17 @@ var
         OnDownloadProgress := TOnDownloadProgress(Stack.GetProc(PStart-4, Caller));
         OnDownloadProgress := TOnDownloadProgress(Stack.GetProc(PStart-4, Caller));
       end;
       end;
 
 
+      const HashVerify = RequiredSHA256OfFile <> '';
+      var Hash: TSHA256Digest;
+      if HashVerify then
+        Hash := SHA256DigestFromString(RequiredSHA256OfFile)
+      else
+        ZeroMemory(@Hash[0], SizeOf(Hash)); { not really necessary }
+
       { Also see Setup.ScriptDlg TDownloadWizardPage.AddExWithISSigVerify }
       { Also see Setup.ScriptDlg TDownloadWizardPage.AddExWithISSigVerify }
       if ISSigVerify then
       if ISSigVerify then
-        DownloadTemporaryFile(GetISSigUrl(Url, ISSigUrl), BaseName + ISSigExt, '', False, '', OnDownloadProgress);
-      Stack.SetInt64(PStart, DownloadTemporaryFile(Url, BaseName, RequiredSHA256OfFile, ISSigVerify, ISSigAllowedKeys, OnDownloadProgress));
+        DownloadTemporaryFile(GetISSigUrl(Url, ISSigUrl), BaseName + ISSigExt, False, False, nil, '', OnDownloadProgress);
+      Stack.SetInt64(PStart, DownloadTemporaryFile(Url, BaseName, HashVerify, ISSigVerify, @Hash[0], ISSigAllowedKeys, OnDownloadProgress));
     end);
     end);
     RegisterScriptFunc('DownloadTemporaryFileSize', sfNoUninstall, procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     RegisterScriptFunc('DownloadTemporaryFileSize', sfNoUninstall, procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
     begin
@@ -1864,7 +1871,7 @@ var
          { Couldn't get the SHA-256 while downloading so need to get and check it now }
          { Couldn't get the SHA-256 while downloading so need to get and check it now }
         const ActualFileHash = ISSigCalcStreamHash(F);
         const ActualFileHash = ISSigCalcStreamHash(F);
         if not SHA256DigestsEqual(ActualFileHash, ExpectedFileHash) then
         if not SHA256DigestsEqual(ActualFileHash, ExpectedFileHash) then
-          ISSigVerifyError(vseFileHashIncorrect);
+          VerificationError(veFileHashIncorrect);
       except
       except
         FreeAndNil(F);
         FreeAndNil(F);
         raise;
         raise;

+ 0 - 2
Projects/Src/Shared.SetupMessageIDs.pas

@@ -93,8 +93,6 @@ type
     msgErrorExtracting,
     msgErrorExtracting,
     msgErrorExtractionAborted,
     msgErrorExtractionAborted,
     msgErrorExtractionFailed,
     msgErrorExtractionFailed,
-    msgErrorFileHash1,
-    msgErrorFileHash2,
     msgErrorFileSize,
     msgErrorFileSize,
     msgErrorFunctionFailed,
     msgErrorFunctionFailed,
     msgErrorFunctionFailedNoCode,
     msgErrorFunctionFailedNoCode,

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

@@ -39,8 +39,8 @@ type
 
 
   TArrayOfECDSAKey = array of TECDSAKey;
   TArrayOfECDSAKey = array of TECDSAKey;
 
 
-  TISSigVerifySignatureError = (vseSignatureMissing, vseSignatureMalformed, vseKeyNotFound,
-    vseSignatureBad, vseFileSizeIncorrect, vseFileHashIncorrect);
+  TVerificationError = (veSignatureMissing, veSignatureMalformed, veKeyNotFound,
+    veSignatureBad, veFileSizeIncorrect, veFileHashIncorrect);
 
 
 const
 const
   crHand = 1;
   crHand = 1;

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

@@ -236,6 +236,7 @@ type
     Tasks, Languages, Check, AfterInstall, BeforeInstall, Excludes,
     Tasks, Languages, Check, AfterInstall, BeforeInstall, Excludes,
     DownloadISSigSource, DownloadUserName, DownloadPassword, ExtractArchivePassword: String;
     DownloadISSigSource, DownloadUserName, DownloadPassword, ExtractArchivePassword: String;
     ISSigAllowedKeys: AnsiString;
     ISSigAllowedKeys: AnsiString;
+    Hash: TSHA256Digest;
     MinVersion, OnlyBelowVersion: TSetupVersionData;
     MinVersion, OnlyBelowVersion: TSetupVersionData;
     LocationEntry: Integer;
     LocationEntry: Integer;
     Attribs: Integer;
     Attribs: Integer;
@@ -251,7 +252,7 @@ type
       foRecurseSubDirsExternal, foReplaceSameVersionIfContentsDiffer,
       foRecurseSubDirsExternal, foReplaceSameVersionIfContentsDiffer,
       foDontVerifyChecksum, foUninsNoSharedFilePrompt, foCreateAllSubDirs,
       foDontVerifyChecksum, foUninsNoSharedFilePrompt, foCreateAllSubDirs,
       fo32Bit, fo64Bit, foExternalSizePreset, foSetNTFSCompression,
       fo32Bit, fo64Bit, foExternalSizePreset, foSetNTFSCompression,
-      foUnsetNTFSCompression, foGacInstall, foISSigVerify, foDownload,
+      foUnsetNTFSCompression, foGacInstall, foHashVerify, foISSigVerify, foDownload,
       foExtractArchive);
       foExtractArchive);
     FileType: (ftUserFile, ftUninstExe);
     FileType: (ftUserFile, ftUninstExe);
   end;
   end;