diff --git a/CMakeLists.txt b/CMakeLists.txt
index d3be22b5..3b28c065 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,38 +44,12 @@ add_library(guiterminal STATIC
 add_library(noterminal STATIC
   noterm.c ldisc.c)
 
-add_library(sshcommon OBJECT
-  ssh1bpp.c ssh1censor.c
-  ssh1connection.c ssh1login.c ssh2bpp-bare.c ssh2bpp.c ssh2censor.c
-  ssh2connection.c ssh2transhk.c ssh2transport.c ssh2userauth.c
-  sshcommon.c sshcrcda.c sshgssc.c sshpubk.c sshrand.c
-  sshverstring.c sshzlib.c
-  pgssapi.c portfwd.c x11fwd.c)
-
-add_library(sftpcommon OBJECT
-  sftpcommon.c)
-
 add_library(all-backends OBJECT
   pinger.c)
 
-add_library(sshclient STATIC
-  ssh1connection-client.c ssh2connection-client.c ssh2kex-client.c
-  sshshare.c ssh.c
-  mainchan.c agentf.c
-  $<TARGET_OBJECTS:sshcommon>
-  $<TARGET_OBJECTS:all-backends>
-  $<TARGET_OBJECTS:logging>)
-
-add_library(sshserver STATIC
-  ssh1connection-server.c ssh1login-server.c ssh2connection-server.c
-  ssh2kex-server.c ssh2userauth-server.c sshserver.c
-  sesschan.c
-  sftpserver.c
-  $<TARGET_OBJECTS:sftpcommon>
-  $<TARGET_OBJECTS:sshcommon>)
-
 add_library(sftpclient STATIC
-  psftpcommon.c sftp.c $<TARGET_OBJECTS:sftpcommon>)
+  psftpcommon.c)
+add_subdirectory(ssh)
 
 add_library(otherbackends STATIC
   telnet.c rlogin.c raw.c supdup.c
@@ -83,7 +57,7 @@ add_library(otherbackends STATIC
   $<TARGET_OBJECTS:logging>)
 
 add_executable(testcrypt
-  testcrypt.c sshpubk.c sshcrcda.c)
+  testcrypt.c sshpubk.c ssh/crc-attack-detector.c)
 target_link_libraries(testcrypt
   keygen crypto utils ${platform_libraries})
 
diff --git a/crypto/diffie-hellman.c b/crypto/diffie-hellman.c
index b3756120..634ef297 100644
--- a/crypto/diffie-hellman.c
+++ b/crypto/diffie-hellman.c
@@ -96,7 +96,7 @@ const ssh_kexes ssh_diffiehellman_gex = { lenof(gex_list), gex_list };
  * Kerberos v5.
  *
  * (The same encoded OID, minus the two-byte DER header, is defined in
- * pgssapi.c as GSS_MECH_KRB5.)
+ * ssh/pgssapi.c as GSS_MECH_KRB5.)
  */
 #define GSS_KRB5_OID_HASH "toWM5Slw5Ew8Mqkay+al2g=="
 
diff --git a/mpunsafe.c b/mpunsafe.c
index a6130018..f33532c4 100644
--- a/mpunsafe.c
+++ b/mpunsafe.c
@@ -10,7 +10,7 @@
 #include "crypto/mpint_i.h"
 
 /*
- * This global symbol is also defined in ssh2kex-client.c, to ensure
+ * This global symbol is also defined in ssh/kex2-client.c, to ensure
  * that these unsafe non-constant-time mp_int functions can't end up
  * accidentally linked in to any PuTTY tool that actually makes an SSH
  * client connection.
diff --git a/pscp.c b/pscp.c
index 0bfda92d..19bc3807 100644
--- a/pscp.c
+++ b/pscp.c
@@ -22,7 +22,7 @@
 #include "putty.h"
 #include "psftp.h"
 #include "ssh.h"
-#include "sftp.h"
+#include "ssh/sftp.h"
 #include "storage.h"
 
 static bool list = false;
diff --git a/psftp.c b/psftp.c
index 40cb73f5..c2791e3b 100644
--- a/psftp.c
+++ b/psftp.c
@@ -12,7 +12,7 @@
 #include "psftp.h"
 #include "storage.h"
 #include "ssh.h"
-#include "sftp.h"
+#include "ssh/sftp.h"
 
 const char *const appname = "PSFTP";
 
diff --git a/psftpcommon.c b/psftpcommon.c
index 21f3737e..e6c8e2d8 100644
--- a/psftpcommon.c
+++ b/psftpcommon.c
@@ -8,7 +8,7 @@
 #include <string.h>
 
 #include "putty.h"
-#include "sftp.h"
+#include "ssh/sftp.h"
 #include "psftp.h"
 
 #define MAX_NAMES_MEMORY ((size_t)8 << 20)
diff --git a/psocks.c b/psocks.c
index f29eeaa9..75dc85d9 100644
--- a/psocks.c
+++ b/psocks.c
@@ -9,7 +9,7 @@
 #include "putty.h"
 #include "misc.h"
 #include "ssh.h"
-#include "sshchan.h"
+#include "ssh/channel.h"
 #include "psocks.h"
 
 /*
diff --git a/putty.h b/putty.h
index d09f89b4..1b3c7c67 100644
--- a/putty.h
+++ b/putty.h
@@ -326,13 +326,13 @@ typedef enum {
     /*
      * Send a POSIX-style signal. (Useful in SSH and also pterm.)
      *
-     * We use the master list in sshsignals.h to define these enum
+     * We use the master list in ssh/signal-list.h to define these enum
      * values, which will come out looking like names of the form
      * SS_SIGABRT, SS_SIGINT etc.
      */
     #define SIGNAL_MAIN(name, text) SS_SIG ## name,
     #define SIGNAL_SUB(name) SS_SIG ## name,
-    #include "sshsignals.h"
+    #include "ssh/signal-list.h"
     #undef SIGNAL_MAIN
     #undef SIGNAL_SUB
 
@@ -356,7 +356,7 @@ struct SessionSpecial {
     int arg;
 };
 
-/* Needed by both sshchan.h and sshppl.h */
+/* Needed by both ssh/channel.h and ssh/ppl.h */
 typedef void (*add_special_fn_t)(
     void *ctx, const char *text, SessionSpecialCode code, int arg);
 
@@ -1925,7 +1925,7 @@ extern const struct BackendVtable rlogin_backend;
 extern const struct BackendVtable telnet_backend;
 
 /*
- * Exports from ssh.c.
+ * Exports from ssh/ssh.c.
  */
 extern const struct BackendVtable ssh_backend;
 extern const struct BackendVtable sshconn_backend;
diff --git a/settings.c b/settings.c
index 547af0dc..3f8f2e92 100644
--- a/settings.c
+++ b/settings.c
@@ -8,8 +8,8 @@
 #include "putty.h"
 #include "storage.h"
 #ifndef NO_GSSAPI
-#include "sshgssc.h"
-#include "sshgss.h"
+#include "ssh/gssc.h"
+#include "ssh/gss.h"
 #endif
 
 
diff --git a/ssh.h b/ssh.h
index 24d7f1a5..61a95c8e 100644
--- a/ssh.h
+++ b/ssh.h
@@ -1612,7 +1612,7 @@ enum {
     /* TTY modes with opcodes defined consistently in the SSH specs. */
     #define TTYMODE_CHAR(name, val, index) SSH_TTYMODE_##name = val,
     #define TTYMODE_FLAG(name, val, field, mask) SSH_TTYMODE_##name = val,
-    #include "sshttymodes.h"
+    #include "ssh/ttymode-list.h"
     #undef TTYMODE_CHAR
     #undef TTYMODE_FLAG
 
diff --git a/ssh/CMakeLists.txt b/ssh/CMakeLists.txt
new file mode 100644
index 00000000..4b0e03fe
--- /dev/null
+++ b/ssh/CMakeLists.txt
@@ -0,0 +1,51 @@
+add_library(sshcommon OBJECT
+  bpp1.c
+  bpp2.c
+  bpp-bare.c
+  censor1.c
+  censor2.c
+  common.c
+  connection1.c
+  connection2.c
+  crc-attack-detector.c
+  gssc.c
+  login1.c
+  pgssapi.c
+  portfwd.c
+  ../sshpubk.c
+  ../sshrand.c
+  transient-hostkey-cache.c
+  transport2.c
+  verstring.c
+  x11fwd.c
+  zlib.c)
+
+add_library(sftpcommon OBJECT sftpcommon.c)
+
+add_library(sshclient STATIC
+  agentf.c
+  connection1-client.c
+  connection2-client.c
+  kex2-client.c
+  mainchan.c
+  sharing.c
+  ssh.c
+  userauth2-client.c
+  $<TARGET_OBJECTS:sshcommon>
+  $<TARGET_OBJECTS:all-backends>
+  $<TARGET_OBJECTS:logging>)
+
+add_library(sshserver STATIC
+  connection1-server.c
+  connection2-server.c
+  kex2-server.c
+  login1-server.c
+  server.c
+  sesschan.c
+  sftpserver.c
+  userauth2-server.c
+  $<TARGET_OBJECTS:sftpcommon>
+  $<TARGET_OBJECTS:sshcommon>)
+
+add_sources_from_current_dir(sftpclient sftp.c)
+target_sources(sftpclient PRIVATE $<TARGET_OBJECTS:sftpcommon>)
diff --git a/agentf.c b/ssh/agentf.c
similarity index 99%
rename from agentf.c
rename to ssh/agentf.c
index dc5bec01..6a5ecee5 100644
--- a/agentf.c
+++ b/ssh/agentf.c
@@ -9,7 +9,7 @@
 #include "putty.h"
 #include "ssh.h"
 #include "pageant.h"
-#include "sshchan.h"
+#include "channel.h"
 
 typedef struct agentf {
     SshChannel *c;
diff --git a/ssh2bpp-bare.c b/ssh/bpp-bare.c
similarity index 97%
rename from ssh2bpp-bare.c
rename to ssh/bpp-bare.c
index 90f196e8..3546d160 100644
--- a/ssh2bpp-bare.c
+++ b/ssh/bpp-bare.c
@@ -7,7 +7,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
+#include "bpp.h"
 #include "sshcr.h"
 
 struct ssh2_bare_bpp_state {
@@ -30,9 +30,9 @@ static const BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = {
     .handle_input = ssh2_bare_bpp_handle_input,
     .handle_output = ssh2_bare_bpp_handle_output,
     .new_pktout = ssh2_bare_bpp_new_pktout,
-    .queue_disconnect = ssh2_bpp_queue_disconnect, /* in sshcommon.c */
+    .queue_disconnect = ssh2_bpp_queue_disconnect, /* in common.c */
 
-    /* packet size limit, per protocol spec in sshshare.c comment */
+    /* packet size limit, per protocol spec in sharing.c comment */
     .packet_size_limit = 0x4000,
 };
 
diff --git a/sshbpp.h b/ssh/bpp.h
similarity index 100%
rename from sshbpp.h
rename to ssh/bpp.h
diff --git a/ssh1bpp.c b/ssh/bpp1.c
similarity index 99%
rename from ssh1bpp.c
rename to ssh/bpp1.c
index 46eccbeb..f84d787b 100644
--- a/ssh1bpp.c
+++ b/ssh/bpp1.c
@@ -6,7 +6,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
+#include "bpp.h"
 #include "sshcr.h"
 
 struct ssh1_bpp_state {
diff --git a/ssh2bpp.c b/ssh/bpp2.c
similarity index 99%
rename from ssh2bpp.c
rename to ssh/bpp2.c
index 09b23e5a..f29b962f 100644
--- a/ssh2bpp.c
+++ b/ssh/bpp2.c
@@ -6,7 +6,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
+#include "bpp.h"
 #include "sshcr.h"
 
 struct ssh2_bpp_direction {
@@ -54,7 +54,7 @@ static const BinaryPacketProtocolVtable ssh2_bpp_vtable = {
     .handle_input = ssh2_bpp_handle_input,
     .handle_output = ssh2_bpp_handle_output,
     .new_pktout = ssh2_bpp_new_pktout,
-    .queue_disconnect = ssh2_bpp_queue_disconnect, /* in sshcommon.c */
+    .queue_disconnect = ssh2_bpp_queue_disconnect, /* in common.c */
     .packet_size_limit = 0xFFFFFFFF, /* no special limit for this bpp */
 };
 
diff --git a/ssh1censor.c b/ssh/censor1.c
similarity index 100%
rename from ssh1censor.c
rename to ssh/censor1.c
diff --git a/ssh2censor.c b/ssh/censor2.c
similarity index 100%
rename from ssh2censor.c
rename to ssh/censor2.c
diff --git a/sshchan.h b/ssh/channel.h
similarity index 100%
rename from sshchan.h
rename to ssh/channel.h
diff --git a/sshcommon.c b/ssh/common.c
similarity index 99%
rename from sshcommon.c
rename to ssh/common.c
index 5485e33a..96e07cf1 100644
--- a/sshcommon.c
+++ b/ssh/common.c
@@ -9,9 +9,9 @@
 #include "putty.h"
 #include "mpint.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 
 /* ----------------------------------------------------------------------
  * Implementation of PacketQueue.
@@ -407,7 +407,7 @@ struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf)
     } modes_names_types[] = {
         #define TTYMODE_CHAR(name, val, index) { #name, val, TYPE_CHAR },
         #define TTYMODE_FLAG(name, val, field, mask) { #name, val, TYPE_BOOL },
-        #include "sshttymodes.h"
+        #include "ttymode-list.h"
         #undef TTYMODE_CHAR
         #undef TTYMODE_FLAG
     };
diff --git a/ssh1connection-client.c b/ssh/connection1-client.c
similarity index 99%
rename from ssh1connection-client.c
rename to ssh/connection1-client.c
index cf7dd04e..f32fefcd 100644
--- a/ssh1connection-client.c
+++ b/ssh/connection1-client.c
@@ -6,11 +6,11 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 #include "sshcr.h"
-#include "ssh1connection.h"
+#include "connection1.h"
 
 void ssh1_connection_direction_specific_setup(
     struct ssh1_connection_state *s)
diff --git a/ssh1connection-server.c b/ssh/connection1-server.c
similarity index 99%
rename from ssh1connection-server.c
rename to ssh/connection1-server.c
index 4d55abe5..1123327c 100644
--- a/ssh1connection-server.c
+++ b/ssh/connection1-server.c
@@ -6,12 +6,12 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 #include "sshcr.h"
-#include "ssh1connection.h"
-#include "sshserver.h"
+#include "connection1.h"
+#include "server.h"
 
 static size_t ssh1sesschan_write(SshChannel *c, bool is_stderr,
                                  const void *, size_t);
diff --git a/ssh1connection.c b/ssh/connection1.c
similarity index 99%
rename from ssh1connection.c
rename to ssh/connection1.c
index d805dd29..7b1765f6 100644
--- a/ssh1connection.c
+++ b/ssh/connection1.c
@@ -7,11 +7,11 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 #include "sshcr.h"
-#include "ssh1connection.h"
+#include "connection1.h"
 
 static int ssh1_rportfwd_cmp(void *av, void *bv)
 {
diff --git a/ssh1connection.h b/ssh/connection1.h
similarity index 100%
rename from ssh1connection.h
rename to ssh/connection1.h
diff --git a/ssh2connection-client.c b/ssh/connection2-client.c
similarity index 99%
rename from ssh2connection-client.c
rename to ssh/connection2-client.c
index 0b13efe6..b07e1eb2 100644
--- a/ssh2connection-client.c
+++ b/ssh/connection2-client.c
@@ -6,11 +6,11 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 #include "sshcr.h"
-#include "ssh2connection.h"
+#include "connection2.h"
 
 static ChanopenResult chan_open_x11(
     struct ssh2_connection_state *s, SshChannel *sc,
diff --git a/ssh2connection-server.c b/ssh/connection2-server.c
similarity index 98%
rename from ssh2connection-server.c
rename to ssh/connection2-server.c
index 1467db11..c871b4b3 100644
--- a/ssh2connection-server.c
+++ b/ssh/connection2-server.c
@@ -6,12 +6,12 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 #include "sshcr.h"
-#include "ssh2connection.h"
-#include "sshserver.h"
+#include "connection2.h"
+#include "server.h"
 
 void ssh2connection_server_configure(
     PacketProtocolLayer *ppl, const SftpServerVtable *sftpserver_vt,
diff --git a/ssh2connection.c b/ssh/connection2.c
similarity index 99%
rename from ssh2connection.c
rename to ssh/connection2.c
index ecb421ea..48436848 100644
--- a/ssh2connection.c
+++ b/ssh/connection2.c
@@ -6,11 +6,11 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 #include "sshcr.h"
-#include "ssh2connection.h"
+#include "connection2.h"
 
 static void ssh2_connection_free(PacketProtocolLayer *);
 static void ssh2_connection_process_queue(PacketProtocolLayer *);
@@ -391,7 +391,7 @@ static bool ssh2_connection_filter_queue(struct ssh2_connection_state *s)
                  * This channel-open request needs to go to a
                  * connection-sharing downstream, so abandon our own
                  * channel-open procedure and just pass the message on
-                 * to sshshare.c.
+                 * to sharing.c.
                  */
                 share_got_pkt_from_server(
                     chanopen_result.u.downstream.share_ctx, pktin->type,
diff --git a/ssh2connection.h b/ssh/connection2.h
similarity index 100%
rename from ssh2connection.h
rename to ssh/connection2.h
diff --git a/sshcrcda.c b/ssh/crc-attack-detector.c
similarity index 100%
rename from sshcrcda.c
rename to ssh/crc-attack-detector.c
diff --git a/sshgss.h b/ssh/gss.h
similarity index 99%
rename from sshgss.h
rename to ssh/gss.h
index c640636d..eaef5dd9 100644
--- a/sshgss.h
+++ b/ssh/gss.h
@@ -32,7 +32,7 @@ typedef gss_name_t Ssh_gss_name;
 
 #define GSS_DEF_REKEY_MINS 2    /* Default minutes between GSS cache checks */
 
-/* Functions, provided by either wingss.c or sshgssc.c */
+/* Functions, provided by either wingss.c or gssc.c */
 
 struct ssh_gss_library;
 
diff --git a/sshgssc.c b/ssh/gssc.c
similarity index 99%
rename from sshgssc.c
rename to ssh/gssc.c
index d9f62c39..0224afe2 100644
--- a/sshgssc.c
+++ b/ssh/gssc.c
@@ -2,7 +2,7 @@
 
 #include <string.h>
 #include <limits.h>
-#include "sshgssc.h"
+#include "gssc.h"
 #include "misc.h"
 
 #ifndef NO_GSSAPI
diff --git a/sshgssc.h b/ssh/gssc.h
similarity index 95%
rename from sshgssc.h
rename to ssh/gssc.h
index 07fac009..d1d99eb1 100644
--- a/sshgssc.h
+++ b/ssh/gssc.h
@@ -4,7 +4,7 @@
 #ifndef NO_GSSAPI
 
 #include "pgssapi.h"
-#include "sshgss.h"
+#include "gss.h"
 
 typedef struct gssapi_ssh_gss_ctx {
     OM_uint32 maj_stat;
diff --git a/ssh2kex-client.c b/ssh/kex2-client.c
similarity index 99%
rename from ssh2kex-client.c
rename to ssh/kex2-client.c
index 1dd960c1..4bbd8765 100644
--- a/ssh2kex-client.c
+++ b/ssh/kex2-client.c
@@ -6,11 +6,11 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
+#include "bpp.h"
+#include "ppl.h"
 #include "sshcr.h"
 #include "storage.h"
-#include "ssh2transport.h"
+#include "transport2.h"
 #include "mpint.h"
 
 /*
diff --git a/ssh2kex-server.c b/ssh/kex2-server.c
similarity index 99%
rename from ssh2kex-server.c
rename to ssh/kex2-server.c
index 1fbb588b..56bdc3c5 100644
--- a/ssh2kex-server.c
+++ b/ssh/kex2-server.c
@@ -6,13 +6,13 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
+#include "bpp.h"
+#include "ppl.h"
 #include "sshcr.h"
-#include "sshserver.h"
+#include "server.h"
 #include "sshkeygen.h"
 #include "storage.h"
-#include "ssh2transport.h"
+#include "transport2.h"
 #include "mpint.h"
 
 void ssh2_transport_provide_hostkeys(PacketProtocolLayer *ppl,
diff --git a/ssh1login-server.c b/ssh/login1-server.c
similarity index 99%
rename from ssh1login-server.c
rename to ssh/login1-server.c
index c9c10eef..040342da 100644
--- a/ssh1login-server.c
+++ b/ssh/login1-server.c
@@ -7,10 +7,10 @@
 #include "putty.h"
 #include "mpint.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
+#include "bpp.h"
+#include "ppl.h"
 #include "sshcr.h"
-#include "sshserver.h"
+#include "server.h"
 #include "sshkeygen.h"
 
 struct ssh1_login_server_state {
diff --git a/ssh1login.c b/ssh/login1.c
similarity index 99%
rename from ssh1login.c
rename to ssh/login1.c
index 8486cbf0..716e248d 100644
--- a/ssh1login.c
+++ b/ssh/login1.c
@@ -8,8 +8,8 @@
 #include "putty.h"
 #include "ssh.h"
 #include "mpint.h"
-#include "sshbpp.h"
-#include "sshppl.h"
+#include "bpp.h"
+#include "ppl.h"
 #include "sshcr.h"
 
 typedef struct agent_key {
diff --git a/mainchan.c b/ssh/mainchan.c
similarity index 99%
rename from mainchan.c
rename to ssh/mainchan.c
index 8653ad02..70033a7a 100644
--- a/mainchan.c
+++ b/ssh/mainchan.c
@@ -8,8 +8,8 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "ppl.h"
+#include "channel.h"
 
 static void mainchan_free(Channel *chan);
 static void mainchan_open_confirmation(Channel *chan);
@@ -433,7 +433,7 @@ static bool mainchan_rcvd_exit_signal(
             exitcode = 128 + SIG ## s;
     #define SIGNAL_MAIN(s, text) SIGNAL_SUB(s)
     #define SIGNALS_LOCAL_ONLY
-    #include "sshsignals.h"
+    #include "signal-list.h"
     #undef SIGNAL_SUB
     #undef SIGNAL_MAIN
     #undef SIGNALS_LOCAL_ONLY
@@ -473,7 +473,7 @@ void mainchan_get_specials(
     #define SIGNAL_MAIN(name, desc) \
     add_special(ctx, "SIG" #name " (" desc ")", SS_SIG ## name, 0);
     #define SIGNAL_SUB(name)
-    #include "sshsignals.h"
+    #include "signal-list.h"
     #undef SIGNAL_MAIN
     #undef SIGNAL_SUB
 
@@ -482,7 +482,7 @@ void mainchan_get_specials(
     #define SIGNAL_MAIN(name, desc)
     #define SIGNAL_SUB(name) \
     add_special(ctx, "SIG" #name, SS_SIG ## name, 0);
-    #include "sshsignals.h"
+    #include "signal-list.h"
     #undef SIGNAL_MAIN
     #undef SIGNAL_SUB
 
@@ -494,7 +494,7 @@ static const char *ssh_signal_lookup(SessionSpecialCode code)
     #define SIGNAL_SUB(name) \
     if (code == SS_SIG ## name) return #name;
     #define SIGNAL_MAIN(name, desc) SIGNAL_SUB(name)
-    #include "sshsignals.h"
+    #include "signal-list.h"
     #undef SIGNAL_MAIN
     #undef SIGNAL_SUB
 
diff --git a/sshnogss.c b/ssh/nogss.c
similarity index 100%
rename from sshnogss.c
rename to ssh/nogss.c
diff --git a/noshare.c b/ssh/nosharing.c
similarity index 100%
rename from noshare.c
rename to ssh/nosharing.c
diff --git a/pgssapi.c b/ssh/pgssapi.c
similarity index 100%
rename from pgssapi.c
rename to ssh/pgssapi.c
diff --git a/pgssapi.h b/ssh/pgssapi.h
similarity index 100%
rename from pgssapi.h
rename to ssh/pgssapi.h
diff --git a/portfwd.c b/ssh/portfwd.c
similarity index 99%
rename from portfwd.c
rename to ssh/portfwd.c
index f3349b80..f96fe31a 100644
--- a/portfwd.c
+++ b/ssh/portfwd.c
@@ -8,7 +8,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshchan.h"
+#include "channel.h"
 
 /*
  * Enumeration of values that live in the 'socks_state' field of
diff --git a/sshppl.h b/ssh/ppl.h
similarity index 99%
rename from sshppl.h
rename to ssh/ppl.h
index b339d67c..363b0e6d 100644
--- a/sshppl.h
+++ b/ssh/ppl.h
@@ -147,7 +147,7 @@ void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text);
 ptrlen ssh2_transport_get_session_id(PacketProtocolLayer *ssh2_transport_ptr);
 void ssh2_transport_notify_auth_done(PacketProtocolLayer *ssh2_transport_ptr);
 
-/* Shared method between ssh2 layers (defined in ssh2transport.c) to
+/* Shared method between ssh2 layers (defined in transport2.c) to
  * handle the common packets between login and connection: DISCONNECT,
  * DEBUG and IGNORE. Those messages are handled by the ssh2transport
  * layer if we have one, but in bare ssh2-connection mode they have to
diff --git a/scpserver.c b/ssh/scpserver.c
similarity index 99%
rename from scpserver.c
rename to ssh/scpserver.c
index 3c6e4559..97b20814 100644
--- a/scpserver.c
+++ b/ssh/scpserver.c
@@ -9,7 +9,7 @@
 #include "putty.h"
 #include "ssh.h"
 #include "sshcr.h"
-#include "sshchan.h"
+#include "channel.h"
 #include "sftp.h"
 
 /*
diff --git a/sshserver.c b/ssh/server.c
similarity index 99%
rename from sshserver.c
rename to ssh/server.c
index cc1c880d..e3fc86fe 100644
--- a/sshserver.c
+++ b/ssh/server.c
@@ -7,13 +7,13 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
-#include "sshserver.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
+#include "server.h"
 #ifndef NO_GSSAPI
-#include "sshgssc.h"
-#include "sshgss.h"
+#include "gssc.h"
+#include "gss.h"
 #endif
 
 struct Ssh { int dummy; };
diff --git a/sshserver.h b/ssh/server.h
similarity index 100%
rename from sshserver.h
rename to ssh/server.h
diff --git a/sesschan.c b/ssh/sesschan.c
similarity index 99%
rename from sesschan.c
rename to ssh/sesschan.c
index 4ab709da..4b204b29 100644
--- a/sesschan.c
+++ b/ssh/sesschan.c
@@ -9,8 +9,8 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshchan.h"
-#include "sshserver.h"
+#include "channel.h"
+#include "server.h"
 #include "sftp.h"
 
 struct agentfwd {
@@ -575,7 +575,7 @@ bool sesschan_send_signal(Channel *chan, ptrlen signame)
     #define SIGNAL_SUB(name) \
         if (ptrlen_eq_string(signame, #name)) code = SS_SIG ## name;
     #define SIGNAL_MAIN(name, text) SIGNAL_SUB(name)
-    #include "sshsignals.h"
+    #include "signal-list.h"
     #undef SIGNAL_MAIN
     #undef SIGNAL_SUB
 
diff --git a/sftp.c b/ssh/sftp.c
similarity index 100%
rename from sftp.c
rename to ssh/sftp.c
diff --git a/sftp.h b/ssh/sftp.h
similarity index 100%
rename from sftp.h
rename to ssh/sftp.h
diff --git a/sftpcommon.c b/ssh/sftpcommon.c
similarity index 100%
rename from sftpcommon.c
rename to ssh/sftpcommon.c
diff --git a/sftpserver.c b/ssh/sftpserver.c
similarity index 100%
rename from sftpserver.c
rename to ssh/sftpserver.c
diff --git a/sshshare.c b/ssh/sharing.c
similarity index 100%
rename from sshshare.c
rename to ssh/sharing.c
diff --git a/sshsignals.h b/ssh/signal-list.h
similarity index 100%
rename from sshsignals.h
rename to ssh/signal-list.h
diff --git a/ssh.c b/ssh/ssh.c
similarity index 99%
rename from ssh.c
rename to ssh/ssh.c
index 00a516ea..b1499a54 100644
--- a/ssh.c
+++ b/ssh/ssh.c
@@ -16,12 +16,12 @@
 #include "marshal.h"
 #include "ssh.h"
 #include "sshcr.h"
-#include "sshbpp.h"
-#include "sshppl.h"
-#include "sshchan.h"
+#include "bpp.h"
+#include "ppl.h"
+#include "channel.h"
 #ifndef NO_GSSAPI
-#include "sshgssc.h"
-#include "sshgss.h"
+#include "gssc.h"
+#include "gss.h"
 #define MIN_CTXT_LIFETIME 5     /* Avoid rekey with short lifetime (seconds) */
 #define GSS_KEX_CAPABLE (1<<0)  /* Can do GSS KEX */
 #define GSS_CRED_UPDATED (1<<1) /* Cred updated since previous delegation */
diff --git a/ssh2transhk.c b/ssh/transient-hostkey-cache.c
similarity index 100%
rename from ssh2transhk.c
rename to ssh/transient-hostkey-cache.c
diff --git a/ssh2transport.c b/ssh/transport2.c
similarity index 99%
rename from ssh2transport.c
rename to ssh/transport2.c
index 4e1b443d..fcd2667a 100644
--- a/ssh2transport.c
+++ b/ssh/transport2.c
@@ -6,12 +6,12 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
+#include "bpp.h"
+#include "ppl.h"
 #include "sshcr.h"
-#include "sshserver.h"
+#include "server.h"
 #include "storage.h"
-#include "ssh2transport.h"
+#include "transport2.h"
 #include "mpint.h"
 
 const struct ssh_signkey_with_user_pref_id ssh2_hostkey_algs[] = {
diff --git a/ssh2transport.h b/ssh/transport2.h
similarity index 99%
rename from ssh2transport.h
rename to ssh/transport2.h
index 349c06f0..80c39ef2 100644
--- a/ssh2transport.h
+++ b/ssh/transport2.h
@@ -6,8 +6,8 @@
 #define PUTTY_SSH2TRANSPORT_H
 
 #ifndef NO_GSSAPI
-#include "sshgssc.h"
-#include "sshgss.h"
+#include "gssc.h"
+#include "gss.h"
 #define MIN_CTXT_LIFETIME 5     /* Avoid rekey with short lifetime (seconds) */
 #define GSS_KEX_CAPABLE (1<<0)  /* Can do GSS KEX */
 #define GSS_CRED_UPDATED (1<<1) /* Cred updated since previous delegation */
diff --git a/sshttymodes.h b/ssh/ttymode-list.h
similarity index 100%
rename from sshttymodes.h
rename to ssh/ttymode-list.h
diff --git a/ssh2userauth.c b/ssh/userauth2-client.c
similarity index 99%
rename from ssh2userauth.c
rename to ssh/userauth2-client.c
index 01243baf..a8f5b2c5 100644
--- a/ssh2userauth.c
+++ b/ssh/userauth2-client.c
@@ -7,13 +7,13 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
+#include "bpp.h"
+#include "ppl.h"
 #include "sshcr.h"
 
 #ifndef NO_GSSAPI
-#include "sshgssc.h"
-#include "sshgss.h"
+#include "gssc.h"
+#include "gss.h"
 #endif
 
 #define BANNER_LIMIT 131072
diff --git a/ssh2userauth-server.c b/ssh/userauth2-server.c
similarity index 99%
rename from ssh2userauth-server.c
rename to ssh/userauth2-server.c
index cacddee6..da1e79c6 100644
--- a/ssh2userauth-server.c
+++ b/ssh/userauth2-server.c
@@ -7,14 +7,14 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
-#include "sshppl.h"
+#include "bpp.h"
+#include "ppl.h"
 #include "sshcr.h"
-#include "sshserver.h"
+#include "server.h"
 
 #ifndef NO_GSSAPI
-#include "sshgssc.h"
-#include "sshgss.h"
+#include "gssc.h"
+#include "gss.h"
 #endif
 
 struct ssh2_userauth_server_state {
diff --git a/sshverstring.c b/ssh/verstring.c
similarity index 99%
rename from sshverstring.c
rename to ssh/verstring.c
index 8951e4cb..2de2ac6c 100644
--- a/sshverstring.c
+++ b/ssh/verstring.c
@@ -8,7 +8,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshbpp.h"
+#include "bpp.h"
 #include "sshcr.h"
 
 #define PREFIX_MAXLEN 64
diff --git a/x11fwd.c b/ssh/x11fwd.c
similarity index 99%
rename from x11fwd.c
rename to ssh/x11fwd.c
index a5066dd1..49dca95a 100644
--- a/x11fwd.c
+++ b/ssh/x11fwd.c
@@ -9,7 +9,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshchan.h"
+#include "channel.h"
 #include "tree234.h"
 
 struct XDMSeen {
diff --git a/sshzlib.c b/ssh/zlib.c
similarity index 100%
rename from sshzlib.c
rename to ssh/zlib.c
diff --git a/testzlib.c b/testzlib.c
index 0e7b424b..0ef4ef19 100644
--- a/testzlib.c
+++ b/testzlib.c
@@ -1,5 +1,5 @@
 /*
- * Main program to compile sshzlib.c into a zlib decoding tool.
+ * Main program to compile ssh/zlib.c into a zlib decoding tool.
  *
  * This is potentially a handy tool in its own right for picking apart
  * Zip files or PDFs or PNGs, because it accepts the bare Deflate
diff --git a/unix/CMakeLists.txt b/unix/CMakeLists.txt
index 9a79f145..c13abdc5 100644
--- a/unix/CMakeLists.txt
+++ b/unix/CMakeLists.txt
@@ -88,7 +88,7 @@ add_executable(psocks
   ${CMAKE_SOURCE_DIR}/psocks.c
   ${CMAKE_SOURCE_DIR}/norand.c
   ${CMAKE_SOURCE_DIR}/nocproxy.c
-  ${CMAKE_SOURCE_DIR}/portfwd.c
+  ${CMAKE_SOURCE_DIR}/ssh/portfwd.c
   uxnogtk.c)
 target_link_libraries(psocks
   eventloop console network utils)
@@ -97,7 +97,7 @@ add_executable(psusan
   uxpsusan.c
   ${CMAKE_SOURCE_DIR}/be_none.c
   ${CMAKE_SOURCE_DIR}/nogss.c
-  ${CMAKE_SOURCE_DIR}/scpserver.c
+  ${CMAKE_SOURCE_DIR}/ssh/scpserver.c
   uxnogtk.c
   uxpty.c)
 target_link_libraries(psusan
@@ -130,13 +130,13 @@ target_link_libraries(testsc crypto utils)
 
 add_executable(testzlib
   ${CMAKE_SOURCE_DIR}/testzlib.c
-  ${CMAKE_SOURCE_DIR}/sshzlib.c)
+  ${CMAKE_SOURCE_DIR}/ssh/zlib.c)
 target_link_libraries(testzlib utils)
 
 add_executable(uppity
   uxserver.c
   ${CMAKE_SOURCE_DIR}/be_none.c
-  ${CMAKE_SOURCE_DIR}/scpserver.c
+  ${CMAKE_SOURCE_DIR}/ssh/scpserver.c
   uxnogtk.c
   uxpty.c
   ${CMAKE_SOURCE_DIR}/nogss.c)
@@ -161,7 +161,7 @@ if(GTK_FOUND)
     gtkask.c
     ux_x11.c
     uxnoise.c
-    ${CMAKE_SOURCE_DIR}/x11fwd.c)
+    ${CMAKE_SOURCE_DIR}/ssh/x11fwd.c)
   target_link_libraries(pageant
     guimisc eventloop console agent settings network crypto utils
     ${GTK_LIBRARIES})
diff --git a/unix/platform.h b/unix/platform.h
index 62f86a74..6d88d84b 100644
--- a/unix/platform.h
+++ b/unix/platform.h
@@ -67,7 +67,7 @@ struct FontSpec *fontspec_new(const char *name);
 
 extern const struct BackendVtable pty_backend;
 
-#define BROKEN_PIPE_ERROR_CODE EPIPE   /* used in sshshare.c */
+#define BROKEN_PIPE_ERROR_CODE EPIPE   /* used in ssh/sharing.c */
 
 /*
  * Under GTK, we send MA_CLICK _and_ MA_2CLK, or MA_CLICK _and_
diff --git a/unix/uxgss.c b/unix/uxgss.c
index 2b4e8537..cd9971c7 100644
--- a/unix/uxgss.c
+++ b/unix/uxgss.c
@@ -1,8 +1,8 @@
 #include "putty.h"
 #ifndef NO_GSSAPI
-#include "pgssapi.h"
-#include "sshgss.h"
-#include "sshgssc.h"
+#include "ssh/pgssapi.h"
+#include "ssh/gss.h"
+#include "ssh/gssc.h"
 
 /* Unix code to set up the GSSAPI library list. */
 
diff --git a/unix/uxpsusan.c b/unix/uxpsusan.c
index c60728ce..a9312c40 100644
--- a/unix/uxpsusan.c
+++ b/unix/uxpsusan.c
@@ -39,7 +39,7 @@
 #include "putty.h"
 #include "mpint.h"
 #include "ssh.h"
-#include "sshserver.h"
+#include "ssh/server.h"
 
 const char *const appname = "psusan";
 
diff --git a/unix/uxpty.c b/unix/uxpty.c
index 7d65a4fc..30e48e50 100644
--- a/unix/uxpty.c
+++ b/unix/uxpty.c
@@ -25,7 +25,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshserver.h" /* to check the prototypes of server-needed things */
+#include "ssh/server.h" /* to check the prototypes of server-needed things */
 #include "tree234.h"
 
 #ifndef OMIT_UTMP
@@ -828,7 +828,7 @@ static void copy_ttymodes_into_termios(
     }
 
 #define TTYMODES_LOCAL_ONLY   /* omit any that this platform doesn't know */
-#include "sshttymodes.h"
+#include "ssh/ttymode-list.h"
 
 #undef TTYMODES_LOCAL_ONLY
 #undef TTYMODE_CHAR
@@ -1468,7 +1468,7 @@ static void pty_special(Backend *be, SessionSpecialCode code, int arg)
         #define SIGNAL_SUB(name) if (code == SS_SIG ## name) sig = SIG ## name;
         #define SIGNAL_MAIN(name, text) SIGNAL_SUB(name)
         #define SIGNALS_LOCAL_ONLY
-        #include "sshsignals.h"
+        #include "ssh/signal-list.h"
         #undef SIGNAL_SUB
         #undef SIGNAL_MAIN
         #undef SIGNALS_LOCAL_ONLY
@@ -1564,7 +1564,7 @@ ptrlen pty_backend_exit_signame(Backend *be, char **aux_msg)
     }
     #define SIGNAL_MAIN(s, desc) SIGNAL_SUB(s)
     #define SIGNALS_LOCAL_ONLY
-    #include "sshsignals.h"
+    #include "ssh/signal-list.h"
     #undef SIGNAL_MAIN
     #undef SIGNAL_SUB
     #undef SIGNALS_LOCAL_ONLY
diff --git a/unix/uxserver.c b/unix/uxserver.c
index 448c6515..1a35451b 100644
--- a/unix/uxserver.c
+++ b/unix/uxserver.c
@@ -41,7 +41,7 @@
 #include "putty.h"
 #include "mpint.h"
 #include "ssh.h"
-#include "sshserver.h"
+#include "ssh/server.h"
 
 const char *const appname = "uppity";
 
diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c
index acefe9bd..7257c5c9 100644
--- a/unix/uxsftpserver.c
+++ b/unix/uxsftpserver.c
@@ -20,8 +20,8 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshserver.h"
-#include "sftp.h"
+#include "ssh/server.h"
+#include "ssh/sftp.h"
 #include "tree234.h"
 
 typedef struct UnixSftpServer UnixSftpServer;
diff --git a/utils/sshutils.c b/utils/sshutils.c
index 1ee3342b..49e82219 100644
--- a/utils/sshutils.c
+++ b/utils/sshutils.c
@@ -8,7 +8,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshchan.h"
+#include "ssh/channel.h"
 
 /* ----------------------------------------------------------------------
  * Centralised standard methods for other channel implementations to
diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt
index d063b9d3..c37abd1e 100644
--- a/windows/CMakeLists.txt
+++ b/windows/CMakeLists.txt
@@ -111,7 +111,7 @@ add_executable(psocks
   ${CMAKE_SOURCE_DIR}/psocks.c
   ${CMAKE_SOURCE_DIR}/norand.c
   ${CMAKE_SOURCE_DIR}/nocproxy.c
-  ${CMAKE_SOURCE_DIR}/portfwd.c)
+  ${CMAKE_SOURCE_DIR}/ssh/portfwd.c)
 target_link_libraries(psocks
   eventloop console network utils
   ${platform_libraries})
diff --git a/windows/platform.h b/windows/platform.h
index cd89d411..0011ed24 100644
--- a/windows/platform.h
+++ b/windows/platform.h
@@ -121,7 +121,7 @@ static inline uintmax_t strtoumax(const char *nptr, char **endptr, int base)
 #define strnicmp strncasecmp
 #endif
 
-#define BROKEN_PIPE_ERROR_CODE ERROR_BROKEN_PIPE   /* used in sshshare.c */
+#define BROKEN_PIPE_ERROR_CODE ERROR_BROKEN_PIPE   /* used in ssh/sharing.c */
 
 /*
  * Dynamically linked functions. These come in two flavours:
@@ -261,7 +261,7 @@ void write_aclip(int clipboard, char *, int, bool);
  * couldn't write it if I wanted to, but I haven't bothered), so
  * it's a macro which always returns NULL. With any luck this will
  * cause the compiler to notice it can optimise away the
- * implementation of XDM-AUTHORIZATION-1 in x11fwd.c :-)
+ * implementation of XDM-AUTHORIZATION-1 in ssh/x11fwd.c :-)
  */
 #define sk_getxdmdata(socket, lenp) (NULL)
 
diff --git a/windows/wingss.c b/windows/wingss.c
index ae36eb13..0b47d9a7 100644
--- a/windows/wingss.c
+++ b/windows/wingss.c
@@ -6,9 +6,9 @@
 #define SECURITY_WIN32
 #include <security.h>
 
-#include "pgssapi.h"
-#include "sshgss.h"
-#include "sshgssc.h"
+#include "ssh/pgssapi.h"
+#include "ssh/gss.h"
+#include "ssh/gssc.h"
 
 #include "misc.h"
 
diff --git a/x11disp.c b/x11disp.c
index 58ffc1e6..1dbc9c07 100644
--- a/x11disp.c
+++ b/x11disp.c
@@ -10,7 +10,7 @@
 
 #include "putty.h"
 #include "ssh.h"
-#include "sshchan.h"
+#include "ssh/channel.h"
 #include "tree234.h"
 
 struct X11Display *x11_setup_display(const char *display, Conf *conf,