Browse Source

Make [Code]'s ISSigVerify use Setup.Install's DoISSigVerify (which is new on this branch) to remove duplicate code. Also add DoISSigVerify support to Setup.Install's DownloadTemporaryFile, not yet used.

Martijn Laan 3 months ago
parent
commit
a801fc579b

+ 58 - 25
Projects/Src/Setup.Install.pas

@@ -11,16 +11,31 @@ unit Setup.Install;
 
 
 interface
 interface
 
 
+uses
+  Classes, SHA256, Shared.FileClass;
+
+type
+  TISSigVerifySignatureError = (vseMissingFile, vseMalformedOrBadSignature, vseKeyNotFound,
+    vseUnknownVerifyResult, vseFileSizeIncorrect, vseFileHashIncorrect);
+
+procedure ISSigVerifyError(const AError: TISSigVerifySignatureError;
+  const ACustomExceptionMessage: String = '');
+
+procedure DoISSigVerify(const SourceF: TFile; const SourceFS: TFileStream;
+  const SourceFilename: String; const ISSigAllowedKeys: AnsiString;
+  out ExpectedFileHash: TSHA256Digest);
+
 procedure PerformInstall(var Succeeded: Boolean; const ChangesEnvironment,
 procedure PerformInstall(var Succeeded: Boolean; const ChangesEnvironment,
   ChangesAssociations: Boolean);
   ChangesAssociations: Boolean);
 
 
-
 type
 type
   TOnDownloadProgress = function(const Url, BaseName: string; const Progress, ProgressMax: Int64): Boolean of object;
   TOnDownloadProgress = function(const Url, BaseName: string; const Progress, ProgressMax: Int64): Boolean of object;
 
 
 procedure ExtractTemporaryFile(const BaseName: String);
 procedure ExtractTemporaryFile(const BaseName: String);
 function ExtractTemporaryFiles(const Pattern: String): Integer;
 function ExtractTemporaryFiles(const Pattern: String): Integer;
-function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String; const OnDownloadProgress: TOnDownloadProgress): Int64;
+function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String;
+  const ISSigVerify: Boolean; 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 SetDownloadCredentials(const User, Pass: String);
 procedure SetDownloadCredentials(const User, Pass: String);
@@ -28,10 +43,10 @@ procedure SetDownloadCredentials(const User, Pass: String);
 implementation
 implementation
 
 
 uses
 uses
-  Windows, SysUtils, Messages, Classes, Forms, ShlObj, Shared.Struct, Setup.UninstallLog, Shared.SetupTypes,
+  Windows, SysUtils, Messages, Forms, ShlObj, Shared.Struct, Setup.UninstallLog, Shared.SetupTypes,
   SetupLdrAndSetup.InstFunc, Setup.InstFunc, Setup.InstFunc.Ole, Setup.SecurityFunc, SetupLdrAndSetup.Messages,
   SetupLdrAndSetup.InstFunc, Setup.InstFunc, Setup.InstFunc.Ole, Setup.SecurityFunc, SetupLdrAndSetup.Messages,
-  Setup.MainFunc, Setup.LoggingFunc, Setup.FileExtractor, Shared.FileClass,
-  Compression.Base, SHA256, PathFunc, ISSigFunc, Shared.CommonFunc.Vcl, Compression.SevenZipDLLDecoder,
+  Setup.MainFunc, Setup.LoggingFunc, Setup.FileExtractor,
+  Compression.Base, PathFunc, ISSigFunc, Shared.CommonFunc.Vcl, Compression.SevenZipDLLDecoder,
   Shared.CommonFunc, SetupLdrAndSetup.RedirFunc, Shared.Int64Em, Shared.SetupMessageIDs,
   Shared.CommonFunc, SetupLdrAndSetup.RedirFunc, Shared.Int64Em, Shared.SetupMessageIDs,
   Setup.WizardForm, Shared.DebugStruct, Setup.DebugClient, Shared.VerInfoFunc, Setup.ScriptRunner, Setup.RegDLL, Setup.Helper,
   Setup.WizardForm, Shared.DebugStruct, Setup.DebugClient, Shared.VerInfoFunc, Setup.ScriptRunner, Setup.RegDLL, Setup.Helper,
   Shared.ResUpdateFunc, Setup.DotNetFunc, TaskbarProgressFunc, NewProgressBar, RestartManager,
   Shared.ResUpdateFunc, Setup.DotNetFunc, TaskbarProgressFunc, NewProgressBar, RestartManager,
@@ -250,24 +265,28 @@ begin
   end;
   end;
 end;
 end;
 
 
-type
-  TISSigVerifySignatureError = (vseMissingFile, vseMalformedOrBadSignature, vseKeyNotFound,
-    vseUnknownVerifyResult, vseFileSizeIncorrect, vseFileHashIncorrect);
-
-procedure ISSigVerifyError(const AError: TISSigVerifySignatureError; const AExceptionMessage: String);
+procedure ISSigVerifyError(const AError: TISSigVerifySignatureError;
+  const ACustomExceptionMessage: String);
 const
 const
   ErrorStrings: array[TISSigVerifySignatureError] of String =
   ErrorStrings: array[TISSigVerifySignatureError] of String =
     ('Signature file does not exist', 'Malformed or bad signature', 'No matching key found',
     ('Signature file does not exist', 'Malformed or bad signature', 'No matching key found',
       'Unknown verify result', 'File size incorrect', 'File hash incorrect');
       'Unknown verify result', 'File size incorrect', 'File hash incorrect');
 begin
 begin
   Log('ISSig verification error: ' + AddPeriod(ErrorStrings[AError]));
   Log('ISSig verification error: ' + AddPeriod(ErrorStrings[AError]));
-  raise Exception.Create(AExceptionMessage);
+  var Msg := ACustomExceptionMessage;
+  if Msg = '' then
+    Msg := SetupMessages[msgSourceIsCorrupted];
+  raise Exception.Create(Msg);
 end;
 end;
 
 
-procedure DoISSigVerify(const SourceF: TFile; const SourceFilename: String;
-  const ISSigAllowedKeys: AnsiString; out ExpectedFileHash: TSHA256Digest);
-{ Caller must check ExpectedFileHash }
+procedure DoISSigVerify(const SourceF: TFile; const SourceFS: TFileStream;
+  const SourceFilename: String; const ISSigAllowedKeys: AnsiString;
+  out ExpectedFileHash: TSHA256Digest);
+{ Either SourceF or SourceFS must be set. Caller must check ExpectedFileHash. }
 begin
 begin
+  if ((SourceF = nil) and (SourceFS = nil)) or ((SourceF <> nil) and (SourceFS <> nil)) then
+    InternalError('DoISSigVerify: Invalid SourceF / SourceFS combination');
+
   var ExpectedFileSize: Int64;
   var ExpectedFileSize: Int64;
   if not ISSigVerifySignature(SourceFilename,
   if not ISSigVerifySignature(SourceFilename,
     GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
     GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
@@ -286,12 +305,17 @@ begin
       else
       else
         VerifyError := vseUnknownVerifyResult;
         VerifyError := vseUnknownVerifyResult;
       end;
       end;
-      ISSigVerifyError(VerifyError, SetupMessages[msgSourceIsCorrupted]);
+      ISSigVerifyError(VerifyError);
     end
     end
   ) then
   ) then
     InternalError('Unexpected ISSigVerifySignature result');
     InternalError('Unexpected ISSigVerifySignature result');
-  if Int64(SourceF.Size) <> ExpectedFileSize then
-    ISSigVerifyError(vseFileSizeIncorrect, SetupMessages[msgSourceIsCorrupted]);
+  var FileSize: Int64;
+  if SourceF <> nil then
+    FileSize := Int64(SourceF.Size)
+  else
+    FileSize := SourceFS.Size;
+  if FileSize <> ExpectedFileSize then
+    ISSigVerifyError(vseFileSizeIncorrect);
 end;
 end;
 
 
 const
 const
@@ -311,7 +335,7 @@ var
 begin
 begin
   var ExpectedFileHash: TSHA256Digest;
   var ExpectedFileHash: TSHA256Digest;
   if ISSigVerify then begin
   if ISSigVerify then begin
-    DoISSigVerify(SourceF, ISSigSourceFilename, ISSigAllowedKeys, ExpectedFileHash);
+    DoISSigVerify(SourceF, nil, ISSigSourceFilename, ISSigAllowedKeys, ExpectedFileHash);
     { ExpectedFileHash checked below after copy }
     { ExpectedFileHash checked below after copy }
     SHA256Init(Context);
     SHA256Init(Context);
   end;
   end;
@@ -353,7 +377,7 @@ begin
 
 
   if ISSigVerify then begin
   if ISSigVerify then begin
     if not SHA256DigestsEqual(SHA256Final(Context), ExpectedFileHash) then
     if not SHA256DigestsEqual(SHA256Final(Context), ExpectedFileHash) then
-      ISSigVerifyError(vseFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
+      ISSigVerifyError(vseFileHashIncorrect);
     Log(ISSigVerificationSuccessfulLogMessage);
     Log(ISSigVerificationSuccessfulLogMessage);
   end;
   end;
 
 
@@ -1943,11 +1967,11 @@ var
               if ISSigVerifySourceF = nil then
               if ISSigVerifySourceF = nil then
                 ISSigVerifySourceF := TFileRedir.Create(DisableFsRedir, ArchiveFilename, fdOpenExisting, faRead, fsRead);
                 ISSigVerifySourceF := TFileRedir.Create(DisableFsRedir, ArchiveFilename, fdOpenExisting, faRead, fsRead);
               var ExpectedFileHash: TSHA256Digest;
               var ExpectedFileHash: TSHA256Digest;
-              DoISSigVerify(ISSigVerifySourceF, ArchiveFilename, CurFile^.ISSigAllowedKeys,
+              DoISSigVerify(ISSigVerifySourceF, nil, ArchiveFilename, CurFile^.ISSigAllowedKeys,
                 ExpectedFileHash);
                 ExpectedFileHash);
               { 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 FileHash = GetSHA256OfFile(DisableFsRedir, ArchiveFilename);
-              if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
+              const ActualFileHash = GetSHA256OfFile(DisableFsRedir, ArchiveFilename);
+              if not SHA256DigestsEqual(ActualFileHash, ExpectedFileHash) then
                 ISSigVerifyError(vseFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
                 ISSigVerifyError(vseFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
               Log(ISSigVerificationSuccessfulLogMessage);
               Log(ISSigVerificationSuccessfulLogMessage);
               { Keeping ISSigVerifySourceF open until extraction has completed }
               { Keeping ISSigVerifySourceF open until extraction has completed }
@@ -3670,7 +3694,9 @@ begin
     Log('Download is not using basic authentication');
     Log('Download is not using basic authentication');
 end;
 end;
 
 
-function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String; const OnDownloadProgress: TOnDownloadProgress): Int64;
+function DownloadTemporaryFile(const Url, BaseName, RequiredSHA256OfFile: String;
+  const ISSigVerify: Boolean; const ISSigAllowedKeys: AnsiString;
+  const OnDownloadProgress: TOnDownloadProgress): Int64;
 var
 var
   DestFile, TempFile: String;
   DestFile, TempFile: String;
   TempF: TFileRedir;
   TempF: TFileRedir;
@@ -3760,8 +3786,15 @@ begin
       FreeAndNil(HandleStream);
       FreeAndNil(HandleStream);
       FreeAndNil(TempF);
       FreeAndNil(TempF);
 
 
-      { Check hash if specified, otherwise check everything else we can check }
-      if RequiredSHA256OfFile <> '' then begin
+      { Check .issig or hash if specified, otherwise check everything else we can check }
+      if ISSigVerify then begin
+        var ExpectedFileHash: TSHA256Digest;
+        DoISSigVerify(TempF, nil, TempFile, ISSigAllowedKeys, ExpectedFileHash);
+        const FileHash = GetSHA256OfFile(DisableFsRedir, TempFile);
+        if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
+          ISSigVerifyError(vseFileHashIncorrect, SetupMessages[msgSourceIsCorrupted]);
+        Log(ISSigVerificationSuccessfulLogMessage);
+      end else if RequiredSHA256OfFile <> '' then begin
         try
         try
           SHA256OfFile := SHA256DigestToString(GetSHA256OfFile(DisableFsRedir, TempFile));
           SHA256OfFile := SHA256DigestToString(GetSHA256OfFile(DisableFsRedir, TempFile));
         except on E: Exception do
         except on E: Exception do

+ 1 - 1
Projects/Src/Setup.ScriptDlg.pas

@@ -1074,7 +1074,7 @@ 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 }
     SetDownloadCredentials(F.UserName, F.Password);
     SetDownloadCredentials(F.UserName, F.Password);
-    Result := Result + DownloadTemporaryFile(F.Url, F.BaseName, F.RequiredSHA256OfFile, InternalOnDownloadProgress);
+    Result := Result + DownloadTemporaryFile(F.Url, F.BaseName, F.RequiredSHA256OfFile,  False, '', InternalOnDownloadProgress);
   end;
   end;
   SetDownloadCredentials('', '');
   SetDownloadCredentials('', '');
 end;
 end;

+ 6 - 33
Projects/Src/Setup.ScriptFunc.pas

@@ -804,7 +804,7 @@ var
     end);
     end);
     RegisterScriptFunc('DownloadTemporaryFile', sfNoUninstall, procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     RegisterScriptFunc('DownloadTemporaryFile', sfNoUninstall, procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
     begin
-      Stack.SetInt64(PStart, DownloadTemporaryFile(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3), TOnDownloadProgress(Stack.GetProc(PStart-4, Caller))));
+      Stack.SetInt64(PStart, DownloadTemporaryFile(Stack.GetString(PStart-1), Stack.GetString(PStart-2), Stack.GetString(PStart-3), False, '', TOnDownloadProgress(Stack.GetProc(PStart-4, Caller))));
     end);
     end);
     RegisterScriptFunc('SetDownloadCredentials', sfNoUninstall, procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     RegisterScriptFunc('SetDownloadCredentials', sfNoUninstall, procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
     begin
@@ -1846,43 +1846,16 @@ var
           InternalError(Format('Unknown RuntimeID ''%s''', [RuntimeID]));
           InternalError(Format('Unknown RuntimeID ''%s''', [RuntimeID]));
       end;
       end;
 
 
-      { Verify signature }
-      var ExpectedFileSize: Int64;
-      var ExpectedFileHash: TSHA256Digest;
-      if not ISSigVerifySignature(Filename,
-        GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
-        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
-      ) then
-        InternalError('Unexpected ISSigVerifySignature result');
-
-      { Verify file, keeping open afterwards if requested
+      { Verify signature & file, keeping open afterwards if requested
         Also see TrustFunc's CheckFileTrust }
         Also see TrustFunc's CheckFileTrust }
       var F := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
       var F := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
       try
       try
-        if Int64(F.Size) <> ExpectedFileSize then
-          raise Exception.Create('File size is incorrect');
+        var ExpectedFileHash: TSHA256Digest;
+        DoISSigVerify(nil, F, Filename, ISSigAllowedKeys, ExpectedFileHash);
+         { 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
-          raise Exception.Create('File hash is incorrect');
+          ISSigVerifyError(vseFileHashIncorrect);
       except
       except
         FreeAndNil(F);
         FreeAndNil(F);
         raise;
         raise;