Browse Source

Minimal changes needed to compile against PuTTY 0.78 and pass tests

Source commit: c717fcdc41b9be7bb3a88e06fc49d45eaf0cfa44
Martin Prikryl 2 years ago
parent
commit
ec808580ce
52 changed files with 1195 additions and 619 deletions
  1. 61 7
      source/Putty.cbproj
  2. 222 156
      source/core/PuttyIntf.cpp
  3. 5 0
      source/core/SecureShell.cpp
  4. 4 4
      source/core/SessionData.cpp
  5. 5 5
      source/core/SessionData.h
  6. 1 1
      source/forms/SiteAdvanced.cpp
  7. 4 1
      source/putty/crypto/aes-ni.c
  8. 12 10
      source/putty/crypto/aes-select.c
  9. 6 2
      source/putty/crypto/aes-sw.c
  10. 22 20
      source/putty/crypto/aes.h
  11. 19 15
      source/putty/crypto/aesgcm-footer.h
  12. 19 4
      source/putty/crypto/aesgcm-ref-poly.c
  13. 9 6
      source/putty/crypto/aesgcm-select.c
  14. 17 3
      source/putty/crypto/aesgcm-sw.c
  15. 2 2
      source/putty/crypto/arcfour.c
  16. 3 3
      source/putty/crypto/blowfish.c
  17. 2 2
      source/putty/crypto/chacha20-poly1305.c
  18. 5 5
      source/putty/crypto/des.c
  19. 102 85
      source/putty/crypto/diffie-hellman.c
  20. 9 7
      source/putty/crypto/dsa.c
  21. 119 95
      source/putty/crypto/ecc-ssh.c
  22. 6 6
      source/putty/crypto/hmac.c
  23. 113 49
      source/putty/crypto/openssh-certs.c
  24. 34 19
      source/putty/crypto/rsa.c
  25. 2 0
      source/putty/misc.h
  26. 8 3
      source/putty/putty.h
  27. 1 14
      source/putty/puttyexp.h
  28. 4 0
      source/putty/settings.c
  29. 10 0
      source/putty/ssh.h
  30. 8 1
      source/putty/ssh/common_p.c
  31. 32 2
      source/putty/ssh/kex2-client.c
  32. 35 10
      source/putty/ssh/transport2.c
  33. 49 6
      source/putty/ssh/userauth2-client.c
  34. 4 0
      source/putty/sshpubk.c
  35. 2 2
      source/putty/stubs/null-opener.c
  36. 4 4
      source/putty/stubs/null-seat.c
  37. 4 1
      source/putty/utils/base64_decode.c
  38. 6 1
      source/putty/utils/base64_encode.c
  39. 42 7
      source/putty/utils/cert-expr.c
  40. 6 1
      source/putty/utils/key_components.c
  41. 2 1
      source/putty/utils/percent_decode.c
  42. 2 1
      source/putty/utils/percent_encode.c
  43. 4 2
      source/putty/utils/ptrlen.c
  44. 4 1
      source/putty/utils/seat_dialog_text.c
  45. 3 2
      source/putty/utils/tempseat.c
  46. 10 0
      source/putty/windows/network.c
  47. 16 2
      source/putty/windows/platform.h
  48. 63 25
      source/putty/windows/storage.c
  49. 4 0
      source/putty/windows/unicode.c
  50. 32 0
      source/putty/windows/utils/registry.c
  51. 19 13
      source/resource/TextsWin.h
  52. 18 13
      source/resource/TextsWin1.rc

+ 61 - 7
source/Putty.cbproj

@@ -103,6 +103,18 @@
 		<CppCompile Include="putty\crypto\aes-common.c">
 			<BuildOrder>9</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\crypto\aesgcm-common.c">
+			<BuildOrder>158</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\crypto\aesgcm-ref-poly.c">
+			<BuildOrder>159</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\crypto\aesgcm-select.c">
+			<BuildOrder>160</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\crypto\aesgcm-sw.c">
+			<BuildOrder>161</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\crypto\aesold.c">
 			<BuildOrder>150</BuildOrder>
 		</CppCompile>
@@ -163,6 +175,9 @@
 		<CppCompile Include="putty\crypto\mpint.c">
 			<BuildOrder>28</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\crypto\openssh-certs.c">
+			<BuildOrder>163</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\crypto\prng.c">
 			<BuildOrder>29</BuildOrder>
 		</CppCompile>
@@ -310,18 +325,42 @@
 		<CppCompile Include="putty\sshrand.c">
 			<BuildOrder>8</BuildOrder>
 		</CppCompile>
-		<CppCompile Include="putty\stubs\nullplug.c">
+		<CppCompile Include="putty\stubs\null-cipher.c">
+			<BuildOrder>153</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\stubs\null-key.c">
+			<BuildOrder>154</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\stubs\null-lp.c">
+			<BuildOrder>99</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\stubs\null-mac.c">
+			<BuildOrder>155</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\stubs\null-opener.c">
+			<BuildOrder>156</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\stubs\null-plug.c">
 			<BuildOrder>76</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\stubs\null-seat.c">
+			<BuildOrder>100</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\antispoof.c">
 			<BuildOrder>77</BuildOrder>
 		</CppCompile>
 		<CppCompile Include="putty\utils\backend_socket_log.c">
 			<BuildOrder>78</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\utils\base64_decode.c">
+			<BuildOrder>145</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\base64_decode_atom.c">
 			<BuildOrder>79</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\utils\base64_encode.c">
+			<BuildOrder>146</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\base64_encode_atom.c">
 			<BuildOrder>80</BuildOrder>
 		</CppCompile>
@@ -331,6 +370,9 @@
 		<CppCompile Include="putty\utils\burnstr.c">
 			<BuildOrder>151</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\utils\cert-expr.c">
+			<BuildOrder>147</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\conf.c">
 			<BuildOrder>82</BuildOrder>
 		</CppCompile>
@@ -355,6 +397,9 @@
 		<CppCompile Include="putty\utils\dupstr.c">
 			<BuildOrder>152</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\utils\host_ca_new_free.c">
+			<BuildOrder>148</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\host_strchr.c">
 			<BuildOrder>92</BuildOrder>
 		</CppCompile>
@@ -370,6 +415,9 @@
 		<CppCompile Include="putty\utils\host_strrchr.c">
 			<BuildOrder>94</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\utils\key_components.c">
+			<BuildOrder>149</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\log_proxy_stderr.c">
 			<BuildOrder>95</BuildOrder>
 		</CppCompile>
@@ -385,12 +433,6 @@
 		<CppCompile Include="putty\utils\memxor.c">
 			<BuildOrder>98</BuildOrder>
 		</CppCompile>
-		<CppCompile Include="putty\utils\null_lp.c">
-			<BuildOrder>99</BuildOrder>
-		</CppCompile>
-		<CppCompile Include="putty\utils\nullseat.c">
-			<BuildOrder>100</BuildOrder>
-		</CppCompile>
 		<CppCompile Include="putty\utils\nullstrcmp.c">
 			<BuildOrder>101</BuildOrder>
 		</CppCompile>
@@ -400,6 +442,12 @@
 		<CppCompile Include="putty\utils\parse_blocksize.c">
 			<BuildOrder>103</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\utils\percent_decode.c">
+			<BuildOrder>150</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\utils\percent_encode.c">
+			<BuildOrder>151</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\prompts.c">
 			<BuildOrder>104</BuildOrder>
 		</CppCompile>
@@ -409,6 +457,9 @@
 		<CppCompile Include="putty\utils\seat_connection_fatal.c">
 			<BuildOrder>107</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\utils\seat_dialog_text.c">
+			<BuildOrder>152</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\utils\sk_free_peer_info.c">
 			<BuildOrder>108</BuildOrder>
 		</CppCompile>
@@ -523,6 +574,9 @@
 		<CppCompile Include="putty\windows\utils\open_for_write_would_lose_data.c">
 			<BuildOrder>149</BuildOrder>
 		</CppCompile>
+		<CppCompile Include="putty\windows\utils\registry.c">
+			<BuildOrder>162</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\windows\utils\security_p.c">
 			<BuildOrder>150</BuildOrder>
 		</CppCompile>

+ 222 - 156
source/core/PuttyIntf.cpp

@@ -257,8 +257,9 @@ static void connection_fatal(Seat * seat, const char * message)
 }
 //---------------------------------------------------------------------------
 SeatPromptResult confirm_ssh_host_key(Seat * seat, const char * host, int port, const char * keytype,
-  char * keystr, const char * DebugUsedArg(keydisp), char ** key_fingerprints, bool DebugUsedArg(mismatch),
-  void (*DebugUsedArg(callback))(void *ctx, SeatPromptResult result), void * DebugUsedArg(ctx))
+  char * keystr, SeatDialogText *, HelpCtx,
+  void (*DebugUsedArg(callback))(void *ctx, SeatPromptResult result), void * DebugUsedArg(ctx),
+  char **key_fingerprints)
 {
   UnicodeString FingerprintSHA256, FingerprintMD5;
   if (key_fingerprints[SSH_FPTYPE_SHA256] != NULL)
@@ -299,6 +300,17 @@ SeatPromptResult confirm_weak_cached_hostkey(Seat *, const char * /*algname*/, c
   return SPR_OK;
 }
 //---------------------------------------------------------------------------
+const SeatDialogPromptDescriptions * prompt_descriptions(Seat *)
+{
+    static const SeatDialogPromptDescriptions descs = {
+        /*.hk_accept_action =*/ "",
+        /*.hk_connect_once_action =*/ "",
+        /*.hk_cancel_action =*/ "",
+        /*.hk_cancel_action_Participle =*/ "",
+    };
+    return &descs;
+}
+//---------------------------------------------------------------------------
 void old_keyfile_warning(void)
 {
   // no reference to TSecureShell instance available
@@ -418,6 +430,7 @@ static const SeatVtable ScpSeatVtable =
     confirm_ssh_host_key,
     confirm_weak_crypto_primitive,
     confirm_weak_cached_hostkey,
+    prompt_descriptions,
     nullseat_is_always_utf8,
     nullseat_echoedit_update,
     nullseat_get_x_display,
@@ -443,183 +456,222 @@ enum TPuttyRegistryMode { prmPass, prmRedirect, prmCollect, prmFail };
 static TPuttyRegistryMode PuttyRegistryMode = prmRedirect;
 typedef std::map<UnicodeString, unsigned long> TPuttyRegistryTypes;
 TPuttyRegistryTypes PuttyRegistryTypes;
+HKEY RandSeedFileStorage = reinterpret_cast<HKEY>(1);
 //---------------------------------------------------------------------------
-static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool CanCreate)
+int reg_override_winscp()
 {
-  long R;
-
-  DebugAssert(Key == HKEY_CURRENT_USER);
-  DebugUsedParam(Key);
-
-  UnicodeString RegKey = SubKey;
-  int PuttyKeyLen = OriginalPuttyRegistryStorageKey.Length();
-  DebugAssert(RegKey.SubString(1, PuttyKeyLen) == OriginalPuttyRegistryStorageKey);
-  RegKey = RegKey.SubString(PuttyKeyLen + 1, RegKey.Length() - PuttyKeyLen);
-  if (!RegKey.IsEmpty())
+  return (PuttyRegistryMode != prmPass);
+}
+//---------------------------------------------------------------------------
+HKEY open_regkey_fn_winscp(bool Create, HKEY Key, const char * Path, ...)
+{
+  HKEY Result;
+  if (PuttyRegistryMode == prmCollect)
   {
-    DebugAssert(RegKey[1] == L'\\');
-    RegKey.Delete(1, 1);
+    Result = reinterpret_cast<HKEY>(1);
   }
-
-  if (RegKey.IsEmpty())
+  else if (PuttyRegistryMode == prmFail)
   {
-    *Result = static_cast<HKEY>(NULL);
-    R = ERROR_SUCCESS;
+    Result = false;
   }
-  else
+  else if (PuttyRegistryMode == prmRedirect)
   {
-    // we expect this to be called only from retrieve_host_key() or store_host_key()
-    DebugAssert(RegKey == L"SshHostKeys");
+    DebugAssert(Key == HKEY_CURRENT_USER);
+    DebugUsedParam(Key);
+
+    UnicodeString SubKey;
+    va_list ap;
+    va_start(ap, Path);
 
-    DebugAssert(PuttyStorage != NULL);
-    DebugAssert(PuttyStorage->AccessMode == (CanCreate ? smReadWrite : smRead));
-    if (PuttyStorage->OpenSubKey(RegKey, CanCreate))
+    for (; Path; Path = va_arg(ap, const char *))
     {
-      *Result = reinterpret_cast<HKEY>(PuttyStorage);
-      R = ERROR_SUCCESS;
+      if (!SubKey.IsEmpty())
+      {
+        SubKey = IncludeTrailingBackslash(SubKey);
+      }
+      SubKey += UnicodeString(UTF8String(Path));
     }
-    else
+
+    int PuttyKeyLen = OriginalPuttyRegistryStorageKey.Length();
+    DebugAssert(SubKey.SubString(1, PuttyKeyLen) == OriginalPuttyRegistryStorageKey);
+    UnicodeString RegKey = SubKey.SubString(PuttyKeyLen + 1, SubKey.Length() - PuttyKeyLen);
+    if (!RegKey.IsEmpty())
     {
-      R = ERROR_CANTOPEN;
+      DebugAssert(RegKey[1] == L'\\');
+      RegKey.Delete(1, 1);
     }
-  }
 
-  return R;
-}
-//---------------------------------------------------------------------------
-long reg_open_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
-{
-  if (PuttyRegistryMode == prmPass)
-  {
-    return RegOpenKeyA(Key, SubKey, Result);
-  }
-  else if (PuttyRegistryMode == prmCollect)
-  {
-    *Result = reinterpret_cast<HKEY>(1);
-    return ERROR_SUCCESS;
+    if (RegKey.IsEmpty())
+    {
+      // Called from access_random_seed()
+      Result = RandSeedFileStorage;
+    }
+    else
+    {
+      // we expect this to be called only from retrieve_host_key() or store_host_key()
+      DebugAssert(RegKey == L"SshHostKeys");
+
+      DebugAssert(PuttyStorage != NULL);
+      DebugAssert(PuttyStorage->AccessMode == (Create ? smReadWrite : smRead));
+      if (PuttyStorage->OpenSubKey(RegKey, Create))
+      {
+        Result = reinterpret_cast<HKEY>(PuttyStorage);
+      }
+      else
+      {
+        Result = NULL;
+      }
+    }
   }
-  else if (PuttyRegistryMode == prmFail)
+  else
   {
-    return ERROR_CANTOPEN;
+    DebugFail();
+    Result = NULL;
   }
-
-  DebugAssert(PuttyRegistryMode == prmRedirect);
-  return OpenWinSCPKey(Key, SubKey, Result, false);
+  return Result;
 }
 //---------------------------------------------------------------------------
-long reg_create_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
+bool get_reg_dword_winscp(HKEY, const char * DebugUsedArg(Name), DWORD * DebugUsedArg(Out))
 {
-  if (PuttyRegistryMode == prmPass)
+  bool Result;
+  if (PuttyRegistryMode == prmFail)
   {
-    return RegCreateKeyA(Key, SubKey, Result);
+    Result = false;
   }
   else if (PuttyRegistryMode == prmCollect)
   {
-    *Result = reinterpret_cast<HKEY>(1);
-    return ERROR_SUCCESS;
+    Result = false;
   }
-
-  DebugAssert(PuttyRegistryMode == prmRedirect);
-  return OpenWinSCPKey(Key, SubKey, Result, true);
+  else
+  {
+    DebugFail();
+    Result = false;
+  }
+  return false;
 }
 //---------------------------------------------------------------------------
-long reg_query_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long * Reserved,
-  unsigned long * Type, unsigned char * Data, unsigned long * DataSize)
+char * get_reg_sz_winscp(HKEY Key, const char * Name)
 {
-  if (PuttyRegistryMode == prmPass)
+  char * Result;
+  if (PuttyRegistryMode == prmCollect)
   {
-    return RegQueryValueExA(Key, ValueName, Reserved, Type, Data, DataSize);
+    Result = NULL;
   }
-  else if (PuttyRegistryMode == prmCollect)
+  else if (DebugAlwaysTrue(PuttyRegistryMode == prmRedirect))
   {
-    return ERROR_READ_FAULT;
-  }
+    DebugAssert(Configuration != NULL);
 
-  DebugAssert(PuttyRegistryMode == prmRedirect);
-  long R;
-  DebugAssert(Configuration != NULL);
-
-  THierarchicalStorage * Storage = reinterpret_cast<THierarchicalStorage *>(Key);
-  AnsiString Value;
-  if (Storage == NULL)
-  {
-    if (UnicodeString(ValueName) == L"RandSeedFile")
+    UnicodeString ValueName = UTF8String(Name);
+    bool Success;
+    UnicodeString Value;
+    if (Key == RandSeedFileStorage)
     {
-      Value = AnsiString(Configuration->RandomSeedFileName);
-      R = ERROR_SUCCESS;
+      if (ValueName == L"RandSeedFile")
+      {
+        Value = Configuration->RandomSeedFileName;
+        Success = true;
+      }
+      else
+      {
+        DebugFail();
+        Success = false;
+      }
     }
     else
     {
-      DebugFail();
-      R = ERROR_READ_FAULT;
+      THierarchicalStorage * Storage = reinterpret_cast<THierarchicalStorage *>(Key);
+      if (Storage->ValueExists(ValueName))
+      {
+        Value = Storage->ReadStringRaw(ValueName, L"");
+        Success = true;
+      }
+      else
+      {
+        Success = false;
+      }
     }
-  }
-  else
-  {
-    if (Storage->ValueExists(ValueName))
+
+    if (!Success)
     {
-      Value = AnsiString(Storage->ReadStringRaw(ValueName, L""));
-      R = ERROR_SUCCESS;
+      Result = NULL;
     }
     else
     {
-      R = ERROR_READ_FAULT;
+      AnsiString ValueAnsi = AnsiString(Value);
+      Result = snewn(ValueAnsi.Length() + 1, char);
+      strcpy(Result, ValueAnsi.c_str());
     }
   }
-
-  if (R == ERROR_SUCCESS)
+  else
   {
-    DebugAssert(Type != NULL);
-    *Type = REG_SZ;
-    char * DataStr = reinterpret_cast<char *>(Data);
-    strncpy(DataStr, Value.c_str(), *DataSize);
-    DataStr[*DataSize - 1] = '\0';
-    *DataSize = strlen(DataStr);
+    Result = NULL;
   }
-
-  return R;
+  return Result;
 }
 //---------------------------------------------------------------------------
-long reg_set_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long Reserved,
-  unsigned long Type, const unsigned char * Data, unsigned long DataSize)
+bool put_reg_dword_winscp(HKEY DebugUsedArg(Key), const char * Name, DWORD DebugUsedArg(Value))
 {
-  if (PuttyRegistryMode == prmPass)
+  bool Result;
+  if (PuttyRegistryMode == prmCollect)
   {
-    return RegSetValueExA(Key, ValueName, Reserved, Type, Data, DataSize);
+    UnicodeString ValueName = UTF8String(Name);
+    PuttyRegistryTypes[ValueName] = REG_DWORD;
+    Result = true;
   }
-  else if (PuttyRegistryMode == prmCollect)
+  else if (PuttyRegistryMode == prmRedirect)
   {
-    PuttyRegistryTypes[ValueName] = Type;
-    return ERROR_SUCCESS;
+    // Might need to implement this for CA
+    DebugFail();
+    Result = false;
   }
-  DebugAssert(PuttyRegistryMode == prmRedirect);
-
-  DebugAssert(Type == REG_SZ);
-  DebugUsedParam(Type);
-  THierarchicalStorage * Storage = reinterpret_cast<THierarchicalStorage *>(Key);
-  DebugAssert(Storage != NULL);
-  if (Storage != NULL)
+  else
   {
-    UnicodeString Value(reinterpret_cast<const char*>(Data), DataSize - 1);
-    Storage->WriteStringRaw(ValueName, Value);
+    DebugFail();
+    return false;
   }
-
-  return ERROR_SUCCESS;
+  return Result;
 }
 //---------------------------------------------------------------------------
-long reg_close_winscp_key(HKEY Key)
+bool put_reg_sz_winscp(HKEY Key, const char * Name, const char * Str)
 {
-  if (PuttyRegistryMode == prmPass)
+  UnicodeString ValueName = UTF8String(Name);
+  bool Result;
+  if (PuttyRegistryMode == prmCollect)
   {
-    return RegCloseKey(Key);
+    PuttyRegistryTypes[ValueName] = REG_SZ;
+    Result = true;
   }
-  else if (PuttyRegistryMode == prmCollect)
+  else if (PuttyRegistryMode == prmRedirect)
   {
-    return ERROR_SUCCESS;
-  }
-  DebugAssert(PuttyRegistryMode == prmRedirect);
+    UnicodeString Value = UTF8String(Str);
+    DebugAssert(Key != RandSeedFileStorage);
+    THierarchicalStorage * Storage = reinterpret_cast<THierarchicalStorage *>(Key);
+    DebugAssert(Storage != NULL);
+    if (Storage != NULL)
+    {
+      Storage->WriteStringRaw(ValueName, Value);
+    }
 
-  return ERROR_SUCCESS;
+    Result = true;
+  }
+  else
+  {
+    DebugFail();
+    Result = false;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void close_regkey_winscp(HKEY)
+{
+  DebugAssert((PuttyRegistryMode == prmCollect) || (PuttyRegistryMode == prmRedirect));
+}
+//---------------------------------------------------------------------------
+strbuf * get_reg_multi_sz_winscp(HKEY, const char * DebugUsedArg(name))
+{
+  // Needed for CA
+  DebugFail();
+  return NULL;
 }
 //---------------------------------------------------------------------------
 TKeyType KeyType(UnicodeString FileName)
@@ -891,41 +943,46 @@ bool __fastcall HasGSSAPI(UnicodeString CustomPath)
 //---------------------------------------------------------------------------
 static void __fastcall DoNormalizeFingerprint(UnicodeString & Fingerprint, UnicodeString & KeyName, UnicodeString & KeyType)
 {
-  const int MaxCount = 10;
-  const ssh_keyalg * SignKeys[MaxCount];
-  int Count = LENOF(SignKeys);
+  cp_ssh_keyalg * SignKeys;
+  int Count;
   // We may use find_pubkey_alg, but it gets complicated with normalized fingerprint
   // as the names have different number of dashes
-  get_hostkey_algs(&Count, SignKeys);
-
-  for (int Index = 0; Index < Count; Index++)
+  get_hostkey_algs(&Count, &SignKeys);
+  try
   {
-    const ssh_keyalg * SignKey = SignKeys[Index];
-    UnicodeString Name = UnicodeString(SignKey->ssh_id);
-    if (StartsStr(Name + L" ", Fingerprint))
+    for (int Index = 0; Index < Count; Index++)
     {
-      UnicodeString Rest = Fingerprint.SubString(Name.Length() + 2, Fingerprint.Length() - Name.Length() - 1);
-      int Space = Rest.Pos(L" ");
-      // If not a number, it's an invalid input,
-      // either something completelly wrong, or it can be OpenSSH base64 public key,
-      // that got here from TPasteKeyHandler::Paste
-      if (IsNumber(Rest.SubString(1, Space - 1)))
+      cp_ssh_keyalg SignKey = SignKeys[Index];
+      UnicodeString Name = UnicodeString(SignKey->ssh_id);
+      if (StartsStr(Name + L" ", Fingerprint))
+      {
+        UnicodeString Rest = Fingerprint.SubString(Name.Length() + 2, Fingerprint.Length() - Name.Length() - 1);
+        int Space = Rest.Pos(L" ");
+        // If not a number, it's an invalid input,
+        // either something completelly wrong, or it can be OpenSSH base64 public key,
+        // that got here from TPasteKeyHandler::Paste
+        if (IsNumber(Rest.SubString(1, Space - 1)))
+        {
+          KeyName = Name;
+          Fingerprint = Rest.SubString(Space + 1, Fingerprint.Length() - Space);
+          Fingerprint = Base64ToUrlSafe(Fingerprint);
+          Fingerprint = MD5ToUrlSafe(Fingerprint);
+          KeyType = UnicodeString(SignKey->cache_id);
+          return;
+        }
+      }
+      else if (StartsStr(Name + NormalizedFingerprintSeparator, Fingerprint))
       {
-        KeyName = Name;
-        Fingerprint = Rest.SubString(Space + 1, Fingerprint.Length() - Space);
-        Fingerprint = Base64ToUrlSafe(Fingerprint);
-        Fingerprint = MD5ToUrlSafe(Fingerprint);
         KeyType = UnicodeString(SignKey->cache_id);
+        KeyName = Name;
+        Fingerprint.Delete(1, Name.Length() + 1);
         return;
       }
     }
-    else if (StartsStr(Name + NormalizedFingerprintSeparator, Fingerprint))
-    {
-      KeyType = UnicodeString(SignKey->cache_id);
-      KeyName = Name;
-      Fingerprint.Delete(1, Name.Length() + 1);
-      return;
-    }
+  }
+  __finally
+  {
+    sfree(SignKeys);
   }
 }
 //---------------------------------------------------------------------------
@@ -1062,7 +1119,8 @@ TStrings * SshCipherList()
 {
   std::unique_ptr<TStrings> Result(new TStringList());
   // Same order as DefaultCipherList
-  const ssh2_ciphers * Ciphers[] = { &ssh2_aes, &ssh2_ccp, &ssh2_blowfish, &ssh2_3des, &ssh2_arcfour, &ssh2_des };
+  const ssh2_ciphers * Ciphers[] = {
+    &ssh2_aes, &ssh2_ccp, &ssh2_aesgcm, &ssh2_3des, &ssh2_des, &ssh2_blowfish, &ssh2_arcfour };
   for (unsigned int Index = 0; Index < LENOF(Ciphers); Index++)
   {
     for (int Index2 = 0; Index2 < Ciphers[Index]->nciphers; Index2++)
@@ -1078,7 +1136,10 @@ TStrings * SshKexList()
 {
   std::unique_ptr<TStrings> Result(new TStringList());
   // Same order as DefaultKexList
-  const ssh_kexes * Kexes[] = { &ssh_ecdh_kex, &ssh_diffiehellman_gex, &ssh_diffiehellman_group14, &ssh_rsa_kex, &ssh_diffiehellman_group1 };
+  const ssh_kexes * Kexes[] = {
+    &ssh_ecdh_kex, &ssh_diffiehellman_gex, &ssh_diffiehellman_group14,
+    &ssh_diffiehellman_group15, &ssh_diffiehellman_group16, &ssh_diffiehellman_group17, &ssh_diffiehellman_group18,
+    &ssh_rsa_kex, &ssh_diffiehellman_group1 };
   for (unsigned int Index = 0; Index < LENOF(Kexes); Index++)
   {
     for (int Index2 = 0; Index2 < Kexes[Index]->nkexes; Index2++)
@@ -1093,16 +1154,21 @@ TStrings * SshKexList()
 TStrings * SshHostKeyList()
 {
   std::unique_ptr<TStrings> Result(new TStringList());
-  const int MaxCount = 10;
-  const ssh_keyalg * SignKeys[MaxCount];
-  int Count = LENOF(SignKeys);
-  get_hostkey_algs(&Count, SignKeys);
-
-  for (int Index = 0; Index < Count; Index++)
+  cp_ssh_keyalg * SignKeys;
+  int Count;
+  get_hostkey_algs(&Count, &SignKeys);
+  try
+  {
+    for (int Index = 0; Index < Count; Index++)
+    {
+      cp_ssh_keyalg SignKey = SignKeys[Index];
+      UnicodeString Name = UnicodeString(SignKey->ssh_id);
+      Result->Add(Name);
+    }
+  }
+  __finally
   {
-    const ssh_keyalg * SignKey = SignKeys[Index];
-    UnicodeString Name = UnicodeString(SignKey->ssh_id);
-    Result->Add(Name);
+    sfree(SignKeys);
   }
   return Result.release();
 }

+ 5 - 0
source/core/SecureShell.cpp

@@ -193,6 +193,7 @@ Conf * __fastcall TSecureShell::StoreToConfig(TSessionData * Data, bool Simple)
       case cipDES: pcipher = CIPHER_DES; break;
       case cipArcfour: pcipher = CIPHER_ARCFOUR; break;
       case cipChaCha20: pcipher = CIPHER_CHACHA20; break;
+      case cipAESGCM: pcipher = CIPHER_AESGCM; break;
       default: DebugFail();
     }
     conf_set_int_int(conf, CONF_ssh_cipherlist, c, pcipher);
@@ -206,6 +207,10 @@ Conf * __fastcall TSecureShell::StoreToConfig(TSessionData * Data, bool Simple)
       case kexWarn: pkex = KEX_WARN; break;
       case kexDHGroup1: pkex = KEX_DHGROUP1; break;
       case kexDHGroup14: pkex = KEX_DHGROUP14; break;
+      case kexDHGroup15: pkex = KEX_DHGROUP15; break;
+      case kexDHGroup16: pkex = KEX_DHGROUP16; break;
+      case kexDHGroup17: pkex = KEX_DHGROUP17; break;
+      case kexDHGroup18: pkex = KEX_DHGROUP18; break;
       case kexDHGEx: pkex = KEX_DHGEX; break;
       case kexRSA: pkex = KEX_RSA; break;
       case kexECDH: pkex = KEX_ECDH; break;

+ 4 - 4
source/core/SessionData.cpp

@@ -31,16 +31,16 @@
 const wchar_t * PingTypeNames = L"Off;Null;Dummy";
 const wchar_t * ProxyMethodNames = L"None;SOCKS4;SOCKS5;HTTP;Telnet;Cmd";
 const wchar_t * DefaultName = L"Default Settings";
-const UnicodeString CipherNames[CIPHER_COUNT] = {L"WARN", L"3des", L"blowfish", L"aes", L"des", L"arcfour", L"chacha20"};
-const UnicodeString KexNames[KEX_COUNT] = {L"WARN", L"dh-group1-sha1", L"dh-group14-sha1", L"dh-gex-sha1", L"rsa", L"ecdh"};
+const UnicodeString CipherNames[CIPHER_COUNT] = {L"WARN", L"3des", L"blowfish", L"aes", L"des", L"arcfour", L"chacha20", "aesgcm"};
+const UnicodeString KexNames[KEX_COUNT] = {L"WARN", L"dh-group1-sha1", L"dh-group14-sha1", L"dh-group15-sha512", L"dh-group16-sha512", L"dh-group17-sha512", L"dh-group18-sha512", L"dh-gex-sha1", L"rsa", L"ecdh"};
 const UnicodeString HostKeyNames[HOSTKEY_COUNT] = {L"WARN", L"rsa", L"dsa", L"ecdsa", L"ed25519", L"ed448"};
 const UnicodeString GssLibNames[GSSLIB_COUNT] = {L"gssapi32", L"sspi", L"custom"};
 // Update also order in Ssh2CipherList()
 const TCipher DefaultCipherList[CIPHER_COUNT] =
-  { cipAES, cipChaCha20, cipBlowfish, cip3DES, cipWarn, cipArcfour, cipDES };
+  { cipAES, cipChaCha20, cipAESGCM, cip3DES, cipWarn, cipDES, cipBlowfish, cipArcfour };
 // Update also order in SshKexList()
 const TKex DefaultKexList[KEX_COUNT] =
-  { kexECDH, kexDHGEx, kexDHGroup14, kexRSA, kexWarn, kexDHGroup1 };
+  { kexECDH, kexDHGEx, kexDHGroup14, kexRSA, kexDHGroup15, kexDHGroup16, kexDHGroup17, kexDHGroup18, kexWarn, kexDHGroup1 };
 const THostKey DefaultHostKeyList[HOSTKEY_COUNT] =
   { hkED448, hkED25519, hkECDSA, hkRSA, hkDSA, hkWarn };
 const TGssLib DefaultGssLibList[GSSLIB_COUNT] =

+ 5 - 5
source/core/SessionData.h

@@ -10,17 +10,17 @@
 #include "Configuration.h"
 #include <Xml.XMLIntf.hpp>
 //---------------------------------------------------------------------------
-enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES, cipArcfour, cipChaCha20 };
-#define CIPHER_COUNT (cipChaCha20+1)
+enum TCipher { cipWarn, cip3DES, cipBlowfish, cipAES, cipDES, cipArcfour, cipChaCha20, cipAESGCM, cipCount };
+#define CIPHER_COUNT (cipCount)
 // explicit values to skip obsoleted fsExternalSSH, fsExternalSFTP
 enum TFSProtocol { fsSCPonly = 0, fsSFTP = 1, fsSFTPonly = 2, fsFTP = 5, fsWebDAV = 6, fsS3 = 7 };
 #define FSPROTOCOL_COUNT (fsS3+1)
 extern const wchar_t * ProxyMethodNames;
 enum TProxyMethod { pmNone, pmSocks4, pmSocks5, pmHTTP, pmTelnet, pmCmd };
-enum TKex { kexWarn, kexDHGroup1, kexDHGroup14, kexDHGEx, kexRSA, kexECDH };
+enum TKex { kexWarn, kexDHGroup1, kexDHGroup14, kexDHGroup15, kexDHGroup16, kexDHGroup17, kexDHGroup18, kexDHGEx, kexRSA, kexECDH };
 #define KEX_COUNT (kexECDH+1)
-enum THostKey { hkWarn, hkRSA, hkDSA, hkECDSA, hkED25519, hkED448, hkMax };
-#define HOSTKEY_COUNT (hkMax)
+enum THostKey { hkWarn, hkRSA, hkDSA, hkECDSA, hkED25519, hkED448, hkCount };
+#define HOSTKEY_COUNT (hkCount)
 enum TGssLib { gssGssApi32, gssSspi, gssCustom };
 #define GSSLIB_COUNT (gssCustom+1)
 // names have to match PuTTY registry entries (see settings.c)

+ 1 - 1
source/forms/SiteAdvanced.cpp

@@ -254,7 +254,7 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
     CompressionCheck->Checked = FSessionData->Compression;
 
     CipherListBox->Items->Clear();
-    DebugAssert(CIPHER_NAME_WARN+CIPHER_COUNT-1 == CIPHER_NAME_CHACHA20);
+    DebugAssert(CIPHER_NAME_WARN+CIPHER_COUNT-1 == CIPHER_NAME_AESGCM);
     for (int Index = 0; Index < CIPHER_COUNT; Index++)
     {
       CipherListBox->Items->AddObject(

+ 4 - 1
source/putty/crypto/aes-ni.c

@@ -273,7 +273,7 @@ static void aes_ni_next_message_gcm(ssh_cipher *ciph)
     msg_counter <<= 32;
     msg_counter |= (uint32_t)_mm_extract_epi32(ctx->iv, 1);
     msg_counter++;
-    ctx->iv = _mm_set_epi32(fixed, msg_counter >> 32, msg_counter, 1);
+    ctx->iv = _mm_set_epi32(fixed, (int)(msg_counter >> 32), (int)msg_counter, 1); // WINSCP
 }
 
 typedef __m128i (*aes_ni_fn)(__m128i v, const __m128i *keysched);
@@ -333,6 +333,9 @@ static inline void aes_encrypt_ecb_block_ni(
     _mm_storeu_si128(blk, ciphertext);
 }
 
+// WINSCP (fixes linker alignment issues for the following function)
+const __m128i DUMMY; // WINSCP
+
 static inline void aes_gcm_ni(
     ssh_cipher *ciph, void *vblk, int blklen, aes_ni_fn encrypt)
 {

+ 12 - 10
source/putty/crypto/aes-select.c

@@ -42,7 +42,7 @@ static ssh_cipher *aes_select(const ssh_cipheralg *alg)
 #define IF_NEON(...)
 #endif
 
-#define AES_SELECTOR_VTABLE(mode_c, id, mode_display, bits, ...)        \
+#define AES_SELECTOR_VTABLE_IMPL(mode_c, id, mode_display, bits, required_mac) /*WINSCP*/       \
     static const ssh_cipheralg *                                        \
     ssh_aes ## bits ## _ ## mode_c ## _impls[] = {                      \
         IF_NI(&ssh_aes ## bits ## _ ## mode_c ## _ni,)                  \
@@ -53,29 +53,31 @@ static ssh_cipher *aes_select(const ssh_cipheralg *alg)
     const ssh_cipheralg ssh_aes ## bits ## _ ## mode_c = {              \
         /* WINSCP */ \
         /*.new =*/ aes_select,                                              \
-        NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
-        /*.ssh2_id =*/ id                                                   \
+        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
+        /*.ssh2_id =*/ id,                                                  \
         /*.blksize =*/ 16,                                                  \
         /*.real_keybits =*/ bits,                                           \
         /*.padded_keybytes =*/ bits/8,                                      \
         0, \
         /*.text_name =*/ "AES-" #bits " " mode_display                      \
         " (dummy selector vtable)",                                     \
-        NULL, \
+        required_mac, /*WINSCP*/                                                        \
         /*.extra =*/ ssh_aes ## bits ## _ ## mode_c ## _impls,              \
-        __VA_ARGS__                                                         \
     }
 
+// WINSCP
+#define AES_SELECTOR_VTABLE(mode_c, id, mode_display, bits, dummy) AES_SELECTOR_VTABLE_IMPL(mode_c, id, mode_display, bits, NULL)
+
 AES_SELECTOR_VTABLE(cbc, "aes128-cbc", "CBC", 128, );
 AES_SELECTOR_VTABLE(cbc, "aes192-cbc", "CBC", 192, );
 AES_SELECTOR_VTABLE(cbc, "aes256-cbc", "CBC", 256, );
 AES_SELECTOR_VTABLE(sdctr, "aes128-ctr", "SDCTR", 128, );
 AES_SELECTOR_VTABLE(sdctr, "aes192-ctr", "SDCTR", 192, );
 AES_SELECTOR_VTABLE(sdctr, "aes256-ctr", "SDCTR", 256, );
-AES_SELECTOR_VTABLE(gcm, "[email protected]", "GCM", 128,
-                    .required_mac = &ssh2_aesgcm_mac);
-AES_SELECTOR_VTABLE(gcm, "[email protected]", "GCM", 256,
-                    .required_mac = &ssh2_aesgcm_mac);
+AES_SELECTOR_VTABLE_IMPL(gcm, "[email protected]", "GCM", 128,
+                    /*.required_mac =*/ &ssh2_aesgcm_mac);
+AES_SELECTOR_VTABLE_IMPL(gcm, "[email protected]", "GCM", 256,
+                    /*.required_mac =*/ &ssh2_aesgcm_mac);
 
 /* 192-bit AES-GCM is included only so that testcrypt can run standard
  * test vectors against it. OpenSSH doesn't define a protocol id for
@@ -87,7 +89,7 @@ AES_SELECTOR_VTABLE(gcm, NULL, "GCM", 192,
 static const ssh_cipheralg ssh_rijndael_lysator = {
     /* Same as aes256_cbc, but with a different protocol ID */
     /*.new =*/ aes_select,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     /*.ssh2_id =*/ "[email protected]",
     /*.blksize =*/ 16,
     /*.real_keybits =*/ 256,

+ 6 - 2
source/putty/crypto/aes-sw.c

@@ -1136,10 +1136,10 @@ static inline void aes_gcm_sw(
     /*WINSCP static*/ void aes##len##_sw_sdctr(                    \
         ssh_cipher *ciph, void *vblk, int blklen)       \
     { aes_sdctr_sw(ciph, vblk, blklen); }               \
-    static void aes##len##_sw_gcm(                      \
+    /*WINSCP static*/ void aes##len##_sw_gcm(                      \
         ssh_cipher *ciph, void *vblk, int blklen)       \
     { aes_gcm_sw(ciph, vblk, blklen); }                 \
-    static void aes##len##_sw_encrypt_ecb_block(        \
+    /*WINSCP static*/ void aes##len##_sw_encrypt_ecb_block(        \
         ssh_cipher *ciph, void *vblk)                   \
     { aes_encrypt_ecb_block_sw(ciph, vblk); }
 
@@ -1152,6 +1152,10 @@ static inline void aes_gcm_sw(
         ssh_cipher *ciph, void *vblk, int blklen);      \
     void aes##len##_sw_sdctr(                           \
         ssh_cipher *ciph, void *vblk, int blklen);      \
+    void aes##len##_sw_gcm(                      \
+        ssh_cipher *ciph, void *vblk, int blklen);       \
+    void aes##len##_sw_encrypt_ecb_block(        \
+        ssh_cipher *ciph, void *vblk);                   \
 
 #endif // WINSCP_VS
 

+ 22 - 20
source/putty/crypto/aes.h

@@ -59,7 +59,7 @@ static inline void aes_encrypt_ecb_block(ssh_cipher *ciph, void *blk)
         /* WINSCP */ \
         /*.check_available =*/ aes ## impl_c ## _available,                 \
         /*.mut =*/ &aes ## impl_c ## _extra_mut,                            \
-        .encrypt_ecb_block = &aes ## bits ## impl_c ## _encrypt_ecb_block, \
+        /*.encrypt_ecb_block =*/ &aes ## bits ## impl_c ## _encrypt_ecb_block, \
     }
 
 #define AES_EXTRA(impl_c)                       \
@@ -82,9 +82,9 @@ static inline void aes_encrypt_ecb_block(ssh_cipher *ciph, void *blk)
         /*.setkey =*/ aes ## impl_c ## _setkey,                             \
         /*.encrypt =*/ aes ## bits ## impl_c ## _cbc_encrypt,               \
         /*.decrypt =*/ aes ## bits ## impl_c ## _cbc_decrypt,               \
-        .next_message = nullcipher_next_message,                        \
         NULL, \
         NULL, \
+        /*.next_message =*/ nullcipher_next_message,                        \
         /*.ssh2_id =*/ ssh_aes ## bits ## _cbc ## impl_c ## ssh2_id, /*WINSCP*/ \
         /*.blksize =*/ 16,                                                  \
         /*.real_keybits =*/ bits,                                           \
@@ -108,7 +108,7 @@ static inline void aes_encrypt_ecb_block(ssh_cipher *ciph, void *blk)
         /*.decrypt =*/ aes ## bits ## impl_c ## _sdctr,                     \
         NULL, \
         NULL, \
-        .next_message = nullcipher_next_message,                        \
+        /*.next_message =*/ nullcipher_next_message,                        \
         /*.ssh2_id =*/ ssh_aes ## bits ## _sdctr ## impl_c ## ssh2_id, /*WINSCP*/ \
         /*.blksize =*/ 16,                                                  \
         /*.real_keybits =*/ bits,                                           \
@@ -120,27 +120,29 @@ static inline void aes_encrypt_ecb_block(ssh_cipher *ciph, void *blk)
     }
 
 #define AES_GCM_VTABLE(impl_c, impl_display, bits)                      \
+    const char ssh_aes ## bits ## _gcm ## impl_c ## ssh2_id[] = "aes" #bits "[email protected]"; /*WINSCP*/ \
+    const char ssh_aes ## bits ## _gcm ## impl_c ## text_name[] = "AES-" #bits " GCM (" impl_display ")"; /*WINSCP*/ \
     const ssh_cipheralg ssh_aes ## bits ## _gcm ## impl_c = {           \
-        .new = aes ## impl_c ## _new,                                   \
-        .free = aes ## impl_c ## _free,                                 \
-        .setiv = aes ## impl_c ## _setiv_gcm,                           \
-        .setkey = aes ## impl_c ## _setkey,                             \
-        .encrypt = aes ## bits ## impl_c ## _gcm,                       \
-        .decrypt = aes ## bits ## impl_c ## _gcm,                       \
-        .encrypt_length = aesgcm_cipher_crypt_length,                   \
-        .decrypt_length = aesgcm_cipher_crypt_length,                   \
-        .next_message = aes ## impl_c ## _next_message_gcm,             \
+        /*.new =*/ aes ## impl_c ## _new,                                   \
+        /*.free =*/ aes ## impl_c ## _free,                                 \
+        /*.setiv =*/ aes ## impl_c ## _setiv_gcm,                           \
+        /*.setkey =*/ aes ## impl_c ## _setkey,                             \
+        /*.encrypt =*/ aes ## bits ## impl_c ## _gcm,                       \
+        /*.decrypt =*/ aes ## bits ## impl_c ## _gcm,                       \
+        /*.encrypt_length =*/ aesgcm_cipher_crypt_length,                   \
+        /*.decrypt_length =*/ aesgcm_cipher_crypt_length,                   \
+        /*.next_message =*/ aes ## impl_c ## _next_message_gcm,             \
         /* 192-bit AES-GCM is included only so that testcrypt can run   \
          * standard test vectors against it. OpenSSH doesn't define a   \
          * protocol id for it. So we set its ssh2_id to NULL. */        \
-        .ssh2_id = bits==192 ? NULL : "aes" #bits "[email protected]",   \
-        .blksize = 16,                                                  \
-        .real_keybits = bits,                                           \
-        .padded_keybytes = bits/8,                                      \
-        .flags = SSH_CIPHER_SEPARATE_LENGTH,                            \
-        .text_name = "AES-" #bits " GCM (" impl_display ")",            \
-        .required_mac = &ssh2_aesgcm_mac,                               \
-        .extra = &aes ## bits ## impl_c ## _extra,                      \
+        /*.ssh2_id =*/ bits==192 ? NULL : ssh_aes ## bits ## _gcm ## impl_c ## ssh2_id,   \
+        /*.blksize =*/ 16,                                                  \
+        /*.real_keybits =*/ bits,                                           \
+        /*.padded_keybytes =*/ bits/8,                                      \
+        /*.flags =*/ SSH_CIPHER_SEPARATE_LENGTH,                            \
+        /*.text_name =*/ ssh_aes ## bits ## _gcm ## impl_c ## text_name,            \
+        /*.required_mac =*/ &ssh2_aesgcm_mac,                               \
+        /*.extra =*/ &aes ## bits ## impl_c ## _extra,                      \
     }
 
 #define AES_ALL_VTABLES(impl_c, impl_display)           \

+ 19 - 15
source/putty/crypto/aesgcm-footer.h

@@ -287,6 +287,7 @@ static void PREFIX(mac_genresult)(ssh2_mac *mac, unsigned char *output)
     /*
      * Consume the final block giving the lengths of the AAD and ciphertext.
      */
+    { // WINSCP
     unsigned char blk[16];
     memset(blk, 0, 16);
     PUT_64BIT_MSB_FIRST(blk, ctx->aadlen * 8);
@@ -300,6 +301,7 @@ static void PREFIX(mac_genresult)(ssh2_mac *mac, unsigned char *output)
 
     smemclr(blk, sizeof(blk));
     smemclr(ctx->partblk, 16);
+    } // WINSCP
 }
 
 static ssh2_mac *PREFIX(mac_new)(const ssh2_macalg *alg, ssh_cipher *cipher)
@@ -308,6 +310,7 @@ static ssh2_mac *PREFIX(mac_new)(const ssh2_macalg *alg, ssh_cipher *cipher)
     if (!check_aesgcm_availability(extra))
         return NULL;
 
+    { // WINSCP
 #ifdef SPECIAL_ALLOC
     CONTEXT *ctx = PREFIX(alloc)();
 #else
@@ -324,6 +327,7 @@ static ssh2_mac *PREFIX(mac_new)(const ssh2_macalg *alg, ssh_cipher *cipher)
     BinarySink_INIT(ctx, PREFIX(mac_BinarySink_write));
     BinarySink_DELEGATE_INIT(&ctx->mac, ctx);
     return &ctx->mac;
+    } // WINSCP
 }
 
 static void PREFIX(set_prefix_lengths)(ssh2_mac *mac, size_t skip, size_t aad)
@@ -347,22 +351,22 @@ static void PREFIX(mac_free)(ssh2_mac *mac)
 static struct aesgcm_extra_mutable PREFIX(extra_mut);
 
 static const struct aesgcm_extra PREFIX(extra) = {
-    .check_available = PREFIX(available),
-    .mut = &PREFIX(extra_mut),
-    .set_prefix_lengths = PREFIX(set_prefix_lengths),
+    /*.check_available =*/ PREFIX(available),
+    /*.mut =*/ &PREFIX(extra_mut),
+    /*.set_prefix_lengths =*/ PREFIX(set_prefix_lengths),
 };
 
 const ssh2_macalg CAT(ssh2_aesgcm_mac_, AESGCM_FLAVOUR) = {
-    .new = PREFIX(mac_new),
-    .free = PREFIX(mac_free),
-    .setkey = PREFIX(mac_setkey),
-    .start = PREFIX(mac_start),
-    .genresult = PREFIX(mac_genresult),
-    .next_message = PREFIX(mac_next_message),
-    .text_name = PREFIX(mac_text_name),
-    .name = "",
-    .etm_name = "", /* Not selectable independently */
-    .len = 16,
-    .keylen = 0,
-    .extra = &PREFIX(extra),
+    /*.new =*/ PREFIX(mac_new),
+    /*.free =*/ PREFIX(mac_free),
+    /*.setkey =*/ PREFIX(mac_setkey),
+    /*.start =*/ PREFIX(mac_start),
+    /*.genresult =*/ PREFIX(mac_genresult),
+    /*.next_message =*/ PREFIX(mac_next_message),
+    /*.text_name =*/ PREFIX(mac_text_name),
+    /*.name =*/ "",
+    /*.etm_name =*/ "", /* Not selectable independently */
+    /*.len =*/ 16,
+    /*.keylen =*/ 0,
+    /*.extra =*/ &PREFIX(extra),
 };

+ 19 - 4
source/putty/crypto/aesgcm-ref-poly.c

@@ -100,17 +100,24 @@ static value128_t pmul(uint64_t x, uint64_t y)
     value128_t r;
     r.hi = r.lo = 0;
 
+    { // WINSCP
     uint64_t bit = 1 & y;
     r.lo ^= x & -bit;
 
-    for (unsigned i = 1; i < 64; i++) {
+    { // WINSCP
+    unsigned i;
+    for (i = 1; i < 64; i++) {
         bit = 1 & (y >> i);
+        { // WINSCP
         uint64_t z = x & -bit;
         r.lo ^= z << i;
         r.hi ^= z >> (64-i);
+        } // WINSCP
     }
+    } // WINSCP
 
     return r;
+    } // WINSCP
 }
 
 /*
@@ -222,10 +229,12 @@ static void aesgcm_ref_poly_setkey_impl(aesgcm_ref_poly *ctx,
     ctx->var.hi = GET_64BIT_MSB_FIRST(var);
     ctx->var.lo = GET_64BIT_MSB_FIRST(var + 8);
 
+    { // WINSCP
     uint64_t bit = 1 & (ctx->var.hi >> 63);
     ctx->var.hi = (ctx->var.hi << 1) ^ (ctx->var.lo >> 63);
     ctx->var.lo = (ctx->var.lo << 1) ^ bit;
-    ctx->var.hi ^= 0xC200000000000000 & -bit;
+    ctx->var.hi ^= 0xC200000000000000LL & -bit; // WINSCP
+    } // WINSCP
 }
 
 static inline void aesgcm_ref_poly_setup(aesgcm_ref_poly *ctx,
@@ -290,6 +299,7 @@ static inline void aesgcm_ref_poly_coeff(aesgcm_ref_poly *ctx,
      * This involves more bookkeeping instructions like XORs, but with
      * any luck those are faster than the main multiplication.
      */
+    { // WINSCP
     uint64_t ah = ctx->acc.hi, al = ctx->acc.lo;
     uint64_t bh = ctx->var.hi, bl = ctx->var.lo;
     /* Compute the outer two terms */
@@ -336,18 +346,23 @@ static inline void aesgcm_ref_poly_coeff(aesgcm_ref_poly *ctx,
 
     /* First step, adding to the middle two words of our number. After
      * this the lowest word (in lo.lo) is ignored. */
-    value128_t r1 = pmul(0xC200000000000000, lo.lo);
+    { // WINSCP
+    value128_t r1 = pmul(0xC200000000000000LL, lo.lo); // WINSCP
     hi.lo ^= r1.hi ^ lo.lo;
     lo.hi ^= r1.lo;
 
     /* Second of those steps, adding to the top two words, and
      * discarding lo.hi. */
-    value128_t r2 = pmul(0xC200000000000000, lo.hi);
+    { // WINSCP
+    value128_t r2 = pmul(0xC200000000000000LL, lo.hi);
     hi.hi ^= r2.hi ^ lo.hi;
     hi.lo ^= r2.lo;
 
     /* Now 'hi' is precisely what we have left. */
     ctx->acc = hi;
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
 static inline void aesgcm_ref_poly_output(aesgcm_ref_poly *ctx,

+ 9 - 6
source/putty/crypto/aesgcm-select.c

@@ -15,7 +15,8 @@ static ssh2_mac *aesgcm_mac_selector_new(const ssh2_macalg *alg,
         NULL,
     };
 
-    for (size_t i = 0; real_algs[i]; i++) {
+    size_t i; // WINSCP
+    for (i = 0; real_algs[i]; i++) {
         const ssh2_macalg *alg = real_algs[i];
         const struct aesgcm_extra *alg_extra =
             (const struct aesgcm_extra *)alg->extra;
@@ -30,9 +31,11 @@ static ssh2_mac *aesgcm_mac_selector_new(const ssh2_macalg *alg,
 }
 
 const ssh2_macalg ssh2_aesgcm_mac = {
-    .new = aesgcm_mac_selector_new,
-    .name = "",
-    .etm_name = "", /* Not selectable independently */
-    .len = 16,
-    .keylen = 0,
+    /*.new =*/ aesgcm_mac_selector_new,
+    NULL, NULL, NULL, NULL, NULL, NULL, // WINSCP
+    /*.name =*/ "",
+    /*.etm_name =*/ "", /* Not selectable independently */
+    /*.len =*/ 16,
+    /*.keylen =*/ 0,
+    NULL, // WINSCP
 };

+ 17 - 3
source/putty/crypto/aesgcm-sw.c

@@ -79,15 +79,20 @@ static void aesgcm_sw_setkey_impl(aesgcm_sw *gcm, const unsigned char *var)
      * logical specification so that's where the logical constant term
      * lives. (See more detailed comment in aesgcm-ref-poly.c.)
      */
-    for (size_t i = 0; i < 128; i++) {
+    { // WINSCP
+    size_t i;
+    for (i = 0; i < 128; i++) {
         gcm->table[127 - i] = v;
 
         /* Multiply v by x, which means shifting right (bit reversal
          * again) and then adding 0xE1 at the top if we shifted a 1 out. */
+        { // WINSCP
         uint64_t lobit = v.lo & 1;
         v.lo = (v.lo >> 1) ^ (v.hi << 63);
         v.hi = (v.hi >> 1) ^ (0xE100000000000000ULL & -lobit);
+        } // WINSCP
     }
+    } // WINSCP
 }
 
 static inline void aesgcm_sw_setup(aesgcm_sw *gcm, const unsigned char *mask)
@@ -107,29 +112,38 @@ static inline void aesgcm_sw_coeff(aesgcm_sw *gcm, const unsigned char *coeff)
      * by XORing together the entries of 'table' corresponding to set
      * bits. */
 
+    { // WINSCP
     value128_t out;
     out.lo = out.hi = 0;
 
+    { // WINSCP
     const value128_t *tableptr = gcm->table;
 
-    for (size_t i = 0; i < 64; i++) {
+    size_t i;
+    for (i = 0; i < 64; i++) {
         uint64_t bit = 1 & gcm->acc.lo;
         gcm->acc.lo >>= 1;
+        { // WINSCP
         uint64_t mask = -bit;
         out.hi ^= mask & tableptr->hi;
         out.lo ^= mask & tableptr->lo;
         tableptr++;
+        } // WINSCP
     }
-    for (size_t i = 0; i < 64; i++) {
+    for (i = 0; i < 64; i++) {
         uint64_t bit = 1 & gcm->acc.hi;
         gcm->acc.hi >>= 1;
+        { // WINSCP
         uint64_t mask = -bit;
         out.hi ^= mask & tableptr->hi;
         out.lo ^= mask & tableptr->lo;
         tableptr++;
+        } // WINSCP
     }
 
     gcm->acc = out;
+    } // WINSCP
+    } // WINSCP
 }
 
 static inline void aesgcm_sw_output(aesgcm_sw *gcm, unsigned char *output)

+ 2 - 2
source/putty/crypto/arcfour.c

@@ -112,7 +112,7 @@ const ssh_cipheralg ssh_arcfour128_ssh2 = {
     /*.encrypt =*/ arcfour_ssh2_block,
     /*.decrypt =*/ arcfour_ssh2_block,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "arcfour128",
     /*.blksize =*/ 1,
     /*.real_keybits =*/ 128,
@@ -131,7 +131,7 @@ const ssh_cipheralg ssh_arcfour256_ssh2 = {
     /*.encrypt =*/ arcfour_ssh2_block,
     /*.decrypt =*/ arcfour_ssh2_block,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "arcfour256",
     /*.blksize =*/ 1,
     /*.real_keybits =*/ 256,

+ 3 - 3
source/putty/crypto/blowfish.c

@@ -656,7 +656,7 @@ const ssh_cipheralg ssh_blowfish_ssh1 = {
     /*.encrypt =*/ blowfish_ssh1_encrypt_blk,
     /*.decrypt =*/ blowfish_ssh1_decrypt_blk,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     NULL, // WINSCP
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 128,
@@ -675,7 +675,7 @@ const ssh_cipheralg ssh_blowfish_ssh2 = {
     /*.encrypt =*/ blowfish_ssh2_encrypt_blk,
     /*.decrypt =*/ blowfish_ssh2_decrypt_blk,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "blowfish-cbc",
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 128,
@@ -694,7 +694,7 @@ const ssh_cipheralg ssh_blowfish_ssh2_ctr = {
     /*.encrypt =*/ blowfish_ssh2_sdctr,
     /*.decrypt =*/ blowfish_ssh2_sdctr,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "blowfish-ctr",
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 256,

+ 2 - 2
source/putty/crypto/chacha20-poly1305.c

@@ -965,7 +965,7 @@ const ssh2_macalg ssh2_poly1305 = {
     /*.setkey =*/ poly_setkey,
     /*.start =*/ poly_start,
     /*.genresult =*/ poly_genresult,
-    .next_message = nullmac_next_message,
+    /*.next_message =*/ nullmac_next_message,
     /*.text_name =*/ poly_text_name,
     /*.name =*/ "",
     /*.etm_name =*/ "", /* Not selectable individually, just part of
@@ -1065,7 +1065,7 @@ const ssh_cipheralg ssh2_chacha20_poly1305 = {
     /*.decrypt =*/ ccp_decrypt,
     /*.encrypt_length =*/ ccp_encrypt_length,
     /*.decrypt_length =*/ ccp_decrypt_length,
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "[email protected]",
     /*.blksize =*/ 1,
     /*.real_keybits =*/ 512,

+ 5 - 5
source/putty/crypto/des.c

@@ -699,7 +699,7 @@ const ssh_cipheralg ssh_des = {
     /*.encrypt =*/ des_cbc_encrypt,
     /*.decrypt =*/ des_cbc_decrypt,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "des-cbc",
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 56,
@@ -719,7 +719,7 @@ const ssh_cipheralg ssh_des_sshcom_ssh2 = {
     /*.encrypt =*/ des_cbc_encrypt,
     /*.decrypt =*/ des_cbc_decrypt,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "[email protected]",
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 56,
@@ -831,7 +831,7 @@ const ssh_cipheralg ssh_3des_ssh2 = {
     /*.encrypt =*/ des3_cbc1_cbc_encrypt,
     /*.decrypt =*/ des3_cbc1_cbc_decrypt,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "3des-cbc",
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 168,
@@ -941,7 +941,7 @@ const ssh_cipheralg ssh_3des_ssh2_ctr = {
     /*.encrypt =*/ des3_sdctr_encrypt_decrypt,
     /*.decrypt =*/ des3_sdctr_encrypt_decrypt,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     /*.ssh2_id =*/ "3des-ctr",
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 168,
@@ -1086,7 +1086,7 @@ const ssh_cipheralg ssh_3des_ssh1 = {
     /*.encrypt =*/ des3_cbc3_cbc_encrypt,
     /*.decrypt =*/ des3_cbc3_cbc_decrypt,
     NULL, NULL, // WINSCP
-    .next_message = nullcipher_next_message,
+    /*.next_message =*/ nullcipher_next_message,
     NULL, // WINSCP
     /*.blksize =*/ 8,
     /*.real_keybits =*/ 168,

+ 102 - 85
source/putty/crypto/diffie-hellman.c

@@ -76,11 +76,12 @@ static const struct dh_extra extra_group1 = {
 };
 
 const ssh_kex ssh_diffiehellman_group1_sha1 = {
-    .name = "diffie-hellman-group1-sha1",
-    .groupname = "group1",
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha1,
-    .extra = &extra_group1,
+    /*.name =*/ "diffie-hellman-group1-sha1",
+    /*.groupname =*/ "group1",
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha1,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group1,
 };
 
 static const ssh_kex *const group1_list[] = {
@@ -94,11 +95,12 @@ static const struct dh_extra extra_group18 = {
 };
 
 const ssh_kex ssh_diffiehellman_group18_sha512 = {
-    .name = "diffie-hellman-group18-sha512",
-    .groupname = "group18",
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha512,
-    .extra = &extra_group18,
+    /*.name =*/ "diffie-hellman-group18-sha512",
+    /*.groupname =*/ "group18",
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group18,
 };
 
 static const ssh_kex *const group18_list[] = {
@@ -114,11 +116,12 @@ static const struct dh_extra extra_group17 = {
 };
 
 const ssh_kex ssh_diffiehellman_group17_sha512 = {
-    .name = "diffie-hellman-group17-sha512",
-    .groupname = "group17",
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha512,
-    .extra = &extra_group17,
+    /*.name =*/ "diffie-hellman-group17-sha512",
+    /*.groupname =*/ "group17",
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group17,
 };
 
 static const ssh_kex *const group17_list[] = {
@@ -134,11 +137,12 @@ static const struct dh_extra extra_group16 = {
 };
 
 const ssh_kex ssh_diffiehellman_group16_sha512 = {
-    .name = "diffie-hellman-group16-sha512",
-    .groupname = "group16",
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha512,
-    .extra = &extra_group16,
+    /*.name =*/ "diffie-hellman-group16-sha512",
+    /*.groupname =*/ "group16",
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group16,
 };
 
 static const ssh_kex *const group16_list[] = {
@@ -154,11 +158,12 @@ static const struct dh_extra extra_group15 = {
 };
 
 const ssh_kex ssh_diffiehellman_group15_sha512 = {
-    .name = "diffie-hellman-group15-sha512",
-    .groupname = "group15",
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha512,
-    .extra = &extra_group15,
+    /*.name =*/ "diffie-hellman-group15-sha512",
+    /*.groupname =*/ "group15",
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group15,
 };
 
 static const ssh_kex *const group15_list[] = {
@@ -174,19 +179,21 @@ static const struct dh_extra extra_group14 = {
 };
 
 const ssh_kex ssh_diffiehellman_group14_sha256 = {
-    .name = "diffie-hellman-group14-sha256",
-    .groupname = "group14",
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha256,
-    .extra = &extra_group14,
+    /*.name =*/ "diffie-hellman-group14-sha256",
+    /*.groupname =*/ "group14",
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha256,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group14,
 };
 
 const ssh_kex ssh_diffiehellman_group14_sha1 = {
-    .name = "diffie-hellman-group14-sha1",
-    .groupname = "group14",
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha1,
-    .extra = &extra_group14,
+    /*.name =*/ "diffie-hellman-group14-sha1",
+    /*.groupname =*/ "group14",
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha1,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group14,
 };
 
 static const ssh_kex *const group14_list[] = {
@@ -201,19 +208,21 @@ const ssh_kexes ssh_diffiehellman_group14 = {
 static const struct dh_extra extra_gex = { true };
 
 static const ssh_kex ssh_diffiehellman_gex_sha256 = {
-    .name = "diffie-hellman-group-exchange-sha256",
-    .groupname = NULL,
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha256,
-    .extra = &extra_gex,
+    /*.name =*/ "diffie-hellman-group-exchange-sha256",
+    /*.groupname =*/ NULL,
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha256,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_gex,
 };
 
 static const ssh_kex ssh_diffiehellman_gex_sha1 = {
-    .name = "diffie-hellman-group-exchange-sha1",
-    .groupname = NULL,
-    .main_type = KEXTYPE_DH,
-    .hash = &ssh_sha1,
-    .extra = &extra_gex,
+    /*.name =*/ "diffie-hellman-group-exchange-sha1",
+    /*.groupname =*/ NULL,
+    /*.main_type =*/ KEXTYPE_DH,
+    /*.hash =*/ &ssh_sha1,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_gex,
 };
 
 static const ssh_kex *const gex_list[] = {
@@ -224,51 +233,57 @@ static const ssh_kex *const gex_list[] = {
 const ssh_kexes ssh_diffiehellman_gex = { lenof(gex_list), gex_list };
 
 static const ssh_kex ssh_gssk5_diffiehellman_gex_sha1 = {
-    .name = "gss-gex-sha1-" GSS_KRB5_OID_HASH,
-    .groupname = NULL,
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha1,
-    .extra = &extra_gex,
+    /*.name =*/ "gss-gex-sha1-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ NULL,
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha1,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_gex,
 };
 
 static const ssh_kex ssh_gssk5_diffiehellman_group18_sha512 = {
-    .name = "gss-group18-sha512-" GSS_KRB5_OID_HASH,
-    .groupname = "group18",
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha512,
-    .extra = &extra_group18,
+    /*.name =*/ "gss-group18-sha512-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ "group18",
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group18,
 };
 
 static const ssh_kex ssh_gssk5_diffiehellman_group17_sha512 = {
-    .name = "gss-group17-sha512-" GSS_KRB5_OID_HASH,
-    .groupname = "group17",
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha512,
-    .extra = &extra_group17,
+    /*.name =*/ "gss-group17-sha512-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ "group17",
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group17,
 };
 
 static const ssh_kex ssh_gssk5_diffiehellman_group16_sha512 = {
-    .name = "gss-group16-sha512-" GSS_KRB5_OID_HASH,
-    .groupname = "group16",
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha512,
-    .extra = &extra_group16,
+    /*.name =*/ "gss-group16-sha512-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ "group16",
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group16,
 };
 
 static const ssh_kex ssh_gssk5_diffiehellman_group15_sha512 = {
-    .name = "gss-group15-sha512-" GSS_KRB5_OID_HASH,
-    .groupname = "group15",
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha512,
-    .extra = &extra_group15,
+    /*.name =*/ "gss-group15-sha512-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ "group15",
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha512,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group15,
 };
 
 static const ssh_kex ssh_gssk5_diffiehellman_group14_sha256 = {
-    .name = "gss-group14-sha256-" GSS_KRB5_OID_HASH,
-    .groupname = "group14",
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha256,
-    .extra = &extra_group14,
+    /*.name =*/ "gss-group14-sha256-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ "group14",
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha256,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group14,
 };
 
 static const ssh_kex *const gssk5_sha2_kex_list[] = {
@@ -284,19 +299,21 @@ const ssh_kexes ssh_gssk5_sha2_kex = {
 };
 
 static const ssh_kex ssh_gssk5_diffiehellman_group14_sha1 = {
-    .name = "gss-group14-sha1-" GSS_KRB5_OID_HASH,
-    .groupname = "group14",
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha1,
-    .extra = &extra_group14,
+    /*.name =*/ "gss-group14-sha1-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ "group14",
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha1,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group14,
 };
 
 static const ssh_kex ssh_gssk5_diffiehellman_group1_sha1 = {
-    .name = "gss-group1-sha1-" GSS_KRB5_OID_HASH,
-    .groupname = "group1",
-    .main_type = KEXTYPE_GSS,
-    .hash = &ssh_sha1,
-    .extra = &extra_group1,
+    /*.name =*/ "gss-group1-sha1-" GSS_KRB5_OID_HASH,
+    /*.groupname =*/ "group1",
+    /*.main_type =*/ KEXTYPE_GSS,
+    /*.hash =*/ &ssh_sha1,
+    NULL, // WINSCP
+    /*.extra =*/ &extra_group1,
 };
 
 static const ssh_kex *const gssk5_sha1_kex_list[] = {

+ 9 - 7
source/putty/crypto/dsa.c

@@ -524,16 +524,18 @@ const ssh_keyalg ssh_dsa = {
     /*.public_blob =*/ dsa_public_blob,
     /*.private_blob =*/ dsa_private_blob,
     /*.openssh_blob =*/ dsa_openssh_blob,
-    .has_private = dsa_has_private,
+    /*.has_private =*/ dsa_has_private,
     /*.cache_str =*/ dsa_cache_str,
     /*.components =*/ dsa_components,
-    .base_key = nullkey_base_key,
+    /*.base_key =*/ nullkey_base_key,
+    NULL, NULL, NULL, NULL, // WINSCP
     /*.pubkey_bits =*/ dsa_pubkey_bits,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    /*.alg_desc =*/ dsa_alg_desc,
+    /*.variable_size =*/ nullkey_variable_size_yes,
+    NULL, // WINSCP
     /*.ssh_id =*/ "ssh-dss",
     /*.cache_id =*/ "dss",
-    NULL,
-    .supported_flags = nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
-    .alg_desc = dsa_alg_desc,
-    .variable_size = nullkey_variable_size_yes,
+    NULL, false, NULL, // WINSCP
 };

+ 119 - 95
source/putty/crypto/ecc-ssh.c

@@ -1479,19 +1479,21 @@ const ssh_keyalg ssh_ecdsa_ed25519 = {
     /*.public_blob =*/ eddsa_public_blob,
     /*.private_blob =*/ eddsa_private_blob,
     /*.openssh_blob =*/ eddsa_openssh_blob,
-    .has_private = eddsa_has_private,
+    /*.has_private =*/ eddsa_has_private,
     /*.cache_str =*/ eddsa_cache_str,
     /*.components =*/ eddsa_components,
+    /*.base_key =*/ nullkey_base_key,
+    NULL, NULL, NULL, NULL, // WINSCP
     /*.pubkey_bits =*/ ec_shared_pubkey_bits,
-    .base_key = nullkey_base_key,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    /*.alg_desc =*/ ec_alg_desc,
+    /*.variable_size =*/ nullkey_variable_size_no,
+    NULL, // WINSCP
     /*.ssh_id =*/ "ssh-ed25519",
     /*.cache_id =*/ "ssh-ed25519",
     /*.extra =*/ &sign_extra_ed25519,
-    0, // WINSCP
-    .supported_flags = nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
-    .alg_desc = ec_alg_desc,
-    .variable_size = nullkey_variable_size_no,
+    false, NULL, // WINSCP
 };
 
 static const struct ecsign_extra sign_extra_ed448 = {
@@ -1510,19 +1512,21 @@ const ssh_keyalg ssh_ecdsa_ed448 = {
     /*.public_blob =*/ eddsa_public_blob,
     /*.private_blob =*/ eddsa_private_blob,
     /*.openssh_blob =*/ eddsa_openssh_blob,
-    .has_private = eddsa_has_private,
+    /*.has_private =*/ eddsa_has_private,
     /*.cache_str =*/ eddsa_cache_str,
     /*.components =*/ eddsa_components,
+    /*.base_key =*/ nullkey_base_key,
+    NULL, NULL, NULL, NULL, // WINSCP
     /*.pubkey_bits =*/ ec_shared_pubkey_bits,
-    .base_key = nullkey_base_key,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    /*.alg_desc =*/ ec_alg_desc,
+    /*.variable_size =*/ nullkey_variable_size_no,
+    NULL, // WINSCP
     /*.ssh_id =*/ "ssh-ed448",
     /*.cache_id =*/ "ssh-ed448",
     /*.extra =*/ &sign_extra_ed448,
-    0, // WINSCP
-    .supported_flags = nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
-    .alg_desc = ec_alg_desc,
-    .variable_size = nullkey_variable_size_no,
+    false, NULL, // WINSCP
 };
 
 /* OID: 1.2.840.10045.3.1.7 (ansiX9p256r1) */
@@ -1545,19 +1549,21 @@ const ssh_keyalg ssh_ecdsa_nistp256 = {
     /*.public_blob =*/ ecdsa_public_blob,
     /*.private_blob =*/ ecdsa_private_blob,
     /*.openssh_blob =*/ ecdsa_openssh_blob,
-    .has_private = ecdsa_has_private,
+    /*.has_private =*/ ecdsa_has_private,
     /*.cache_str =*/ ecdsa_cache_str,
     /*.components =*/ ecdsa_components,
+    /*.base_key =*/ nullkey_base_key,
+    NULL, NULL, NULL, NULL, // WINSC
     /*.pubkey_bits =*/ ec_shared_pubkey_bits,
-    .base_key = nullkey_base_key,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    /*.alg_desc =*/ ec_alg_desc,
+    /*.variable_size =*/ nullkey_variable_size_no,
+    NULL, // WINSCP
     /*.ssh_id =*/ "ecdsa-sha2-nistp256",
     /*.cache_id =*/ "ecdsa-sha2-nistp256",
     /*.extra =*/ &sign_extra_nistp256,
-    0, // WINSCP
-    .supported_flags = nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
-    .alg_desc = ec_alg_desc,
-    .variable_size = nullkey_variable_size_no,
+    false, NULL, // WINSCP
 };
 
 /* OID: 1.3.132.0.34 (secp384r1) */
@@ -1580,19 +1586,21 @@ const ssh_keyalg ssh_ecdsa_nistp384 = {
     /*.public_blob =*/ ecdsa_public_blob,
     /*.private_blob =*/ ecdsa_private_blob,
     /*.openssh_blob =*/ ecdsa_openssh_blob,
-    .has_private = ecdsa_has_private,
+    /*.has_private =*/ ecdsa_has_private,
     /*.cache_str =*/ ecdsa_cache_str,
     /*.components =*/ ecdsa_components,
+    /*.base_key =*/ nullkey_base_key,
+    NULL, NULL, NULL, NULL, // WINSCP
     /*.pubkey_bits =*/ ec_shared_pubkey_bits,
-    .base_key = nullkey_base_key,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    /*.alg_desc =*/ ec_alg_desc,
+    /*.variable_size =*/ nullkey_variable_size_no,
+    NULL, // WINSCP
     /*.ssh_id =*/ "ecdsa-sha2-nistp384",
     /*.cache_id =*/ "ecdsa-sha2-nistp384",
     /*.extra =*/ &sign_extra_nistp384,
-    0, // WINSCP
-    .supported_flags = nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
-    .alg_desc = ec_alg_desc,
-    .variable_size = nullkey_variable_size_no,
+    false, NULL, // WINSCP
 };
 
 /* OID: 1.3.132.0.35 (secp521r1) */
@@ -1615,19 +1623,21 @@ const ssh_keyalg ssh_ecdsa_nistp521 = {
     /*.public_blob =*/ ecdsa_public_blob,
     /*.private_blob =*/ ecdsa_private_blob,
     /*.openssh_blob =*/ ecdsa_openssh_blob,
-    .has_private = ecdsa_has_private,
+    /*.has_private =*/ ecdsa_has_private,
     /*.cache_str =*/ ecdsa_cache_str,
     /*.components =*/ ecdsa_components,
+    /*.base_key =*/ nullkey_base_key,
+    NULL, NULL, NULL, NULL, // WINSCP
     /*.pubkey_bits =*/ ec_shared_pubkey_bits,
-    .base_key = nullkey_base_key,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    /*.alg_desc =*/ ec_alg_desc,
+    /*.variable_size =*/ nullkey_variable_size_no,
+    NULL, // WINSCP
     /*.ssh_id =*/ "ecdsa-sha2-nistp521",
     /*.cache_id =*/ "ecdsa-sha2-nistp521",
     /*.extra =*/ &sign_extra_nistp521,
-    0, // WINSCP
-    .supported_flags = nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
-    .alg_desc = ec_alg_desc,
-    .variable_size = nullkey_variable_size_no,
+    false, NULL, // WINSCP
 };
 
 /* ----------------------------------------------------------------------
@@ -1666,6 +1676,7 @@ static ecdh_key *ssh_ecdhkex_w_new(const ssh_kex *kex, bool is_server)
     dhw->extra = extra;
     dhw->curve = curve;
 
+    { // WINSCP
     mp_int *one = mp_from_integer(1);
     dhw->private = mp_random_in_range(one, dhw->curve->w.G_order);
     mp_free(one);
@@ -1673,6 +1684,7 @@ static ecdh_key *ssh_ecdhkex_w_new(const ssh_kex *kex, bool is_server)
     dhw->w_public = ecc_weierstrass_multiply(dhw->curve->w.G, dhw->private);
 
     return &dhw->ek;
+    } // WINSCP
 }
 
 static ecdh_key *ssh_ecdhkex_m_new(const ssh_kex *kex, bool is_server)
@@ -1685,6 +1697,7 @@ static ecdh_key *ssh_ecdhkex_m_new(const ssh_kex *kex, bool is_server)
     dhm->extra = extra;
     dhm->curve = curve;
 
+    { // WINSCP
     strbuf *bytes = strbuf_new_nm();
     random_read(strbuf_append(bytes, dhm->curve->fieldBytes),
                 dhm->curve->fieldBytes);
@@ -1708,6 +1721,7 @@ static ecdh_key *ssh_ecdhkex_m_new(const ssh_kex *kex, bool is_server)
     dhm->m_public = ecc_montgomery_multiply(dhm->curve->m.G, dhm->private);
 
     return &dhm->ek;
+    } // WINSCP
 }
 
 static void ssh_ecdhkex_w_getpublic(ecdh_key *dh, BinarySink *bs)
@@ -1850,101 +1864,111 @@ static char *ssh_ecdhkex_description(const ssh_kex *kex)
 static const struct eckex_extra kex_extra_curve25519 = { ec_curve25519 };
 
 static const ecdh_keyalg ssh_ecdhkex_m_alg = {
-    .new = ssh_ecdhkex_m_new,
-    .free = ssh_ecdhkex_m_free,
-    .getpublic = ssh_ecdhkex_m_getpublic,
-    .getkey = ssh_ecdhkex_m_getkey,
-    .description = ssh_ecdhkex_description,
+    /*.new =*/ ssh_ecdhkex_m_new,
+    /*.free =*/ ssh_ecdhkex_m_free,
+    /*.getpublic =*/ ssh_ecdhkex_m_getpublic,
+    /*.getkey =*/ ssh_ecdhkex_m_getkey,
+    /*.description =*/ ssh_ecdhkex_description,
 };
 const ssh_kex ssh_ec_kex_curve25519 = {
-    .name = "curve25519-sha256",
-    .main_type = KEXTYPE_ECDH,
-    .hash = &ssh_sha256,
-    .ecdh_vt = &ssh_ecdhkex_m_alg,
-    .extra = &kex_extra_curve25519,
+    /*.name =*/ "curve25519-sha256",
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_ECDH,
+    /*.hash =*/ &ssh_sha256,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_m_alg,
+    /*.extra =*/ &kex_extra_curve25519,
 };
 /* Pre-RFC alias */
 static const ssh_kex ssh_ec_kex_curve25519_libssh = {
-    .name = "[email protected]",
-    .main_type = KEXTYPE_ECDH,
-    .hash = &ssh_sha256,
-    .ecdh_vt = &ssh_ecdhkex_m_alg,
-    .extra = &kex_extra_curve25519,
+    /*.name =*/ "[email protected]",
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_ECDH,
+    /*.hash =*/ &ssh_sha256,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_m_alg,
+    /*.extra =*/ &kex_extra_curve25519,
 };
 /* GSSAPI variant */
 static const ssh_kex ssh_ec_kex_curve25519_gss = {
-    .name = "gss-curve25519-sha256-" GSS_KRB5_OID_HASH,
-    .main_type = KEXTYPE_GSS_ECDH,
-    .hash = &ssh_sha256,
-    .ecdh_vt = &ssh_ecdhkex_m_alg,
-    .extra = &kex_extra_curve25519,
+    /*.name =*/ "gss-curve25519-sha256-" GSS_KRB5_OID_HASH,
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_GSS_ECDH,
+    /*.hash =*/ &ssh_sha256,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_m_alg,
+    /*.extra =*/ &kex_extra_curve25519,
 };
 
 static const struct eckex_extra kex_extra_curve448 = { ec_curve448 };
 const ssh_kex ssh_ec_kex_curve448 = {
-    .name = "curve448-sha512",
-    .main_type = KEXTYPE_ECDH,
-    .hash = &ssh_sha512,
-    .ecdh_vt = &ssh_ecdhkex_m_alg,
-    .extra = &kex_extra_curve448,
+    /*.name =*/ "curve448-sha512",
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_ECDH,
+    /*.hash =*/ &ssh_sha512,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_m_alg,
+    /*.extra =*/ &kex_extra_curve448,
 };
 
 static const ecdh_keyalg ssh_ecdhkex_w_alg = {
-    .new = ssh_ecdhkex_w_new,
-    .free = ssh_ecdhkex_w_free,
-    .getpublic = ssh_ecdhkex_w_getpublic,
-    .getkey = ssh_ecdhkex_w_getkey,
-    .description = ssh_ecdhkex_description,
+    /*.new =*/ ssh_ecdhkex_w_new,
+    /*.free =*/ ssh_ecdhkex_w_free,
+    /*.getpublic =*/ ssh_ecdhkex_w_getpublic,
+    /*.getkey =*/ ssh_ecdhkex_w_getkey,
+    /*.description =*/ ssh_ecdhkex_description,
 };
 static const struct eckex_extra kex_extra_nistp256 = { ec_p256 };
 const ssh_kex ssh_ec_kex_nistp256 = {
-    .name = "ecdh-sha2-nistp256",
-    .main_type = KEXTYPE_ECDH,
-    .hash = &ssh_sha256,
-    .ecdh_vt = &ssh_ecdhkex_w_alg,
-    .extra = &kex_extra_nistp256,
+    /*.name =*/ "ecdh-sha2-nistp256",
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_ECDH,
+    /*.hash =*/ &ssh_sha256,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_w_alg,
+    /*.extra =*/ &kex_extra_nistp256,
 };
 /* GSSAPI variant */
 static const ssh_kex ssh_ec_kex_nistp256_gss = {
-    .name = "gss-nistp256-sha256-" GSS_KRB5_OID_HASH,
-    .main_type = KEXTYPE_GSS_ECDH,
-    .hash = &ssh_sha256,
-    .ecdh_vt = &ssh_ecdhkex_w_alg,
-    .extra = &kex_extra_nistp256,
+    /*.name =*/ "gss-nistp256-sha256-" GSS_KRB5_OID_HASH,
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_GSS_ECDH,
+    /*.hash =*/ &ssh_sha256,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_w_alg,
+    /*.extra =*/ &kex_extra_nistp256,
 };
 
 static const struct eckex_extra kex_extra_nistp384 = { ec_p384 };
 const ssh_kex ssh_ec_kex_nistp384 = {
-    .name = "ecdh-sha2-nistp384",
-    .main_type = KEXTYPE_ECDH,
-    .hash = &ssh_sha384,
-    .ecdh_vt = &ssh_ecdhkex_w_alg,
-    .extra = &kex_extra_nistp384,
+    /*.name =*/ "ecdh-sha2-nistp384",
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_ECDH,
+    /*.hash =*/ &ssh_sha384,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_w_alg,
+    /*.extra =*/ &kex_extra_nistp384,
 };
 /* GSSAPI variant */
 static const ssh_kex ssh_ec_kex_nistp384_gss = {
-    .name = "gss-nistp384-sha384-" GSS_KRB5_OID_HASH,
-    .main_type = KEXTYPE_GSS_ECDH,
-    .hash = &ssh_sha384,
-    .ecdh_vt = &ssh_ecdhkex_w_alg,
-    .extra = &kex_extra_nistp384,
+    /*.name =*/ "gss-nistp384-sha384-" GSS_KRB5_OID_HASH,
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_GSS_ECDH,
+    /*.hash =*/ &ssh_sha384,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_w_alg,
+    /*.extra =*/ &kex_extra_nistp384,
 };
 
 static const struct eckex_extra kex_extra_nistp521 = { ec_p521 };
 const ssh_kex ssh_ec_kex_nistp521 = {
-    .name = "ecdh-sha2-nistp521",
-    .main_type = KEXTYPE_ECDH,
-    .hash = &ssh_sha512,
-    .ecdh_vt = &ssh_ecdhkex_w_alg,
-    .extra = &kex_extra_nistp521,
+    /*.name =*/ "ecdh-sha2-nistp521",
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_ECDH,
+    /*.hash =*/ &ssh_sha512,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_w_alg,
+    /*.extra =*/ &kex_extra_nistp521,
 };
 /* GSSAPI variant */
 static const ssh_kex ssh_ec_kex_nistp521_gss = {
-    .name = "gss-nistp521-sha512-" GSS_KRB5_OID_HASH,
-    .main_type = KEXTYPE_GSS_ECDH,
-    .hash = &ssh_sha512,
-    .ecdh_vt = &ssh_ecdhkex_w_alg,
-    .extra = &kex_extra_nistp521,
+    /*.name =*/ "gss-nistp521-sha512-" GSS_KRB5_OID_HASH,
+    NULL, // WINSCP
+    /*.main_type =*/ KEXTYPE_GSS_ECDH,
+    /*.hash =*/ &ssh_sha512,
+    /*.ecdh_vt =*/ &ssh_ecdhkex_w_alg,
+    /*.extra =*/ &kex_extra_nistp521,
 };
 
 static const ssh_kex *const ec_kex_list[] = {

+ 6 - 6
source/putty/crypto/hmac.c

@@ -175,7 +175,7 @@ const ssh2_macalg ssh_hmac_sha256 = {
     /*.setkey =*/ hmac_key,
     /*.start =*/ hmac_start,
     /*.genresult =*/ hmac_genresult,
-    .next_message = nullmac_next_message,
+    /*.next_message =*/ nullmac_next_message,
     /*.text_name =*/ hmac_text_name,
     /*.name =*/ "hmac-sha2-256",
     /*.etm_name =*/ "[email protected]",
@@ -192,7 +192,7 @@ const ssh2_macalg ssh_hmac_md5 = {
     /*.setkey =*/ hmac_key,
     /*.start =*/ hmac_start,
     /*.genresult =*/ hmac_genresult,
-    .next_message = nullmac_next_message,
+    /*.next_message =*/ nullmac_next_message,
     /*.text_name =*/ hmac_text_name,
     /*.name =*/ "hmac-md5",
     /*.etm_name =*/ "[email protected]",
@@ -210,7 +210,7 @@ const ssh2_macalg ssh_hmac_sha1 = {
     /*.setkey =*/ hmac_key,
     /*.start =*/ hmac_start,
     /*.genresult =*/ hmac_genresult,
-    .next_message = nullmac_next_message,
+    /*.next_message =*/ nullmac_next_message,
     /*.text_name =*/ hmac_text_name,
     /*.name =*/ "hmac-sha1",
     /*.etm_name =*/ "[email protected]",
@@ -228,7 +228,7 @@ const ssh2_macalg ssh_hmac_sha1_96 = {
     /*.setkey =*/ hmac_key,
     /*.start =*/ hmac_start,
     /*.genresult =*/ hmac_genresult,
-    .next_message = nullmac_next_message,
+    /*.next_message =*/ nullmac_next_message,
     /*.text_name =*/ hmac_text_name,
     /*.name =*/ "hmac-sha1-96",
     /*.etm_name =*/ "[email protected]",
@@ -248,7 +248,7 @@ const ssh2_macalg ssh_hmac_sha1_buggy = {
     /*.setkey =*/ hmac_key,
     /*.start =*/ hmac_start,
     /*.genresult =*/ hmac_genresult,
-    .next_message = nullmac_next_message,
+    /*.next_message =*/ nullmac_next_message,
     /*.text_name =*/ hmac_text_name,
     /*.name =*/ "hmac-sha1",
     NULL, // WINSCP
@@ -268,7 +268,7 @@ const ssh2_macalg ssh_hmac_sha1_96_buggy = {
     /*.setkey =*/ hmac_key,
     /*.start =*/ hmac_start,
     /*.genresult =*/ hmac_genresult,
-    .next_message = nullmac_next_message,
+    /*.next_message =*/ nullmac_next_message,
     /*.text_name =*/ hmac_text_name,
     /*.name =*/ "hmac-sha1-96",
     NULL, // WINSCP

+ 113 - 49
source/putty/crypto/openssh-certs.c

@@ -147,7 +147,9 @@ static inline bool blobtrans_read(BlobTransformer *bt, BinarySource *src,
                                   blob_fmt blob)
 {
     size_t nparts = bt->nparts;
-    for (size_t i = 0; i < blob.len; i++)
+    { // WINSCP
+    size_t i;
+    for (i = 0; i < blob.len; i++)
         if (nparts < blob.fmt[i]+1)
             nparts = blob.fmt[i]+1;
 
@@ -157,7 +159,7 @@ static inline bool blobtrans_read(BlobTransformer *bt, BinarySource *src,
             bt->parts[bt->nparts++] = make_ptrlen(NULL, 0);
     }
 
-    for (size_t i = 0; i < blob.len; i++) {
+    for (i = 0; i < blob.len; i++) {
         size_t j = blob.fmt[i];
         ptrlen part = get_string(src);
         if (bt->parts[j].ptr) {
@@ -175,13 +177,15 @@ static inline bool blobtrans_read(BlobTransformer *bt, BinarySource *src,
     }
 
     return true;
+    } // WINSCP
 }
 
 static inline void blobtrans_write(BlobTransformer *bt, BinarySink *bs,
                                    blob_fmt blob)
 {
-    for (size_t i = 0; i < blob.len; i++) {
-        assert(i < bt->nparts);
+    size_t i; // WINSCP
+    for (i = 0; i < blob.len; i++) {
+        pinitassert(i < bt->nparts);
         ptrlen part = bt->parts[blob.fmt[i]];
         assert(part.ptr);
         put_stringpl(bs, part);
@@ -241,46 +245,46 @@ static const ssh_keyalg *opensshcert_related_alg(const ssh_keyalg *self,
 
 #define KEYALG_DEF(name, ssh_alg_id_prefix, ssh_key_id_prefix, fmt_prefix) \
     static const struct opensshcert_extra opensshcert_##name##_extra = { \
-        .pub_fmt = { .fmt = fmt_prefix ## _pub_fmt,                     \
-                     .len = lenof(fmt_prefix ## _pub_fmt) },            \
-        .base_ossh_fmt = { .fmt = fmt_prefix ## _base_ossh_fmt,         \
-                           .len = lenof(fmt_prefix ## _base_ossh_fmt) }, \
-        .cert_ossh_fmt = { .fmt = fmt_prefix ## _cert_ossh_fmt,         \
-                           .len = lenof(fmt_prefix ## _cert_ossh_fmt) }, \
-        .cert_key_ssh_id = ssh_key_id_prefix "[email protected]",   \
-        .base_key_ssh_id = ssh_key_id_prefix,                           \
+        /*.pub_fmt =*/ { /*.fmt =*/ fmt_prefix ## _pub_fmt,                     \
+                     /*.len =*/ lenof(fmt_prefix ## _pub_fmt) },            \
+        /*.base_ossh_fmt =*/ { /*.fmt =*/ fmt_prefix ## _base_ossh_fmt,         \
+                           /*.len =*/ lenof(fmt_prefix ## _base_ossh_fmt) }, \
+        /*.cert_ossh_fmt =*/ { /*.fmt =*/ fmt_prefix ## _cert_ossh_fmt,         \
+                           /*.len =*/ lenof(fmt_prefix ## _cert_ossh_fmt) }, \
+        /*.cert_key_ssh_id =*/ ssh_key_id_prefix "[email protected]",   \
+        /*.base_key_ssh_id =*/ ssh_key_id_prefix,                           \
     };                                                                  \
                                                                         \
     const ssh_keyalg opensshcert_##name = {                             \
-        .new_pub = opensshcert_new_pub,                                 \
-        .new_priv = opensshcert_new_priv,                               \
-        .new_priv_openssh = opensshcert_new_priv_openssh,               \
-        .freekey = opensshcert_freekey,                                 \
-        .invalid = opensshcert_invalid,                                 \
-        .sign = opensshcert_sign,                                       \
-        .verify = opensshcert_verify,                                   \
-        .public_blob = opensshcert_public_blob,                         \
-        .private_blob = opensshcert_private_blob,                       \
-        .openssh_blob = opensshcert_openssh_blob,                       \
-        .has_private = opensshcert_has_private,                         \
-        .cache_str = opensshcert_cache_str,                             \
-        .components = opensshcert_components,                           \
-        .base_key = opensshcert_base_key,                               \
-        .ca_public_blob = opensshcert_ca_public_blob,                   \
-        .check_cert = opensshcert_check_cert,                           \
-        .cert_id_string = opensshcert_cert_id_string,                   \
-        .cert_info = opensshcert_cert_info,                             \
-        .pubkey_bits = opensshcert_pubkey_bits,                         \
-        .supported_flags = opensshcert_supported_flags,                 \
-        .alternate_ssh_id = opensshcert_alternate_ssh_id,               \
-        .alg_desc = opensshcert_alg_desc,                               \
-        .variable_size = opensshcert_variable_size,                     \
-        .related_alg = opensshcert_related_alg,                         \
-        .ssh_id = ssh_alg_id_prefix "[email protected]",            \
-        .cache_id = "opensshcert-" ssh_key_id_prefix,                   \
-        .extra = &opensshcert_##name##_extra,                           \
-        .is_certificate = true,                                         \
-        .base_alg = &name,                                              \
+        /*.new_pub =*/ opensshcert_new_pub,                                 \
+        /*.new_priv =*/ opensshcert_new_priv,                               \
+        /*.new_priv_openssh =*/ opensshcert_new_priv_openssh,               \
+        /*.freekey =*/ opensshcert_freekey,                                 \
+        /*.invalid =*/ opensshcert_invalid,                                 \
+        /*.sign =*/ opensshcert_sign,                                       \
+        /*.verify =*/ opensshcert_verify,                                   \
+        /*.public_blob =*/ opensshcert_public_blob,                         \
+        /*.private_blob =*/ opensshcert_private_blob,                       \
+        /*.openssh_blob =*/ opensshcert_openssh_blob,                       \
+        /*.has_private =*/ opensshcert_has_private,                         \
+        /*.cache_str =*/ opensshcert_cache_str,                             \
+        /*.components =*/ opensshcert_components,                           \
+        /*.base_key =*/ opensshcert_base_key,                               \
+        /*.ca_public_blob =*/ opensshcert_ca_public_blob,                   \
+        /*.check_cert =*/ opensshcert_check_cert,                           \
+        /*.cert_id_string =*/ opensshcert_cert_id_string,                   \
+        /*.cert_info =*/ opensshcert_cert_info,                             \
+        /*.pubkey_bits =*/ opensshcert_pubkey_bits,                         \
+        /*.supported_flags =*/ opensshcert_supported_flags,                 \
+        /*.alternate_ssh_id =*/ opensshcert_alternate_ssh_id,               \
+        /*.alg_desc =*/ opensshcert_alg_desc,                               \
+        /*.variable_size =*/ opensshcert_variable_size,                     \
+        /*.related_alg =*/ opensshcert_related_alg,                         \
+        /*.ssh_id =*/ ssh_alg_id_prefix "[email protected]",            \
+        /*.cache_id =*/ "opensshcert-" ssh_key_id_prefix,                   \
+        /*.extra =*/ &opensshcert_##name##_extra,                           \
+        /*.is_certificate =*/ true,                                         \
+        /*.base_alg =*/ &name,                                              \
     };
 KEYALG_LIST(KEYALG_DEF)
 #undef KEYALG_DEF
@@ -303,12 +307,14 @@ static strbuf *get_base_public_blob(BinarySource *src,
      * does ensure that the right amount of data is copied so that
      * src ends up in the right position to read the remaining
      * certificate fields. */
+    { // WINSCP
     BLOBTRANS_DECLARE(bt);
     blobtrans_read(bt, src, extra->pub_fmt);
     blobtrans_write(bt, BinarySink_UPCAST(basepub), extra->pub_fmt);
     blobtrans_clear(bt);
 
     return basepub;
+    } // WINSCP
 }
 
 static opensshcert_key *opensshcert_new_shared(
@@ -323,11 +329,13 @@ static opensshcert_key *opensshcert_new_shared(
     if (!ptrlen_eq_string(get_string(src), extra->cert_key_ssh_id))
         return NULL;
 
+    { // WINSCP
     opensshcert_key *ck = snew(opensshcert_key);
     memset(ck, 0, sizeof(*ck));
     ck->sshk.vt = self;
 
     ck->nonce = strbuf_dup(get_string(src));
+    { // WINSCP
     strbuf *basepub = get_base_public_blob(src, extra);
     ck->serial = get_uint64(src);
     ck->type = get_uint32(src);
@@ -350,6 +358,8 @@ static opensshcert_key *opensshcert_new_shared(
 
     *basepub_out = basepub;
     return ck;
+    } // WINSCP
+    } // WINSCP
 }
 
 static ssh_key *opensshcert_new_pub(const ssh_keyalg *self, ptrlen pub)
@@ -402,6 +412,7 @@ static ssh_key *opensshcert_new_priv_openssh(
     if (!ck)
         return NULL;
 
+    { // WINSCP
     strbuf *baseossh = strbuf_new();
 
     /* Make the base OpenSSH key blob out of the public key blob
@@ -415,6 +426,7 @@ static ssh_key *opensshcert_new_priv_openssh(
 
     /* blobtrans_read might fail in this case, because we're reading
      * from two sources and they might fail to match */
+    { // WINSCP
     bool success = blobtrans_read(bt, pubsrc, extra->pub_fmt) &&
         blobtrans_read(bt, src, extra->cert_ossh_fmt);
 
@@ -430,6 +442,7 @@ static ssh_key *opensshcert_new_priv_openssh(
 
     strbuf_free(basepub);
 
+    { // WINSCP
     BinarySource osshsrc[1];
     BinarySource_BARE_INIT_PL(osshsrc, ptrlen_from_strbuf(baseossh));
     ck->basekey = ssh_key_new_priv_openssh(self->base_alg, osshsrc);
@@ -441,6 +454,9 @@ static ssh_key *opensshcert_new_priv_openssh(
     }
 
     return &ck->sshk;
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
 static void opensshcert_freekey(ssh_key *key)
@@ -485,11 +501,13 @@ static ssh_key *opensshcert_ca_pub_key(
     if (algname)
         *algname = pubkey_blob_to_alg_name(alg_source);
 
+    { // WINSCP
     const ssh_keyalg *ca_alg = pubkey_blob_to_alg(alg_source);
     if (!ca_alg)
         return NULL;  /* don't even recognise the certifying key type */
 
     return ssh_key_new_pub(ca_alg, ca_keyblob);
+    } // WINSCP
 }
 
 static void opensshcert_signature_preimage(opensshcert_key *ck, BinarySink *bs)
@@ -498,8 +516,10 @@ static void opensshcert_signature_preimage(opensshcert_key *ck, BinarySink *bs)
     put_stringz(bs, extra->cert_key_ssh_id);
     put_stringpl(bs, ptrlen_from_strbuf(ck->nonce));
 
+    { // WINSCP
     strbuf *basepub = strbuf_new();
     ssh_key_public_blob(ck->basekey, BinarySink_UPCAST(basepub));
+    { // WINSCP
     BinarySource src[1];
     BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(basepub));
     get_string(src); /* skip initial key type string */
@@ -516,6 +536,8 @@ static void opensshcert_signature_preimage(opensshcert_key *ck, BinarySink *bs)
     put_stringpl(bs, ptrlen_from_strbuf(ck->extensions));
     put_stringpl(bs, ptrlen_from_strbuf(ck->reserved));
     put_stringpl(bs, ptrlen_from_strbuf(ck->signature_key));
+    } // WINSCP
+    } // WINSCP
 }
 
 static void opensshcert_public_blob(ssh_key *key, BinarySink *bs)
@@ -541,17 +563,23 @@ static void opensshcert_openssh_blob(ssh_key *key, BinarySink *bs)
     ssh_key_public_blob(key, BinarySink_UPCAST(cert));
     put_stringsb(bs, cert);
 
+    { // WINSCP
     strbuf *baseossh = strbuf_new_nm();
     ssh_key_openssh_blob(ck->basekey, BinarySink_UPCAST(baseossh));
+    { // WINSCP
     BinarySource basesrc[1];
     BinarySource_BARE_INIT_PL(basesrc, ptrlen_from_strbuf(baseossh));
 
+    { // WINSCP
     BLOBTRANS_DECLARE(bt);
     blobtrans_read(bt, basesrc, extra->base_ossh_fmt);
     blobtrans_write(bt, bs, extra->cert_ossh_fmt);
     blobtrans_clear(bt);
 
     strbuf_free(baseossh);
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
 static void opensshcert_ca_public_blob(ssh_key *key, BinarySink *bs)
@@ -592,21 +620,30 @@ static void opensshcert_string_list_key_components(
     BinarySource src[1];
     BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(input));
 
-    const char *titles[2] = { title, title2 };
+    { // WINSCP
+    const char *titles[2]; // WINSCP
+    titles[0] = title;
+    titles[1] = title2;
+    { // WINSCP
     size_t ntitles = (title2 ? 2 : 1);
 
     unsigned index = 0;
     while (get_avail(src)) {
-        for (size_t ti = 0; ti < ntitles; ti++) {
+        size_t ti; // WINSCP
+        for (ti = 0; ti < ntitles; ti++) {
             ptrlen value = get_string(src);
             if (get_err(src))
                 break;
+            { // WINSCP
             char *name = dupprintf("%s_%u", titles[ti], index);
             key_components_add_text_pl(kc, name, value);
             sfree(name);
+            } // WINSCP
         }
         index++;
     }
+    } // WINSCP
+    } // WINSCP
 }
 
 static key_components *opensshcert_components(ssh_key *key)
@@ -643,7 +680,7 @@ static key_components *opensshcert_components(ssh_key *key)
                                    ptrlen_from_strbuf(date));
         strbuf_free(date);
     }
-    if (ck->valid_before != 0xFFFFFFFFFFFFFFFF) {
+    if (ck->valid_before != 0xFFFFFFFFFFFFFFFFLL ) { // WINSCP
         strbuf *date = strbuf_new();
         opensshcert_time_to_iso8601(BinarySink_UPCAST(date), ck->valid_before);
         key_components_add_text_pl(kc, "cert_valid_before_date",
@@ -659,6 +696,7 @@ static key_components *opensshcert_components(ssh_key *key)
     key_components_add_binary(kc, "cert_ca_key", ptrlen_from_strbuf(
                                   ck->signature_key));
 
+    { // WINSCP
     ptrlen ca_algname;
     ssh_key *ca_key = opensshcert_ca_pub_key(ck, make_ptrlen(NULL, 0),
                                              &ca_algname);
@@ -666,7 +704,8 @@ static key_components *opensshcert_components(ssh_key *key)
 
     if (ca_key) {
         key_components *kc_ca_key = ssh_key_components(ca_key);
-        for (size_t i = 0; i < kc_ca_key->ncomponents; i++) {
+        size_t i; // WINSCP
+        for (i = 0; i < kc_ca_key->ncomponents; i++) {
             key_component *comp = &kc_ca_key->components[i];
             char *subname = dupcat("cert_ca_key_", comp->name);
             key_components_add_copy(kc, subname, comp);
@@ -679,10 +718,14 @@ static key_components *opensshcert_components(ssh_key *key)
     key_components_add_binary(kc, "cert_ca_sig", ptrlen_from_strbuf(
                                   ck->signature));
     return kc;
+    } // WINSCP
 }
 
 static SeatDialogText *opensshcert_cert_info(ssh_key *key)
 {
+#ifdef WINSCP
+    return NULL;
+#else
     opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
     SeatDialogText *text = seat_dialog_text_new();
     strbuf *tmp = strbuf_new();
@@ -714,6 +757,7 @@ static SeatDialogText *opensshcert_cert_info(ssh_key *key)
         BinarySource src[1];
         BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
                                       ck->valid_principals));
+        { // WINSCP
         const char *sep = "";
         strbuf_clear(tmp);
         while (get_avail(src)) {
@@ -726,13 +770,14 @@ static SeatDialogText *opensshcert_cert_info(ssh_key *key)
         }
         seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
                                 "%s", tmp->s);
+        } // WINSCP
     }
 
     seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
                             "Validity period");
     strbuf_clear(tmp);
     if (ck->valid_after == 0) {
-        if (ck->valid_before == 0xFFFFFFFFFFFFFFFF) {
+        if (ck->valid_before == 0xFFFFFFFFFFFFFFFFLL) { // WINSCP
             put_dataz(tmp, "forever");
         } else {
             put_dataz(tmp, "until ");
@@ -740,7 +785,7 @@ static SeatDialogText *opensshcert_cert_info(ssh_key *key)
                                         ck->valid_before);
         }
     } else {
-        if (ck->valid_before == 0xFFFFFFFFFFFFFFFF) {
+        if (ck->valid_before == 0xFFFFFFFFFFFFFFFFLL) { // WINSCP
             put_dataz(tmp, "after ");
             opensshcert_time_to_iso8601(BinarySink_UPCAST(tmp),
                                         ck->valid_after);
@@ -773,20 +818,24 @@ static SeatDialogText *opensshcert_cert_info(ssh_key *key)
                 ptrlen_eq_string(key, "source-address")) {
                 BinarySource src2[1];
                 BinarySource_BARE_INIT_PL(src2, value);
+                { // WINSCP
                 ptrlen addresslist = get_string(src2);
                 seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
                                         "Permitted client IP addresses");
                 seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
                                         "%.*s", PTRLEN_PRINTF(addresslist));
+                } // WINSCP
             } else if (ck->type == SSH_CERT_TYPE_USER &&
                        ptrlen_eq_string(key, "force-command")) {
                 BinarySource src2[1];
                 BinarySource_BARE_INIT_PL(src2, value);
+                { // WINSCP
                 ptrlen command = get_string(src2);
                 seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
                                         "Forced remote command");
                 seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
                                         "%.*s", PTRLEN_PRINTF(command));
+                } // WINSCP
             }
         }
     }
@@ -800,6 +849,7 @@ static SeatDialogText *opensshcert_cert_info(ssh_key *key)
      * things that _aren't_ enabled.
      */
 
+    { // WINSCP
     bool x11_ok = false, agent_ok = false, portfwd_ok = false;
     bool pty_ok = false, user_rc_ok = false;
 
@@ -863,6 +913,7 @@ static SeatDialogText *opensshcert_cert_info(ssh_key *key)
     seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
                             "%" PRIu64, ck->serial);
 
+    { // WINSCP
     char *fp = ssh2_fingerprint_blob(ptrlen_from_strbuf(ck->signature_key),
                                      SSH_FPTYPE_DEFAULT);
     seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
@@ -878,6 +929,9 @@ static SeatDialogText *opensshcert_cert_info(ssh_key *key)
 
     strbuf_free(tmp);
     return text;
+    } // WINSCP
+    } // WINSCP
+#endif
 }
 
 static int opensshcert_pubkey_bits(const ssh_keyalg *self, ptrlen blob)
@@ -887,11 +941,13 @@ static int opensshcert_pubkey_bits(const ssh_keyalg *self, ptrlen blob)
 
     get_string(src);                   /* key type */
     get_string(src);                   /* nonce */
+    { // WINSCP
     strbuf *basepub = get_base_public_blob(src, self->extra);
     int bits = ssh_key_public_bits(
         self->base_alg, ptrlen_from_strbuf(basepub));
     strbuf_free(basepub);
     return bits;
+    } // WINSCP
 }
 
 static unsigned opensshcert_supported_flags(const ssh_keyalg *self)
@@ -904,7 +960,8 @@ static const char *opensshcert_alternate_ssh_id(const ssh_keyalg *self,
 {
     const char *base_id = ssh_keyalg_alternate_ssh_id(self->base_alg, flags);
 
-    for (size_t i = 0; i < lenof(opensshcert_all_keyalgs); i++) {
+    size_t i; // WINSCP
+    for (i = 0; i < lenof(opensshcert_all_keyalgs); i++) {
         const ssh_keyalg *alg_i = opensshcert_all_keyalgs[i];
         if (!strcmp(base_id, alg_i->base_alg->ssh_id))
             return alg_i->ssh_id;
@@ -929,7 +986,8 @@ static bool opensshcert_variable_size(const ssh_keyalg *self)
 static const ssh_keyalg *opensshcert_related_alg(const ssh_keyalg *self,
                                                  const ssh_keyalg *base)
 {
-    for (size_t i = 0; i < lenof(opensshcert_all_keyalgs); i++) {
+    size_t i; // WINSCP
+    for (i = 0; i < lenof(opensshcert_all_keyalgs); i++) {
         const ssh_keyalg *alg_i = opensshcert_all_keyalgs[i];
         if (base == alg_i->base_alg)
             return alg_i;
@@ -994,6 +1052,7 @@ static bool opensshcert_check_cert(
     /* Check which signature algorithm is actually in use, because
      * that might be a reason to reject the certificate (e.g. ssh-rsa
      * when we wanted rsa-sha2-*). */
+    { // WINSCP
     const ssh_keyalg *sig_alg = ssh_key_alg(ca_key);
     if ((sig_alg == &ssh_rsa && !opts->permit_rsa_sha1) ||
         (sig_alg == &ssh_rsa_sha256 && !opts->permit_rsa_sha256) ||
@@ -1010,6 +1069,7 @@ static bool opensshcert_check_cert(
         goto out;
     }
 
+    { // WINSCP
     uint32_t expected_type = host ? SSH_CERT_TYPE_HOST : SSH_CERT_TYPE_USER;
     if (ck->type != expected_type) {
         put_fmt(error, "Certificate type is ");
@@ -1079,6 +1139,7 @@ static bool opensshcert_check_cert(
                 host ? "hostname" : "username");
         BinarySource_BARE_INIT_PL(
             src, ptrlen_from_strbuf(ck->valid_principals));
+        { // WINSCP
         const char *sep = "";
         while (get_avail(src)) {
             ptrlen valid_principal = get_string(src);
@@ -1093,6 +1154,7 @@ static bool opensshcert_check_cert(
         put_fmt(error, "\"");
         goto out;
       principal_ok:;
+        } // WINSCP
     }
 
     /*
@@ -1142,6 +1204,8 @@ static bool opensshcert_check_cert(
         ssh_key_free(ca_key);
     strbuf_free(preimage);
     return result;
+    } // WINSCP
+    } // WINSCP
 }
 
 static bool opensshcert_verify(ssh_key *key, ptrlen sig, ptrlen data)

+ 34 - 19
source/putty/crypto/rsa.c

@@ -922,44 +922,55 @@ static const struct ssh2_rsa_extra
     /*.public_blob =*/ rsa2_public_blob,            \
     /*.private_blob =*/ rsa2_private_blob,          \
     /*.openssh_blob =*/ rsa2_openssh_blob,          \
+    /*.has_private =*/ rsa2_has_private,            \
     /*.cache_str =*/ rsa2_cache_str,                \
-    .has_private = rsa2_has_private,            \
     /*.components =*/ rsa2_components,              \
-    /*.pubkey_bits =*/ rsa2_pubkey_bits             \
-    .base_key = nullkey_base_key,               \
-    .alg_desc = rsa2_alg_desc,                  \
-    .variable_size = nullkey_variable_size_yes,
+    /*.base_key =*/ nullkey_base_key,               \
+    NULL, NULL, NULL, NULL, \
+    /*.pubkey_bits =*/ rsa2_pubkey_bits
+#define COMMON_KEYALG_FIELDS1a \
+    /*.alg_desc =*/ rsa2_alg_desc,                  \
+    /*.variable_size =*/ nullkey_variable_size_yes, \
+    NULL
 #define COMMON_KEYALG_FIELDS2 \
     /*.cache_id =*/ "rsa2"
+#define COMMON_KEYALG_FIELDS3 \
+    false, NULL
 
 const ssh_keyalg ssh_rsa = {
     // WINSCP
     COMMON_KEYALG_FIELDS,
+    /*.supported_flags =*/ ssh_rsa_supported_flags,
+    /*.alternate_ssh_id =*/ ssh_rsa_alternate_ssh_id,
+    COMMON_KEYALG_FIELDS1a,
     /*.ssh_id =*/ "ssh-rsa",
     COMMON_KEYALG_FIELDS2,
-    /*.supported_flags =*/ ssh_rsa_supported_flags,
-    .alternate_ssh_id = ssh_rsa_alternate_ssh_id,
     /*.extra =*/ &rsa_extra,
+    COMMON_KEYALG_FIELDS3,
 };
 
 const ssh_keyalg ssh_rsa_sha256 = {
     // WINSCP
     COMMON_KEYALG_FIELDS,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    COMMON_KEYALG_FIELDS1a,
     /*.ssh_id =*/ "rsa-sha2-256",
     COMMON_KEYALG_FIELDS2,
     /*.extra =*/ &rsa_sha256_extra,
-    /*.supported_flags =*/ nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
+    COMMON_KEYALG_FIELDS3,
 };
 
 const ssh_keyalg ssh_rsa_sha512 = {
     // WINSCP
     COMMON_KEYALG_FIELDS,
+    /*.supported_flags =*/ nullkey_supported_flags,
+    /*.alternate_ssh_id =*/ nullkey_alternate_ssh_id,
+    COMMON_KEYALG_FIELDS1a,
     /*.ssh_id =*/ "rsa-sha2-512",
     COMMON_KEYALG_FIELDS2,
     /*.extra =*/ &rsa_sha512_extra,
-    /*.supported_flags =*/ nullkey_supported_flags,
-    .alternate_ssh_id = nullkey_alternate_ssh_id,
+    COMMON_KEYALG_FIELDS3,
 };
 
 RSAKey *ssh_rsakex_newkey(ptrlen data)
@@ -1175,17 +1186,21 @@ static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha1 = { 1024 };
 static const struct ssh_rsa_kex_extra ssh_rsa_kex_extra_sha256 = { 2048 };
 
 static const ssh_kex ssh_rsa_kex_sha1 = {
-    .name = "rsa1024-sha1",
-    .main_type = KEXTYPE_RSA,
-    .hash = &ssh_sha1,
-    .extra = &ssh_rsa_kex_extra_sha1,
+    /*.name =*/ "rsa1024-sha1",
+    NULL,
+    /*.main_type =*/ KEXTYPE_RSA,
+    /*.hash =*/ &ssh_sha1,
+    NULL, // WINSCP
+    /*.extra =*/ &ssh_rsa_kex_extra_sha1,
 };
 
 static const ssh_kex ssh_rsa_kex_sha256 = {
-    .name = "rsa2048-sha256",
-    .main_type = KEXTYPE_RSA,
-    .hash = &ssh_sha256,
-    .extra = &ssh_rsa_kex_extra_sha256,
+    /*.name =*/ "rsa2048-sha256",
+    NULL,
+    /*.main_type =*/ KEXTYPE_RSA,
+    /*.hash =*/ &ssh_sha256,
+    NULL, // WINSCP
+    /*.extra =*/ &ssh_rsa_kex_extra_sha256,
 };
 
 static const ssh_kex *const rsa_kex_list[] = {

+ 2 - 0
source/putty/misc.h

@@ -185,10 +185,12 @@ static inline ptrlen make_ptrlen_startend(const void *startv, const void *endv)
 {
     const char *start = (const char *)startv, *end = (const char *)endv;
     assert(end >= start);
+    { // WINSCP
     ptrlen pl;
     pl.ptr = start;
     pl.len = end - start;
     return pl;
+    } // WINSCP
 }
 
 static inline ptrlen ptrlen_from_asciz(const char *str)

+ 8 - 3
source/putty/putty.h

@@ -429,7 +429,9 @@ enum {
     KEX_DHGEX,
     KEX_RSA,
     KEX_ECDH,
+#ifndef WINSCP
     KEX_NTRU_HYBRID,
+#endif
     KEX_MAX
 };
 
@@ -1283,7 +1285,8 @@ struct SeatVtable {
     SeatPromptResult (*confirm_ssh_host_key)(
         Seat *seat, const char *host, int port, const char *keytype,
         char *keystr, SeatDialogText *text, HelpCtx helpctx,
-        void (*callback)(void *ctx, SeatPromptResult result), void *ctx);
+        void (*callback)(void *ctx, SeatPromptResult result), void *ctx,
+        char **fingerprints); // WINSCP
 
     /*
      * Check with the seat whether it's OK to use a cryptographic
@@ -1439,9 +1442,11 @@ static inline void seat_set_busy_status(Seat *seat, BusyStatus status)
 static inline SeatPromptResult seat_confirm_ssh_host_key(
     InteractionReadySeat iseat, const char *h, int p, const char *ktyp,
     char *kstr, SeatDialogText *text, HelpCtx helpctx,
-    void (*cb)(void *ctx, SeatPromptResult result), void *ctx)
+    void (*cb)(void *ctx, SeatPromptResult result), void *ctx,
+    char **fingerprints) // WINSCP
 { return iseat.seat->vt->confirm_ssh_host_key(
-        iseat.seat, h, p, ktyp, kstr, text, helpctx, cb, ctx); }
+        iseat.seat, h, p, ktyp, kstr, text, helpctx, cb, ctx,
+        fingerprints); }
 static inline SeatPromptResult seat_confirm_weak_crypto_primitive(
     InteractionReadySeat iseat, const char *atyp, const char *aname,
     void (*cb)(void *ctx, SeatPromptResult result), void *ctx)

+ 1 - 14
source/putty/puttyexp.h

@@ -20,7 +20,7 @@ const struct ssh_decompressor * get_sccomp(Backend * be);
 unsigned int winscp_query(Backend * be, int query);
 void md5checksum(const char * buffer, int len, unsigned char output[16]);
 typedef const struct ssh_keyalg * cp_ssh_keyalg;
-void get_hostkey_algs(int * count, cp_ssh_keyalg * SignKeys);
+void get_hostkey_algs(int * count, cp_ssh_keyalg ** sign_keys);
 void get_macs(int * count, const struct ssh2_macalg *** amacs);
 int have_any_ssh2_hostkey(Seat * seat, const char * host, int port);
 
@@ -35,19 +35,6 @@ void wingss_cleanup(void);
 int is_pfwd(Plug * plug);
 Seat * get_pfwd_seat(Plug * plug);
 
-// for winstore.c
-
-#include <windows.h>
-
-long reg_open_winscp_key(HKEY Key, const char * SubKey, HKEY * Result);
-long reg_create_winscp_key(HKEY Key, const char * SubKey, HKEY * Result);
-long reg_query_winscp_value_ex(HKEY Key, const char * ValueName,
-  unsigned long * Reserved, unsigned long * Type, unsigned char * Data,
-  unsigned long * DataSize);
-long reg_set_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long Reserved,
-  unsigned long Type, const unsigned char * Data, unsigned long DataSize);
-long reg_close_winscp_key(HKEY Key);
-
 // from winnet.c
 
 void select_result(WPARAM wParam, LPARAM lParam);

+ 4 - 0
source/putty/settings.c

@@ -29,7 +29,9 @@ static const struct keyvalwhere ciphernames[] = {
  * compatibility warts in load_open_settings(), and should be kept
  * in sync with those. */
 static const struct keyvalwhere kexnames[] = {
+#ifndef WINSCP
     { "ntru-curve25519",    KEX_NTRU_HYBRID, -1, +1 },
+#endif
     { "ecdh",               KEX_ECDH,       -1, +1 },
     /* This name is misleading: it covers both SHA-256 and SHA-1 variants */
     { "dh-gex-sha1",        KEX_DHGEX,      -1, -1 },
@@ -1330,6 +1332,7 @@ static int sessioncmp(const void *av, const void *bv)
 
 bool sesslist_demo_mode = false;
 
+#ifndef WINSCP
 void get_sesslist(struct sesslist *list, bool allocate)
 {
     int i;
@@ -1389,3 +1392,4 @@ void get_sesslist(struct sesslist *list, bool allocate)
         list->sessions = NULL;
     }
 }
+#endif

+ 10 - 0
source/putty/ssh.h

@@ -727,8 +727,12 @@ static inline void ssh_cipher_next_message(ssh_cipher *c)
 static inline const struct ssh_cipheralg *ssh_cipher_alg(ssh_cipher *c)
 { return c->vt; }
 
+#endif
+
 void nullcipher_next_message(ssh_cipher *);
 
+#ifndef WINSCP_VS
+
 struct ssh2_ciphers {
     int nciphers;
     const ssh_cipheralg *const *list;
@@ -857,10 +861,12 @@ struct ssh_kex {
     const void *extra;                 /* private to the kex methods */
 };
 
+#ifndef __cplusplus // WINSCP not needed and won't compile, as KEYTYPE_* needs type
 static inline bool kex_is_gss(const struct ssh_kex *kex)
 {
     return kex->main_type == KEXTYPE_GSS || kex->main_type == KEXTYPE_GSS_ECDH;
 }
+#endif
 
 struct ssh_kexes {
     int nkexes;
@@ -1236,7 +1242,9 @@ extern const ssh2_macalg ssh_hmac_sha1_96;
 extern const ssh2_macalg ssh_hmac_sha1_96_buggy;
 extern const ssh2_macalg ssh_hmac_sha256;
 extern const ssh2_macalg ssh2_poly1305;
+#endif
 extern const ssh2_macalg ssh2_aesgcm_mac;
+#ifndef WINSCP_VS
 extern const ssh2_macalg ssh2_aesgcm_mac_sw;
 extern const ssh2_macalg ssh2_aesgcm_mac_ref_poly;
 extern const ssh2_macalg ssh2_aesgcm_mac_clmul;
@@ -1568,6 +1576,7 @@ static inline bool ssh_fptype_is_cert(FingerprintType fptype)
 {
     return fptype >= SSH_FPTYPE_MD5_CERT;
 }
+#ifndef __cplusplus // WINSCP not needed and won't compile
 static inline FingerprintType ssh_fptype_from_cert(FingerprintType fptype)
 {
     if (ssh_fptype_is_cert(fptype))
@@ -1580,6 +1589,7 @@ static inline FingerprintType ssh_fptype_to_cert(FingerprintType fptype)
         fptype += (SSH_FPTYPE_MD5_CERT - SSH_FPTYPE_MD5);
     return fptype;
 }
+#endif
 
 #define SSH_N_FPTYPES (SSH_FPTYPE_SHA256_CERT + 1)
 #define SSH_FPTYPE_DEFAULT SSH_FPTYPE_SHA256

+ 8 - 1
source/putty/ssh/common_p.c

@@ -961,6 +961,7 @@ SeatPromptResult verify_ssh_host_key(
      * The key is either missing from the cache, or does not match.
      * Either way, fall back to an interactive prompt from the Seat.
      */
+    { // WINSCP
     SeatDialogText *text = seat_dialog_text_new();
     const SeatDialogPromptDescriptions *pds =
         seat_prompt_descriptions(iseat.seat);
@@ -971,6 +972,7 @@ SeatPromptResult verify_ssh_host_key(
     seat_dialog_text_append(
         text, SDT_TITLE, "%s Security Alert", appname);
 
+    { // WINSCP
     HelpCtx helpctx;
 
     if (key && ssh_key_alg(key)->is_certificate) {
@@ -1106,11 +1108,16 @@ SeatPromptResult verify_ssh_host_key(
                                 fingerprints[SSH_FPTYPE_MD5]);
     }
 
+    { // WINSCP
     SeatPromptResult toret = seat_confirm_ssh_host_key(
-        iseat, host, port, keytype, keystr, text, helpctx, callback, ctx);
+        iseat, host, port, keytype, keystr, text, helpctx, callback, ctx,
+        fingerprints); // WINSCP
     seat_dialog_text_free(text);
     return toret;
     } // WINSCP
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
 /* ----------------------------------------------------------------------

+ 32 - 2
source/putty/ssh/kex2-client.c

@@ -156,6 +156,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                 return;
             }
         }
+        { // WINSCP
         mp_int *K = dh_find_K(s->dh_ctx, s->f);
         put_mp_ssh2(s->kex_shared_secret, K);
         mp_free(K);
@@ -184,6 +185,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
             mp_free(s->g); s->g = NULL;
             mp_free(s->p); s->p = NULL;
         }
+        } // WINSCP
     } else if (s->kex_alg->main_type == KEXTYPE_ECDH) {
         char *desc = ecdh_keyalg_description(s->kex_alg);
         ppl_logevent("Doing %s, using hash %s", desc,
@@ -228,6 +230,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
         {
             ptrlen keydata = get_string(pktin);
             put_stringpl(s->exhash, keydata);
+            { // WINSCP
             bool ok = ecdh_key_getkey(s->ecdh_key, keydata,
                                       BinarySink_UPCAST(s->kex_shared_secret));
             if (!get_err(pktin) && !ok) {
@@ -236,6 +239,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                 *aborted = true;
                 return;
             }
+            } // WINSCP
         }
 
         s->sigdata = get_string(pktin);
@@ -282,10 +286,12 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
         if (s->kex_alg->main_type == KEXTYPE_GSS_ECDH) {
             s->ecdh_key = ecdh_key_new(s->kex_alg, false);
 
+            { // WINSCP
             char *desc = ecdh_keyalg_description(s->kex_alg);
             ppl_logevent("Doing GSSAPI (with Kerberos V5) %s with hash %s",
                          desc, ssh_hash_alg(s->exhash)->text_name);
             sfree(desc);
+            } // WINSCP
         } else if (dh_is_gex(s->kex_alg)) {
             /*
              * Work out how big a DH group we will need to allow that
@@ -516,9 +522,11 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                 *aborted = true;
                 return;
             }
+            { // WINSCP
             mp_int *K = dh_find_K(s->dh_ctx, s->f);
             put_mp_ssh2(s->kex_shared_secret, K);
             mp_free(K);
+            } // WINSCP
         }
 
         /* We assume everything from now on will be quick, and it might
@@ -899,9 +907,11 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                 }
             }
 
+            { // WINSCP
             ssh2_userkey uk; // WINSCP
             uk.key = s->hkey; // WINSCP
             uk.comment = NULL; // WINSCP
+            { // WINSCP
             char **fingerprints = ssh2_all_fingerprints(s->hkey);
 
             FingerprintType fptype_default =
@@ -924,18 +934,28 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                 ppl_logevent("%s", base_fp);
                 sfree(base_fp);
 
+                { // WINSCP
                 strbuf *id_string = strbuf_new();
+                #ifndef WINSCP
                 StripCtrlChars *id_string_scc = stripctrl_new(
                     BinarySink_UPCAST(id_string), false, L'\0');
+                #endif
                 ssh_key_cert_id_string(
-                    s->hkey, BinarySink_UPCAST(id_string_scc));
+                    s->hkey, BinarySink_UPCAST(id_string/*WINSCP _scc*/));
+                #ifndef WINSCP
                 stripctrl_free(id_string_scc);
+                #endif
                 ppl_logevent("Certificate ID string is \"%s\"", id_string->s);
                 strbuf_free(id_string);
 
+                { // WINSCP
                 strbuf *ca_pub = strbuf_new();
                 ssh_key_ca_public_blob(s->hkey, BinarySink_UPCAST(ca_pub));
-                host_ca hca_search = { .ca_public_key = ca_pub };
+                { // WINSCP
+                host_ca hca_search;
+                smemclr(&hca_search, sizeof(hca_search));
+                hca_search.ca_public_key = ca_pub;
+                { // WINSCP
                 host_ca *hca_found = find234(s->host_cas, &hca_search, NULL);
 
                 char *ca_fp = ssh2_fingerprint_blob(ptrlen_from_strbuf(ca_pub),
@@ -946,6 +966,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
 
                 strbuf_free(ca_pub);
 
+                { // WINSCP
                 strbuf *error = strbuf_new();
                 bool cert_ok = false;
 
@@ -973,6 +994,11 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                     strbuf_free(error);
                     /* now fall through into normal host key checking */
                 }
+                } // WINSCP
+                } // WINSCP
+                } // WINSCP
+                } // WINSCP
+                } // WINSCP
             }
 
             {
@@ -1021,6 +1047,8 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
              */
             strbuf_clear(s->hostkeyblob);
             ssh_key_public_blob(s->hkey, BinarySink_UPCAST(s->hostkeyblob));
+            } // WINSCP
+            } // WINSCP
         } else if (s->cross_certifying) {
             assert(s->hkey);
             assert(ssh_key_alg(s->hkey) == s->cross_certifying);
@@ -1050,6 +1078,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
              */
             strbuf *thisblob = strbuf_new();
             ssh_key_public_blob(s->hkey, BinarySink_UPCAST(thisblob));
+            { // WINSCP
             bool match = ptrlen_eq_ptrlen(ptrlen_from_strbuf(thisblob),
                                           ptrlen_from_strbuf(s->hostkeyblob));
             strbuf_free(thisblob);
@@ -1061,6 +1090,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
                 return;
 #endif
             }
+            } // WINSCP
         }
 
     sfree(s->keystr);

+ 35 - 10
source/putty/ssh/transport2.c

@@ -230,7 +230,9 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl)
         ssh_key_free(s->hkey);
         s->hkey = NULL;
     }
-    for (size_t i = 0; i < NKEXLIST; i++)
+    { // WINSCP
+    size_t i;
+    for (i = 0; i < NKEXLIST; i++)
         sfree(s->kexlists[i].algs);
     if (s->f) mp_free(s->f);
     if (s->p) mp_free(s->p);
@@ -256,6 +258,7 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl)
 
     expire_timer_context(s);
     sfree(s);
+    } // WINSCP
 }
 
 /*
@@ -327,14 +330,17 @@ static void ssh2_mkkey(
 static struct kexinit_algorithm *ssh2_kexinit_addalg_pl(
     struct kexinit_algorithm_list *list, ptrlen name)
 {
-    for (size_t i = 0; i < list->nalgs; i++)
+    size_t i; // WINSCP
+    for (i = 0; i < list->nalgs; i++)
         if (ptrlen_eq_ptrlen(list->algs[i].name, name))
             return &list->algs[i];
 
     sgrowarray(list->algs, list->algsize, list->nalgs);
+    { // WINSCP
     struct kexinit_algorithm *entry = &list->algs[list->nalgs++];
     entry->name = name;
     return entry;
+    } // WINSCP
 }
 
 static struct kexinit_algorithm *ssh2_kexinit_addalg(
@@ -576,10 +582,12 @@ static void ssh2_write_kexinit_lists(
             preferred_kex[n_preferred_kex++] =
                 &ssh_ecdh_kex;
             break;
+          #ifndef WINSCP
           case KEX_NTRU_HYBRID:
             preferred_kex[n_preferred_kex++] =
                 &ssh_ntru_hybrid_kex;
             break;
+          #endif
           case KEX_WARN:
             /* Flag for later. Don't bother if it's the last in
              * the list. */
@@ -679,12 +687,15 @@ static void ssh2_write_kexinit_lists(
             alg->u.hk.hkflags = 0;
             alg->u.hk.warn = false;
 
+            { // WINSCP
             uint32_t supported_flags = ssh_keyalg_supported_flags(keyalg);
             static const uint32_t try_flags[] = {
                 SSH_AGENT_RSA_SHA2_256,
                 SSH_AGENT_RSA_SHA2_512,
             };
-            for (size_t i = 0; i < lenof(try_flags); i++) {
+            { // WINSCP
+            size_t i;
+            for (i = 0; i < lenof(try_flags); i++) {
                 if (try_flags[i] & ~supported_flags)
                     continue;          /* these flags not supported */
 
@@ -696,6 +707,8 @@ static void ssh2_write_kexinit_lists(
                 alg->u.hk.hkflags = try_flags[i];
                 alg->u.hk.warn = false;
             }
+            } // WINSCP
+            } // WINSCP
         }
     } else if (first_time) {
         /*
@@ -713,6 +726,7 @@ static void ssh2_write_kexinit_lists(
          */
 
         bool accept_certs = false;
+        #ifndef WINSCP
         {
             host_ca_enum *handle = enum_host_ca_start();
             if (handle) {
@@ -735,6 +749,7 @@ static void ssh2_write_kexinit_lists(
                 strbuf_free(name);
             }
         }
+        #endif
 
         if (accept_certs) {
             /* Add all the certificate algorithms first, in preference order */
@@ -1247,14 +1262,19 @@ static void filter_outgoing_kexinit(struct ssh2_transport_state *s)
      * lists the same as the rest. In the rest of this code base we
      * ignore those.
      */
+    { // WINSCP
     strbuf *out = strbuf_new();
-    for (size_t i = 0; i < NKEXLIST+2; i++) {
+    size_t i; // WINSCP
+    for (i = 0; i < NKEXLIST+2; i++) {
         strbuf_clear(out);
+        { // WINSCP
         ptrlen olist = get_string(osrc), ilist = get_string(isrc);
-        for (ptrlen oword; get_commasep_word(&olist, &oword) ;) {
+        ptrlen oword; // WINSCP
+        for (; get_commasep_word(&olist, &oword) ;) {
             ptrlen ilist_copy = ilist;
             bool add = false;
-            for (ptrlen iword; get_commasep_word(&ilist_copy, &iword) ;) {
+            ptrlen iword; // WINSCP
+            for (; get_commasep_word(&ilist_copy, &iword) ;) {
                 if (ptrlen_eq_ptrlen(oword, iword)) {
                     /* Found this word in the incoming list. */
                     add = true;
@@ -1278,6 +1298,7 @@ static void filter_outgoing_kexinit(struct ssh2_transport_state *s)
                 add_to_commasep_pl(out, oword);
         }
         put_stringpl(pktout, ptrlen_from_strbuf(out));
+        } // WINSCP
     }
     strbuf_free(out);
 
@@ -1296,6 +1317,7 @@ static void filter_outgoing_kexinit(struct ssh2_transport_state *s)
     strbuf_shrink_to(s->outgoing_kexinit, 1); /* keep the type byte */
     put_datapl(s->outgoing_kexinit, ptrlen_from_strbuf(pktout));
     strbuf_free(pktout);
+    } // WINSCP
 }
 
 void ssh2transport_finalise_exhash(struct ssh2_transport_state *s)
@@ -1497,7 +1519,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
          */
         s->n_uncert_hostkeys = 0;
 
-        for (int i = 0; i < hks.n; i++) {
+        { // WINSCP
+        int i;
+        for (i = 0; i < hks.n; i++) {
             int j = hks.indices[i];
             if (ssh2_hostkey_algs[j].alg != s->hostkey_alg &&
                 ssh2_hostkey_algs[j].alg->cache_id &&
@@ -1508,6 +1532,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
         }
 
         sfree(hks.indices);
+        } // WINSCP
     }
 
     if (s->warn_kex) {
@@ -2454,14 +2479,14 @@ void call_ssh_timer(Backend * be)
 }
 
 // WINSCP
-void get_hostkey_algs(int * count, cp_ssh_keyalg * SignKeys)
+void get_hostkey_algs(int * count, cp_ssh_keyalg ** sign_keys)
 {
     int i;
-    assert(lenof(ssh2_hostkey_algs) <= *count);
     *count = lenof(ssh2_hostkey_algs);
+    *sign_keys = snewn(*count, cp_ssh_keyalg *);
     for (i = 0; i < *count; i++)
     {
-        *(SignKeys + i) = ssh2_hostkey_algs[i].alg;
+        *((*sign_keys) + i) = ssh2_hostkey_algs[i].alg;
     }
 }
 

+ 49 - 6
source/putty/ssh/userauth2-client.c

@@ -299,10 +299,12 @@ static bool ssh2_userauth_signflags(struct ssh2_userauth_state *s,
 {
     *signflags = 0;                    /* default */
 
+    { // WINSCP
     const ssh_keyalg *alg = find_pubkey_alg(*algname);
     if (!alg)
         return false;          /* we don't know how to upgrade this */
 
+    { // WINSCP
     unsigned supported_flags = ssh_keyalg_supported_flags(alg);
 
     if (s->ppl.bpp->ext_info_rsa_sha512_ok &&
@@ -317,6 +319,8 @@ static bool ssh2_userauth_signflags(struct ssh2_userauth_state *s,
 
     *algname = ssh_keyalg_alternate_ssh_id(alg, *signflags);
     return true;
+    } // WINSCP
+    } // WINSCP
 }
 
 static void authplugin_plug_log(Plug *plug, PlugLogType type, SockAddr *addr,
@@ -357,10 +361,11 @@ static void authplugin_plug_sent(Plug *plug, size_t bufsize)
 }
 
 static const PlugVtable authplugin_plugvt = {
-    .log = authplugin_plug_log,
-    .closing = authplugin_plug_closing,
-    .receive = authplugin_plug_receive,
-    .sent = authplugin_plug_sent,
+    /*.log =*/ authplugin_plug_log,
+    /*.closing =*/ authplugin_plug_closing,
+    /*.receive =*/ authplugin_plug_receive,
+    /*.sent =*/ authplugin_plug_sent,
+    NULL, // WINSCP
 };
 
 static strbuf *authplugin_newmsg(uint8_t type)
@@ -386,9 +391,11 @@ static bool authplugin_expect_msg(struct ssh2_userauth_state *s,
         *type = PLUGIN_EOF;
         return true;
     }
+    { // WINSCP
     uint8_t len[4];
     if (!bufchain_try_fetch(&s->authplugin_bc, len, 4))
         return false;
+    { // WINSCP
     size_t size = GET_32BIT_MSB_FIRST(len);
     if (bufchain_size(&s->authplugin_bc) - 4 < size)
         return false;
@@ -407,6 +414,8 @@ static bool authplugin_expect_msg(struct ssh2_userauth_state *s,
     if (get_err(src))
         *type = PLUGIN_NOTYPE;
     return true;
+    } // WINSCP
+    } // WINSCP
 }
 
 static void authplugin_bad_packet(struct ssh2_userauth_state *s,
@@ -436,11 +445,13 @@ static void authplugin_bad_packet(struct ssh2_userauth_state *s,
     }
     if (fmt) {
         put_dataz(msg, " (");
+        { // WINSCP
         va_list ap;
         va_start(ap, fmt);
         put_fmt(msg, fmt, ap);
         va_end(ap);
         put_dataz(msg, ")");
+        } // WINSCP
     }
     ssh_sw_abort(s->ppl.ssh, "%s", msg->s);
     strbuf_free(msg);
@@ -516,6 +527,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
 
         ppl_logevent("Reading certificate file \"%s\"",
                      filename_to_str(s->detached_cert_file));
+        { // WINSCP
         int keytype = key_type(s->detached_cert_file);
         if (!(keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 ||
               keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH)) {
@@ -523,6 +535,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
             goto cert_load_done;
         }
 
+        { // WINSCP
         const char *error;
         bool success = ppk_loadpub_f(
             s->detached_cert_file, &algname,
@@ -533,6 +546,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
             goto cert_load_done;
         }
 
+        { // WINSCP
         const ssh_keyalg *certalg = find_pubkey_alg(algname);
         if (!certalg) {
             cert_error = dupprintf(
@@ -567,6 +581,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
             strbuf_free(cert_blob);
         sfree(algname);
         sfree(comment);
+        } // WINSCP
+        } // WINSCP
+        } // WINSCP
     }
 
     /*
@@ -685,12 +702,14 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
         put_stringz(amsg, s->username ? s->username : "");
         authplugin_send_free(s, amsg);
 
+        { // WINSCP
         BinarySource src[1];
         unsigned type;
         crMaybeWaitUntilV(authplugin_expect_msg(s, &type, src));
         switch (type) {
           case PLUGIN_INIT_RESPONSE: {
             s->authplugin_version = get_uint32(src);
+            { // WINSCP
             ptrlen username = get_string(src);
             if (get_err(src)) {
                 ssh_sw_abort(s->ppl.ssh, "Received malformed "
@@ -709,6 +728,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                 ppl_logevent("Authentication plugin set username '%s'",
                              s->default_username);
             }
+            } // WINSCP
             break;
           }
           case PLUGIN_INIT_FAILURE: {
@@ -734,6 +754,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                                   "PLUGIN_INIT_FAILURE");
             return;
         }
+        } // WINSCP
     }
 
     /*
@@ -1058,6 +1079,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                  * Attempt public-key authentication using a key from Pageant.
                  */
                 s->agent_keyalg = s->agent_keys[s->agent_key_index].algorithm;
+                { // WINSCP
                 char *alg_tmp = mkstr(s->agent_keyalg);
                 const char *newalg = alg_tmp;
                 if (ssh2_userauth_signflags(s, &s->signflags, &newalg))
@@ -1168,6 +1190,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                 /* Do we have any keys left to try? */
                 if (++s->agent_key_index >= s->agent_key_limit)
                     s->done_agent = true;
+                } // WINSCP
 
             } else if (s->can_pubkey && s->publickey_blob &&
                        s->privatekey_available && !s->tried_pubkey_config) {
@@ -1184,6 +1207,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                  *
                  * First, try to upgrade its algorithm.
                  */
+                { // WINSCP
                 const char *newalg = s->publickey_algorithm;
                 if (ssh2_userauth_signflags(s, &s->signflags, &newalg)) {
                     sfree(s->publickey_algorithm);
@@ -1357,6 +1381,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                     sfree(key);
                     s->is_trivial_auth = false;
                 }
+                } // WINSCP
 
 #ifndef NO_GSSAPI
             } else if (s->can_gssapi && !s->tried_gssapi) {
@@ -1594,6 +1619,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                     put_stringz(amsg, "keyboard-interactive");
                     authplugin_send_free(s, amsg);
 
+                    { // WINSCP
                     BinarySource src[1];
                     unsigned type;
                     crMaybeWaitUntilV(authplugin_expect_msg(s, &type, src));
@@ -1643,6 +1669,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                             "PLUGIN_PROTOCOL_REJECT");
                         return;
                     }
+                    } // WINSCP
                 } else {
                     s->authplugin_ki_active = false;
                 }
@@ -1730,6 +1757,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                         put_datapl(amsg, get_data(pktin, get_avail(pktin)));
                         authplugin_send_free(s, amsg);
 
+                        { // WINSCP
                         BinarySource src[1];
                         unsigned type;
                         while (true) {
@@ -1760,11 +1788,13 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                             /*
                              * Send the responses on to the plugin.
                              */
+                            { // WINSCP
                             strbuf *amsg = authplugin_newmsg(
                                 PLUGIN_KI_USER_RESPONSE);
                             ssh2_userauth_ki_write_responses(
                                 s, BinarySink_UPCAST(amsg));
                             authplugin_send_free(s, amsg);
+                            } // WINSCP
                         }
 
                         if (type != PLUGIN_KI_SERVER_RESPONSE) {
@@ -1786,6 +1816,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                          */
                         crMaybeWaitUntilV(
                             (pktin = ssh2_userauth_pop(s)) != NULL);
+                        } // WINSCP
                     }
                 }
 
@@ -1823,11 +1854,13 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                         BinarySource_BARE_INIT(
                             src, get_ptr(pktin), get_avail(pktin));
                         get_string(pktin); /* skip methods */
+                        { // WINSCP
                         bool partial_success = get_bool(pktin);
                         if (!get_err(src)) {
                             plugin_msg = partial_success ?
                                 PLUGIN_AUTH_SUCCESS : PLUGIN_AUTH_FAILURE;
                         }
+                        } // WINSCP
                     }
 
                     if (plugin_msg >= 0) {
@@ -2154,8 +2187,11 @@ static bool ssh2_userauth_ki_setup_prompts(
      * Get any prompt(s) from the packet.
      */
     s->num_prompts = get_uint32(src);
-    for (uint32_t i = 0; i < s->num_prompts; i++) {
+    { // WINSCP
+    uint32_t i; // WINSCP
+    for (i = 0; i < s->num_prompts; i++) {
         s->is_trivial_auth = false;
+        { // WINSCP
         ptrlen prompt = get_string(src);
         bool echo = get_bool(src);
 
@@ -2179,7 +2215,9 @@ static bool ssh2_userauth_ki_setup_prompts(
             put_datapl(sb, prompt);
         }
         add_prompt(s->cur_prompt, strbuf_to_str(sb), echo);
+        } // WINSCP
     }
+    } // WINSCP
 
     /*
      * Make the header strings. This includes the 'name' (optional
@@ -2260,8 +2298,11 @@ static void ssh2_userauth_ki_write_responses(
     struct ssh2_userauth_state *s, BinarySink *bs)
 {
     put_uint32(bs, s->num_prompts);
-    for (uint32_t i = 0; i < s->num_prompts; i++)
+    { // WINSCP
+    uint32_t i;
+    for (i = 0; i < s->num_prompts; i++)
         put_stringz(bs, prompt_get_result_ref(s->cur_prompt->prompts[i]));
+    } // WINSCP
 
     /*
      * Free the prompts structure from this iteration. If there's
@@ -2351,6 +2392,7 @@ static void ssh2_userauth_add_alg_and_publickey(
          * base public key.
          */
 
+        { // WINSCP
         const ssh_keyalg *certalg = pubkey_blob_to_alg(detached_cert_pl);
         assert(certalg); /* we checked this before setting s->detached_blob */
         assert(certalg->is_certificate); /* and this too */
@@ -2456,6 +2498,7 @@ static void ssh2_userauth_add_alg_and_publickey(
         /* And if we did, don't fall through to the alternative below */
         if (done)
             return;
+        } // WINSCP
     }
 
     /* In all other cases, just put in what we were given. */

+ 4 - 0
source/putty/sshpubk.c

@@ -1894,6 +1894,7 @@ char *ssh2_double_fingerprint_blob(ptrlen blob, FingerprintType fptype)
     if (ssh_fptype_is_cert(fptype))
         fptype = ssh_fptype_from_cert(fptype);
 
+    { // WINSCP
     char *fp = ssh2_fingerprint_blob(blob, fptype);
     char *p = strrchr(fp, ' ');
     char *hash = p ? p + 1 : fp;
@@ -1910,6 +1911,7 @@ char *ssh2_double_fingerprint_blob(ptrlen blob, FingerprintType fptype)
 
     sfree(fpc);
     return fp;
+    } // WINSCP
 }
 
 char **ssh2_all_fingerprints_for_blob(ptrlen blob)
@@ -1935,9 +1937,11 @@ char *ssh2_double_fingerprint(ssh_key *data, FingerprintType fptype)
 {
     strbuf *blob = strbuf_new();
     ssh_key_public_blob(data, BinarySink_UPCAST(blob));
+    { // WINSCP
     char *ret = ssh2_double_fingerprint_blob(ptrlen_from_strbuf(blob), fptype);
     strbuf_free(blob);
     return ret;
+    } // WINSCP
 }
 
 char **ssh2_all_fingerprints(ssh_key *data)

+ 2 - 2
source/putty/stubs/null-opener.c

@@ -9,10 +9,10 @@
 static void null_opener_free(DeferredSocketOpener *opener) {}
 
 static const DeferredSocketOpenerVtable NullOpener_vt = {
-    .free = null_opener_free,
+    /*.free =*/ null_opener_free,
 };
 
-static DeferredSocketOpener null_opener = { .vt = &NullOpener_vt };
+static DeferredSocketOpener null_opener = { /*.vt =*/ &NullOpener_vt };
 
 DeferredSocketOpener *null_deferred_socket_opener(void)
 {

+ 4 - 4
source/putty/stubs/null-seat.c

@@ -56,10 +56,10 @@ bool nullseat_get_cursor_position(Seat *seat, int *x, int *y) { return false; }
 const SeatDialogPromptDescriptions *nullseat_prompt_descriptions(Seat *seat)
 {
     static const SeatDialogPromptDescriptions descs = {
-        .hk_accept_action = "",
-        .hk_connect_once_action = "",
-        .hk_cancel_action = "",
-        .hk_cancel_action_Participle = "",
+        /*.hk_accept_action =*/ "",
+        /*.hk_connect_once_action =*/ "",
+        /*.hk_cancel_action =*/ "",
+        /*.hk_cancel_action_Participle =*/ "",
     };
     return &descs;
 }

+ 4 - 1
source/putty/utils/base64_decode.c

@@ -9,7 +9,9 @@ void base64_decode_bs(BinarySink *bs, ptrlen input)
         char b64atom[4];
         unsigned char binatom[3];
 
-        for (size_t i = 0; i < 4 ;) {
+        { // WINSCP
+        size_t i;
+        for (i = 0; i < 4 ;) {
             char c = get_byte(src);
             if (get_err(src))
                 c = '=';
@@ -17,6 +19,7 @@ void base64_decode_bs(BinarySink *bs, ptrlen input)
                 continue;
             b64atom[i++] = c;
         }
+        } // WINSCP
 
         put_data(bs, binatom, base64_decode_atom(b64atom, binatom));
     }

+ 6 - 1
source/putty/utils/base64_encode.c

@@ -4,6 +4,7 @@ void base64_encode_bs(BinarySink *bs, ptrlen input, int cpl)
 {
     BinarySource src[1];
     BinarySource_BARE_INIT_PL(src, input);
+    { // WINSCP
     int linelen = 0;
 
     while (get_avail(src)) {
@@ -12,7 +13,9 @@ void base64_encode_bs(BinarySink *bs, ptrlen input, int cpl)
 
         char b64atom[4];
         base64_encode_atom(binatom.ptr, binatom.len, b64atom);
-        for (size_t i = 0; i < 4; i++) {
+        { // WINSCP
+        size_t i;
+        for (i = 0; i < 4; i++) {
             if (cpl > 0 && linelen >= cpl) {
                 linelen = 0;
                 put_byte(bs, '\n');
@@ -20,9 +23,11 @@ void base64_encode_bs(BinarySink *bs, ptrlen input, int cpl)
             put_byte(bs, b64atom[i]);
             linelen++;
         }
+        } // WINSCP
     }
     if (cpl > 0)
         put_byte(bs, '\n');
+    } // WINSCP
 }
 
 void base64_encode_fp(FILE *fp, ptrlen input, int cpl)

+ 42 - 7
source/putty/utils/cert-expr.c

@@ -201,6 +201,7 @@ static Token lex(ptrlen *text, ptrlen *token, char **err)
     while (p < e && is_space(*p))
         p++;
 
+    { // WINSCP
     const char *start = p;
 
     if (!(p < e)) {
@@ -221,7 +222,9 @@ static Token lex(ptrlen *text, ptrlen *token, char **err)
             {PTRLEN_DECL_LITERAL("!"), TOK_NOT},
         };
 
-        for (size_t i = 0; i < lenof(operators); i++) {
+        { // WINSCP
+        size_t i;
+        for (i = 0; i < lenof(operators); i++) {
             const struct operator *op = &operators[i];
             if (e - p >= op->text.len &&
                 ptrlen_eq_ptrlen(op->text, make_ptrlen(p, op->text.len))) {
@@ -230,6 +233,7 @@ static Token lex(ptrlen *text, ptrlen *token, char **err)
                 goto out;
             }
         }
+        } // WINSCP
 
         /*
          * Report an error if one of the operator characters is used
@@ -268,6 +272,7 @@ static Token lex(ptrlen *text, ptrlen *token, char **err)
     text->ptr = p;
     text->len = e - p;
     return type;
+    } // WINSCP
 }
 
 typedef enum Operator {
@@ -314,8 +319,11 @@ static void exprnode_free(ExprNode *en)
     switch (en->op) {
       case OP_AND:
       case OP_OR:
-        for (size_t i = 0; i < en->nsubexprs; i++)
+        { // WINSCP
+        size_t i;
+        for (i = 0; i < en->nsubexprs; i++)
             exprnode_free(en->subexprs[i]);
+        } // WINSCP
         sfree(en->subexprs);
         break;
       case OP_NOT:
@@ -336,7 +344,8 @@ static void exprnode_free(ExprNode *en)
 static unsigned ptrlen_to_port_number(ptrlen input)
 {
     unsigned val = 0;
-    for (const char *p = input.ptr, *end = p + input.len; p < end; p++) {
+    const char *p, *end; // WINSCP
+    for (p = input.ptr, end = p + input.len; p < end; p++) {
         assert('0' <= *p && *p <= '9'); /* expect parser to have checked */
         val = 10 * val + (*p - '0');
         if (val >= 65536)
@@ -386,6 +395,7 @@ static ExprNode *parse_atom(ParserState *ps)
         ptrlen openpar = ps->toktext;
         advance(ps);                   /* eat the ( */
 
+        { // WINSCP
         ExprNode *subexpr = parse_expr(ps);
         if (!subexpr)
             return NULL;
@@ -397,6 +407,7 @@ static ExprNode *parse_atom(ParserState *ps)
             return NULL;
         }
 
+        { // WINSCP
         ptrlen closepar = ps->toktext;
         advance(ps);                   /* eat the ) */
 
@@ -406,21 +417,27 @@ static ExprNode *parse_atom(ParserState *ps)
         subexpr->text = make_ptrlen_startend(
             openpar.ptr, ptrlen_end(closepar));
         return subexpr;
+        } // WINSCP
+        } // WINSCP
     }
 
     if (ps->tok == TOK_NOT) {
         ptrlen notloc = ps->toktext;
         advance(ps);                   /* eat the ! */
 
+        { // WINSCP
         ExprNode *subexpr = parse_atom(ps);
         if (!subexpr)
             return NULL;
 
+        { // WINSCP
         ExprNode *en = exprnode_new(
             OP_NOT, make_ptrlen_startend(
                 notloc.ptr, ptrlen_end(subexpr->text)));
         en->subexpr = subexpr;
         return en;
+        } // WINSCP
+        } // WINSCP
     }
 
     if (ps->tok == TOK_ATOM) {
@@ -432,6 +449,7 @@ static ExprNode *parse_atom(ParserState *ps)
             return en;
         }
 
+        { // WINSCP
         ptrlen tail;
         if (ptrlen_startswith(ps->toktext, PTRLEN_LITERAL("port:"), &tail)) {
             /* Port number (single or range). */
@@ -484,12 +502,15 @@ static ExprNode *parse_atom(ParserState *ps)
             }
 
 
+            { // WINSCP
             ExprNode *en = exprnode_new(OP_PORT_RANGE, ps->toktext);
             en->lo = lo;
             en->hi = hi;
             advance(ps);
             return en;
+            } // WINSCP
         }
+        } // WINSCP
     }
 
     error(ps, dupstr("expected a predicate or a parenthesised subexpression"),
@@ -506,6 +527,7 @@ static ExprNode *parse_expr(ParserState *ps)
     if (ps->tok != TOK_AND && ps->tok != TOK_OR)
         return subexpr;
 
+    { // WINSCP
     Token operator = ps->tok;
     ExprNode *en = exprnode_new(ps->tok == TOK_AND ? OP_AND : OP_OR,
                                 subexpr->text);
@@ -537,6 +559,7 @@ static ExprNode *parse_expr(ParserState *ps)
             return NULL;
         }
     }
+    } // WINSCP
 }
 
 static ExprNode *parse(ptrlen expr, char **error_msg, ptrlen *error_loc)
@@ -546,6 +569,7 @@ static ExprNode *parse(ptrlen expr, char **error_msg, ptrlen *error_loc)
     ps->err = NULL;
     advance(ps);
 
+    { // WINSCP
     ExprNode *en = parse_expr(ps);
     if (en && ps->tok != TOK_END) {
         error(ps, dupstr("unexpected text at end of expression"),
@@ -565,22 +589,29 @@ static ExprNode *parse(ptrlen expr, char **error_msg, ptrlen *error_loc)
     }
 
     return en;
+    } // WINSCP
 }
 
 static bool eval(ExprNode *en, const char *hostname, unsigned port)
 {
     switch (en->op) {
       case OP_AND:
-        for (size_t i = 0; i < en->nsubexprs; i++)
+        { // WINSCP
+        size_t i;
+        for (i = 0; i < en->nsubexprs; i++)
             if (!eval(en->subexprs[i], hostname, port))
                 return false;
         return true;
+        } // WINSCP
 
       case OP_OR:
-        for (size_t i = 0; i < en->nsubexprs; i++)
+        { // WINSCP
+        size_t i;
+        for (i = 0; i < en->nsubexprs; i++)
             if (eval(en->subexprs[i], hostname, port))
                 return true;
         return false;
+        } // WINSCP
 
       case OP_NOT:
         return !eval(en->subexpr, hostname, port);
@@ -603,9 +634,11 @@ bool cert_expr_match_str(const char *expression,
     if (!en)
         return false;
 
+    { // WINSCP
     bool matched = eval(en, hostname, port);
     exprnode_free(en);
     return matched;
+    } // WINSCP
 }
 
 bool cert_expr_valid(const char *expression,
@@ -635,7 +668,8 @@ CertExprBuilder *cert_expr_builder_new(void)
 
 void cert_expr_builder_free(CertExprBuilder *eb)
 {
-    for (size_t i = 0; i < eb->nwcs; i++)
+    size_t i; // WINSCP
+    for (i = 0; i < eb->nwcs; i++)
         sfree(eb->wcs[i]);
     sfree(eb->wcs);
     sfree(eb);
@@ -664,7 +698,8 @@ void cert_expr_builder_add(CertExprBuilder *eb, const char *wildcard)
 char *cert_expr_expression(CertExprBuilder *eb)
 {
     strbuf *sb = strbuf_new();
-    for (size_t i = 0; i < eb->nwcs; i++) {
+    size_t i; // WINSCP
+    for (i = 0; i < eb->nwcs; i++) {
         if (i)
             put_dataz(sb, " || ");
         put_dataz(sb, eb->wcs[i]);

+ 6 - 1
source/putty/utils/key_components.c

@@ -14,10 +14,12 @@ static void key_components_add_str(key_components *kc, const char *name,
                                    KeyComponentType type, ptrlen data)
 {
     sgrowarray(kc->components, kc->componentsize, kc->ncomponents);
+    { // WINSCP
     size_t n = kc->ncomponents++;
     kc->components[n].name = dupstr(name);
     kc->components[n].type = type;
     kc->components[n].str = strbuf_dup_nm(data);
+    } // WINSCP
 }
 
 void key_components_add_text(key_components *kc,
@@ -42,10 +44,12 @@ void key_components_add_mp(key_components *kc,
                            const char *name, mp_int *value)
 {
     sgrowarray(kc->components, kc->componentsize, kc->ncomponents);
+    { // WINSCP
     size_t n = kc->ncomponents++;
     kc->components[n].name = dupstr(name);
     kc->components[n].type = KCT_MPINT;
     kc->components[n].mp = mp_copy(value);
+    } // WINSCP
 }
 
 void key_components_add_uint(key_components *kc,
@@ -73,7 +77,8 @@ void key_components_add_copy(key_components *kc,
 
 void key_components_free(key_components *kc)
 {
-    for (size_t i = 0; i < kc->ncomponents; i++) {
+    size_t i; // WINSCP
+    for (i = 0; i < kc->ncomponents; i++) {
         key_component *comp = &kc->components[i];
         sfree(comp->name);
         switch (comp->type) {

+ 2 - 1
source/putty/utils/percent_decode.c

@@ -8,7 +8,8 @@
 
 void percent_decode_bs(BinarySink *bs, ptrlen data)
 {
-    for (const char *p = data.ptr, *e = ptrlen_end(data); p < e; p++) {
+    const char *p, *e; // WINSCP
+    for (p = data.ptr, e = ptrlen_end(data); p < e; p++) {
         char c = *p;
         if (c == '%' && e-p >= 3 &&
             isxdigit((unsigned char)p[1]) &&

+ 2 - 1
source/putty/utils/percent_encode.c

@@ -10,7 +10,8 @@
 
 void percent_encode_bs(BinarySink *bs, ptrlen data, const char *badchars)
 {
-    for (const char *p = data.ptr, *e = ptrlen_end(data); p < e; p++) {
+    const char *p, *e; // WINSCP
+    for (p = data.ptr, e = ptrlen_end(data); p < e; p++) {
         char c = *p;
         if (c == '%' || c < ' ' || (badchars && strchr(badchars, c)))
             put_fmt(bs, "%%%02X", (unsigned char)c);

+ 4 - 2
source/putty/utils/ptrlen.c

@@ -56,7 +56,8 @@ bool ptrlen_endswith(ptrlen whole, ptrlen suffix, ptrlen *tail)
 
 bool ptrlen_contains(ptrlen input, const char *characters)
 {
-    for (const char *p = input.ptr, *end = p + input.len; p < end; p++)
+    const char *p, *end; // WINSCP
+    for (p = input.ptr, end = p + input.len; p < end; p++)
         if (strchr(characters, *p))
             return true;
     return false;
@@ -64,7 +65,8 @@ bool ptrlen_contains(ptrlen input, const char *characters)
 
 bool ptrlen_contains_only(ptrlen input, const char *characters)
 {
-    for (const char *p = input.ptr, *end = p + input.len; p < end; p++)
+    const char *p, *end; // WINSCP
+    for (p = input.ptr, end = p + input.len; p < end; p++)
         if (!strchr(characters, *p))
             return false;
     return true;

+ 4 - 1
source/putty/utils/seat_dialog_text.c

@@ -16,7 +16,8 @@ SeatDialogText *seat_dialog_text_new(void)
 
 void seat_dialog_text_free(SeatDialogText *sdt)
 {
-    for (size_t i = 0; i < sdt->nitems; i++)
+    size_t i; // WINSCP
+    for (i = 0; i < sdt->nitems; i++)
         sfree(sdt->items[i].text);
     sfree(sdt->items);
     sfree(sdt);
@@ -26,9 +27,11 @@ static void seat_dialog_text_append_v(
     SeatDialogText *sdt, SeatDialogTextType type, const char *fmt, va_list ap)
 {
     sgrowarray(sdt->items, sdt->itemsize, sdt->nitems);
+    { // WINSCP
     SeatDialogTextItem *item = &sdt->items[sdt->nitems++];
     item->type = type;
     item->text = dupvprintf(fmt, ap);
+    } // WINSCP
 }
 
 void seat_dialog_text_append(SeatDialogText *sdt, SeatDialogTextType type,

+ 3 - 2
source/putty/utils/tempseat.c

@@ -249,7 +249,8 @@ static size_t tempseat_banner(Seat *seat, const void *data, size_t len)
 static SeatPromptResult tempseat_confirm_ssh_host_key(
     Seat *seat, const char *host, int port, const char *keytype,
     char *keystr, SeatDialogText *text, HelpCtx helpctx,
-    void (*callback)(void *ctx, SeatPromptResult result), void *ctx)
+    void (*callback)(void *ctx, SeatPromptResult result), void *ctx,
+    char **fingerprints) // WINSCP
 {
     unreachable("confirm_ssh_host_key should never be called on TempSeat");
 }
@@ -334,7 +335,7 @@ static const struct SeatVtable tempseat_vt = {
     /*.confirm_ssh_host_key =*/ tempseat_confirm_ssh_host_key,
     /*.confirm_weak_crypto_primitive =*/ tempseat_confirm_weak_crypto_primitive,
     /*.confirm_weak_cached_hostkey =*/ tempseat_confirm_weak_cached_hostkey,
-    .prompt_descriptions = tempseat_prompt_descriptions,
+    /*.prompt_descriptions =*/ tempseat_prompt_descriptions,
     /*.is_utf8 =*/ tempseat_is_utf8,
     /*.echoedit_update =*/ tempseat_echoedit_update,
     /*.get_x_display =*/ tempseat_get_x_display,

+ 10 - 0
source/putty/windows/network.c

@@ -484,6 +484,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname,
 {
     *canonicalname = NULL;
 
+    { // WINSCP
     SockAddr *addr = snew(SockAddr);
     memset(addr, 0, sizeof(SockAddr));
     addr->superfamily = UNRESOLVED;
@@ -505,6 +506,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname,
         hints.ai_socktype = SOCK_STREAM;
 
         /* strip [] on IPv6 address literals */
+        { // WINSCP
         char *trimmed_host = host_strduptrim(host);
         int err = p_getaddrinfo(trimmed_host, NULL, &hints, &addr->ais);
         sfree(trimmed_host);
@@ -519,6 +521,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname,
             addr->error = namelookup_strerror(err);
         }
         return addr;
+        } // WINSCP
     }
 #endif
 
@@ -528,6 +531,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname,
      * old-fashioned approach, which is to start by manually checking
      * for an IPv4 literal and then use gethostbyname.
      */
+    { // WINSCP
     unsigned long a = p_inet_addr(host);
     if (a != (unsigned long) INADDR_NONE) {
         addr->addresses = snew(unsigned long);
@@ -538,10 +542,12 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname,
         return addr;
     }
 
+    { // WINSCP
     struct hostent *h = p_gethostbyname(host);
     if (h) {
         addr->superfamily = IP;
 
+        { // WINSCP
         size_t n;
         for (n = 0; h->h_addr_list[n]; n++);
         addr->addresses = snewn(n, unsigned long);
@@ -553,11 +559,15 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname,
         }
 
         *canonicalname = dupstr(h->h_name);
+        } // WINSCP
     } else {
         DWORD err = p_WSAGetLastError();
         addr->error = namelookup_strerror(err);
     }
     return addr;
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
 static SockAddr *sk_special_addr(SuperFamily superfamily, const char *name)

+ 16 - 2
source/putty/windows/platform.h

@@ -25,8 +25,11 @@
 
 #include "tree234.h"
 
-#ifndef MPEXT
+#ifndef WINSCP
 #include "help.h"
+#else
+typedef const char *HelpCtx;
+#define HELPCTX(x) #x
 #endif
 
 #if defined _M_IX86 || defined _M_AMD64
@@ -42,8 +45,12 @@
 #elif defined _MSC_VER
 #define THREADLOCAL __declspec(thread)
 #else
+#ifdef WINSCP
+#define THREADLOCAL __thread
+#else
 #error Do not know how to declare thread-local storage with this toolchain
 #endif
+#endif
 
 /* Randomly-chosen dwData value identifying a WM_COPYDATA message as
  * being a Pageant transaction */
@@ -743,16 +750,23 @@ char *get_jumplist_registry_entries(void);
 #define CLIPUI_DEFAULT_INS CLIPUI_EXPLICIT
 
 /* In utils */
+int reg_override_winscp(void);
 HKEY open_regkey_fn(bool create, HKEY base, const char *path, ...);
+HKEY open_regkey_fn_winscp(bool create, HKEY base, const char *path, ...);
 #define open_regkey(create, base, ...) \
-    open_regkey_fn(create, base, __VA_ARGS__, (const char *)NULL)
+    reg_override_winscp() ? open_regkey_fn_winscp(create, base, __VA_ARGS__, (const char *)NULL) : open_regkey_fn(create, base, __VA_ARGS__, (const char *)NULL)
 void close_regkey(HKEY key);
+void close_regkey_winscp(HKEY key);
 void del_regkey(HKEY key, const char *name);
 char *enum_regkey(HKEY key, int index);
 bool get_reg_dword(HKEY key, const char *name, DWORD *out);
+bool get_reg_dword_winscp(HKEY key, const char *name, DWORD *out);
 bool put_reg_dword(HKEY key, const char *name, DWORD value);
+bool put_reg_dword_winscp(HKEY key, const char *name, DWORD value);
 char *get_reg_sz(HKEY key, const char *name);
+char *get_reg_sz_winscp(HKEY key, const char *name);
 bool put_reg_sz(HKEY key, const char *name, const char *str);
+bool put_reg_sz_winscp(HKEY key, const char *name, const char *str);
 strbuf *get_reg_multi_sz(HKEY key, const char *name);
 bool put_reg_multi_sz(HKEY key, const char *name, strbuf *str);
 

+ 63 - 25
source/putty/windows/storage.c

@@ -3,20 +3,6 @@
  * defined in storage.h.
  */
 
-#ifdef MPEXT
-
-#include "puttyexp.h"
-
-#pragma option push -w-dup
-#define RegOpenKey reg_open_winscp_key
-#define RegCreateKey reg_create_winscp_key
-#define RegQueryValueEx reg_query_winscp_value_ex
-#define RegSetValueEx reg_set_winscp_value_ex
-#define RegCloseKey reg_close_winscp_key
-#pragma option pop
-
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <limits.h>
@@ -53,9 +39,11 @@ settings_w *open_settings_w(const char *sessionname, char **errmsg)
     if (!sessionname || !*sessionname)
         sessionname = "Default Settings";
 
+    { // WINSCP
     strbuf *sb = strbuf_new();
     escape_registry_key(sessionname, sb);
 
+    { // WINSCP
     HKEY sesskey = open_regkey(true, HKEY_CURRENT_USER, puttystr, sb->s);
     if (!sesskey) {
         *errmsg = dupprintf("Unable to create registry key\n"
@@ -70,6 +58,8 @@ settings_w *open_settings_w(const char *sessionname, char **errmsg)
     toret->sesskey = sesskey;
     return toret;
     } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
 void write_setting_s(settings_w *handle, const char *key, const char *value)
@@ -99,8 +89,10 @@ settings_r *open_settings_r(const char *sessionname)
     if (!sessionname || !*sessionname)
         sessionname = "Default Settings";
 
+    { // WINSCP
     strbuf *sb = strbuf_new();
     escape_registry_key(sessionname, sb);
+    { // WINSCP
     HKEY sesskey = open_regkey(false, HKEY_CURRENT_USER, puttystr, sb->s);
     strbuf_free(sb);
 
@@ -112,6 +104,8 @@ settings_r *open_settings_r(const char *sessionname)
     toret->sesskey = sesskey;
     return toret;
     } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
 char *read_setting_s(settings_r *handle, const char *key)
@@ -212,12 +206,14 @@ void close_settings_r(settings_r *handle)
     }
 }
 
+#ifndef WINSCP
 void del_settings(const char *sessionname)
 {
     HKEY rkey = open_regkey(false, HKEY_CURRENT_USER, puttystr);
     if (!rkey)
         return;
 
+    { // WINSCP
     strbuf *sb = strbuf_new();
     escape_registry_key(sessionname, sb);
     del_regkey(rkey, sb->s);
@@ -226,6 +222,7 @@ void del_settings(const char *sessionname)
     close_regkey(rkey);
 
     remove_session_from_jumplist(sessionname);
+    } // WINSCP
 }
 
 struct settings_e {
@@ -239,6 +236,7 @@ settings_e *enum_settings_start(void)
     if (!key)
         return NULL;
 
+    { // WINSCP
     settings_e *ret = snew(settings_e);
     if (ret) {
         ret->key = key;
@@ -246,6 +244,7 @@ settings_e *enum_settings_start(void)
     }
 
     return ret;
+    } // WINSCP
 }
 
 bool enum_settings_next(settings_e *e, strbuf *sb)
@@ -265,6 +264,7 @@ void enum_settings_finish(settings_e *e)
     close_regkey(e->key);
     sfree(e);
 }
+#endif
 
 static void hostkey_regname(strbuf *sb, const char *hostname,
                             int port, const char *keytype)
@@ -281,16 +281,13 @@ int check_stored_host_key(const char *hostname, int port,
                           const char *keytype, const char *key)
 #endif
 {
-#ifdef MPEXT
-    len = maxlen;
-#else
-#endif
     /*
      * Read a saved key in from the registry and see what it says.
      */
     strbuf *regname = strbuf_new();
     hostkey_regname(regname, hostname, port, keytype);
 
+    { // WINSCP
     HKEY rkey = open_regkey(false, HKEY_CURRENT_USER,
                             PUTTY_REG_POS "\\SshHostKeys");
     if (!rkey) {
@@ -298,6 +295,7 @@ int check_stored_host_key(const char *hostname, int port,
         return 1;                      /* key does not exist in registry */
     }
 
+    { // WINSCP
     char *otherstr = get_reg_sz(rkey, regname->s);
     if (!otherstr && !strcmp(keytype, "rsa")) {
         /*
@@ -362,13 +360,15 @@ int check_stored_host_key(const char *hostname, int port,
     close_regkey(rkey);
 
 #ifdef MPEXT
-    // make sure it is zero terminated, what it is not, particularly when
-    // RegQueryValueEx fails (the key is unknown)
-    otherstr[len - 1] = '\0';
-#endif
-#ifdef MPEXT
-    strncpy(key, otherstr, maxlen);
-    key[maxlen - 1] = '\0';
+    if (otherstr)
+    {
+        strncpy(key, otherstr, maxlen);
+        key[maxlen - 1] = '\0';
+    }
+    else
+    {
+        key[0] = '\0';
+    }
 #else
     int compare = otherstr ? strcmp(otherstr, key) : -1;
 #endif
@@ -384,6 +384,8 @@ int check_stored_host_key(const char *hostname, int port,
 #endif
     else
         return 0;                      /* key matched OK in registry */
+    } // WINSCP
+    } // WINSCP
 }
 
 #ifndef MPEXT
@@ -404,6 +406,7 @@ void store_host_key(const char *hostname, int port,
     strbuf *regname = strbuf_new();
     hostkey_regname(regname, hostname, port, keytype);
 
+    { // WINSCP
     HKEY rkey = open_regkey(true, HKEY_CURRENT_USER,
                             PUTTY_REG_POS "\\SshHostKeys");
     if (rkey) {
@@ -412,6 +415,7 @@ void store_host_key(const char *hostname, int port,
     } /* else key does not exist in registry */
 
     strbuf_free(regname);
+    } // WINSCP
 }
 
 struct host_ca_enum {
@@ -452,6 +456,7 @@ void enum_host_ca_finish(host_ca_enum *e)
     sfree(e);
 }
 
+#ifndef WINSCP
 host_ca *host_ca_load(const char *name)
 {
     strbuf *sb;
@@ -459,15 +464,18 @@ host_ca *host_ca_load(const char *name)
 
     sb = strbuf_new();
     escape_registry_key(name, sb);
+    { // WINSCP
     HKEY rkey = open_regkey(false, HKEY_CURRENT_USER, host_ca_key, sb->s);
     strbuf_free(sb);
 
     if (!rkey)
         return NULL;
 
+    { // WINSCP
     host_ca *hca = host_ca_new();
     hca->name = dupstr(name);
 
+    { // WINSCP
     DWORD val;
 
     if ((s = get_reg_sz(rkey, "PublicKey")) != NULL)
@@ -479,6 +487,7 @@ host_ca *host_ca_load(const char *name)
     } else if ((sb = get_reg_multi_sz(rkey, "MatchHosts")) != NULL) {
         BinarySource src[1];
         BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(sb));
+        { // WINSCP
         CertExprBuilder *eb = cert_expr_builder_new();
 
         const char *wc;
@@ -487,6 +496,7 @@ host_ca *host_ca_load(const char *name)
 
         hca->validity_expression = cert_expr_expression(eb);
         cert_expr_builder_free(eb);
+        } // WINSCP
     }
 
     if (get_reg_dword(rkey, "PermitRSASHA1", &val))
@@ -498,15 +508,21 @@ host_ca *host_ca_load(const char *name)
 
     close_regkey(rkey);
     return hca;
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
+#endif
 
 char *host_ca_save(host_ca *hca)
 {
     if (!*hca->name)
         return dupstr("CA record must have a name");
 
+    { // WINSCP
     strbuf *sb = strbuf_new();
     escape_registry_key(hca->name, sb);
+    { // WINSCP
     HKEY rkey = open_regkey(true, HKEY_CURRENT_USER, host_ca_key, sb->s);
     if (!rkey) {
         char *err = dupprintf("Unable to create registry key\n"
@@ -516,11 +532,13 @@ char *host_ca_save(host_ca *hca)
     }
     strbuf_free(sb);
 
+    { // WINSCP
     strbuf *base64_pubkey = base64_encode_sb(
         ptrlen_from_strbuf(hca->ca_public_key), 0);
     put_reg_sz(rkey, "PublicKey", base64_pubkey->s);
     strbuf_free(base64_pubkey);
 
+    { // WINSCP
     strbuf *validity = percent_encode_sb(
         ptrlen_from_asciz(hca->validity_expression), NULL);
     put_reg_sz(rkey, "Validity", validity->s);
@@ -532,21 +550,29 @@ char *host_ca_save(host_ca *hca)
 
     close_regkey(rkey);
     return NULL;
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
+    } // WINSCP
 }
 
+#ifndef WINSCP
 char *host_ca_delete(const char *name)
 {
     HKEY rkey = open_regkey(false, HKEY_CURRENT_USER, host_ca_key);
     if (!rkey)
         return NULL;
 
+    { // WINSCP
     strbuf *sb = strbuf_new();
     escape_registry_key(name, sb);
     del_regkey(rkey, sb->s);
     strbuf_free(sb);
 
     return NULL;
+    } // WINSCP
 }
+#endif
 
 /*
  * Open (or delete) the random seed file.
@@ -717,6 +743,7 @@ void write_random_seed(void *data, int len)
     }
 }
 
+#ifndef WINSCP
 /*
  * Internal function supporting the jump list registry code. All the
  * functions to add, remove and read the list have substantially
@@ -734,6 +761,7 @@ static int transform_jumplist_registry(
         return JUMPLISTREG_ERROR_KEYOPENCREATE_FAILURE;
 
     /* Get current list of saved sessions in the registry. */
+    { // WINSCP
     strbuf *oldlist = get_reg_multi_sz(rkey, reg_jumplist_value);
     if (!oldlist) {
         /* Start again with the empty list. */
@@ -744,10 +772,12 @@ static int transform_jumplist_registry(
     /*
      * Modify the list, if we're modifying.
      */
+    { // WINSCP
     bool write_failure = false;
     if (add || rem) {
         BinarySource src[1];
         BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(oldlist));
+        { // WINSCP
         strbuf *newlist = strbuf_new();
 
         /* First add the new item to the beginning of the list. */
@@ -776,6 +806,7 @@ static int transform_jumplist_registry(
 
         strbuf_free(oldlist);
         oldlist = newlist;
+        } // WINSCP
     }
 
     close_regkey(rkey);
@@ -789,6 +820,8 @@ static int transform_jumplist_registry(
         return JUMPLISTREG_ERROR_VALUEWRITE_FAILURE;
     else
         return JUMPLISTREG_OK;
+    } // WINSCP
+    } // WINSCP
 }
 
 /* Adds a new entry to the jumplist entries in the registry. */
@@ -857,6 +890,7 @@ void cleanup_all(void)
     /*
      * Open the main PuTTY registry key and remove everything in it.
      */
+    { // WINSCP
     HKEY key = open_regkey(false, HKEY_CURRENT_USER, PUTTY_REG_POS);
     if (key) {
         registry_recursive_remove(key);
@@ -870,6 +904,7 @@ void cleanup_all(void)
     if ((key = open_regkey(false, HKEY_CURRENT_USER,
                            PUTTY_REG_PARENT)) != NULL) {
         del_regkey(key, PUTTY_REG_PARENT_CHILD);
+        { // WINSCP
         char *name = enum_regkey(key, 0);
         close_regkey(key);
 
@@ -887,8 +922,11 @@ void cleanup_all(void)
                 close_regkey(key);
             }
         }
+        } // WINSCP
     }
     /*
      * Now we're done.
      */
+    } // WINSCP
 }
+#endif // WINSCP

+ 4 - 0
source/putty/windows/unicode.c

@@ -1328,6 +1328,9 @@ int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen,
 int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen,
              wchar_t *wcstr, int wclen)
 {
+    #ifdef WINSCP
+    pinitassert(codepage == DEFAULT_CODEPAGE);
+    #else
     if (codepage >= 65536) {
         /* Character set not known to Windows, so we'll have to
          * translate it ourself */
@@ -1356,6 +1359,7 @@ int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen,
 
         return p - wcstr;
     }
+    #endif
 
     int ret = MultiByteToWideChar(codepage, flags, mbstr, mblen, wcstr, wclen);
     if (ret)

+ 32 - 0
source/putty/windows/utils/registry.c

@@ -11,6 +11,7 @@ HKEY open_regkey_fn(bool create, HKEY hk, const char *path, ...)
     bool hk_needs_close = false;
     va_list ap;
     va_start(ap, path);
+    assert(!reg_override_winscp());
 
     for (; path; path = va_arg(ap, const char *)) {
         HKEY hk_sub = NULL;
@@ -46,18 +47,26 @@ HKEY open_regkey_fn(bool create, HKEY hk, const char *path, ...)
 
 void close_regkey(HKEY key)
 {
+    if (reg_override_winscp())
+    {
+        close_regkey_winscp(key);
+        return;
+    }
     RegCloseKey(key);
 }
 
+#ifndef WINSCP
 void del_regkey(HKEY key, const char *name)
 {
     RegDeleteKey(key, name);
 }
+#endif
 
 char *enum_regkey(HKEY key, int index)
 {
     size_t regbuf_size = MAX_PATH + 1;
     char *regbuf = snewn(regbuf_size, char);
+    assert(!reg_override_winscp());
 
     while (1) {
         LONG status = RegEnumKey(key, index, regbuf, regbuf_size);
@@ -74,6 +83,10 @@ char *enum_regkey(HKEY key, int index)
 bool get_reg_dword(HKEY key, const char *name, DWORD *out)
 {
     DWORD type, size;
+    if (reg_override_winscp())
+    {
+        return get_reg_dword_winscp(key, name, out);
+    }
     size = sizeof(*out);
 
     if (RegQueryValueEx(key, name, 0, &type,
@@ -86,6 +99,11 @@ bool get_reg_dword(HKEY key, const char *name, DWORD *out)
 
 bool put_reg_dword(HKEY key, const char *name, DWORD value)
 {
+    if (reg_override_winscp())
+    {
+        return put_reg_dword_winscp(key, name, value);
+    }
+
     return RegSetValueEx(key, name, 0, REG_DWORD, (CONST BYTE *) &value,
                          sizeof(value)) == ERROR_SUCCESS;
 }
@@ -94,10 +112,16 @@ char *get_reg_sz(HKEY key, const char *name)
 {
     DWORD type, size;
 
+    if (reg_override_winscp())
+    {
+        return get_reg_sz_winscp(key, name);
+    }
+
     if (RegQueryValueEx(key, name, 0, &type, NULL,
                         &size) != ERROR_SUCCESS || type != REG_SZ)
         return NULL;                   /* not a string */
 
+    { // WINSCP
     size_t allocsize = size+1;         /* allow for an extra NUL if needed */
     char *toret = snewn(allocsize, char);
     if (RegQueryValueEx(key, name, 0, &type, (BYTE *)toret,
@@ -110,15 +134,22 @@ char *get_reg_sz(HKEY key, const char *name)
                          * didn't supply one */
 
     return toret;
+    } // WINSCP
 }
 
 bool put_reg_sz(HKEY key, const char *name, const char *str)
 {
+    if (reg_override_winscp())
+    {
+        return put_reg_sz_winscp(key, name, str);
+    }
+
     /* You have to store the trailing NUL as well */
     return RegSetValueEx(key, name, 0, REG_SZ, (CONST BYTE *)str,
                          1 + strlen(str)) == ERROR_SUCCESS;
 }
 
+#ifndef WINSCP
 /*
  * REG_MULTI_SZ items are stored as a concatenation of NUL-terminated
  * strings, terminated in turn with an empty string, i.e. a second
@@ -182,3 +213,4 @@ char *get_reg_sz_simple(HKEY key, const char *name, const char *leaf)
     RegCloseKey(subkey);
     return toret;
 }
+#endif // WINSCP

+ 19 - 13
source/resource/TextsWin.h

@@ -452,19 +452,6 @@
 #define SPECIAL_FOLDER_DESKTOP  1791
 #define COMMAND_LINE_LABEL      1792
 #define COPY_PARAM_SAVE_SETTINGS 1793
-#define CIPHER_NAME_WARN        1794
-#define CIPHER_NAME_3DES        1795
-#define CIPHER_NAME_BLOWFISH    1796
-#define CIPHER_NAME_AES2        1797
-#define CIPHER_NAME_DES         1798
-#define CIPHER_NAME_ARCFOUR2    1799
-#define CIPHER_NAME_CHACHA20    1800
-#define KEX_NAME_WARN           1801
-#define KEX_NAME_DHGROUP1       1802
-#define KEX_NAME_DHGROUP14      1803
-#define KEX_NAME_DHGEX          1804
-#define KEX_NAME_RSA            1805
-#define KEX_NAME_ECDH           1806
 #define LOGIN_SELECT_LOCAL_PROXY 1807
 #define LOGIN_PROXY_COMMAND_PATTERNS_HINT 1808
 #define LOGIN_DUPLICATE_SESSION_FOLDER_WORKSPACE 1809
@@ -666,6 +653,25 @@
 #define PROPERTIES_S3_W_ACL_HINT 6051
 #define LOGIN_S3_GENERAL_CREDENTIALS 6052
 #define GENERATE_URL_PS_ARG_PASSING 6053
+#define CIPHER_NAME_WARN        6054
+#define CIPHER_NAME_3DES        6055
+#define CIPHER_NAME_BLOWFISH    6056
+#define CIPHER_NAME_AES2        6057
+#define CIPHER_NAME_DES         6058
+#define CIPHER_NAME_ARCFOUR2    6059
+#define CIPHER_NAME_CHACHA20    6060
+#define CIPHER_NAME_AESGCM      6061
+#define KEX_NAME_WARN           6070
+#define KEX_NAME_DHGROUP1       6071
+#define KEX_NAME_DHGROUP14      6072
+#define KEX_NAME_DHGROUP15      6073
+#define KEX_NAME_DHGROUP16      6074
+#define KEX_NAME_DHGROUP17      6075
+#define KEX_NAME_DHGROUP18      6076
+#define KEX_NAME_DHGEX          6077
+#define KEX_NAME_RSA            6078
+#define KEX_NAME_ECDH           6079
+// Keep few indexes unused for future algos
 
 // 2xxx is reserved for TextsFileZilla.h
 

+ 18 - 13
source/resource/TextsWin1.rc

@@ -458,19 +458,6 @@ BEGIN
         SPECIAL_FOLDER_DESKTOP, "Desktop"
         COMMAND_LINE_LABEL, "Command"
         COPY_PARAM_SAVE_SETTINGS, "&Set as Default"
-        CIPHER_NAME_WARN, "-- warn below here --"
-        CIPHER_NAME_3DES, "3DES"
-        CIPHER_NAME_BLOWFISH, "Blowfish"
-        CIPHER_NAME_AES2, "AES"
-        CIPHER_NAME_DES, "DES"
-        CIPHER_NAME_ARCFOUR2, "Arcfour"
-        CIPHER_NAME_CHACHA20, "ChaCha20"
-        KEX_NAME_WARN, "-- warn below here --"
-        KEX_NAME_DHGROUP1, "Diffie-Hellman group 1"
-        KEX_NAME_DHGROUP14, "Diffie-Hellman group 14"
-        KEX_NAME_DHGEX, "Diffie-Hellman group exchange"
-        KEX_NAME_RSA, "RSA-based key exchange"
-        KEX_NAME_ECDH, "ECDH key exchange"
         LOGIN_SELECT_LOCAL_PROXY, "Select local proxy application"
         LOGIN_PROXY_COMMAND_PATTERNS_HINT, "Patterns:\n\\n for new line\n\\r for carriage return\n\\t for tab\n\\xXX for any hex ascii code\n\\\\ for backslash\n%host expands to hostname\n%port expands to port number\n%user expands to proxy username\n%pass expands to proxy password\n%% for percent sign"
         LOGIN_DUPLICATE_SESSION_FOLDER_WORKSPACE, "Site folder or workspace with name '%s' already exists."
@@ -671,6 +658,24 @@ BEGIN
         PROPERTIES_S3_W_ACL_HINT, "Write ACL"
         LOGIN_S3_GENERAL_CREDENTIALS, "General"
         GENERATE_URL_PS_ARG_PASSING, "Needed for PowerShell 7.3 and newer"
+        CIPHER_NAME_WARN, "-- warn below here --"
+        CIPHER_NAME_3DES, "3DES"
+        CIPHER_NAME_BLOWFISH, "Blowfish"
+        CIPHER_NAME_AES2, "AES"
+        CIPHER_NAME_DES, "DES"
+        CIPHER_NAME_ARCFOUR2, "Arcfour"
+        CIPHER_NAME_CHACHA20, "ChaCha20"
+        CIPHER_NAME_AESGCM, "AES-GCM"
+        KEX_NAME_WARN, "-- warn below here --"
+        KEX_NAME_DHGROUP1, "Diffie-Hellman group 1"
+        KEX_NAME_DHGROUP14, "Diffie-Hellman group 14"
+        KEX_NAME_DHGROUP15, "Diffie-Hellman group 14"
+        KEX_NAME_DHGROUP16, "Diffie-Hellman group 14"
+        KEX_NAME_DHGROUP17, "Diffie-Hellman group 14"
+        KEX_NAME_DHGROUP18, "Diffie-Hellman group 14"
+        KEX_NAME_DHGEX, "Diffie-Hellman group exchange"
+        KEX_NAME_RSA, "RSA-based key exchange"
+        KEX_NAME_ECDH, "ECDH key exchange"
 
         WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
         WINSCP_COPYRIGHT, "Copyright © 2000–2022 Martin Prikryl"