Ver código fonte

Initial support for issigverify + external. Todo: initialize ISSigKeys array only once + do something with the error strings. I suppose this needs a Default.isl change :(

Martijn Laan 4 meses atrás
pai
commit
6b3cb3e3d5

+ 4 - 1
Projects/Setup.dpr

@@ -95,7 +95,10 @@ uses
   PBKDF2 in '..\Components\PBKDF2.pas',
   PBKDF2 in '..\Components\PBKDF2.pas',
   Compression.SevenZipDecoder in 'Src\Compression.SevenZipDecoder.pas',
   Compression.SevenZipDecoder in 'Src\Compression.SevenZipDecoder.pas',
   PSStackHelper in '..\Components\PSStackHelper.pas',
   PSStackHelper in '..\Components\PSStackHelper.pas',
-  Setup.ScriptFunc.HelperFunc in 'Src\Setup.ScriptFunc.HelperFunc.pas';
+  Setup.ScriptFunc.HelperFunc in 'Src\Setup.ScriptFunc.HelperFunc.pas',
+  ECDSA in '..\Components\ECDSA.pas',
+  ISSigFunc in '..\Components\ISSigFunc.pas',
+  StringScanner in '..\Components\StringScanner.pas';
 
 
 {$SETPEOSVERSION 6.1}
 {$SETPEOSVERSION 6.1}
 {$SETPESUBSYSVERSION 6.1}
 {$SETPESUBSYSVERSION 6.1}

+ 3 - 0
Projects/Setup.dproj

@@ -168,6 +168,9 @@
         <DCCReference Include="Src\Compression.SevenZipDecoder.pas"/>
         <DCCReference Include="Src\Compression.SevenZipDecoder.pas"/>
         <DCCReference Include="..\Components\PSStackHelper.pas"/>
         <DCCReference Include="..\Components\PSStackHelper.pas"/>
         <DCCReference Include="Src\Setup.ScriptFunc.HelperFunc.pas"/>
         <DCCReference Include="Src\Setup.ScriptFunc.HelperFunc.pas"/>
+        <DCCReference Include="..\Components\ECDSA.pas"/>
+        <DCCReference Include="..\Components\ISSigFunc.pas"/>
+        <DCCReference Include="..\Components\StringScanner.pas"/>
         <BuildConfiguration Include="Base">
         <BuildConfiguration Include="Base">
             <Key>Base</Key>
             <Key>Base</Key>
         </BuildConfiguration>
         </BuildConfiguration>

+ 0 - 3
Projects/Src/Compiler.SetupCompiler.pas

@@ -5351,9 +5351,6 @@ begin
           if (AExcludes.Count > 0) then
           if (AExcludes.Count > 0) then
             AbortCompile(SCompilerFilesCantHaveExternalExclude)
             AbortCompile(SCompilerFilesCantHaveExternalExclude)
           else if Sign <> fsNoSetting then
           else if Sign <> fsNoSetting then
-            AbortCompileFmt(SCompilerParamErrorBadCombo2,
-              [ParamCommonFlags, 'external', SignFlags[Sign]])
-          else if foISSigVerify in Options then
             AbortCompileFmt(SCompilerParamErrorBadCombo2,
             AbortCompileFmt(SCompilerParamErrorBadCombo2,
               [ParamCommonFlags, 'external', SignFlags[Sign]]);
               [ParamCommonFlags, 'external', SignFlags[Sign]]);
         end;
         end;

+ 67 - 6
Projects/Src/Setup.Install.pas

@@ -31,7 +31,8 @@ uses
   Windows, SysUtils, Messages, Classes, Forms, ShlObj, Shared.Struct, Setup.UninstallLog, Shared.SetupTypes,
   Windows, SysUtils, Messages, Classes, 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,
   Setup.MainFunc, Setup.LoggingFunc, Setup.FileExtractor, Shared.FileClass,
-  Compression.Base, SHA256, PathFunc, Shared.CommonFunc.Vcl, Shared.CommonFunc, SetupLdrAndSetup.RedirFunc, Shared.Int64Em, Shared.SetupMessageIDs,
+  Compression.Base, SHA256, PathFunc, ECDSA, ISSigFunc, Shared.CommonFunc.Vcl,
+  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,
   Net.HTTPClient, Net.URLClient, NetEncoding, RegStr;
   Net.HTTPClient, Net.URLClient, NetEncoding, RegStr;
@@ -249,16 +250,69 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure CopySourceFileToDestFile(const SourceF, DestF: TFile;
-  AMaxProgress: Integer64);
+procedure ISSigVerifyError(const AReason: String);
+begin
+  Log('ISSig verification error: ' + AddPeriod(AReason));
+  raise Exception.Create(AReason);
+end;
+
+procedure CopySourceFileToDestFile(const SourceF, DestF: TFile; const ISSigVerify: Boolean;
+  const SourceFilename: 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. SourceFilename is only used if
+  ISSigVerify is True. }
+const
+  ISSigMissingFile = 'Signature file does not exist';
+  ISSigMalformedOrBadSignature = 'Malformed or bad signature';
+  ISSigKeyNotFound = 'Incorrect key ID';
+  ISSigUnknownVerifyResult  = 'Unknown verify result';
+  ISSigFileSizeIncorrect = 'File size incorrect';
+  ISSigFileHashIncorrect = 'File hash incorrect';
 var
 var
   BytesLeft: Integer64;
   BytesLeft: Integer64;
   NewProgress: Integer64;
   NewProgress: Integer64;
   BufSize: Cardinal;
   BufSize: Cardinal;
   Buf: array[0..16383] of Byte;
   Buf: array[0..16383] of Byte;
+  ISSigKeys: array of TECDSAKey;
+  Context: TSHA256Context;
 begin
 begin
+  var ExpectedFileHash: TSHA256Digest;
+  if ISSigVerify then begin
+    SetLength(ISSigKeys, Entries[seISSigKey].Count);
+    for var N := 0 to Entries[seISSigKey].Count-1 do begin
+      var ISSigKeyEntry := PSetupISSigKeyEntry(Entries[seISSigKey][N]);
+      ISSigKeys[N] := TECDSAKey.Create;
+      if ISSigImportPublicKey(ISSigKeys[N], '', ISSigKeyEntry.PublicX, ISSigKeyEntry.PublicY) <> ikrSuccess then
+        InternalError('ISSigImportPublicKey failed')
+    end;
+
+    const SigFilename = SourceFilename + '.issig';
+    if not NewFileExists(SigFilename) then
+      ISSigVerifyError(ISSigMissingFile);
+    const SigText = ISSigLoadTextFromFile(SigFilename);
+    var ExpectedFileSize: Int64;
+    const VerifyResult = ISSigVerifySignatureText(ISSigKeys, 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);
+    end;
+    if Int64(SourceF.Size) <> ExpectedFileSize then
+      ISSigVerifyError(ISSigFileSizeIncorrect);
+    { ExpectedFileHash checked below after copy }
+
+    for var N := 0 to Length(ISSigKeys)-1 do
+      ISSigKeys[N].Free;
+
+    SHA256Init(Context);
+  end;
+
   Inc6464(AMaxProgress, CurProgress);
   Inc6464(AMaxProgress, CurProgress);
   BytesLeft := SourceF.Size;
   BytesLeft := SourceF.Size;
 
 
@@ -279,6 +333,9 @@ begin
     DestF.WriteBuffer(Buf, BufSize);
     DestF.WriteBuffer(Buf, BufSize);
     Dec64(BytesLeft, BufSize);
     Dec64(BytesLeft, BufSize);
 
 
+    if ISSigVerify then
+      SHA256Update(Context, Buf, BufSize);
+
     NewProgress := CurProgress;
     NewProgress := CurProgress;
     Inc64(NewProgress, BufSize);
     Inc64(NewProgress, BufSize);
     if Compare64(NewProgress, AMaxProgress) > 0 then
     if Compare64(NewProgress, AMaxProgress) > 0 then
@@ -288,6 +345,10 @@ begin
     ProcessEvents;
     ProcessEvents;
   end;
   end;
 
 
+  if ISSigVerify then
+    if not SHA256DigestsEqual(SHA256Final(Context), ExpectedFileHash) then
+      ISSigVerifyError(ISSigFileHashIncorrect);
+
   { 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
     progress bar to the maximum amount }
     progress bar to the maximum amount }
   SetProgress(AMaxProgress);
   SetProgress(AMaxProgress);
@@ -1441,9 +1502,9 @@ var
               try
               try
                 LastOperation := SetupMessages[msgErrorCopying];
                 LastOperation := SetupMessages[msgErrorCopying];
                 if Assigned(CurFileLocation) then
                 if Assigned(CurFileLocation) then
-                  CopySourceFileToDestFile(SourceF, DestF, CurFileLocation^.OriginalSize)
+                  CopySourceFileToDestFile(SourceF, DestF, False, '', CurFileLocation^.OriginalSize)
                 else
                 else
-                  CopySourceFileToDestFile(SourceF, DestF, AExternalSize);
+                  CopySourceFileToDestFile(SourceF, DestF, foISSigVerify in CurFile^.Options, SourceFile, AExternalSize);
               finally
               finally
                 SourceF.Free;
                 SourceF.Free;
               end;
               end;