소스 검색

Merge branch 'issig-v2-filename'

Martijn Laan 2 달 전
부모
커밋
3cecf1869f

+ 69 - 32
Components/ISSigFunc.pas

@@ -28,21 +28,22 @@ function ISSigLoadTextFromFile(const AFilename: String): String;
 procedure ISSigSaveTextToFile(const AFilename, AText: String);
 procedure ISSigSaveTextToFile(const AFilename, AText: String);
 
 
 function ISSigCreateSignatureText(const AKey: TECDSAKey;
 function ISSigCreateSignatureText(const AKey: TECDSAKey;
-  const AFileSize: Int64; const AFileHash: TSHA256Digest): String;
+  const AFileName: String; const AFileSize: Int64; const AFileHash: TSHA256Digest): String;
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
-  const AText: String; out AFileSize: Int64;
+  const AText: String; out AFileName: String; out AFileSize: Int64;
   out AFileHash: TSHA256Digest): TISSigVerifySignatureResult; overload;
   out AFileHash: TSHA256Digest): TISSigVerifySignatureResult; overload;
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
-  const AText: String; out AFileSize: Int64;
+  const AText: String; out AFileName: 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;
 function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
-  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest; out AKeyUsedID: String;
+  out AExpectedFileName: String; out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
+  out AKeyUsedID: String;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean; overload;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean; overload;
 function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
 function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
-  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
+  out AExpectedFileName: String; out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean; overload;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean; overload;
@@ -77,9 +78,11 @@ uses
   StringScanner;
   StringScanner;
 
 
 const
 const
-  ISSigTextFileLengthLimit = 500;
+  ISSigTextFileLengthLimit = 1500;
 
 
   NonControlASCIICharsSet = [#32..#126];
   NonControlASCIICharsSet = [#32..#126];
+  UTF8HighCharsSet = [#128..#244];
+  AllHighCharsSet = [#128..#255];
   DigitsSet = ['0'..'9'];
   DigitsSet = ['0'..'9'];
   HexDigitsSet = DigitsSet + ['a'..'f'];
   HexDigitsSet = DigitsSet + ['a'..'f'];
 
 
@@ -93,11 +96,18 @@ begin
   TSHA256Digest(Result) := SHA256DigestFromString(S);
   TSHA256Digest(Result) := SHA256DigestFromString(S);
 end;
 end;
 
 
-function CalcHashToSign(const AFileSize: Int64;
+function CalcHashToSign(const AIncludeFileName: Boolean; const AFileName: String; const AFileSize: Int64;
   const AFileHash: TSHA256Digest): TSHA256Digest;
   const AFileHash: TSHA256Digest): TSHA256Digest;
 begin
 begin
   var Context: TSHA256Context;
   var Context: TSHA256Context;
   SHA256Init(Context);
   SHA256Init(Context);
+  if AIncludeFileName then begin
+    const UTF8FileName = UTF8String(AFileName);
+    const UTF8FileNameLength: Cardinal = Length(UTF8FileName);
+    SHA256Update(Context, UTF8FileNameLength, SizeOf(UTF8FileNameLength));
+    if UTF8FileNameLength > 0 then
+      SHA256Update(Context, Pointer(UTF8FileName)^, UTF8FileNameLength*SizeOf(UTF8FileName[1]));
+  end;
   SHA256Update(Context, AFileSize, SizeOf(AFileSize));
   SHA256Update(Context, AFileSize, SizeOf(AFileSize));
   SHA256Update(Context, AFileHash, SizeOf(AFileHash));
   SHA256Update(Context, AFileHash, SizeOf(AFileHash));
   Result := SHA256Final(Context);
   Result := SHA256Final(Context);
@@ -110,15 +120,18 @@ end;
 
 
 function ConsumeLineValue(var SS: TStringScanner; const AIdent: String;
 function ConsumeLineValue(var SS: TStringScanner; const AIdent: String;
   var AValue: String; const AMinValueLength, AMaxValueLength: Integer;
   var AValue: String; const AMinValueLength, AMaxValueLength: Integer;
-  const AAllowedChars: TSysCharSet): Boolean;
+  const AAllowedChars: TSysCharSet; const AAllowAllCharsAboveFF: Boolean = False;
+  const ARequireQuotes: Boolean = False): Boolean;
 begin
 begin
   Result := False;
   Result := False;
-  if SS.Consume(AIdent) and SS.Consume(' ') then
-    if SS.ConsumeMultiToString(AAllowedChars, AValue, AMinValueLength,
-       AMaxValueLength) > 0 then begin
-      { CRLF and LF line breaks are allowed (but not CR) }
-      SS.Consume(#13);
-      Result := SS.Consume(#10);
+  if SS.Consume(AIdent) and SS.Consume(' ') and (not ARequireQuotes or SS.Consume('"')) then
+    if SS.ConsumeMultiToString(AAllowedChars, AValue, AAllowAllCharsAboveFF,
+       AMinValueLength, AMaxValueLength) >= AMinValueLength then begin
+      if not ARequireQuotes or SS.Consume('"') then begin
+        { CRLF and LF line breaks are allowed (but not CR) }
+        SS.Consume(#13);
+        Result := SS.Consume(#10);
+      end;
     end;
     end;
 end;
 end;
 
 
@@ -143,13 +156,18 @@ begin
   end;
   end;
 
 
   { Defense-in-depth: Reject any non-CRLF control characters up front, as well
   { Defense-in-depth: Reject any non-CRLF control characters up front, as well
-    as any non-ASCII characters (to avoid any possible issues with converting
-    invalid multibyte characters) }
+    as any non-ASCII and non-UTF8-high characters (to avoid any possible issues with
+    converting invalid multibyte characters) }
   for var C in U do
   for var C in U do
-    if not (CharInSet(C, [#10, #13]) or CharInSet(C, NonControlASCIICharsSet)) then
+    if not (CharInSet(C, [#10, #13]) or CharInSet(C, NonControlASCIICharsSet) or
+            CharInSet(C, UTF8HighCharsSet)) then
       Exit('');
       Exit('');
+  { Do round-trip check to catch invalid sequences }
+  const UTF16Text = String(U);
+  if UTF8String(UTF16Text) <> U then
+    Exit('');
 
 
-  Result := String(U);
+  Result := UTF16Text;
 end;
 end;
 
 
 procedure ISSigSaveTextToFile(const AFilename, AText: String);
 procedure ISSigSaveTextToFile(const AFilename, AText: String);
@@ -165,8 +183,18 @@ begin
 end;
 end;
 
 
 function ISSigCreateSignatureText(const AKey: TECDSAKey;
 function ISSigCreateSignatureText(const AKey: TECDSAKey;
-  const AFileSize: Int64; const AFileHash: TSHA256Digest): String;
+  const AFileName: String; const AFileSize: Int64; const AFileHash: TSHA256Digest): String;
 begin
 begin
+  { Ensure unverifiable signature files can't be created accidentally }
+  const UTF8FileName = UTF8String(AFileName);
+  if Length(UTF8FileName) > 1000 then
+    raise Exception.Create('File name is too long');
+  if String(UTF8FileName) <> AFileName then
+    raise Exception.Create('File name contains invalid surrogate pairs');
+  for var C in UTF8FileName do
+    if not (C in ((NonControlASCIICharsSet - ['"']) + UTF8HighCharsSet)) then { Note this rejects quotes }
+      raise Exception.Create('File name contains invalid characters');
+
   { File size is limited to 16 digits (enough for >9 EB) }
   { File size is limited to 16 digits (enough for >9 EB) }
   if (AFileSize < 0) or (AFileSize > {$IF CompilerVersion >= 36.0} 9_999_999_999_999_999 {$ELSE} 9999999999999999 {$ENDIF} ) then
   if (AFileSize < 0) or (AFileSize > {$IF CompilerVersion >= 36.0} 9_999_999_999_999_999 {$ELSE} 9999999999999999 {$ENDIF} ) then
     raise Exception.Create('File size out of range');
     raise Exception.Create('File size out of range');
@@ -174,18 +202,20 @@ begin
   var PublicKey: TECDSAPublicKey;
   var PublicKey: TECDSAPublicKey;
   AKey.ExportPublicKey(PublicKey);
   AKey.ExportPublicKey(PublicKey);
 
 
-  const HashToSign = CalcHashToSign(AFileSize, AFileHash);
+  const HashToSign = CalcHashToSign(True, AFileName, AFileSize, AFileHash);
   var Sig: TECDSASignature;
   var Sig: TECDSASignature;
   AKey.SignHash(HashToSign, Sig);
   AKey.SignHash(HashToSign, Sig);
 
 
   Result := Format(
   Result := Format(
-    'format issig-v1'#13#10 +
+    'format issig-v2'#13#10 +
+    'file-name "%s"'#13#10 +
     'file-size %d'#13#10 +
     'file-size %d'#13#10 +
     'file-hash %s'#13#10 +
     'file-hash %s'#13#10 +
     'key-id %s'#13#10 +
     'key-id %s'#13#10 +
     'sig-r %s'#13#10 +
     'sig-r %s'#13#10 +
     'sig-s %s'#13#10,
     'sig-s %s'#13#10,
-    [AFileSize,
+    [AFileName,
+     AFileSize,
      SHA256DigestToString(AFileHash),
      SHA256DigestToString(AFileHash),
      SHA256DigestToString(CalcKeyID(PublicKey)),
      SHA256DigestToString(CalcKeyID(PublicKey)),
      ECDSAInt256ToString(Sig.Sig_r),
      ECDSAInt256ToString(Sig.Sig_r),
@@ -193,15 +223,16 @@ begin
 end;
 end;
 
 
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
-  const AText: String; out AFileSize: Int64;
+  const AText: String; out AFileName: String; out AFileSize: Int64;
   out AFileHash: TSHA256Digest; out AKeyUsedID: String): TISSigVerifySignatureResult;
   out AFileHash: TSHA256Digest; out AKeyUsedID: String): TISSigVerifySignatureResult;
 var
 var
   TextValues: record
   TextValues: record
-    Format, FileSize, FileHash, KeyID, Sig_r, Sig_s: String;
+    Format, FileName, FileSize, FileHash, KeyID, Sig_r, Sig_s: String;
   end;
   end;
 begin
 begin
   { To be extra safe, clear the "out" parameters just in case the caller isn't
   { To be extra safe, clear the "out" parameters just in case the caller isn't
     properly checking the function result }
     properly checking the function result }
+  AFileName := '';
   AFileSize := -1;
   AFileSize := -1;
   FillChar(AFileHash, SizeOf(AFileHash), 0);
   FillChar(AFileHash, SizeOf(AFileHash), 0);
   AKeyUsedID := '';
   AKeyUsedID := '';
@@ -213,7 +244,9 @@ begin
 
 
   var SS := TStringScanner.Create(AText);
   var SS := TStringScanner.Create(AText);
   if not ConsumeLineValue(SS, 'format', TextValues.Format, 8, 8, NonControlASCIICharsSet) or
   if not ConsumeLineValue(SS, 'format', TextValues.Format, 8, 8, NonControlASCIICharsSet) or
-     (TextValues.Format <> 'issig-v1') or
+     ((TextValues.Format <> 'issig-v1') and ((TextValues.Format <> 'issig-v2'))) or
+     ((TextValues.Format = 'issig-v2') and not ConsumeLineValue(SS, 'file-name', TextValues.FileName, 0, MaxInt,
+       (NonControlASCIICharsSet - ['"']) + AllHighCharsSet, True, True)) or
      not ConsumeLineValue(SS, 'file-size', TextValues.FileSize, 1, 16, DigitsSet) or
      not ConsumeLineValue(SS, 'file-size', TextValues.FileSize, 1, 16, DigitsSet) or
      not ConsumeLineValue(SS, 'file-hash', TextValues.FileHash, 64, 64, HexDigitsSet) or
      not ConsumeLineValue(SS, 'file-hash', TextValues.FileHash, 64, 64, HexDigitsSet) or
      not ConsumeLineValue(SS, 'key-id', TextValues.KeyID, 64, 64, HexDigitsSet) or
      not ConsumeLineValue(SS, 'key-id', TextValues.KeyID, 64, 64, HexDigitsSet) or
@@ -242,13 +275,16 @@ begin
     Exit(vsrKeyNotFound);
     Exit(vsrKeyNotFound);
   AKeyUsedID := TextValues.KeyID;
   AKeyUsedID := TextValues.KeyID;
 
 
+  const UnverifiedFileName = TextValues.FileName;
   const UnverifiedFileSize = StrToInt64(TextValues.FileSize);
   const UnverifiedFileSize = StrToInt64(TextValues.FileSize);
   const UnverifiedFileHash = SHA256DigestFromString(TextValues.FileHash);
   const UnverifiedFileHash = SHA256DigestFromString(TextValues.FileHash);
-  const HashToSign = CalcHashToSign(UnverifiedFileSize, UnverifiedFileHash);
+  const HashToSign = CalcHashToSign(TextValues.Format <> 'issig-v1', UnverifiedFileName,
+    UnverifiedFileSize, UnverifiedFileHash);
   var Sig: TECDSASignature;
   var Sig: TECDSASignature;
   Sig.Sig_r := ECDSAInt256FromString(TextValues.Sig_r);
   Sig.Sig_r := ECDSAInt256FromString(TextValues.Sig_r);
   Sig.Sig_s := ECDSAInt256FromString(TextValues.Sig_s);
   Sig.Sig_s := ECDSAInt256FromString(TextValues.Sig_s);
   if KeyUsed.VerifySignature(HashToSign, Sig) then begin
   if KeyUsed.VerifySignature(HashToSign, Sig) then begin
+    AFileName := UnverifiedFileName;
     AFileSize := UnverifiedFileSize;
     AFileSize := UnverifiedFileSize;
     AFileHash := UnverifiedFileHash;
     AFileHash := UnverifiedFileHash;
     Result := vsrSuccess;
     Result := vsrSuccess;
@@ -257,15 +293,16 @@ begin
 end;
 end;
 
 
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
 function ISSigVerifySignatureText(const AAllowedKeys: array of TECDSAKey;
-  const AText: String; out AFileSize: Int64;
+  const AText: String; out AFileName: String; out AFileSize: Int64;
   out AFileHash: TSHA256Digest): TISSigVerifySignatureResult;
   out AFileHash: TSHA256Digest): TISSigVerifySignatureResult;
 begin
 begin
   var KeyUsedID: String;
   var KeyUsedID: String;
-  Result := ISSigVerifySignatureText(AAllowedKeys, AText, AFileSize, AFileHash, KeyUsedID);
+  Result := ISSigVerifySignatureText(AAllowedKeys, AText, AFileName, AFileSize, AFileHash, KeyUsedID);
 end;
 end;
 
 
 function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
 function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
-  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest; out AKeyUsedID: String;
+  out AExpectedFileName: String; out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
+  out AKeyUsedID: String;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean;
@@ -294,20 +331,20 @@ begin
   end;
   end;
   const SigText = ISSigLoadTextFromFile(SigFilename);
   const SigText = ISSigLoadTextFromFile(SigFilename);
   const VerifyResult = ISSigVerifySignatureText(AAllowedKeys, SigText,
   const VerifyResult = ISSigVerifySignatureText(AAllowedKeys, SigText,
-    AExpectedFileSize, AExpectedFileHash, AKeyUsedID);
+    AExpectedFileName, AExpectedFileSize, AExpectedFileHash, AKeyUsedID);
   Result := VerifyResult = vsrSuccess;
   Result := VerifyResult = vsrSuccess;
   if not Result and Assigned(AVerificationFailedErrorProc) then
   if not Result and Assigned(AVerificationFailedErrorProc) then
     AVerificationFailedErrorProc(AFilename, SigFilename, VerifyResult);
     AVerificationFailedErrorProc(AFilename, SigFilename, VerifyResult);
 end;
 end;
 
 
 function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
 function ISSigVerifySignature(const AFilename: String; const AAllowedKeys: array of TECDSAKey;
-  out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
+  out AExpectedFileName: String; out AExpectedFileSize: Int64; out AExpectedFileHash: TSHA256Digest;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const AFileMissingErrorProc: TISSigVerifySignatureFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const ASigFileMissingErrorProc: TISSigVerifySignatureSigFileMissingErrorProc;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean;
   const AVerificationFailedErrorProc: TISSigVerifySignatureVerificationFailedErrorProc): Boolean;
 begin
 begin
   var KeyUsedID: String;
   var KeyUsedID: String;
-  Result := ISSigVerifySignature(AFilename, AAllowedKeys, AExpectedFileSize,
+  Result := ISSigVerifySignature(AFilename, AAllowedKeys, AExpectedFileName, AExpectedFileSize,
     AExpectedFileHash, KeyUsedID, AFileMissingErrorProc, ASigFileMissingErrorProc,
     AExpectedFileHash, KeyUsedID, AFileMissingErrorProc, ASigFileMissingErrorProc,
     AVerificationFailedErrorProc);
     AVerificationFailedErrorProc);
 end;
 end;

+ 6 - 0
Components/PathFunc.pas

@@ -19,6 +19,7 @@ function PathCharIsTrailByte(const S: String; const Index: Integer): Boolean;
 function PathCharLength(const S: String; const Index: Integer): Integer;
 function PathCharLength(const S: String; const Index: Integer): Integer;
 function PathCombine(const Dir, Filename: String): String;
 function PathCombine(const Dir, Filename: String): String;
 function PathCompare(const S1, S2: String): Integer;
 function PathCompare(const S1, S2: String): Integer;
+function PathSame(const S1, S2: String): Boolean;
 function PathDrivePartLength(const Filename: String): Integer;
 function PathDrivePartLength(const Filename: String): Integer;
 function PathDrivePartLengthEx(const Filename: String;
 function PathDrivePartLengthEx(const Filename: String;
   const IncludeSignificantSlash: Boolean): Integer;
   const IncludeSignificantSlash: Boolean): Integer;
@@ -157,6 +158,11 @@ begin
   Result := CompareStr(PathLowercase(S1), PathLowercase(S2));
   Result := CompareStr(PathLowercase(S1), PathLowercase(S2));
 end;
 end;
 
 
+function PathSame(const S1, S2: String): Boolean;
+begin
+  Result := PathCompare(S1, S2) = 0;
+end;
+
 function PathDrivePartLength(const Filename: String): Integer;
 function PathDrivePartLength(const Filename: String): Integer;
 begin
 begin
   Result := PathDrivePartLengthEx(Filename, False);
   Result := PathDrivePartLengthEx(Filename, False);

+ 17 - 13
Components/StringScanner.pas

@@ -25,11 +25,12 @@ type
     class function Create(const AString: String): TStringScanner; static;
     class function Create(const AString: String): TStringScanner; static;
     function Consume(const C: Char): Boolean; overload;
     function Consume(const C: Char): Boolean; overload;
     function Consume(const S: String): Boolean; overload;
     function Consume(const S: String): Boolean; overload;
-    function ConsumeMulti(const C: TSysCharSet; const AMinChars: Integer = 1;
-      const AMaxChars: Integer = Maxint): Integer;
-    function ConsumeMultiToString(const C: TSysCharSet;
-      var ACapturedString: String; const AMinChars: Integer = 1;
-      const AMaxChars: Integer = Maxint): Integer;
+    function ConsumeMulti(const AAllowedChars: TSysCharSet;
+      const AAllowAllCharsAboveFF: Boolean = False; const AMinChars: Integer = 1;
+      const AMaxChars: Integer = MaxInt): Integer;
+    function ConsumeMultiToString(const AAllowedChars: TSysCharSet;
+      var ACapturedString: String; const AAllowAllCharsAboveFF: Boolean = False;
+      const AMinChars: Integer = 1; const AMaxChars: Integer = MaxInt): Integer;
     property ReachedEnd: Boolean read GetReachedEnd;
     property ReachedEnd: Boolean read GetReachedEnd;
     property RemainingCount: Integer read GetRemainingCount;
     property RemainingCount: Integer read GetRemainingCount;
     property Str: String read FStr;
     property Str: String read FStr;
@@ -68,10 +69,12 @@ begin
   Result := True;
   Result := True;
 end;
 end;
 
 
-function TStringScanner.ConsumeMulti(const C: TSysCharSet;
-  const AMinChars: Integer = 1; const AMaxChars: Integer = Maxint): Integer;
+function TStringScanner.ConsumeMulti(const AAllowedChars: TSysCharSet;
+  const AAllowAllCharsAboveFF: Boolean = False; const AMinChars: Integer = 1;
+  const AMaxChars: Integer = MaxInt): Integer;
 begin
 begin
-  if (AMinChars <= 0) or (AMinChars > AMaxChars) then
+  { AMinChars may be 0; it functions the same as 1 }
+  if (AMinChars < 0) or (AMinChars > AMaxChars) then
     raise Exception.Create('TStringScanner.ConsumeMulti: Invalid parameter');
     raise Exception.Create('TStringScanner.ConsumeMulti: Invalid parameter');
 
 
   const Remain = GetRemainingCount;
   const Remain = GetRemainingCount;
@@ -80,7 +83,8 @@ begin
 
 
   Result := 0;
   Result := 0;
   while (Result < AMaxChars) and (Result < Remain) and
   while (Result < AMaxChars) and (Result < Remain) and
-     CharInSet(FStr[FPosition + Result], C) do
+     (CharInSet(FStr[FPosition + Result], AAllowedChars) or
+      (AAllowAllCharsAboveFF and (Ord(FStr[FPosition + Result]) > $FF))) do
     Inc(Result);
     Inc(Result);
 
 
   if Result < AMinChars then
   if Result < AMinChars then
@@ -89,12 +93,12 @@ begin
     Inc(FPosition, Result);
     Inc(FPosition, Result);
 end;
 end;
 
 
-function TStringScanner.ConsumeMultiToString(const C: TSysCharSet;
-  var ACapturedString: String; const AMinChars: Integer = 1;
-  const AMaxChars: Integer = Maxint): Integer;
+function TStringScanner.ConsumeMultiToString(const AAllowedChars: TSysCharSet;
+  var ACapturedString: String; const AAllowAllCharsAboveFF: Boolean = False;
+  const AMinChars: Integer = 1; const AMaxChars: Integer = MaxInt): Integer;
 begin
 begin
   const StartPos = FPosition;
   const StartPos = FPosition;
-  Result := ConsumeMulti(C, AMinChars, AMaxChars);
+  Result := ConsumeMulti(AAllowedChars, AAllowAllCharsAboveFF, AMinChars, AMaxChars);
   if Result > 0 then
   if Result > 0 then
     ACapturedString := Copy(FStr, StartPos, Result)
     ACapturedString := Copy(FStr, StartPos, Result)
   else
   else

+ 20 - 19
Components/TrustFunc.pas

@@ -26,13 +26,13 @@ type
   TLoadTrustedLibraryOption = (ltloTrustAllOnDebug);
   TLoadTrustedLibraryOption = (ltloTrustAllOnDebug);
   TLoadTrustedLibraryOptions = set of TLoadTrustedLibraryOption;
   TLoadTrustedLibraryOptions = set of TLoadTrustedLibraryOption;
 
 
-function CheckFileTrust(const FileName: String; const Options: TCheckFileTrustOptions): TFileStream;
-function LoadTrustedLibrary(const FileName: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
+function CheckFileTrust(const Filename: String; const Options: TCheckFileTrustOptions): TFileStream;
+function LoadTrustedLibrary(const Filename: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
 
 
 implementation
 implementation
 
 
 uses
 uses
-  Winapi.Windows, System.SysUtils {$IFNDEF TRUSTALL}, ECDSA, SHA256, ISSigFunc {$ENDIF};
+  Winapi.Windows, System.SysUtils {$IFNDEF TRUSTALL}, ECDSA, SHA256, ISSigFunc, PathFunc {$ENDIF};
 
 
 function Win32ErrorString(ErrorCode: Integer): String;
 function Win32ErrorString(ErrorCode: Integer): String;
 { Like SysErrorMessage but also passes the FORMAT_MESSAGE_IGNORE_INSERTS flag
 { Like SysErrorMessage but also passes the FORMAT_MESSAGE_IGNORE_INSERTS flag
@@ -49,13 +49,13 @@ begin
   SetString(Result, Buffer, Len);
   SetString(Result, Buffer, Len);
 end;
 end;
 
 
-function CheckFileTrust(const FileName: String; const Options: TCheckFileTrustOptions): TFileStream;
+function CheckFileTrust(const Filename: String; const Options: TCheckFileTrustOptions): TFileStream;
 {$IFNDEF TRUSTALL}
 {$IFNDEF TRUSTALL}
 var
 var
   AllowedKeys: array of TECDSAKey;
   AllowedKeys: array of TECDSAKey;
 {$ENDIF}
 {$ENDIF}
 begin
 begin
-  var Attr := GetFileAttributes(PChar(FileName));
+  var Attr := GetFileAttributes(PChar(Filename));
   if (Attr = INVALID_FILE_ATTRIBUTES) or (Attr and faDirectory <> 0) then
   if (Attr = INVALID_FILE_ATTRIBUTES) or (Attr and faDirectory <> 0) then
     raise Exception.Create(Win32ErrorString(ERROR_FILE_NOT_FOUND));
     raise Exception.Create(Win32ErrorString(ERROR_FILE_NOT_FOUND));
 {$IFNDEF TRUSTALL}
 {$IFNDEF TRUSTALL}
@@ -63,6 +63,7 @@ begin
   if cftoTrustAllOnDebug in Options then
   if cftoTrustAllOnDebug in Options then
     Exit(nil);
     Exit(nil);
 {$ENDIF}
 {$ENDIF}
+  var ExpectedFileName: String;
   var ExpectedFileSize: Int64;
   var ExpectedFileSize: Int64;
   var ExpectedFileHash: TSHA256Digest;
   var ExpectedFileHash: TSHA256Digest;
 
 
@@ -87,15 +88,15 @@ begin
       AllowedKeys := [Key1];
       AllowedKeys := [Key1];
 
 
     { Verify signature }
     { Verify signature }
-    if not ISSigVerifySignature(Filename, AllowedKeys, ExpectedFileSize, ExpectedFileHash,
+    if not ISSigVerifySignature(Filename, AllowedKeys, ExpectedFileName, ExpectedFileSize, ExpectedFileHash,
       nil,
       nil,
       procedure(const Filename, SigFilename: String)
       procedure(const Filename, SigFilename: String)
       begin
       begin
-        raise Exception.CreateFmt('Signature file "%s" does not exist', [SigFileName]);
+        raise Exception.CreateFmt('Signature file "%s" does not exist', [SigFilename]);
       end,
       end,
       procedure(const Filename, SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
       procedure(const Filename, SigFilename: String; const VerifyResult: TISSigVerifySignatureResult)
       begin
       begin
-        raise Exception.CreateFmt('Signature file "%s" is not valid', [SigFileName]);
+        raise Exception.CreateFmt('Signature file "%s" is not valid', [SigFilename]);
       end
       end
     ) then
     ) then
       raise Exception.Create('Unexpected ISSigVerifySignature result');
       raise Exception.Create('Unexpected ISSigVerifySignature result');
@@ -105,15 +106,15 @@ begin
   end;
   end;
   
   
   { Verify file, keeping open afterwards if requested
   { Verify file, keeping open afterwards if requested
-    Also see Setup.ScriptFunc's ISSigVerify }
-  var F := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+    Also see Setup.ScriptFunc's ISSigVerify which can also keep open afterwards }
+  if (ExpectedFileName <> '') and not PathSame(PathExtractName(Filename), ExpectedFileName) then
+    raise Exception.CreateFmt('File "%s" is not trusted (incorrect name).', [Filename]);
+  var F := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
   try
   try
     if F.Size <> ExpectedFileSize then
     if F.Size <> ExpectedFileSize then
-      raise Exception.CreateFmt('File "%s" is not trusted (incorrect size).',
-        [FileName]);
+      raise Exception.CreateFmt('File "%s" is not trusted (incorrect size).', [Filename]);
     if not SHA256DigestsEqual(ISSigCalcStreamHash(F), ExpectedFileHash) then
     if not SHA256DigestsEqual(ISSigCalcStreamHash(F), ExpectedFileHash) then
-      raise Exception.CreateFmt('File "%s" is not trusted (incorrect hash).',
-        [FileName]);
+      raise Exception.CreateFmt('File "%s" is not trusted (incorrect hash).', [Filename]);
   except
   except
     FreeAndNil(F);
     FreeAndNil(F);
     raise;
     raise;
@@ -127,21 +128,21 @@ begin
 {$ENDIF}
 {$ENDIF}
 end;
 end;
 
 
-function DoLoadLibrary(const FileName: String): HMODULE;
+function DoLoadLibrary(const Filename: String): HMODULE;
 begin
 begin
-  Result := SafeLoadLibrary(PChar(FileName), SEM_NOOPENFILEERRORBOX);
+  Result := SafeLoadLibrary(PChar(Filename), SEM_NOOPENFILEERRORBOX);
   if Result = 0 then
   if Result = 0 then
     raise Exception.Create(Win32ErrorString(GetLastError));
     raise Exception.Create(Win32ErrorString(GetLastError));
 end;
 end;
 
 
-function LoadTrustedLibrary(const FileName: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
+function LoadTrustedLibrary(const Filename: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
 begin
 begin
   var CheckFileTrustOptions: TCheckFileTrustOptions := [cftoKeepOpen];
   var CheckFileTrustOptions: TCheckFileTrustOptions := [cftoKeepOpen];
   if ltloTrustAllOnDebug in Options then
   if ltloTrustAllOnDebug in Options then
     Include(CheckFileTrustOptions, cftoTrustAllOnDebug);
     Include(CheckFileTrustOptions, cftoTrustAllOnDebug);
-  const F = CheckFileTrust(FileName, CheckFileTrustOptions);
+  const F = CheckFileTrust(Filename, CheckFileTrustOptions);
   try
   try
-    Result := DoLoadLibrary(FileName);
+    Result := DoLoadLibrary(Filename);
   finally
   finally
     F.Free;
     F.Free;
   end;
   end;

+ 4 - 3
Examples/MyDll.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "MyDll.dll"
 file-size 21280
 file-size 21280
 file-hash f4e549ef947c33a61520a38c855583e48cfd1702303815123662f7e2e4e73e09
 file-hash f4e549ef947c33a61520a38c855583e48cfd1702303815123662f7e2e4e73e09
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 180da3187e447b568029067128d435e679f5f6989aa64b39880ed73288bf7c5c
-sig-s 237b83598d51f7e205ca437223fbe65f78598774b006b309805e48445399d29c
+sig-r 0ba33df66764201f643189531b10d687767275d5b42f61da16568854b2196577
+sig-s c19753f32422be3d924ca4ecca7529bcc098441d6b9055940fcbcf1c0e3fc4bc

+ 4 - 3
Examples/MyProg-Arm64.exe.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "MyProg-Arm64.exe"
 file-size 77960
 file-size 77960
 file-hash ca7812155ff5935264177277b7c351ef35deacfda114fe8418d65cbcf105883a
 file-hash ca7812155ff5935264177277b7c351ef35deacfda114fe8418d65cbcf105883a
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r bb674f9dedab8fa5ac52e2c7e7962b7ce259b8464d2c59b5fed1ae644a26ff9c
-sig-s c8f039a9d89c83704c47d94bf63515f635d452e54cefd61d99c50aa5e8fac257
+sig-r f3bdb92812f621a6de7ef9828368f7edf2576f96b984d50bbcefb2eba8cd9240
+sig-s b64a5109feb59393f3237df84c5b21965b46b4b76117316557d8e07d4dea86a0

+ 4 - 3
Examples/MyProg-x64.exe.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "MyProg-x64.exe"
 file-size 77960
 file-size 77960
 file-hash b50952f9af310be586746356508b9fd430dcbbaa155a04e6f9563632de0a023b
 file-hash b50952f9af310be586746356508b9fd430dcbbaa155a04e6f9563632de0a023b
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 5a2a353204285614686df1928a7953a78542a2eb83b129a8e97b526126948854
-sig-s fc65ef8728f1ac0b48ccaa228794191745ec361d2d92175c9aafac85f0aaffcd
+sig-r 0d70aa66576f8cb97ace74dc1d0348c7dfbd6d7d23ed1122185ecca3f79a8e76
+sig-s 6f04303418f230cf52e26285362e0214875f2bf40e9be1c5f9a1dad15649ef24

+ 4 - 3
Examples/MyProg.exe.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "MyProg.exe"
 file-size 78984
 file-size 78984
 file-hash be272491050410c39db97101f05e80ed5d30a10caca6bc9f02228aa9499e19c9
 file-hash be272491050410c39db97101f05e80ed5d30a10caca6bc9f02228aa9499e19c9
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r c9b85f334dcadca472e016f297b3c4c76a55f6a3997727eaf140676bcc74792c
-sig-s df60e6c6e59d8934b0694e5682503e4c34918dd73f1cbb99897ebb18944ac834
+sig-r a2475468aafe1b1841d57e2f863b3d4b30a9956bda1985b8937d0a75bddf13df
+sig-s 3d4a6eb8f93db576e61adf5a2f63e5c6db2cc5bfbd0cf5da8cbada673d458ca6

+ 4 - 3
Files/is7z.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "is7z.dll"
 file-size 992912
 file-size 992912
 file-hash 74081e3749ab6f833618c4a9efbb75537a4e68e6e0579a7b43270a38224dcb66
 file-hash 74081e3749ab6f833618c4a9efbb75537a4e68e6e0579a7b43270a38224dcb66
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 8e2689da63e4c4f9926a1c24b3cc1a70b3523d36b64a2e526c1e0c96e79644e8
-sig-s 8cb1f83607d7e62c5538dbc819dd2b566f321bffb7fc48000e53343a6ef62496
+sig-r 8a2fc6735ee531c609e8a42a6066082964146303014e2fb531f9ef7be4cbc7cd
+sig-s 18d2b1a76ac430bda8b45d3430084df49776ad572cc884ca041e0d8cf26276c6

+ 4 - 3
Files/is7zxa.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "is7zxa.dll"
 file-size 256656
 file-size 256656
 file-hash 930152b344518fe0a15592269d432c4433b675bbb898213b6c13d8e526d51edd
 file-hash 930152b344518fe0a15592269d432c4433b675bbb898213b6c13d8e526d51edd
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r cdb0f1f640929f50fa06b1ad5a071dfabdbfbe6721929264f6a3b5b3069c54c3
-sig-s 7abe56f825963e61a2bd8498e34e3e011c89ace7dd6726da53c6e248c60c187c
+sig-r bbfca4a72f28d37760e75e270e6f3019dc2702e665d97584b0afcd0b76b8ad60
+sig-s a7b5be3e031dd78e3ce7f90630ebf51fb6e27e4b47ac564db9dc818827f3023d

+ 4 - 3
Files/is7zxr.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "is7zxr.dll"
 file-size 208016
 file-size 208016
 file-hash a73acb58b85cce5cb686df5409eb18643797c44ed1820a32d092b20146ad1f6c
 file-hash a73acb58b85cce5cb686df5409eb18643797c44ed1820a32d092b20146ad1f6c
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r df4f24260ec3ea6fbd1420e1302fb2449e358106a1a42ae61dcf4ed15b39eb76
-sig-s 571e55a619f820d513746289ab2e1f815ce8e7cc392f90f4edaf56d25f808dff
+sig-r 1d0a3c4b863b4290c60b4af709909e0f4c8a109096c315ce5062d050e0c254fc
+sig-s 672acfb5b9a826c50e39a1607dc0c04647aaef75e9ee93113839fd179f64d009

+ 4 - 3
Files/isbunzip.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "isbunzip.dll"
 file-size 35616
 file-size 35616
 file-hash 31d04c1e4bfdfa34704c142fa98f80c0a3076e4b312d6ada57c4be9d9c7dcf26
 file-hash 31d04c1e4bfdfa34704c142fa98f80c0a3076e4b312d6ada57c4be9d9c7dcf26
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 460e8f09454711a91475bfecc3a1d13c18ca4041b75e79c8f863a9f6ac3f0855
-sig-s 398a131094d6d4965f616a1ae8d5fd7a3084fb2904a8cfc14ad659503887e4bb
+sig-r 6c4817d6d038737484fb61c62f8b7c7d6aa6beeb5670c11b5f8d6ae42dd6b4cf
+sig-s c62ef533b240cdba85350f01f9369e7cebfc8b30e2d83e15d2fef9302ba4861b

+ 4 - 3
Files/isbzip.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "isbzip.dll"
 file-size 39200
 file-size 39200
 file-hash 8072e83385afc4a84006271a87a11fc0a22b149cbd77322669ca56c470d28ced
 file-hash 8072e83385afc4a84006271a87a11fc0a22b149cbd77322669ca56c470d28ced
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r c5d2720f9be49d87c4800bd8717066613173fae1e26ffb9f31f304a1be40e71e
-sig-s c68f97d069e34e7b2b410222032401254c35641d293ebf3fa0078d19b3478db4
+sig-r 7d093d4fce5875c77a9ce077596c26bd1a06ff15f2795c59c0ccb2403f1081f9
+sig-s b1f7738c3e21f627748185d59132e926bb1519940249bb579c316449aefbcb89

+ 4 - 3
Files/islzma.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "islzma.dll"
 file-size 135816
 file-size 135816
 file-hash b252471e95f0853902b15ae71a90574f9b168f8d4a0c474b20537511f90220a5
 file-hash b252471e95f0853902b15ae71a90574f9b168f8d4a0c474b20537511f90220a5
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 63d9a298fdb44394705221a9e65d1fb459d20c73d26aa56cdacf8d0942896b64
-sig-s f7621fc374e28c22f21fcb0ce77acf8a6723c5d0934e6aa0f5a718afeea6cfb3
+sig-r e9202d1a1e43b43b44bf6187c0709b8ca461934499941e147f24f6b123ac9b62
+sig-s baa08eede390e0c152dd1b238b74aa91e057cad50be7a2eab76721d0c658c9b0

+ 4 - 3
Files/islzma32.exe.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "islzma32.exe"
 file-size 199304
 file-size 199304
 file-hash 5665e03297af04d4f90423b56e8b016b2924d91ba781573036b710044e843f0a
 file-hash 5665e03297af04d4f90423b56e8b016b2924d91ba781573036b710044e843f0a
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 53e7bc7e2f24dca57da19a5b921c0d8c693e3de6b70bf5e4eee8e46409885c82
-sig-s d0348f1cf9633d688163ecfb0af5f7213fd3f16270f8f515229ab05e08ed78f4
+sig-r 6c4aec258115243eacd7db49103ce1772c489cf7bc4c9931f095745203387f61
+sig-s 37e3f126dece0547de4f0cc810b5a84984fbd325a6a030e911d1c1eff6c6ed03

+ 4 - 3
Files/islzma64.exe.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "islzma64.exe"
 file-size 230536
 file-size 230536
 file-hash b0ad1857da7fb94b54988c7633578dc057b51cf921b94f6f2f7b57a113310712
 file-hash b0ad1857da7fb94b54988c7633578dc057b51cf921b94f6f2f7b57a113310712
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 12999c74a0cd2229d70f862efa4ea36acdaacc546148b60fc276ee4fa2de0dc4
-sig-s 11256db23361add72dee940e870bcad5dc179c77957d143a5a9201d70eb56499
+sig-r 6ffd0494e423b05ca1358fa9717591ce43ce4d43467d6ca0cc581fde426cef15
+sig-s 26e70aaa5db22b8d7261a837405dc61083593dfb864ccef0bd0eac3223abeb60

+ 4 - 3
Files/isscint.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "isscint.dll"
 file-size 809616
 file-size 809616
 file-hash 1a837b73d60a4d98060e8129a8da0b27e25445a2ee8f03b0118b0ec6213172b5
 file-hash 1a837b73d60a4d98060e8129a8da0b27e25445a2ee8f03b0118b0ec6213172b5
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 0bf97beadb36dc0c2fe551da903aaa47a48ed6e45675561f9981494c7c12587f
-sig-s 9be02aeb41908ade412eab6a1770a3356d09c8fa43e0445dedc4493a0fde74bc
+sig-r 4f4093af223ba477bd768ba65b61017f009f1f20bf9fceccae358d5e5675ced0
+sig-s 0d5b283181342e44d49c0363706355432526400211585d69ea3b14d743b26efd

+ 4 - 3
Files/isunzlib.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "isunzlib.dll"
 file-size 29472
 file-size 29472
 file-hash 8287d0e287a66ee78537c8d1d98e426562b95c50f569b92cea9ce36a9fa57e64
 file-hash 8287d0e287a66ee78537c8d1d98e426562b95c50f569b92cea9ce36a9fa57e64
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r c3250004a73dc6ed3be3c4faad66aee0768e49a7b4d0a6f9ec3f03d1924b1411
-sig-s 00da1d34b90c23ca78515e71263c768e0df0a0923c3d7532223ea60f8bab4936
+sig-r bef7420079e4b440739822dcc03031489e90e017ca17763627b75a3639910610
+sig-s e835d7ea5bc6fa9b0ef55377f01d276040b78708206bf875c6f7ed69f5ca2139

+ 4 - 3
Files/iszlib.dll.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "iszlib.dll"
 file-size 34592
 file-size 34592
 file-hash 14c0d4a2a41572384f8309cdf03de5c6e7ed46bef64cce70d989b2665eff1a47
 file-hash 14c0d4a2a41572384f8309cdf03de5c6e7ed46bef64cce70d989b2665eff1a47
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r e245c707db5d1f1d3f47226aa3923e0240e23abb8fa5077eb4fb7ffc776a89ff
-sig-s bf84dbda5c76cce509931aa05bdd9992f96154f9493345e7f1669e169f0b810c
+sig-r 590d17da6ab0782ce599550c483446fdd5bae5eb16dd8bd912d4ce61ef8b4a3e
+sig-s c745f5d6cb756f02ecac092cd48bff47a79b37c2bd05de292dd592642ac76a7e

+ 3 - 2
ISHelp/isxfunc.xml

@@ -1965,9 +1965,10 @@ end;</pre></example>
     <subcategory>
     <subcategory>
       <function>
       <function>
         <name>ISSigVerify</name>
         <name>ISSigVerify</name>
-        <prototype>function ISSigVerify(const AllowedKeysRuntimeIDs: TStringList; const Filename: String; const KeepOpen: Boolean): TFileStream;</prototype>
+        <prototype>function ISSigVerify(const AllowedKeysRuntimeIDs: TStringList; const Filename: String; const VerifyFilename: Boolean; const KeepOpen: Boolean): TFileStream;</prototype>
         <description><p>Verifies the signature of the specified file using the specified allowed keys, looked up using <link topic="issigkeyssection">[ISSigKeys] section</link> parameter <tt>RuntimeID</tt>. To allow all keys set AllowedKeysRuntimeIDs to <tt>nil</tt>. An exception will be raised upon failure.</p>
         <description><p>Verifies the signature of the specified file using the specified allowed keys, looked up using <link topic="issigkeyssection">[ISSigKeys] section</link> parameter <tt>RuntimeID</tt>. To allow all keys set AllowedKeysRuntimeIDs to <tt>nil</tt>. An exception will be raised upon failure.</p>
-<p>Returns a handle to the still open file if True is specified in the KeepOpen parameter, <tt>nil</tt> otherwise. It is recommended that you always specify True if you plan to use the file for anything after verification. Otherwise, you risk creating a Time-Of-Check to Time-Of-Use (TOCTOU) problem.</p></description>
+<p>If VerifyFilename is set to False the verification allows signatures for a different filename. It is recommended that you only set it to False if you don't know the name the file had when it the signature was created. The size and hash of the file must always match.</p>        
+<p>Returns a handle to the still open file if KeepOpen is set to True, <tt>nil</tt> otherwise. It is recommended that you always set it to True if you plan to use the file for anything after verification. Otherwise, you risk creating a Time-Of-Check to Time-Of-Use (TOCTOU) problem.</p></description>
         <example><pre>var
         <example><pre>var
   F: TFileStream;
   F: TFileStream;
 begin
 begin

+ 16 - 6
Projects/ISSigTool.dpr

@@ -170,6 +170,7 @@ procedure SignSingleFile(const AKey: TECDSAKey; const AFilename: String);
 begin
 begin
   PrintFmtUnlessQuiet('%s: ', [AFilename], False);
   PrintFmtUnlessQuiet('%s: ', [AFilename], False);
 
 
+  const FileName = PathExtractName(AFilename);
   var FileSize: Int64;
   var FileSize: Int64;
   var FileHash: TSHA256Digest;
   var FileHash: TSHA256Digest;
   const F = TFile.Create(AFilename, fdOpenExisting, faRead, fsRead);
   const F = TFile.Create(AFilename, fdOpenExisting, faRead, fsRead);
@@ -184,20 +185,23 @@ begin
     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
-    all up to date, then we skip creation of a new .issig file. }
+    verify the existing .issig file. If the existing values exactly match
+    what we would have written, then we skip creation of a new .issig file.
+    Note that "file-name" is compared case-sensitively here because we don't
+    want to impede the user's ability to correct case mistakes. }
+  var ExistingFileName: String;
   var ExistingFileSize: Int64;
   var ExistingFileSize: Int64;
   var ExistingFileHash: TSHA256Digest;
   var ExistingFileHash: TSHA256Digest;
   const Verified = ISSigVerifySignature(AFilename, [AKey],
   const Verified = ISSigVerifySignature(AFilename, [AKey],
-    ExistingFileSize, ExistingFileHash, nil, nil, nil);
+    ExistingFileName, ExistingFileSize, ExistingFileHash, nil, nil, nil);
 
 
-  if Verified and (FileSize = ExistingFileSize) and
+  if Verified and (FileName = ExistingFileName) and (FileSize = ExistingFileSize) and
      SHA256DigestsEqual(FileHash, ExistingFileHash) then begin
      SHA256DigestsEqual(FileHash, ExistingFileHash) then begin
     PrintUnlessQuiet('signature unchanged');
     PrintUnlessQuiet('signature unchanged');
     Exit;
     Exit;
   end;
   end;
 
 
-  const SigText = ISSigCreateSignatureText(AKey, FileSize, FileHash);
+  const SigText = ISSigCreateSignatureText(AKey, FileName, FileSize, FileHash);
   ISSigSaveTextToFile(AFilename + ISSigExt, SigText);
   ISSigSaveTextToFile(AFilename + ISSigExt, SigText);
   PrintUnlessQuiet('signature written');
   PrintUnlessQuiet('signature written');
 end;
 end;
@@ -220,9 +224,10 @@ begin
   Result := False;
   Result := False;
   PrintFmtUnlessQuiet('%s: ', [AFilename], False);
   PrintFmtUnlessQuiet('%s: ', [AFilename], False);
 
 
+  var ExpectedFileName: String;
   var ExpectedFileSize: Int64;
   var ExpectedFileSize: Int64;
   var ExpectedFileHash: TSHA256Digest;
   var ExpectedFileHash: TSHA256Digest;
-  if not ISSigVerifySignature(AFilename, [AKey], ExpectedFileSize, ExpectedFileHash,
+  if not ISSigVerifySignature(AFilename, [AKey], ExpectedFileName, ExpectedFileSize, ExpectedFileHash,
     procedure(const Filename: String)
     procedure(const Filename: String)
     begin
     begin
       PrintUnlessQuiet('MISSINGFILE (File does not exist)');
       PrintUnlessQuiet('MISSINGFILE (File does not exist)');
@@ -245,6 +250,11 @@ begin
   ) then
   ) then
     Exit;
     Exit;
 
 
+  if (ExpectedFileName <> '') and not PathSame(PathExtractName(AFilename), ExpectedFileName) then begin
+    PrintUnlessQuiet('WRONGNAME (File name is incorrect)');
+    Exit;
+  end;
+
   const F = TFile.Create(AFilename, fdOpenExisting, faRead, fsRead);
   const F = TFile.Create(AFilename, fdOpenExisting, faRead, fsRead);
   try
   try
     if Int64(F.Size) <> ExpectedFileSize then begin
     if Int64(F.Size) <> ExpectedFileSize then begin

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

@@ -90,6 +90,7 @@ const
   SCompilerVerificationSignatureMalformed = 'The signature file "%s" is malformed';
   SCompilerVerificationSignatureMalformed = 'The signature file "%s" is malformed';
   SCompilerVerificationSignatureBad = 'The signature file "%s" is bad';
   SCompilerVerificationSignatureBad = 'The signature file "%s" is bad';
   SCompilerVerificationKeyNotFound = 'The signature file "%s" uses an unknown key';
   SCompilerVerificationKeyNotFound = 'The signature file "%s" uses an unknown key';
+  SCompilerVerificationFileNameIncorrect = 'The name of the file is incorrect';
   SCompilerVerificationFileSizeIncorrect = 'The size of the file is incorrect';
   SCompilerVerificationFileSizeIncorrect = 'The size of the file is incorrect';
   SCompilerVerificationFileHashIncorrect = 'The hash of the file is incorrect';
   SCompilerVerificationFileHashIncorrect = 'The hash of the file is incorrect';
   SCompilerCopyError3a = 'Could not copy "%s" to "%s".' + SNewLine2 + 'Error %s';
   SCompilerCopyError3a = 'Could not copy "%s" to "%s".' + SNewLine2 + 'Error %s';

+ 6 - 2
Projects/Src/Compiler.SetupCompiler.pas

@@ -6680,7 +6680,8 @@ const
   Messages: array[TVerificationError] of String =
   Messages: array[TVerificationError] of String =
     (SCompilerVerificationSignatureDoesntExist, SCompilerVerificationSignatureMalformed,
     (SCompilerVerificationSignatureDoesntExist, SCompilerVerificationSignatureMalformed,
      SCompilerVerificationKeyNotFound, SCompilerVerificationSignatureBad,
      SCompilerVerificationKeyNotFound, SCompilerVerificationSignatureBad,
-     SCompilerVerificationFileSizeIncorrect, SCompilerVerificationFileHashIncorrect);
+     SCompilerVerificationFileNameIncorrect, SCompilerVerificationFileSizeIncorrect,
+     SCompilerVerificationFileHashIncorrect);
 begin
 begin
   { Also see Setup.Install for a similar function }
   { Also see Setup.Install for a similar function }
   AbortCompileFmt(SCompilerSourceFileVerificationFailed,
   AbortCompileFmt(SCompilerSourceFileVerificationFailed,
@@ -7186,10 +7187,11 @@ 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']);
+            var ExpectedFileName: String;
             var ExpectedFileSize: Int64;
             var ExpectedFileSize: Int64;
             if not ISSigVerifySignature(FileLocationEntryFilenames[I],
             if not ISSigVerifySignature(FileLocationEntryFilenames[I],
               GetISSigAllowedKeys(ISSigAvailableKeys, FLExtraInfo.Verification.ISSigAllowedKeys),
               GetISSigAllowedKeys(ISSigAvailableKeys, FLExtraInfo.Verification.ISSigAllowedKeys),
-              ExpectedFileSize, ExpectedFileHash, FLExtraInfo.ISSigKeyUsedID,
+              ExpectedFileName, ExpectedFileSize, ExpectedFileHash, FLExtraInfo.ISSigKeyUsedID,
               nil,
               nil,
               procedure(const Filename, SigFilename: String)
               procedure(const Filename, SigFilename: String)
               begin
               begin
@@ -7208,6 +7210,8 @@ var
               end
               end
             ) then
             ) then
               AbortCompileFmt(SCompilerCompressInternalError, ['Unexpected ISSigVerifySignature result']);
               AbortCompileFmt(SCompilerCompressInternalError, ['Unexpected ISSigVerifySignature result']);
+            if (ExpectedFileName <> '') and not PathSame(PathExtractName(FileLocationEntryFilenames[I]), ExpectedFileName) then
+              VerificationError(veFileNameIncorrect, FileLocationEntryFilenames[I]);
             if Int64(SourceFile.Size) <> ExpectedFileSize then
             if Int64(SourceFile.Size) <> ExpectedFileSize then
               VerificationError(veFileSizeIncorrect, FileLocationEntryFilenames[I]);
               VerificationError(veFileSizeIncorrect, FileLocationEntryFilenames[I]);
             { ExpectedFileHash checked below after compression }
             { ExpectedFileHash checked below after compression }

+ 4 - 3
Projects/Src/Compression.LZMA1SmallDecompressor/LzmaDecode/LzmaDecodeInno.obj.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "LzmaDecodeInno.obj"
 file-size 8111
 file-size 8111
 file-hash 25a946de5cd685e1b010293665ee04eaa24ac9a345a31afaa82217e273459b2c
 file-hash 25a946de5cd685e1b010293665ee04eaa24ac9a345a31afaa82217e273459b2c
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r ebd4a121bba6483e335759c41c285aa582a3d9d1fe5aa0261d86a187d19fc035
-sig-s c0f9e67aaa8c548bf13edb5f4edb1ada130aaa0355e3e702bc837f3121be964c
+sig-r f6485228a0d808247279e2a353749a009fe9fb8db1bb317d4fee446fb8c59528
+sig-s 360700779e90850e42d67d0962cc8ff6debbd532f7eec8003cb20fcf0c823b51

+ 4 - 3
Projects/Src/Compression.LZMADecompressor/Lzma2Decode/ISLzmaDec.obj.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "ISLzmaDec.obj"
 file-size 21751
 file-size 21751
 file-hash 79bb11fbe0b862b6a42af2db4664748daa54347d56b3c40998dcb860111195ac
 file-hash 79bb11fbe0b862b6a42af2db4664748daa54347d56b3c40998dcb860111195ac
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 9dd4d53f2270c6a0f415fcc553e561b67cc0ba9f067c497f9aa4c40625263737
-sig-s ad98a5f58bff21054c51bc25f4c95fad3e7f669bf1b7068901a52b503414516b
+sig-r d183a61aaf8de0b72176e9dd613cc568371866be46683d0b47953794879c6db2
+sig-s ae48b841c532c852fc985d9fe95ae030fe4220735c53eb8d7d9374922a364636

+ 4 - 3
Projects/Src/Compression.SevenZipDecoder/7zDecode/IS7zDec.obj.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "IS7zDec.obj"
 file-size 93886
 file-size 93886
 file-hash 43ef412680232ecf42556737b7ea1c341f8134e64bf0b36932458e97d569d7c5
 file-hash 43ef412680232ecf42556737b7ea1c341f8134e64bf0b36932458e97d569d7c5
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r 6311ecc5160524349d2ae725ca31f605cfed4452f9b501bc082e6f8a75211106
-sig-s f2162f7b1aae75c9328b79b334d1d66474de3ef417440ceb500a0d83c249f371
+sig-r b3ecb3cf5bbf3c5feded032817f2821df7d845b690f67572584342f9c4f7ab95
+sig-s bd4b2d56fe4133866bc3466acd533eb6972cee09553963a0a35f2e630d389704

+ 4 - 3
Projects/Src/Setup.HelperEXEs.res.issig

@@ -1,6 +1,7 @@
-format issig-v1
+format issig-v2
+file-name "Setup.HelperEXEs.res"
 file-size 6240
 file-size 6240
 file-hash 0c384c152e4686c6a6a1dbdb1376f9076baa13ad7d6db9891745187f8212f393
 file-hash 0c384c152e4686c6a6a1dbdb1376f9076baa13ad7d6db9891745187f8212f393
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
 key-id def0147c3bbc17ab99bf7b7a9c2de1390283f38972152418d7c2a4a7d7131a38
-sig-r ae63371b72241fb9bc4d2ada583a4ff3443261a59885fe5e0b5362c41dde704e
-sig-s 529f2dd4c752daa00e78cdb19579bc22a404b578dcd487209b93580ee652bce9
+sig-r 0c69711682123f852b3690a952743f283386d3f79f8a8131193acddb054eff14
+sig-s 425cbce2b075dc68d91b51b180fe3dfdce5d8e42d803968005b9be57cecdaa11

+ 17 - 11
Projects/Src/Setup.Install.pas

@@ -20,7 +20,7 @@ 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;
-  const SourceFilename: String; const ISSigAllowedKeys: AnsiString;
+  const SourceFilename: String; const VerifySourceFilename: Boolean; const ISSigAllowedKeys: AnsiString;
   out ExpectedFileHash: TSHA256Digest);
   out ExpectedFileHash: TSHA256Digest);
 
 
 procedure PerformInstall(var Succeeded: Boolean; const ChangesEnvironment,
 procedure PerformInstall(var Succeeded: Boolean; const ChangesEnvironment,
@@ -301,10 +301,11 @@ procedure VerificationError(const AError: TVerificationError;
 const
 const
   LogMessages: array[TVerificationError] 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 name is incorrect', 'File size is incorrect', 'File hash is incorrect');
   SetupMessageIDs: array[TVerificationError] of TSetupMessageID =
   SetupMessageIDs: array[TVerificationError] of TSetupMessageID =
     (msgVerificationSignatureDoesntExist, msgVerificationSignatureInvalid, msgVerificationKeyNotFound,
     (msgVerificationSignatureDoesntExist, msgVerificationSignatureInvalid, msgVerificationKeyNotFound,
-     msgVerificationSignatureInvalid, msgVerificationFileSizeIncorrect, msgVerificationFileHashIncorrect);
+     msgVerificationSignatureInvalid, msgVerificationFileNameIncorrect, msgVerificationFileSizeIncorrect,
+     msgVerificationFileHashIncorrect);
 begin
 begin
   { Also see Compiler.SetupCompiler for a similar function }
   { Also see Compiler.SetupCompiler for a similar function }
   Log('Verification error: ' + AddPeriod(LogMessages[AError]));
   Log('Verification error: ' + AddPeriod(LogMessages[AError]));
@@ -313,7 +314,7 @@ begin
 end;
 end;
 
 
 procedure DoISSigVerify(const SourceF: TFile; const SourceFS: TFileStream;
 procedure DoISSigVerify(const SourceF: TFile; const SourceFS: TFileStream;
-  const SourceFilename: String; const ISSigAllowedKeys: AnsiString;
+  const SourceFilename: String; const VerifySourceFilename: Boolean; const ISSigAllowedKeys: AnsiString;
   out ExpectedFileHash: TSHA256Digest);
   out ExpectedFileHash: TSHA256Digest);
 { Does not disable FS redirection. Either SourceF or SourceFS must be set, which
 { Does not disable FS redirection. Either SourceF or SourceFS must be set, which
   may be opened for writing instead of reading.  }
   may be opened for writing instead of reading.  }
@@ -321,10 +322,11 @@ begin
   if ((SourceF = nil) and (SourceFS = nil)) or ((SourceF <> nil) and (SourceFS <> nil)) then
   if ((SourceF = nil) and (SourceFS = nil)) or ((SourceF <> nil) and (SourceFS <> nil)) then
     InternalError('DoISSigVerify: Invalid SourceF / SourceFS combination');
     InternalError('DoISSigVerify: Invalid SourceF / SourceFS combination');
 
 
+  var ExpectedFileName: String;
   var ExpectedFileSize: Int64;
   var ExpectedFileSize: Int64;
   if not ISSigVerifySignature(SourceFilename,
   if not ISSigVerifySignature(SourceFilename,
     GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
     GetISSigAllowedKeys(ISSigAvailableKeys, ISSigAllowedKeys),
-    ExpectedFileSize, ExpectedFileHash,
+    ExpectedFileName, ExpectedFileSize, ExpectedFileHash,
     nil,
     nil,
     procedure(const Filename, SigFilename: String)
     procedure(const Filename, SigFilename: String)
     begin
     begin
@@ -342,6 +344,8 @@ begin
     end
     end
   ) then
   ) then
     InternalError('Unexpected ISSigVerifySignature result');
     InternalError('Unexpected ISSigVerifySignature result');
+  if VerifySourceFilename and (ExpectedFileName <> '') and not PathSame(PathExtractName(SourceFilename), ExpectedFileName) then
+    VerificationError(veFileNameIncorrect);
   var FileSize: Int64;
   var FileSize: Int64;
   if SourceF <> nil then
   if SourceF <> nil then
     FileSize := Int64(SourceF.Size)
     FileSize := Int64(SourceF.Size)
@@ -371,7 +375,7 @@ begin
     if Verification.Typ = fvHash then
     if Verification.Typ = fvHash then
       ExpectedFileHash := Verification.Hash
       ExpectedFileHash := Verification.Hash
     else
     else
-      DoISSigVerify(SourceF, nil, ISSigSourceFilename, Verification.ISSigAllowedKeys, ExpectedFileHash);
+      DoISSigVerify(SourceF, nil, ISSigSourceFilename, True, Verification.ISSigAllowedKeys, ExpectedFileHash);
     { ExpectedFileHash checked below after copy }
     { ExpectedFileHash checked below after copy }
     SHA256Init(Context);
     SHA256Init(Context);
   end;
   end;
@@ -2052,8 +2056,8 @@ var
               if CurFile^.Verification.Typ = fvHash then
               if CurFile^.Verification.Typ = fvHash then
                 ExpectedFileHash := CurFile^.Verification.Hash
                 ExpectedFileHash := CurFile^.Verification.Hash
               else begin
               else begin
-                DoISSigVerify(VerifySourceF, nil, ArchiveFilename, CurFile^.Verification.ISSigAllowedKeys,
-                ExpectedFileHash);
+                DoISSigVerify(VerifySourceF, nil, ArchiveFilename, True, CurFile^.Verification.ISSigAllowedKeys,
+                  ExpectedFileHash);
               end;
               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(VerifySourceF);
               const ActualFileHash = GetSHA256OfFile(VerifySourceF);
@@ -3874,7 +3878,7 @@ begin
         if Verification.Typ = fvHash then
         if Verification.Typ = fvHash then
           ExpectedFileHash := Verification.Hash
           ExpectedFileHash := Verification.Hash
         else
         else
-          DoISSigVerify(DestF, nil, ISSigSourceFilename, Verification.ISSigAllowedKeys, ExpectedFileHash);
+          DoISSigVerify(DestF, nil, ISSigSourceFilename, False, Verification.ISSigAllowedKeys, ExpectedFileHash);
         const FileHash = GetSHA256OfFile(DestF);
         const FileHash = GetSHA256OfFile(DestF);
         if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
         if not SHA256DigestsEqual(FileHash, ExpectedFileHash) then
           VerificationError(veFileHashIncorrect);
           VerificationError(veFileHashIncorrect);
@@ -3931,12 +3935,14 @@ begin
         Exit;
         Exit;
       end;
       end;
     end else if Verification.Typ = fvISSig then begin
     end else if Verification.Typ = fvISSig then begin
+      var ExistingFileName: String;
       var ExistingFileSize: Int64;
       var ExistingFileSize: Int64;
       var ExistingFileHash: TSHA256Digest;
       var ExistingFileHash: TSHA256Digest;
       if ISSigVerifySignature(DestFile, GetISSigAllowedKeys(ISSigAvailableKeys, Verification.ISSigAllowedKeys),
       if ISSigVerifySignature(DestFile, GetISSigAllowedKeys(ISSigAvailableKeys, Verification.ISSigAllowedKeys),
-           ExistingFileSize, ExistingFileHash, nil, nil, nil) then begin
+           ExistingFileName, ExistingFileSize, ExistingFileHash, nil, nil, nil) then begin
         const DestF = TFile.Create(DestFile, fdOpenExisting, faRead, fsReadWrite);
         const DestF = TFile.Create(DestFile, fdOpenExisting, faRead, fsReadWrite);
         try
         try
+          { Not checking ExistingFileName because we can't be sure what the original filename was }
           if (Int64(DestF.Size) = ExistingFileSize) and
           if (Int64(DestF.Size) = ExistingFileSize) and
              (SHA256DigestsEqual(GetSHA256OfFile(DestF), ExistingFileHash)) then begin
              (SHA256DigestsEqual(GetSHA256OfFile(DestF), ExistingFileHash)) then begin
             Log('  File already downloaded.');
             Log('  File already downloaded.');
@@ -4013,7 +4019,7 @@ begin
         if Verification.Typ = fvHash then
         if Verification.Typ = fvHash then
           ExpectedFileHash := Verification.Hash
           ExpectedFileHash := Verification.Hash
         else
         else
-          DoISSigVerify(TempF, nil, DestFile, Verification.ISSigAllowedKeys, ExpectedFileHash);
+          DoISSigVerify(TempF, nil, DestFile, False, Verification.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

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

@@ -1879,14 +1879,15 @@ var
     begin
     begin
       const ISSigAllowedKeys = ConvertAllowedKeysRuntimeIDsToISSigAllowedKeys(TStringList(Stack.GetClass(PStart-1)));
       const ISSigAllowedKeys = ConvertAllowedKeysRuntimeIDsToISSigAllowedKeys(TStringList(Stack.GetClass(PStart-1)));
       const Filename = Stack.GetString(PStart-2);
       const Filename = Stack.GetString(PStart-2);
-      const KeepOpen = Stack.GetBool(PStart-3);
+      const VerifyFilename = Stack.GetBool(PStart-3);
+      const KeepOpen = Stack.GetBool(PStart-4);
 
 
       { Verify signature & file, keeping open afterwards if requested
       { Verify signature & file, keeping open afterwards if requested
-        Also see TrustFunc's CheckFileTrust }
+        Also see TrustFunc's CheckFileTrust which can also keep open afterwards }
       var F := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
       var F := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
       try
       try
         var ExpectedFileHash: TSHA256Digest;
         var ExpectedFileHash: TSHA256Digest;
-        DoISSigVerify(nil, F, Filename, ISSigAllowedKeys, ExpectedFileHash);
+        DoISSigVerify(nil, F, Filename, VerifyFilename, ISSigAllowedKeys, ExpectedFileHash);
          { 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

+ 1 - 1
Projects/Src/Shared.ScriptFunc.pas

@@ -547,7 +547,7 @@ initialization
     'function StringJoin(const Separator: String; const Values: TArrayOfString): String;',
     'function StringJoin(const Separator: String; const Values: TArrayOfString): String;',
     'function StringSplit(const S: String; const Separators: TArrayOfString; const Typ: TSplitType): TArrayOfString;',
     'function StringSplit(const S: String; const Separators: TArrayOfString; const Typ: TSplitType): TArrayOfString;',
     'function StringSplitEx(const S: String; const Separators: TArrayOfString; const Quote: Char; const Typ: TSplitType): TArrayOfString;',
     'function StringSplitEx(const S: String; const Separators: TArrayOfString; const Quote: Char; const Typ: TSplitType): TArrayOfString;',
-    'function ISSigVerify(const AllowedKeysRuntimeIDs: TStringList; const Filename: String; const KeepOpen: Boolean): TFileStream;'
+    'function ISSigVerify(const AllowedKeysRuntimeIDs: TStringList; const Filename: String; const VerifyFilename: Boolean; const KeepOpen: Boolean): TFileStream;'
   ];
   ];
 
 
   {$IFDEF COMPIL32PROJ}
   {$IFDEF COMPIL32PROJ}

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

@@ -40,7 +40,7 @@ type
   TArrayOfECDSAKey = array of TECDSAKey;
   TArrayOfECDSAKey = array of TECDSAKey;
 
 
   TVerificationError = (veSignatureMissing, veSignatureMalformed, veKeyNotFound,
   TVerificationError = (veSignatureMissing, veSignatureMalformed, veKeyNotFound,
-    veSignatureBad, veFileSizeIncorrect, veFileHashIncorrect);
+    veSignatureBad, veFileNameIncorrect, veFileSizeIncorrect, veFileHashIncorrect);
 
 
 const
 const
   crHand = 1;
   crHand = 1;