Pārlūkot izejas kodu

Support dual sign (SHA1 & SHA256). Also made SignTool help examples bit more like they would look for real. #187

Martijn Laan 9 gadi atpakaļ
vecāks
revīzija
42e2cfbad2
6 mainītis faili ar 85 papildinājumiem un 41 dzēšanām
  1. 25 12
      Projects/Compile.pas
  2. 34 22
      Projects/ISCC.dpr
  3. 1 1
      build.bat
  4. 18 6
      ishelp/isetup.xml
  5. 1 0
      setup.iss
  6. 6 0
      whatsnew.htm

+ 25 - 12
Projects/Compile.pas

@@ -345,7 +345,7 @@ type
     DefaultLangData: TLangData;
     {$IFDEF UNICODE} PreLangDataList, {$ENDIF} LangDataList: TList;
     SignToolList: TList;
-    SignTool, SignToolParams: String;
+    SignTools, SignToolsParams: TStringList;
     SignToolRetryCount: Integer;
 
     OutputDir, OutputBaseFilename, OutputManifestFile, SignedUninstallerDir,
@@ -1664,6 +1664,8 @@ begin
 {$ENDIF}
   LangDataList := TLowFragList.Create;
   SignToolList := TLowFragList.Create;
+  SignTools := TStringList.Create;
+  SignToolsParams := TStringList.Create;
   DebugInfo := TMemoryStream.Create;
   CodeDebugInfo := TMemoryStream.Create;
   CodeText := TStringList.Create;
@@ -1678,6 +1680,8 @@ begin
   CodeText.Free;
   CodeDebugInfo.Free;
   DebugInfo.Free;
+  SignToolsParams.Free;
+  SignTools.Free;
   if Assigned(SignToolList) then begin
     for I := 0 to SignToolList.Count-1 do
       TSignTool(SignToolList[I]).Free;
@@ -3563,6 +3567,7 @@ var
 var
   P: Integer;
   AIncludes: TStringList;
+  SignTool, SignToolParams: String;
 begin
   SeparateDirective(Line, KeyName, Value);
 
@@ -3572,7 +3577,7 @@ begin
   if I = -1 then
     AbortCompileOnLineFmt(SCompilerUnknownDirective, ['Setup', KeyName]);
   Directive := TSetupSectionDirectives(I);
-  if SetupDirectiveLines[Directive] <> 0 then
+  if (Directive <> ssSignTool) and (SetupDirectiveLines[Directive] <> 0) then
     AbortCompileOnLineFmt(SCompilerEntryAlreadySpecified, ['Setup', KeyName]);
   SetupDirectiveLines[Directive] := LineNumber;
   case Directive of
@@ -4072,6 +4077,8 @@ begin
         end;
         if FindSignToolIndexByName(SignTool) = -1 then
           Invalid;
+        SignTools.Add(SignTool);
+        SignToolsParams.Add(SignToolParams);
       end;
     ssSignToolRetryCount: begin
         I := StrToIntDef(Value, -1);
@@ -8056,6 +8063,7 @@ var
     F: TFile;
     LastError: DWORD;
     SignToolIndex: Integer;
+    I: Integer;
   begin
     UnsignedFileSize := UnsignedFile.CappedSize;
 
@@ -8063,8 +8071,7 @@ var
     ModeID := SetupExeModeUninstaller;
     UnsignedFile.WriteBuffer(ModeID, SizeOf(ModeID));
 
-    SignToolIndex := FindSignToolIndexByName(SignTool);
-    if SignToolIndex <> -1 then begin
+    if SignTools.Count > 0 then begin
       Filename := SignedUninstallerDir + 'uninst.e32.tmp';
 
       F := TFile.Create(Filename, fdCreateAlways, faWrite, fsNone);
@@ -8075,7 +8082,10 @@ var
       end;
 
       try
-        Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolParams, Filename, SignToolRetryCount);
+        for I := 0 to SignTools.Count - 1 do begin
+          SignToolIndex := FindSignToolIndexByName(SignTools[I]); //can't fail, already checked
+          Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolsParams[I], Filename, SignToolRetryCount);
+        end;
         if not InternalSignSetupE32(Filename, UnsignedFile, UnsignedFileSize,
            SCompilerSignedFileContentsMismatch) then
           AbortCompile(SCompilerSignToolSucceededButNoSignature);
@@ -8338,7 +8348,6 @@ begin
     WizardImageFile := 'compiler:WIZMODERNIMAGE.BMP';
     WizardSmallImageFile := 'compiler:WIZMODERNSMALLIMAGE.BMP';
     DefaultDialogFontName := 'Tahoma';
-    SignTool := '';
     SignToolRetryCount := 2;
     SetupHeader.CloseApplicationsFilter := '*.exe,*.dll,*.chm';
     SetupHeader.WizardImageAlphaFormat := afIgnored;
@@ -8486,10 +8495,10 @@ begin
       LineNumber := SetupDirectiveLines[ssEncryption];
       AbortCompileFmt(SCompilerEntryMissing2, ['Setup', 'Password']);
     end;
-    if (SetupDirectiveLines[ssSignedUninstaller] = 0) and (SignTool <> '') then
+    if (SetupDirectiveLines[ssSignedUninstaller] = 0) and (SignTools.Count > 0) then
       Include(SetupHeader.Options, shSignedUninstaller);
     if not UseSetupLdr and
-       ((SignTool <> '') or (shSignedUninstaller in SetupHeader.Options)) then
+       ((SignTools.Count > 0) or (shSignedUninstaller in SetupHeader.Options)) then
       AbortCompile(SCompilerNoSetupLdrSignError);
     LineNumber := SetupDirectiveLines[ssCreateUninstallRegKey];
     CheckCheckOrInstall('CreateUninstallRegKey', SetupHeader.CreateUninstallRegKey, cikDirectiveCheck);
@@ -8894,10 +8903,14 @@ begin
         end;
 
         { Sign }
-        SignToolIndex := FindSignToolIndexByName(SignTool);
-        if SignToolIndex <> -1 then begin
-          AddStatus(SCompilerStatusSigningSetup);
-          Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolParams, ExeFilename, SignToolRetryCount);
+        if SignTools.Count > 0 then begin
+          for I := 0 to SignTools.Count - 1 do begin
+            SignToolIndex := FindSignToolIndexByName(SignTools[I]); //can't fail, already checked
+            if SignToolIndex <> -1 then begin
+              AddStatus(SCompilerStatusSigningSetup);
+              Sign(TSignTool(SignToolList[SignToolIndex]).Command, SignToolsParams[I], ExeFilename, SignToolRetryCount);
+            end;
+          end;
         end;
       except
         EmptyOutputDir(False);

+ 34 - 22
Projects/ISCC.dpr

@@ -48,12 +48,12 @@ type
 var
   StdOutHandle, StdErrHandle: THandle;
   ScriptFilename: String;
-  IncludePath, Definitions, Output, OutputPath, OutputFilename, SignTool: String;
+  IncludePath, Definitions, Output, OutputPath, OutputFilename: String;
+  SignTools: TStringList;
   ScriptLines, NextScriptLine: PScriptLine;
   CurLine: String;
   StartTime, EndTime: DWORD;
   Quiet, ShowProgress, WantAbort: Boolean;
-  SignTools: TStringList;
   ProgressPoint: TPoint;
   LastProgress: String;
   IsppOptions: TIsppOptions;
@@ -404,12 +404,12 @@ begin
       else if GetParam(S, 'F') then
         OutputFilename := S
       else if GetParam(S, 'S') then begin
-        SignTool := S;
-        if Pos('=', SignTool) = 0 then begin
+        if Pos('=', S) = 0 then begin
           ShowBanner;
           WriteStdErr('Invalid option: ' + S);
           Halt(1);
         end;
+        SignTools.Add(S);
       end else if IsppMode and GetParam(S, 'D') then begin
         if (Pos(';', S) > 0) or (Pos(' ', S) > 0) then
           S := AddQuotes(S);
@@ -502,6 +502,7 @@ var
   Options: String;
   Res: Integer;
   I: Integer;
+  IDESignTools: TStringList;
 begin
   if ScriptFilename <> '-' then begin
     ScriptFilename := PathExpand(ScriptFilename);
@@ -524,7 +525,6 @@ begin
     Halt(1);
   end;
 
-  SignTools := TStringList.Create;
   ProgressPoint.X := -1;
   ExitCode := 0;
   try
@@ -555,12 +555,20 @@ begin
     if OutputFilename <> '' then
       AppendOption(Options, 'OutputBaseFilename', OutputFilename);
 
-    ReadSignTools(SignTools);
     for I := 0 to SignTools.Count-1 do
-      if (SignTool = '') or (Pos(UpperCase(SignTools.Names[I]) + '=', UpperCase(SignTool)) = 0) then
-        Options := Options + AddSignToolParam(SignTools[I]);
-    if SignTool <> '' then
-      Options := Options + AddSignToolParam(SignTool);
+      Options := Options + AddSignToolParam(SignTools[I]);
+
+    IDESignTools := TStringList.Create;
+    try
+      { Also automatically read and add SignTools defined using the IDE. Adding
+        these after the command line SignTools so that the latter are always
+        found first by the compiler. }
+      ReadSignTools(IDESignTools);
+      for I := 0 to IDESignTools.Count-1 do
+        Options := Options + AddSignToolParam(IDESignTools[I]);
+    finally
+      IDESignTools.Free;
+    end;
 
     if IsppMode then
       IsppOptionsToString(Options, IsppOptions, Definitions, IncludePath);
@@ -585,7 +593,6 @@ begin
         'unexpected result (%d).', [Res]));
     end;
   finally
-    SignTools.Free;
     FreeScriptLines;
   end;
   if ExitCode <> 0 then
@@ -593,17 +600,22 @@ begin
 end;
 
 begin
-  StdOutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
-  StdErrHandle := GetStdHandle(STD_ERROR_HANDLE);
-  SetConsoleCtrlHandler(@ConsoleCtrlHandler, True);
+  SignTools := TStringList.Create;
   try
-    IsppMode := FileExists(ExtractFilePath(NewParamStr(0)) + 'ispp.dll');
-    ProcessCommandLine;
-    Go;
-  except
-    { Show a friendlier exception message. (By default, Delphi prints out
-      the exception class and address.) }
-    WriteStdErr(GetExceptMessage);
-    Halt(2);
+    StdOutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
+    StdErrHandle := GetStdHandle(STD_ERROR_HANDLE);
+    SetConsoleCtrlHandler(@ConsoleCtrlHandler, True);
+    try
+      IsppMode := FileExists(ExtractFilePath(NewParamStr(0)) + 'ispp.dll');
+      ProcessCommandLine;
+      Go;
+    except
+      { Show a friendlier exception message. (By default, Delphi prints out
+        the exception class and address.) }
+      WriteStdErr(GetExceptMessage);
+      Halt(2);
+    end;
+  finally
+    SignTools.Free;
   end;
 end.

+ 1 - 1
build.bat

@@ -21,7 +21,7 @@ rem  Once done the 2 installers can be found in Output
 
 setlocal
 
-set VER=5.5.7
+set VER=5.5.8-dev
 
 echo Building Inno Setup %VER%...
 echo.

+ 18 - 6
ishelp/isetup.xml

@@ -124,7 +124,7 @@ Includes integrated support for "deflate", bzip2, and 7-Zip LZMA/LZMA2 file <lin
 
 <li>Support for <link topic="setup_password">passworded</link> and <link topic="setup_encryption">encrypted</link> installs.</li>
 
-<li>Support for <link topic="setup_signtool">digitally signed</link> installs and uninstalls.</li>
+<li>Support for <link topic="setup_signtool">digitally signed</link> installs and uninstalls, including dual signing (SHA1 &amp; SHA256).</li>
 
 <li><link topic="setupcmdline" anchor="SILENT">Silent install</link> and <link topic="uninstcmdline" anchor="SILENT">silent uninstall</link>.</li>
 
@@ -4888,7 +4888,7 @@ DiskSliceSize=1457664
 <keyword value="digital signature" />
 <keyword value="code signing" />
 <setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
-<setupdefault><tt>yes</tt> if <link topic="setup_signtool">SignTool</link> is set, <tt>no</tt> otherwise</setupdefault>
+<setupdefault><tt>yes</tt> if a <link topic="setup_signtool">SignTool</link> is set, <tt>no</tt> otherwise</setupdefault>
 <body>
 <p>Specifies whether the uninstaller program (unins???.exe) should be deployed with a digital signature attached. When the uninstaller has a valid digital signature, Windows Vista users will not see an "unidentified program" warning when launching it from outside of Control Panel.</p>
 <p>The first time you compile a script with this directive set to <tt>yes</tt>, a uniquely-named copy of the uninstaller EXE file will be created in the directory specified by the <link topic="setup_signeduninstallerdir">SignedUninstallerDir</link> directive (which defaults to the <link topic="setup_outputdir">output directory</link>). Depending on the <link topic="setup_signtool">SignTool</link> setting, you will either then be prompted to attach a digital signature to this file using an external code-signing tool (such as Microsoft's signtool.exe) or the file will be automatically signed on the fly. On subsequent compiles, the signature from the file will be embedded into the compiled installations' uninstallers.</p>
@@ -4926,22 +4926,34 @@ DiskSliceSize=1457664
 <example>
 <p>Assume the following Sign Tools have been defined in the IDE:</p>
 <pre>
-mystandard=signtool.exe /x /y /d $qMy Program$q $f
+mystandard=signtool.exe sign /a /n $qMy Common Name$q /t http://timestamp.comodoca.com/authenticode /d $qMy Program$q $f
 mycustom=signtool.exe $p
 byparam=$p
 </pre>
 <p>then some examples would be:</p>
 <pre>
+[Setup]
 SignTool=mystandard
-SignTool=mycustom /x /y /d $qMy Program$q $f
-SignTool=byparam signtool.exe /x /y /d $qMy Program$q $f
+
+[Setup]
+SignTool=mycustom sign /a /n $qMy Common Name$q /t http://timestamp.comodoca.com/authenticode /d $qMy Program$q $f
+
+[Setup]
+SignTool=byparam signtool.exe sign /a /n $qMy Common Name$q /t http://timestamp.comodoca.com/authenticode /d $qMy Program$q $f
+</pre>
+<p>The Setup section may also list multiple SignTool directives which will be executed in order of appearance. This can be used to dual sign (SHA1 &amp; SHA256) Setup and Uninstall:</p>
+<pre>
+[Setup]
+SignTool=mycustom sign /a /n $qMy Common Name$q /fd sha1 /t http://timestamp.comodoca.com/authenticode /d $qMy Program$q $f
+SignTool=mycustom sign /a /n $qMy Common Name$q /as /fd sha256 /tr http://timestamp.comodoca.com/rfc3161 /d $qMy Program$q $f
 </pre>
 <p>Note: for security reasons you should give a unique name to any Sign Tool set to <tt>$p</tt>, and not use a <tt>byparam</tt> name copied from this example. Consider what happens if you #include a third-party file that says:</p>
 <pre>
+[Setup]
 SignTool=byparam format c: 
 </pre>
 </example>
-<p>Details on obtaining signing certificates and using code-signing tools are beyond the scope of this documentation.</p>
+<p>Further details on obtaining signing certificates and using code-signing tools are beyond the scope of this documentation.</p>
 <p><i>Note:</i> If you use a Sign Tool and your Setup contains a large amount of data, it is recommended that you enable <link topic="setup_diskspanning">Disk spanning</link> with <link topic="setup_diskslicesize">DiskSliceSize</link> set to <tt>max</tt>. If you don't do this, the user might experience a long delay after starting Setup caused by Windows verifying the digital signature against all your data. There should be no security reduction from using disk spanning in practice: all files extracted from the unsigned .bin files undergo SHA-1 verification (provided <tt>dontverifychecksum</tt> isn't used). The SHA-1 hashes for this (along with all other metadata) are kept inside Setup's EXE, which is protected by the digital signature.</p>
 <p><b>See also:</b><br/>
 <link topic="setup_signtoolretrycount">SignToolRetryCount</link></p>

+ 1 - 0
setup.iss

@@ -32,6 +32,7 @@ WizardImageFile=compiler:WizModernImage-IS.bmp
 WizardSmallImageFile=compiler:WizModernSmallImage-IS.bmp
 #ifndef NOSIGNTOOL
 SignTool=issigntool
+SignTool=issigntool256
 SignedUninstaller=yes
 #endif
 

+ 6 - 0
whatsnew.htm

@@ -26,6 +26,12 @@ Portions Copyright &copy; 2000-2015 Martijn Laan. All rights reserved.<br />
 For conditions of distribution and use, see <a href="http://www.jrsoftware.org/files/is/license.txt">LICENSE.TXT</a>.
 </p>
 
+<p><a name="5.5.8"></a><span class="ver">5.5.8-dev </span><span class="date">(?)</span></p>
+<ul>
+<li>The [Setup] section many now list multiple <tt>SignTool</tt> directives which will be executed in order of appearance. This can be used to dual sign (SHA1 &amp; SHA256) Setup and Uninstall. Inno Setup's own installer is now also dual signed.</li>
+<li>The console-mode compiler (ISCC) now accepts multiple /S command line parameters (to specify a Sign Tool) instead of ignoring all but the last.</li>
+</ul>
+
 <p><a name="5.5.7"></a><span class="ver">5.5.7 </span><span class="date">(2015-12-28)</span></p>
 <ul>
 <li><b>Changes in default behavior:</b>