diff --git a/3rdp/build/GNUmakefile b/3rdp/build/GNUmakefile
index 5987bff65fc8398b560fe837a616fce391568b2e..1e29e1b2e2c79c8e75140b1f0caadebb43d75112 100644
--- a/3rdp/build/GNUmakefile
+++ b/3rdp/build/GNUmakefile
@@ -88,12 +88,13 @@ $(CRYPT_SRC): | $(3RDPSRCDIR)
 $(CRYPT_IDIR): | $(3RDPODIR)
 	$(QUIET)$(IFNOTEXIST) mkdir $(CRYPT_IDIR)
 
-$(CRYPTLIB_BUILD): $(3RDP_ROOT)/dist/cryptlib.zip $(3RDP_ROOT)/build/terminal-params.patch $(3RDP_ROOT)/build/cl-mingw32-static.patch $(3RDP_ROOT)/build/cl-ranlib.patch $(3RDP_ROOT)/build/cl-win32-noasm.patch $(3RDP_ROOT)/build/cl-zz-country.patch $(3RDP_ROOT)/build/cl-algorithms.patch $(3RDP_ROOT)/build/cl-allow-duplicate-ext.patch $(3RDP_ROOT)/build/cl-macosx-minver.patch $(3RDP_ROOT)/build/cl-endian.patch $(3RDP_ROOT)/build/cl-cryptodev.patch $(3RDP_ROOT)/build/cl-posix-me-gently.patch $(3RDP_ROOT)/build/cl-tpm-linux.patch $(3RDP_ROOT)/build/cl-PAM-noprompts.patch $(3RDP_ROOT)/build/cl-zlib.patch $(3RDP_ROOT)/build/Dynamic-linked-static-lib.patch $(3RDP_ROOT)/build/SSL-fix.patch $(3RDP_ROOT)/build/cl-bigger-maxattribute.patch $(3RDP_ROOT)/build/cl-vcxproj.patch $(3RDP_ROOT)/build/cl-mingw-vcver.patch $(3RDP_ROOT)/build/cl-win32-build-fix.patch $(3RDP_ROOT)/build/cl-gcc-non-const-time-val.patch $(3RDP_ROOT)/build/cl-no-odbc.patch $(3RDP_ROOT)/build/cl-noasm-defines.patch $(3RDP_ROOT)/build/cl-bn-noasm64-fix.patch $(3RDP_ROOT)/build/cl-no-RSA-suites.patch $(3RDP_ROOT)/build/cl-fix-ECC-RSA.patch $(3RDP_ROOT)/build/cl-prefer-ECC.patch $(3RDP_ROOT)/build/cl-prefer-ECC-harder.patch $(3RDP_ROOT)/build/cl-more-RSA-ECC-fixes.patch $(3RDP_ROOT)/build/cl-DH-key-init.patch $(3RDP_ROOT)/build/cl-clear-GCM-flag.patch $(3RDP_ROOT)/build/cl-use-ssh-ctr.patch $(3RDP_ROOT)/build/cl-ssh-list-ctr-modes.patch $(3RDP_ROOT)/build/cl-ssh-incCtr.patch $(3RDP_ROOT)/build/cl-ssl-suite-blocksizes.patch $(3RDP_ROOT)/build/cl-no-tpm.patch $(3RDP_ROOT)/build/cl-no-via-aes.patch $(3RDP_ROOT)/build/cl-fix-ssh-ecc-ephemeral.patch $(3RDP_ROOT)/build/cl-just-use-cc.patch $(3RDP_ROOT)/build/cl-learn-numbers.patch $(3RDP_ROOT)/build/cl-no-safe-stack.patch $(3RDP_ROOT)/build/cl-allow-pkcs12.patch $(3RDP_ROOT)/build/cl-uint64_t-redefine.patch $(3RDP_ROOT)/build/cl-random-openbsd.patch $(3RDP_ROOT)/build/cl-openbsd-threads.patch $(3RDP_ROOT)/build/cl-allow-none-auth.patch $(3RDP_ROOT)/build/cl-mingw-add-m32.patch $(3RDP_ROOT)/build/cl-poll-not-select.patch $(3RDP_ROOT)/build/cl-check-before-use.patch $(3RDP_ROOT)/build/cl-linux-yield.patch $(3RDP_ROOT)/build/cl-good-sockets.patch $(3RDP_ROOT)/build/cl-moar-objects.patch $(3RDP_ROOT)/build/cl-pthread_yield.patch $(3RDP_ROOT)/build/cl-check-cert-dont-modify.patch $(3RDP_ROOT)/build/cl-server-term-support.patch $(3RDP_ROOT)/build/cl-add-pubkey-attribute.patch $(3RDP_ROOT)/build/cl-allow-ssh-auth-retries.patch $(3RDP_ROOT)/build/cl-fix-ssh-channel-close.patch | $(CRYPT_SRC) $(CRYPT_IDIR) $(3RDP_ROOT)/build/cl-remove-march.patch
+$(CRYPTLIB_BUILD): $(3RDP_ROOT)/dist/cryptlib.zip $(3RDP_ROOT)/build/cl-fix-test-select.patch $(3RDP_ROOT)/build/cl-terminal-params.patch $(3RDP_ROOT)/build/cl-mingw32-static.patch $(3RDP_ROOT)/build/cl-ranlib.patch $(3RDP_ROOT)/build/cl-win32-noasm.patch $(3RDP_ROOT)/build/cl-zz-country.patch $(3RDP_ROOT)/build/cl-algorithms.patch $(3RDP_ROOT)/build/cl-allow-duplicate-ext.patch $(3RDP_ROOT)/build/cl-macosx-minver.patch $(3RDP_ROOT)/build/cl-posix-me-gently.patch $(3RDP_ROOT)/build/cl-PAM-noprompts.patch $(3RDP_ROOT)/build/cl-zlib.patch $(3RDP_ROOT)/build/cl-Dynamic-linked-static-lib.patch $(3RDP_ROOT)/build/cl-SSL-fix.patch $(3RDP_ROOT)/build/cl-bigger-maxattribute.patch $(3RDP_ROOT)/build/cl-endian.patch $(3RDP_ROOT)/build/cl-vcxproj.patch $(3RDP_ROOT)/build/cl-mingw-vcver.patch $(3RDP_ROOT)/build/cl-win32-build-fix.patch $(3RDP_ROOT)/build/cl-no-odbc.patch $(3RDP_ROOT)/build/cl-noasm-defines.patch $(3RDP_ROOT)/build/cl-bn-noasm64-fix.patch $(3RDP_ROOT)/build/cl-prefer-ECC.patch $(3RDP_ROOT)/build/cl-prefer-ECC-harder.patch $(3RDP_ROOT)/build/cl-clear-GCM-flag.patch $(3RDP_ROOT)/build/cl-use-ssh-ctr.patch $(3RDP_ROOT)/build/cl-ssl-suite-blocksizes.patch $(3RDP_ROOT)/build/cl-no-tpm.patch $(3RDP_ROOT)/build/cl-no-via-aes.patch $(3RDP_ROOT)/build/cl-fix-ssh-ecc-ephemeral.patch $(3RDP_ROOT)/build/cl-just-use-cc.patch $(3RDP_ROOT)/build/cl-no-safe-stack.patch $(3RDP_ROOT)/build/cl-allow-pkcs12.patch $(3RDP_ROOT)/build/cl-openbsd-threads.patch $(3RDP_ROOT)/build/cl-allow-none-auth.patch $(3RDP_ROOT)/build/cl-mingw-add-m32.patch $(3RDP_ROOT)/build/cl-poll-not-select.patch $(3RDP_ROOT)/build/cl-good-sockets.patch $(3RDP_ROOT)/build/cl-moar-objects.patch $(3RDP_ROOT)/build/cl-server-term-support.patch $(3RDP_ROOT)/build/cl-add-pubkey-attribute.patch $(3RDP_ROOT)/build/cl-allow-ssh-auth-retries.patch $(3RDP_ROOT)/build/cl-fix-ssh-channel-close.patch $(3RDP_ROOT)/build/cl-vt-lt-2005-always-defined.patch $(3RDP_ROOT)/build/cl-no-pie.patch $(3RDP_ROOT)/build/cl-no-testobjs.patch $(3RDP_ROOT)/build/cl-win32-lean-and-mean.patch $(3RDP_ROOT)/build/cl-thats-not-asm.patch $(3RDP_ROOT)/build/cl-make-channels-work.patch $(3RDP_ROOT)/build/cl-allow-ssh-2.0-go.patch $(3RDP_ROOT)/build/cl-read-timeout-every-time.patch $(3RDP_ROOT)/build/cl-allow-servercheck-pubkeys.patch $(3RDP_ROOT)/build/cl-pass-after-pubkey.patch $(3RDP_ROOT)/build/cl-ssh-list-ctr-modes.patch | $(CRYPT_SRC) $(CRYPT_IDIR) $(3RDP_ROOT)/build/cl-remove-march.patch
 	@echo Creating $@ ...
 	$(QUIET)-rm -rf $(CRYPT_SRC)/*
 	$(QUIET)unzip -oa $(3RDPDISTDIR)/cryptlib.zip -d $(CRYPT_SRC)
 	$(QUIET)perl -pi.bak -e 's/\r//' $(CRYPT_SRC)/crypt32.vcxproj
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < terminal-params.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-fix-test-select.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-terminal-params.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-mingw32-static.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-ranlib.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-vcxproj.patch
@@ -103,54 +104,50 @@ $(CRYPTLIB_BUILD): $(3RDP_ROOT)/dist/cryptlib.zip $(3RDP_ROOT)/build/terminal-pa
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-algorithms.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-allow-duplicate-ext.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-macosx-minver.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-cryptodev.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-posix-me-gently.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-tpm-linux.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-PAM-noprompts.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-zlib.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < Dynamic-linked-static-lib.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < SSL-fix.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-Dynamic-linked-static-lib.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-SSL-fix.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-bigger-maxattribute.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-mingw-vcver.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-win32-build-fix.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-gcc-non-const-time-val.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-no-odbc.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-noasm-defines.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-bn-noasm64-fix.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-no-RSA-suites.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-fix-ECC-RSA.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-prefer-ECC.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-prefer-ECC-harder.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-more-RSA-ECC-fixes.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-DH-key-init.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-clear-GCM-flag.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-use-ssh-ctr.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-ssh-list-ctr-modes.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-ssh-incCtr.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-ssl-suite-blocksizes.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-no-tpm.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-no-via-aes.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-fix-ssh-ecc-ephemeral.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-just-use-cc.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-learn-numbers.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-no-safe-stack.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-allow-pkcs12.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-uint64_t-redefine.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-random-openbsd.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-openbsd-threads.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-allow-none-auth.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-mingw-add-m32.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-poll-not-select.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-check-before-use.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-linux-yield.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-good-sockets.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-moar-objects.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-remove-march.patch
-	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-pthread_yield.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-server-term-support.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-add-pubkey-attribute.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-allow-ssh-auth-retries.patch
 	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-fix-ssh-channel-close.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-vt-lt-2005-always-defined.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-no-pie.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-no-testobjs.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-win32-lean-and-mean.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-thats-not-asm.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-make-channels-work.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-allow-ssh-2.0-go.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-read-timeout-every-time.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-pass-after-pubkey.patch
+	$(QUIET)patch -b -p0 -d $(CRYPT_SRC) < cl-allow-servercheck-pubkeys.patch
 ifeq ($(os),win32)
 	$(QUIET)cd $(CRYPT_SRC) && env - PATH="$(PATH)" CC="$(CC)" AR="$(AR)" RANLIB="$(RANLIB)" make directories
 	$(QUIET)cd $(CRYPT_SRC) && env - PATH="$(PATH)" CC="$(CC)" AR="$(AR)" RANLIB="$(RANLIB)" make toolscripts
diff --git a/3rdp/build/cl-DH-key-init.patch b/3rdp/build/cl-DH-key-init.patch
deleted file mode 100644
index 08e3084e0511234f79f58a0138b7edeff40e74dc..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-DH-key-init.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- session/ssl_kmgmt.c.orig	2019-01-11 01:54:56.000000000 -0500
-+++ session/ssl_kmgmt.c	2020-01-23 18:18:40.754040000 -0500
-@@ -448,7 +448,7 @@
- 			status = krnlSendMessage( createInfo.cryptHandle, 
- 									  IMESSAGE_SETATTRIBUTE, 
- 									  ( MESSAGE_CAST ) &eccParams, 
--									  CRYPT_IATTRIBUTE_KEY_DLPPARAM );
-+									  CRYPT_IATTRIBUTE_KEY_ECCPARAM );
- 			}
- 		else
- #endif /* USE_ECDH */
diff --git a/3rdp/build/Dynamic-linked-static-lib.patch b/3rdp/build/cl-Dynamic-linked-static-lib.patch
similarity index 100%
rename from 3rdp/build/Dynamic-linked-static-lib.patch
rename to 3rdp/build/cl-Dynamic-linked-static-lib.patch
diff --git a/3rdp/build/cl-PAM-noprompts.patch b/3rdp/build/cl-PAM-noprompts.patch
index e99ed54aec03255c2cc5563e2aabed9440ba32c2..c6e0205e8602389e2d170669caf767d33ee05003 100644
--- a/3rdp/build/cl-PAM-noprompts.patch
+++ b/3rdp/build/cl-PAM-noprompts.patch
@@ -1,5 +1,5 @@
---- ../tmp2/session/ssh2_authc.c	2018-12-14 17:31:34.000000000 -0500
-+++ session/ssh2_authc.c	2019-06-03 16:41:49.956986000 -0400
+--- ../tmp2/session/ssh2_authcli.c	2018-12-14 17:31:34.000000000 -0500
++++ session/ssh2_authcli.c	2019-06-03 16:41:49.956986000 -0400
 @@ -868,7 +868,7 @@
  		if( !cryptStatusError( status ) )
  			{
diff --git a/3rdp/build/SSL-fix.patch b/3rdp/build/cl-SSL-fix.patch
similarity index 100%
rename from 3rdp/build/SSL-fix.patch
rename to 3rdp/build/cl-SSL-fix.patch
diff --git a/3rdp/build/cl-add-pubkey-attribute.patch b/3rdp/build/cl-add-pubkey-attribute.patch
index d30bd2ab13af64de2dcd348fdb0291a05f57d89a..8b8318bf38285d32a7674f1c6a83f01f713418a7 100644
--- a/3rdp/build/cl-add-pubkey-attribute.patch
+++ b/3rdp/build/cl-add-pubkey-attribute.patch
@@ -1,14 +1,3 @@
-diff -ur ../cl-old/context/ctx_attr.c ./context/ctx_attr.c
---- ../cl-old/context/ctx_attr.c	2023-12-28 05:19:27.058456000 -0500
-+++ ./context/ctx_attr.c	2023-12-28 05:41:08.265717000 -0500
-@@ -419,6 +419,7 @@
- 		case CRYPT_IATTRIBUTE_KEY_SSH:
- 		case CRYPT_IATTRIBUTE_KEY_SSL:
- 		case CRYPT_IATTRIBUTE_KEY_SSL_EXT:
-+		case CRYPT_CTXINFO_SSH_PUBLIC_KEY:
- 			{
- 			const PKC_WRITEKEY_FUNCTION writePublicKeyFunction = \
- 				( PKC_WRITEKEY_FUNCTION ) \
 diff -ur ../cl-old/context/keyload.c ./context/keyload.c
 --- ../cl-old/context/keyload.c	2023-12-28 05:19:27.069792000 -0500
 +++ ./context/keyload.c	2023-12-28 05:41:08.270975000 -0500
@@ -46,3 +35,17 @@ diff -ur ../cl-old/kernel/attr_acl.c ./kernel/attr_acl.c
  	MKACL_END(), MKACL_END()
  	};
  
+--- context/ctx_attr.c.orig	2023-02-08 05:36:06.000000000 -0500
++++ context/ctx_attr.c	2024-01-07 19:38:26.173540000 -0500
+@@ -422,6 +422,11 @@
+ 				}
+ 			STDC_FALLTHROUGH;
+ 
++		case CRYPT_CTXINFO_SSH_PUBLIC_KEY:
++			if ( needsKey( contextInfoPtr ) )
++				return CRYPT_ERROR_NOTFOUND;
++			if (contextType != CONTEXT_PKC)
++				return CRYPT_ERROR_NOTFOUND;
+ 		case CRYPT_IATTRIBUTE_KEY_PGP:
+ 		case CRYPT_IATTRIBUTE_KEY_SSH:
+ 		case CRYPT_IATTRIBUTE_KEY_TLS:
diff --git a/3rdp/build/cl-allow-none-auth.patch b/3rdp/build/cl-allow-none-auth.patch
index 95ab0fd6985c068f9bd2092abf2aaee3b541be31..2aee3f47139ba16eb92d20210c8b6df9d9d15f95 100644
--- a/3rdp/build/cl-allow-none-auth.patch
+++ b/3rdp/build/cl-allow-none-auth.patch
@@ -1,17 +1,17 @@
---- ../cl-old/cryptlib.h	2021-03-16 04:15:50.265534000 -0400
-+++ ./cryptlib.h	2021-03-16 06:53:47.582168000 -0400
-@@ -1215,6 +1215,7 @@
- 	CRYPT_SESSINFO_SSH_CHANNEL_ARG1,/* SSH channel argument 1 */
+--- ./cryptlib.h.orig	2023-12-31 09:28:53.203654000 -0500
++++ ./cryptlib.h	2023-12-31 09:38:13.586441000 -0500
+@@ -1262,6 +1262,7 @@
  	CRYPT_SESSINFO_SSH_CHANNEL_ARG2,/* SSH channel argument 2 */
  	CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE,/* SSH channel active */
+ 	CRYPT_SESSINFO_SSH_PREAUTH,		/* SSH pre-authentication value */
 +	CRYPT_SESSINFO_SSH_OPTIONS,		/* SSH protocol options */
- 	CRYPT_SESSINFO_SSL_OPTIONS,		/* SSL/TLS protocol options */
- 	CRYPT_SESSINFO_SSL_SUBPROTOCOL,	/* SSL/TLS additional sub-protocol */
- 	CRYPT_SESSINFO_SSL_WSPROTOCOL,	/* SSL/TLS WebSockets sub-protocol */
-@@ -1680,6 +1681,14 @@
- #define CRYPT_SSLOPTION_SUITEB_256			0x200	/*  vanish in future releases) */
+ 	CRYPT_SESSINFO_TLS_OPTIONS,		/* SSL/TLS protocol options */
+ 		CRYPT_SESSINFO_SSL_OPTIONS = CRYPT_SESSINFO_TLS_OPTIONS,
+ 	CRYPT_SESSINFO_TLS_SUBPROTOCOL,	/* SSL/TLS additional sub-protocol */
+@@ -1762,6 +1763,14 @@
+ #define CRYPT_TLSOPTION_SUITEB_256			0x200	/*  vanish in future releases) */
  #ifdef _CRYPT_DEFINED
- #define CRYPT_SSLOPTION_MAX					0x7F	/* Defines for range checking */
+ #define CRYPT_TLSOPTION_MAX					0x07F	/* Defines for range checking */
 +#endif /* _CRYPT_DEFINED */
 +
 +/* SSH protocol options. */
@@ -23,38 +23,91 @@
  #endif /* _CRYPT_DEFINED */
  
  /****************************************************************************
-diff -ur ../cl-old/kernel/attr_acl.c ./kernel/attr_acl.c
---- ../cl-old/kernel/attr_acl.c	2021-03-16 04:15:50.398060000 -0400
-+++ ./kernel/attr_acl.c	2021-03-16 06:53:47.606473000 -0400
-@@ -3731,6 +3731,12 @@
- 		ST_NONE, ST_NONE, ST_SESS_SSH | ST_SESS_SSH_SVR, 
- 		MKPERM_SSH_EXT( RWx_xxx ),
- 		ROUTE( OBJECT_TYPE_SESSION ) ),
+--- ./kernel/attr_acl.c.orig	2023-12-31 09:39:13.241750000 -0500
++++ ./kernel/attr_acl.c	2023-12-31 09:40:15.337914000 -0500
+@@ -3883,6 +3883,12 @@
+ 		ST_NONE, ST_NONE, ST_SESS_SSH | ST_SESS_SSH_SVR,
+ 		MKPERM_SSH( Rxx_RWD ),
+ 		ROUTE( OBJECT_TYPE_SESSION ), RANGE( 2, CRYPT_MAX_TEXTSIZE ) ),
 +	MKACL_N(	/* SSH protocol options */
 +		CRYPT_SESSINFO_SSH_OPTIONS,
 +		ST_NONE, ST_NONE, ST_SESS_SSH, 
-+		MKPERM_SSH_EXT( Rxx_RWx ),
++		MKPERM_SESSIONS( Rxx_RWx ),
 +		ROUTE( OBJECT_TYPE_SESSION ),
 +		RANGE( CRYPT_SSHOPTION_NONE, CRYPT_SSHOPTION_MAX ) ),
  
- 	MKACL_N(	/* SSL/TLS protocol options */
- 		CRYPT_SESSINFO_SSL_OPTIONS,
-@@ -4653,7 +4659,7 @@
+ 	MKACL_N(        /* TLS protocol options */
+ 		CRYPT_SESSINFO_TLS_OPTIONS,
+@@ -4883,7 +4889,7 @@
  	static_assert( CRYPT_CERTINFO_FIRST_EXTENSION == 2200, "Attribute value" );
  	static_assert( CRYPT_CERTINFO_FIRST_CMS == 2500, "Attribute value" );
- 	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6016, "Attribute value" );
--	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6031, "Attribute value" );
-+	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6032, "Attribute value" );
- 	static_assert( CRYPT_CERTFORMAT_LAST == 12, "Attribute value" );
+ 	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6017, "Attribute value" );
+-	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6035, "Attribute value" );
++	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6036, "Attribute value" );
+ 	static_assert( CRYPT_CERTFORMAT_LAST == 13, "Attribute value" );
  
  	/* Perform a consistency check on the attribute ACLs.  The ACLs are
-diff -ur ../cl-old/session/ssh.c ./session/ssh.c
---- ../cl-old/session/ssh.c	2021-03-16 04:15:50.257467000 -0400
-+++ ./session/ssh.c	2021-03-16 06:53:47.638940000 -0400
-@@ -980,6 +980,18 @@
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE );
+--- ./session/ssh2_authcli.c.orig	2023-12-31 09:44:20.876065000 -0500
++++ ./session/ssh2_authcli.c	2023-12-31 09:46:41.813246000 -0500
+@@ -334,13 +334,22 @@
+ 	assert( isWritePtr( authType, sizeof( SSH_AUTHTYPE_TYPE ) ) );
+ 	assert( isWritePtr( furtherAuthRequired, sizeof( BOOLEAN ) ) );
+ 
+-	REQUIRES( isShortIntegerRangeNZ( length ) );
+ 	REQUIRES( isBooleanValue( usedPasswordAuth ) );
+ 
+ 	/* Clear return values */
+ 	*authType = SSH_AUTHTYPE_NONE;
+ 	*furtherAuthRequired = FALSE;
  
++	if (length == 0 && GET_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_DUMMYUSERAUTH ) && !usedPasswordAuth)
++		{
++		CLEAR_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_DUMMYUSERAUTH );
++		*furtherAuthRequired = TRUE;
++		*authType = SSH_AUTHTYPE_PASSWORD;
++		return( CRYPT_OK );
++		}
++
++	REQUIRES( isShortIntegerRangeNZ( length ) );
++
+ 	/* Before we can try and interpret the response, we have to check for an
+ 	   empty response */
+ 	if( length >= LENGTH_SIZE && \
+@@ -671,6 +680,8 @@
+ 								  SSH_MSG_USERAUTH_REQUEST );
+ 	if( cryptStatusError( status ) )
+ 		return( status );
++	if (passwordPtr == NULL && GET_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_DUMMYUSERAUTH ))
++		return( OK_SPECIAL );
+ 	if( usePasswordAuth )
+ 		{
+ 		/*	byte	type = SSH_MSG_USERAUTH_REQUEST
+@@ -1251,6 +1262,11 @@
+ 	   auth required */
+ 	if( !hasPassword )
+ 		{
++		if (length == 0)
++			{
++			return( reportAuthFailure( sessionInfoPtr, SSH_AUTHTYPE_PASSWORD, 
++									   requiredAuthType, TRUE ) );
++			}
+ 		return( reportAuthFailure( sessionInfoPtr, SSH_AUTHTYPE_PUBKEY, 
+ 								   requiredAuthType, TRUE ) );
+ 		}
+--- session/ssh.c.orig	2023-05-06 19:14:38.000000000 -0400
++++ session/ssh.c	2024-01-07 21:22:26.535903000 -0500
+@@ -540,6 +540,7 @@
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG1 || \
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
++			  type == CRYPT_SESSINFO_SSH_OPTIONS || \
+ 			  type == CRYPT_SESSINFO_SSH_PREAUTH );
+ #else
+ 	REQUIRES( type == CRYPT_SESSINFO_SSH_PREAUTH );
+@@ -561,6 +562,19 @@
+ 							   attributeListPtr->valueLength ) );
+ 		}
+ #ifdef USE_SSH_EXTENDED
 +	if( type == CRYPT_SESSINFO_SSH_OPTIONS )
 +		{
 +			int *valuePtr = ( int * ) data;
@@ -66,26 +119,30 @@ diff -ur ../cl-old/session/ssh.c ./session/ssh.c
 +
 +			return( CRYPT_OK );
 +		}
++
 +
  	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
  		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE )
  		{
-@@ -1010,11 +1022,13 @@
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_TYPE || \
+@@ -596,6 +610,7 @@
  			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG1 || \
  			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
 +			  type == CRYPT_SESSINFO_SSH_OPTIONS || \
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE );
- 
+ 			  type == CRYPT_SESSINFO_SSH_PREAUTH );
+ #else
+ 	REQUIRES( type == CRYPT_SESSINFO_SSH_PREAUTH );
+@@ -613,7 +628,8 @@
+ #ifdef USE_SSH_EXTENDED
  	/* Get the data value if it's an integer parameter */
  	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
 -		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE )
 +		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
-+		type == CRYPT_SESSINFO_SSH_OPTIONS)
++		type == CRYPT_SESSINFO_SSH_OPTIONS )
  		value = *( ( int * ) data );
  
  	/* If we're selecting a channel and there's unwritten data from a
-@@ -1038,6 +1052,13 @@
+@@ -647,6 +663,13 @@
  		return( createChannel( sessionInfoPtr ) );
  		}
  
@@ -99,8 +156,8 @@ diff -ur ../cl-old/session/ssh.c ./session/ssh.c
  	/* If we 're setting the channel-active attribute, this implicitly
  	   activates or deactivates the channel rather than setting any
  	   attribute value */
-@@ -1165,8 +1186,6 @@
- 		 SESSION_FLAG_NONE,			/* Flags */
+@@ -776,8 +799,6 @@
+ 		 SESSION_PROTOCOL_FIXEDSIZECREDENTIALS,	/* Flags */
  		SSH_PORT,					/* SSH port */
  		SESSION_NEEDS_USERID |		/* Client attributes */
 -			SESSION_NEEDS_PASSWORD | \
@@ -108,51 +165,3 @@ diff -ur ../cl-old/session/ssh.c ./session/ssh.c
  			SESSION_NEEDS_PRIVKEYSIGN,
  				/* The client private key is optional, but if present it has
  				   to be signature-capable */
-diff -ur ../cl-old/session/ssh2_authc.c ./session/ssh2_authc.c
---- ../cl-old/session/ssh2_authc.c	2021-03-16 04:15:50.264206000 -0400
-+++ ./session/ssh2_authc.c	2021-03-16 07:46:47.873769000 -0400
-@@ -315,13 +315,22 @@
- 	assert( isWritePtr( authAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
- 	assert( isWritePtr( furtherAuthRequired, sizeof( BOOLEAN ) ) );
- 
--	REQUIRES( isShortIntegerRangeNZ( length ) );
- 	REQUIRES( usedPasswordAuth == TRUE || usedPasswordAuth == FALSE );
- 
- 	/* Clear return values */
- 	*authAlgo = CRYPT_ALGO_NONE;
- 	*furtherAuthRequired = FALSE;
- 
-+	if (length == 0 && GET_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_DUMMYUSERAUTH ) && !usedPasswordAuth)
-+		{
-+		CLEAR_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_DUMMYUSERAUTH );
-+		*furtherAuthRequired = TRUE;
-+		*authAlgo = CRYPT_PSEUDOALGO_PASSWORD;
-+		return( CRYPT_OK );
-+		}
-+
-+	REQUIRES( isShortIntegerRangeNZ( length ) );
-+
- 	/* Before we can try and interpret the response, we have to check for an
- 	   empty response */
- 	if( length >= LENGTH_SIZE && \
-@@ -647,6 +656,8 @@
- 								  SSH_MSG_USERAUTH_REQUEST );
- 	if( cryptStatusError( status ) )
- 		return( status );
-+	if (passwordPtr == NULL && GET_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_DUMMYUSERAUTH ))
-+		return( OK_SPECIAL );
- 	if( usePasswordAuth )
- 		{
- 		/*	byte	type = SSH_MSG_USERAUTH_REQUEST
-@@ -1220,6 +1231,11 @@
- 	   auth required */
- 	if( !hasPassword )
- 		{
-+		if (length == 0)
-+			{
-+			return( reportAuthFailure( sessionInfoPtr, CRYPT_PSEUDOALGO_PASSWORD, 
-+									   requiredAuthAlgo, TRUE ) );
-+			}
- 		return( reportAuthFailure( sessionInfoPtr, CRYPT_ALGO_RSA, 
- 								   requiredAuthAlgo, TRUE ) );
- 		}
diff --git a/3rdp/build/cl-allow-pkcs12.patch b/3rdp/build/cl-allow-pkcs12.patch
index 8d0bfdd1796ee50b4c9070c45d8b538f7093ba56..5e877d8b98aa6fdd42394a1a142c9d469ef6245e 100644
--- a/3rdp/build/cl-allow-pkcs12.patch
+++ b/3rdp/build/cl-allow-pkcs12.patch
@@ -1,18 +1,18 @@
---- misc/config.h.orig	2021-01-25 23:06:22.266896000 -0500
-+++ misc/config.h	2021-01-25 23:31:45.451504000 -0500
-@@ -494,7 +494,7 @@
-    indirectly as a result of any use of cryptlib with this change made.  If
-    you receive the code with the safety features already disabled, you must
-    immediately obtain and use an original, unmodified version */
+--- ./misc/config.h.orig	2023-12-31 08:00:17.038610000 -0500
++++ ./misc/config.h	2023-12-31 08:01:00.988147000 -0500
+@@ -602,7 +602,7 @@
+    manner you must immediately obtain and use an original, unmodified 
+    version */
+ 
 -/* #define USE_PKCS12 */
 +#define USE_PKCS12
+ 
  /* Going beyond the PKCS #12 read capability which exists solely to allow 
     the import of keys supplied in that format by third parties, cryptlib has
-    a PKCS #12 write capability.  This exists purely to allow the export of
-@@ -509,7 +509,7 @@
-    PKCS #12 read capability, as well as the fact that PKCS #12 write is an 
-    unsupported facility with special-case usage restrictions that doesn't 
-    work like any normal keyset */
+@@ -620,7 +620,7 @@
+    PKCS #12 write is an unsupported facility with special-case usage 
+    restrictions that doesn't work like any normal keyset */
+ 
 -/* #define USE_PKCS12_WRITE */
 +#define USE_PKCS12_WRITE
  
diff --git a/3rdp/build/cl-allow-servercheck-pubkeys.patch b/3rdp/build/cl-allow-servercheck-pubkeys.patch
new file mode 100644
index 0000000000000000000000000000000000000000..bdc98831ad896debddc0d38ea0715d9d001c9bc2
--- /dev/null
+++ b/3rdp/build/cl-allow-servercheck-pubkeys.patch
@@ -0,0 +1,290 @@
+--- cryptlib.h.orig	2024-01-18 23:57:53.642105000 -0500
++++ cryptlib.h	2024-01-18 23:58:23.323178000 -0500
+@@ -1236,6 +1236,7 @@
+ 	CRYPT_SESSINFO_PASSWORD,		/* Password */
+ 	CRYPT_SESSINFO_AUTHTOKEN,		/* Authentication token, e.g. TOTP */
+ 	CRYPT_SESSINFO_PRIVATEKEY,		/* Server/client private key */
++	CRYPT_SESSINFO_PUBLICKEY,		/* Other sides public key */
+ 	CRYPT_SESSINFO_KEYSET,			/* Certificate store */
+ 	CRYPT_SESSINFO_AUTHRESPONSE,	/* Session authorisation OK */
+ 
+--- kernel/attr_acl.c.orig	2024-01-19 00:01:33.318597000 -0500
++++ kernel/attr_acl.c	2024-01-19 00:06:16.927122000 -0500
+@@ -3739,6 +3739,15 @@
+ 		MKPERM_SESSIONS( xWx_xWx ),
+ 		ROUTE( OBJECT_TYPE_SESSION ),
+ 		subACL_SessinfoPrivatekey ),
++	MKACL_S(	/* Other side public key */
++		/* We can read this attribute in the low state because we might be
++		   going back to the caller for confirmation before we transition
++		   into the high state */
++		CRYPT_SESSINFO_PUBLICKEY,
++		ST_NONE, ST_NONE, ST_SESS_SSH_SVR, 
++		MKPERM_SESSIONS( Rxx_Rxx ),
++		ROUTE( OBJECT_TYPE_SESSION ),
++		RANGE( 1, CRYPT_MAX_TEXTSIZE ) ),
+ 	MKACL_ST(	/* Certificate store/auth.keyset */
+ 		CRYPT_SESSINFO_KEYSET,
+ 		ST_NONE, ST_NONE, MK_ST_EXCEPTION( ST_SESS_ANY_SVR, ST_SESS_TSP_SVR ) | \
+@@ -4942,8 +4951,8 @@
+ 	static_assert( CRYPT_CERTINFO_LAST_GENERALNAME == 2115, "Attribute value" );
+ 	static_assert( CRYPT_CERTINFO_FIRST_EXTENSION == 2200, "Attribute value" );
+ 	static_assert( CRYPT_CERTINFO_FIRST_CMS == 2500, "Attribute value" );
+-	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6017, "Attribute value" );
+-	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6040, "Attribute value" );
++	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6018, "Attribute value" );
++	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6041, "Attribute value" );
+ 	static_assert( CRYPT_CERTFORMAT_LAST == 13, "Attribute value" );
+ 
+ 	/* Perform a consistency check on the attribute ACLs.  The ACLs are
+--- session/sess_iattr.c.orig	2024-01-19 02:24:29.979555000 -0500
++++ session/sess_iattr.c	2024-01-19 02:25:37.172862000 -0500
+@@ -327,7 +327,8 @@
+ 			attributeListPtr = DATAPTR_GET( attributeListPtr->next );
+ 			if( attributeListPtr == NULL || \
+ 				( attributeListPtr->attributeID != CRYPT_SESSINFO_PASSWORD && \
+-				  attributeListPtr->attributeID != CRYPT_SESSINFO_AUTHTOKEN ) )
++				  attributeListPtr->attributeID != CRYPT_SESSINFO_AUTHTOKEN && \
++				  attributeListPtr->attributeID != CRYPT_SESSINFO_PUBLICKEY ) )
+ 				{
+ 				/* We report the missing attribute as a password, which is 
+ 				   more likely and more understandable than a missing 
+--- session/ssh2_authsvr.c.orig	2023-02-26 03:33:26.000000000 -0500
++++ session/ssh2_authsvr.c	2024-01-19 12:21:51.007398000 -0500
+@@ -396,7 +396,7 @@
+ 	/* If we've already seen a standard authentication method then the new 
+ 	   method must be the same */
+ 	if( sshInfo->authType != authType )
+-		return( CRYPT_ERROR_INVALID );
++		sshInfo->authType = authType;
+ 
+ 	return( CRYPT_OK );
+ 	}
+@@ -511,66 +511,69 @@
+ 	   assume that any certificate present will be a cryptlib-generated one 
+ 	   used as a bit-bagging mechanism to get the key into a database, and
+ 	   therefore that sKID == hash( subjectPublicKey ) */
+-	setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
+-	status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, 
+-							  IMESSAGE_GETATTRIBUTE_S, &msgData, 
+-							  CRYPT_IATTRIBUTE_KEYID );
+-	if( cryptStatusOK( status ) )
++	if (sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
+ 		{
+-		setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID, 
+-							   msgData.data, msgData.length, NULL, 0, 
+-							   KEYMGMT_FLAG_NONE );
+-		status = krnlSendMessage( sessionInfoPtr->cryptKeyset, 
+-								  IMESSAGE_KEY_GETKEY, &getkeyInfo, 
+-								  KEYMGMT_ITEM_PUBLICKEY );
+-		}
+-	if( cryptStatusError( status ) )
+-		{
++		setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
++		status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, 
++								  IMESSAGE_GETATTRIBUTE_S, &msgData, 
++								  CRYPT_IATTRIBUTE_KEYID );
++		if( cryptStatusOK( status ) )
++			{
++			setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID, 
++								   msgData.data, msgData.length, NULL, 0, 
++								   KEYMGMT_FLAG_NONE );
++			status = krnlSendMessage( sessionInfoPtr->cryptKeyset, 
++									  IMESSAGE_KEY_GETKEY, &getkeyInfo, 
++									  KEYMGMT_ITEM_PUBLICKEY );
++			}
++		if( cryptStatusError( status ) )
++			{
+ #ifdef USE_ERRMSGS
+-		char keyIDText[ CRYPT_MAX_TEXTSIZE + 8 ];
++			char keyIDText[ CRYPT_MAX_TEXTSIZE + 8 ];
+ #endif /* USE_ERRMSGS */
+ 
+-		formatHexData( keyIDText, CRYPT_MAX_TEXTSIZE, keyID, 
+-					   msgData.length );
+-		retExt( CRYPT_ERROR_PERMISSION,
+-				( CRYPT_ERROR_PERMISSION, SESSION_ERRINFO, 
+-				  "Client public key with ID '%s' is not trusted for "
+-				  "authentication purposes", keyIDText ) );
+-		}
++			formatHexData( keyIDText, CRYPT_MAX_TEXTSIZE, keyID, 
++						   msgData.length );
++			retExt( CRYPT_ERROR_PERMISSION,
++					( CRYPT_ERROR_PERMISSION, SESSION_ERRINFO, 
++					  "Client public key with ID '%s' is not trusted for "
++					  "authentication purposes", keyIDText ) );
++			}
+ 
+-	/* Check that the name in the certificate matches the supplied user 
+-	   name */
+-	setMessageData( &msgData, holderName, CRYPT_MAX_TEXTSIZE );
+-	status = krnlSendMessage( getkeyInfo.cryptHandle, IMESSAGE_GETATTRIBUTE_S,
++		/* Check that the name in the certificate matches the supplied user 
++		   name */
++		setMessageData( &msgData, holderName, CRYPT_MAX_TEXTSIZE );
++		status = krnlSendMessage( getkeyInfo.cryptHandle, IMESSAGE_GETATTRIBUTE_S,
+ 							  &msgData, CRYPT_IATTRIBUTE_HOLDERNAME );
+-	krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DESTROY );
+-	if( cryptStatusOK( status ) )
+-		{
+-		holderNameLen = msgData.length;
+-		if( userNameLength != holderNameLen || \
+-			compareDataConstTime( userName, holderName, 
+-								  userNameLength ) != TRUE )
+-			status = CRYPT_ERROR_INVALID;
+-		}
+-	else
+-		{
+-		memcpy( holderName, "<Unknown>", 9 );
+-		holderNameLen = 9;
+-		}
+-	if( cryptStatusError( status ) )
+-		{
+-		BYTE userNameBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
++		krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DESTROY );
++		if( cryptStatusOK( status ) )
++			{
++			holderNameLen = msgData.length;
++			if( userNameLength != holderNameLen || \
++				compareDataConstTime( userName, holderName, 
++									  userNameLength ) != TRUE )
++				status = CRYPT_ERROR_INVALID;
++			}
++		else
++			{
++			memcpy( holderName, "<Unknown>", 9 );
++			holderNameLen = 9;
++			}
++		if( cryptStatusError( status ) )
++			{
++			BYTE userNameBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
+ 
+-		REQUIRES( rangeCheck( userNameLength, 1, CRYPT_MAX_TEXTSIZE ) );
+-		memcpy( userNameBuffer, userName, userNameLength );
+-		retExt( CRYPT_ERROR_INVALID,
+-				( CRYPT_ERROR_INVALID, SESSION_ERRINFO, 
+-				  "Client public key name '%s' doesn't match supplied user "
+-				  "name '%s'", 
+-				  sanitiseString( holderName, CRYPT_MAX_TEXTSIZE, 
+-								  holderNameLen ),
+-				  sanitiseString( userNameBuffer, CRYPT_MAX_TEXTSIZE, 
+-								  userNameLength ) ) );
++			REQUIRES( rangeCheck( userNameLength, 1, CRYPT_MAX_TEXTSIZE ) );
++			memcpy( userNameBuffer, userName, userNameLength );
++			retExt( CRYPT_ERROR_INVALID,
++					( CRYPT_ERROR_INVALID, SESSION_ERRINFO, 
++					  "Client public key name '%s' doesn't match supplied user "
++					  "name '%s'", 
++					  sanitiseString( holderName, CRYPT_MAX_TEXTSIZE, 
++									  holderNameLen ),
++					  sanitiseString( userNameBuffer, CRYPT_MAX_TEXTSIZE, 
++									  userNameLength ) ) );
++			}
+ 		}
+ 
+ 	/* Get a pointer to the portion of the packet that gets signed */
+@@ -662,8 +665,8 @@
+ 							IN_BOOL const BOOLEAN initialAuth )
+ 	{
+ 	STREAM stream;
+-	const BOOLEAN allowPubkeyAuth = \
+-			( sessionInfoPtr->cryptKeyset != CRYPT_ERROR ) ? TRUE : FALSE;
++	// Always allow public key auth...
++	const BOOLEAN allowPubkeyAuth = TRUE;
+ 	const AUTHTYPE_INFO *authTypeInfoTblPtr = allowPubkeyAuth ? \
+ 			authTypeInfoTbl : authTypeInfoPasswordTbl;
+ 	const int authTypeInfoTblSize = allowPubkeyAuth ? \
+@@ -1098,23 +1101,67 @@
+ 			}
+ 		CFI_CHECK_UPDATE( "checkPublicKeySig" );
+ 
+-		/* The user has successfully authenticated, let the client know and 
+-		   indicate this through a failsafe two-value return status (see the 
+-		   comment for processFixedAuth()/processServerAuth() for details) */
+-		status = sendResponseSuccess( sessionInfoPtr );
+-		if( cryptStatusError( status ) )
+-			return( status );
+-		*userAuthInfo = USERAUTH_SUCCESS;
+-		CFI_CHECK_UPDATE( "sendResponseSuccess" );
++		if (sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
++			{
++			/* The user has successfully authenticated, let the client know and 
++			   indicate this through a failsafe two-value return status (see the 
++			   comment for processFixedAuth()/processServerAuth() for details) */
++			status = sendResponseSuccess( sessionInfoPtr );
++			if( cryptStatusError( status ) )
++				return( status );
++			CFI_CHECK_UPDATE( "sendResponseSuccess" );
+ 
+-		ENSURES( CFI_CHECK_SEQUENCE_8( "readAuthPacketSSH2", 
+-									   "checkAuthPacketSSH2", 
+-									   "checkQueryValidity", "readAuthInfo", 
+-									   "findSessionInfoEx", 
+-									   "SSH_AUTHTYPE_QUERY",
+-									   "checkPublicKeySig", 
+-									   "sendResponseSuccess" ) );
+-		return( CRYPT_OK );
++			ENSURES( CFI_CHECK_SEQUENCE_8( "readAuthPacketSSH2", 
++										   "checkAuthPacketSSH2", 
++										   "checkQueryValidity", "readAuthInfo", 
++										   "findSessionInfoEx", 
++										   "SSH_AUTHTYPE_QUERY",
++										   "checkPublicKeySig", 
++										   "sendResponseSuccess" ) );
++			*userAuthInfo = USERAUTH_SUCCESS;
++			return( CRYPT_OK );
++			}
++		else
++			{
++			/* There are no pre-set credentials present to match against, record the 
++			   public key for the caller to check, making it an ephemeral attribute 
++			   since the client could try and re-enter it on a subsequent iteration 
++			   if we tell them that it's incorrect. */
++			MESSAGE_DATA msgData;
++			BYTE keyBuffer[2056];
++			setMessageData( &msgData, keyBuffer, sizeof(keyBuffer) - 8);
++			status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_KEY_SSH );
++
++			if( cryptStatusError( status ) )
++				{
++				retExt( status,
++						( status, SESSION_ERRINFO, 
++						  "Error getting public key for user '%s'",
++						  sanitiseString( userNameBuffer, CRYPT_MAX_TEXTSIZE,
++										  userNameLength ) ) );
++				}
++			status = updateSessionInfo( sessionInfoPtr, CRYPT_SESSINFO_PUBLICKEY,
++										msgData.data, msgData.length,
++										sizeof(keyBuffer) - 8, ATTR_FLAG_EPHEMERAL );
++			if( cryptStatusError( status ) )
++				{
++				retExt( status,
++						( status, SESSION_ERRINFO, 
++						  "Error recording public key for user '%s'",
++						  sanitiseString( userNameBuffer, CRYPT_MAX_TEXTSIZE,
++										  userNameLength ) ) );
++				}
++			CFI_CHECK_UPDATE( "updateSessionInfo" );
++			ENSURES( CFI_CHECK_SEQUENCE_8( "readAuthPacketSSH2", 
++										   "checkAuthPacketSSH2", 
++										   "checkQueryValidity", "readAuthInfo", 
++										   "findSessionInfoEx", 
++										   "SSH_AUTHTYPE_QUERY",
++										   "checkPublicKeySig",
++										   "updateSessionInfo" ) );
++			*userAuthInfo = USERAUTH_CALLERCHECK;
++			return( OK_SPECIAL );
++			}
+ 		}
+ 	sMemDisconnect( &stream );
+ 	CFI_CHECK_UPDATE( "SSH_AUTHTYPE_PUBKEY" );
+--- session/sess_attr.c.orig	2024-01-19 15:00:59.583402000 -0500
++++ session/sess_attr.c	2024-01-19 15:01:28.125584000 -0500
+@@ -884,6 +884,7 @@
+ 		case CRYPT_SESSINFO_SERVER_FINGERPRINT_SHA1:
+ 		case CRYPT_SESSINFO_SERVER_NAME:
+ 		case CRYPT_SESSINFO_CLIENT_NAME:
++		case CRYPT_SESSINFO_PUBLICKEY:
+ 			attributeListPtr = findSessionInfo( sessionInfoPtr, attribute );
+ 			if( attributeListPtr == NULL )
+ 				return( exitErrorNotInited( sessionInfoPtr, attribute ) );
diff --git a/3rdp/build/cl-allow-ssh-2.0-go.patch b/3rdp/build/cl-allow-ssh-2.0-go.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6c534d8b760737901fb63e042f6c76eb9fee05e1
--- /dev/null
+++ b/3rdp/build/cl-allow-ssh-2.0-go.patch
@@ -0,0 +1,11 @@
+--- session/ssh2_id.c.orig	2024-01-14 12:27:01.156907000 -0500
++++ session/ssh2_id.c	2024-01-14 12:26:48.539941000 -0500
+@@ -901,7 +901,7 @@
+ 		versionStringLength = length - startOffset;
+ 		}
+ 	if( cryptStatusError( status ) || \
+-		!isShortIntegerRangeMin( versionStringLength, 3 ) )
++		!isShortIntegerRangeMin( versionStringLength, 2 ) )
+ 		{
+ 		/* We need at least "-x.y" after the initial ID string, we can't 
+ 		   require any more than this because of CuteFTP (see note below).
diff --git a/3rdp/build/cl-allow-ssh-auth-retries.patch b/3rdp/build/cl-allow-ssh-auth-retries.patch
index 46f3354b18b85fb83adb1fdf857c077d8a829db0..59dcf0ade288d7560704751edd5e3f07741ee9db 100644
--- a/3rdp/build/cl-allow-ssh-auth-retries.patch
+++ b/3rdp/build/cl-allow-ssh-auth-retries.patch
@@ -1,5 +1,5 @@
---- ./session/ssh2_authc.c.orig	2023-12-28 09:41:49.741680000 -0500
-+++ ./session/ssh2_authc.c	2023-12-28 09:48:19.999152000 -0500
+--- ./session/ssh2_authcli.c.orig	2023-12-28 09:41:49.741680000 -0500
++++ ./session/ssh2_authcli.c	2023-12-28 09:48:19.999152000 -0500
 @@ -583,7 +583,5 @@
  					  "Server requested password authentication but only a "
  					  "public/private key was available" ) );
@@ -9,33 +9,15 @@
 -				  "Server reported: Invalid public-key authentication" ) );
 +		return CRYPT_ENVELOPE_RESOURCE;
 		}
---- session/sess_attr.c.orig	2023-12-29 10:12:33.284671000 -0500
-+++ session/sess_attr.c	2023-12-29 11:34:14.207575000 -0500
-@@ -292,6 +292,7 @@
- 		   of, and leads to exceptions to exceptions, so we keep it simple 
- 		   and only allow passwords to be added if there's an immediately 
- 		   preceding username */
-+#if 0
- 		if( cryptStatusError( status ) )
- 			{
- 			return( exitErrorNotInited( sessionInfoPtr, 
-@@ -305,6 +301,7 @@
- 			return( exitErrorNotInited( sessionInfoPtr, 
- 										CRYPT_SESSINFO_USERNAME ) );
- 			}
-+#endif
- 		}
- 
- 	/* If it could be an encoded PKI value, check its validity */
 --- kernel/attr_acl.c.orig	2023-12-29 11:53:27.990291000 -0500
 +++ kernel/attr_acl.c	2023-12-29 11:54:01.468829000 -0500
 @@ -3655,7 +3655,7 @@
  		subACL_SessinfoKeyset ),
- 	MKACL_EX(	/* Session authorisation OK */
- 		CRYPT_SESSINFO_AUTHRESPONSE, ATTRIBUTE_VALUE_NUMERIC,
--		ST_NONE, ST_NONE, ST_SESS_SSL | ST_SESS_SSL_SVR | ST_SESS_SSH_SVR, 
-+		ST_NONE, ST_NONE, ST_SESS_SSL | ST_SESS_SSL_SVR | ST_SESS_SSH | ST_SESS_SSH_SVR, 
- 		MKPERM_SESSIONS( RWx_RWx ), 0,
+ 	MKACL_SL(	/* Session authorisation OK */
+ 		CRYPT_SESSINFO_AUTHRESPONSE, 
+-		ST_NONE, ST_NONE, ST_SESS_TLS | ST_SESS_TLS_SVR | ST_SESS_SSH_SVR, 
++		ST_NONE, ST_NONE, ST_SESS_TLS | ST_SESS_TLS_SVR | ST_SESS_SSH | ST_SESS_SSH_SVR, 
+ 		MKPERM_SESSIONS( RWx_RWx ), 
  		ROUTE( OBJECT_TYPE_SESSION ),
  		RANGE_ALLOWEDVALUES, allowedAuthResponses ),
 --- session/ssh.c.orig	2023-12-29 12:02:24.938661000 -0500
@@ -47,7 +29,7 @@
 +	/* If we're completing a handshake that was interrupted while we got
 +	   confirmation of the client auth, skip the initial handshake stages
 +	   and go straight to the handshake completion stage */
-+	if( TEST_FLAG( sessionInfoPtr->flags, SESSION_FLAG_PARTIALOPEN ) )
++	if( (!isServer(sessionInfoPtr)) && TEST_FLAG( sessionInfoPtr->flags, SESSION_FLAG_PARTIALOPEN ) )
 +		{
 +		SSH_HANDSHAKE_INFO handshakeInfo;
 +
@@ -59,24 +41,53 @@
  	shutdownFunction = ( SES_SHUTDOWN_FUNCTION ) \
  					   FNPTR_GET( sessionInfoPtr->shutdownFunction );
  	REQUIRES( shutdownFunction != NULL );
---- session/ssh2_cli.c.orig	2018-12-21 04:12:46.000000000 -0500
-+++ session/ssh2_cli.c	2023-12-29 12:33:18.988457000 -0500
-@@ -963,230 +963,238 @@
+--- ./session/sess_attr.c.orig	2023-12-31 09:02:53.666275000 -0500
++++ ./session/sess_attr.c	2023-12-31 09:06:17.870218000 -0500
+@@ -442,6 +442,7 @@
+ 			   back out of, and leads to exceptions to exceptions, so we 
+ 			   keep it simple and only allow passwords to be added if 
+ 			   there's an immediately preceding username */
++#if 0
+ 			if( cryptStatusError( status ) )
+ 				{
+ 				return( exitErrorNotInited( sessionInfoPtr, 
+@@ -455,6 +456,7 @@
+ 				return( exitErrorNotInited( sessionInfoPtr, 
+ 											CRYPT_SESSINFO_USERNAME ) );
+ 				}
++#endif
  
+ 			break;
+ 
+--- ./session/ssh2_cli.c.orig	2023-02-25 00:51:44.000000000 -0500
++++ ./session/ssh2_cli.c	2023-12-31 09:10:49.225311000 -0500
+@@ -985,232 +985,239 @@
  	REQUIRES( sanityCheckSessionSSH( sessionInfoPtr ) );
+ 	REQUIRES( sanityCheckSSHHandshakeInfo( handshakeInfo ) );
  
 -	/* Set up the security information required for the session */
 -	status = initSecurityInfo( sessionInfoPtr, handshakeInfo );
 -	if( cryptStatusError( status ) )
 -		return( status );
 -	CFI_CHECK_UPDATE( "initSecurityInfo" );
--
++	if( !TEST_FLAG( sessionInfoPtr->flags, SESSION_FLAG_PARTIALOPEN ) )
++		{
++		/* Set up the security information required for the session */
++		status = initSecurityInfo( sessionInfoPtr, handshakeInfo );
++		if( cryptStatusError( status ) )
++			return( status );
++		CFI_CHECK_UPDATE( "initSecurityInfo" );
+ 
 -	/* Build our change cipherspec message and request authentication with
 -	   the server:
--
++		/* Build our change cipherspec message and request authentication with
++		   the server:
+ 
 -		byte	type = SSH_MSG_NEWKEYS
 -		...
--
++			byte	type = SSH_MSG_NEWKEYS
++			...
+ 
 -	   After this point the write channel is in the secure state, so we 
 -	   switch from wrapPlaintextPacketSSH2() to wrapPacketSSH2() */
 -	status = openPacketStreamSSH( &stream, sessionInfoPtr, SSH_MSG_NEWKEYS );
@@ -84,41 +95,82 @@
 -		return( status );
 -	status = wrapPlaintextPacketSSH2( sessionInfoPtr, &stream, 0 );
 -	if( cryptStatusError( status ) )
-+	if( !TEST_FLAG( sessionInfoPtr->flags, SESSION_FLAG_PARTIALOPEN ) )
- 		{
+-		{
 -		sMemDisconnect( &stream );
 -		return( status );
 -		}
 -	SET_FLAG( sessionInfoPtr->flags, SESSION_FLAG_ISSECURE_WRITE );
 -	CFI_CHECK_UPDATE( "SSH_MSG_NEWKEYS" );
-+		/* Set up the security information required for the session */
-+		status = initSecurityInfo( sessionInfoPtr, handshakeInfo );
++		   After this point the write channel is in the secure state, so we 
++		   switch from wrapPlaintextPacketSSH2() to wrapPacketSSH2() */
++		status = openPacketStreamSSH( &stream, sessionInfoPtr, SSH_MSG_NEWKEYS );
 +		if( cryptStatusError( status ) )
 +			return( status );
-+		CFI_CHECK_UPDATE( "initSecurityInfo" );
++		status = wrapPlaintextPacketSSH2( sessionInfoPtr, &stream, 0 );
++		if( cryptStatusError( status ) )
++			{
++			sMemDisconnect( &stream );
++			return( status );
++			}
++		SET_FLAG( sessionInfoPtr->flags, SESSION_FLAG_ISSECURE_WRITE );
++		CFI_CHECK_UPDATE( "SSH_MSG_NEWKEYS" );
  
 -#if 0
 -	/*   byte       SSH_MSG_EXT_INFO
 -	     uint32     nr-extensions
 -	       string   extension-name
 -	       string   extension-value (binary) */
--	status = continuePacketStreamSSH( &stream, SSH_MSG_EXT_INFO, 
--									  &packetOffset );
--	if( cryptStatusOK( status ) )
--		{
--		writeUint32( &stream, 1 );
--		writeString32( &stream, "global-requests-ok", 18 );
--		status = writeUint32( &stream, 0 );
--		}
--	if( cryptStatusOK( status ) )
+-	if( !TEST_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_NOEXTINFO ) )
 -		{
--		status = wrapPacketSSH2( sessionInfoPtr, &stream, packetOffset, 
--								 FALSE );
+-		status = continuePacketStreamSSH( &stream, SSH_MSG_EXT_INFO, 
+-										  &packetOffset );
+-		if( cryptStatusOK( status ) )
++#if 0
++		/*   byte       SSH_MSG_EXT_INFO
++		     uint32     nr-extensions
++		       string   extension-name
++		       string   extension-value (binary) */
++		if( !TEST_FLAG( sessionInfoPtr->protocolFlags, SSH_PFLAG_NOEXTINFO ) )
+ 			{
+-			writeUint32( &stream, 1 );
+-			writeString32( &stream, "global-requests-ok", 18 );
+-			status = writeUint32( &stream, 0 );
++			status = continuePacketStreamSSH( &stream, SSH_MSG_EXT_INFO, 
++											  &packetOffset );
++			if( cryptStatusOK( status ) )
++				{
++				writeUint32( &stream, 1 );
++				writeString32( &stream, "global-requests-ok", 18 );
++				status = writeUint32( &stream, 0 );
++				}
++			if( cryptStatusOK( status ) )
++				{
++				status = wrapPacketSSH2( sessionInfoPtr, &stream, packetOffset, 
++										 FALSE );
++				}
+ 			}
++#endif /* Test handling of trigger for global request after authentication */ 
++
++		/*	...
++			byte	type = SSH_MSG_SERVICE_REQUEST
++			string	service_name = "ssh-userauth".
++			
++		   For some reason SSH requires the use of two authentication messages, 
++		   an "I'm about to authenticate" packet and an "I'm authenticating" 
++		   packet, so we have to perform the authentication in two parts (dum 
++		   loquimur, fugerit invida aetas) */
++		status = continuePacketStreamSSH( &stream, SSH_MSG_SERVICE_REQUEST,
++										  &packetOffset );
+ 		if( cryptStatusOK( status ) )
++			status = writeString32( &stream, "ssh-userauth", 12 );
++		if( cryptStatusOK( status ) )
+ 			{
+ 			status = wrapPacketSSH2( sessionInfoPtr, &stream, packetOffset, 
+ 									 FALSE );
+ 			}
 -		}
 -#endif /* Test handling of trigger for global request after authentication */ 
-+		/* Build our change cipherspec message and request authentication with
-+		   the server:
- 
+-
 -	/*	...
 -		byte	type = SSH_MSG_SERVICE_REQUEST
 -		string	service_name = "ssh-userauth".
@@ -142,15 +194,13 @@
 -		return( status );
 -		}
 -	CFI_CHECK_UPDATE( "SSH_MSG_SERVICE_REQUEST" );
-+			byte	type = SSH_MSG_NEWKEYS
-+			...
- 
+-
 -	/* Send the whole mess to the server.  This is yet another place where 
--	   the SSH spec's vagueness over message ordering causes problems.  SSL 
+-	   the SSH spec's vagueness over message ordering causes problems.  TLS 
 -	   at this point uses a Finished message in which the client and server 
 -	   do a mutual proof-of-possession of encryption and MAC keys via a 
 -	   pipeline-stalling message that prevents any further (sensitive) data 
--	   from being exchanged until the PoP has concluded (the SSL Finished 
+-	   from being exchanged until the PoP has concluded (the TLS Finished 
 -	   also authenticates the handshake messages) but SSH doesn't have any
 -	   such requirements.  The signed exchange hash from the server proves 
 -	   to the client that the server knows the master secret but not 
@@ -196,7 +246,7 @@
 -	   authentication" to be "Something completely different from what we're 
 -	   doing here" which means that we could send the two packets together 
 -	   without having to wait for the server, but it's probably better to 
--	   use SSL-tyle Finished semantics at this point even if it adds an 
+-	   use TLS-tyle Finished semantics at this point even if it adds an 
 -	   extra RTT delay */
 -	status = sendPacketSSH2( sessionInfoPtr, &stream );
 -	sMemDisconnect( &stream );
@@ -222,13 +272,7 @@
 -		   packet without looking at the contents */
 -		status = readHSPacketSSH2( sessionInfoPtr, SSH_MSG_SERVICE_ACCEPT, 
 -								   ID_SIZE );
-+		   After this point the write channel is in the secure state, so we 
-+		   switch from wrapPlaintextPacketSSH2() to wrapPacketSSH2() */
-+		status = openPacketStreamSSH( &stream, sessionInfoPtr, SSH_MSG_NEWKEYS );
  		if( cryptStatusError( status ) )
-+			return( status );
-+		status = wrapPlaintextPacketSSH2( sessionInfoPtr, &stream, 0 );
-+		if( cryptStatusError( status ) )
  			{
 -			/* This is the first message after the change cipherspec, a 
 -			   basic packet format error is more likely to be due to an 
@@ -238,7 +282,7 @@
 -						 SESSION_ERRINFO, 
 -						 "Invalid packet data for SSH_MSG_SERVICE_ACCEPT, "
 -						 "probably due to incorrect encryption keys being "
--						 "negotiated during the handshake:" ) );
+-						 "negotiated during the handshake" ) );
 +			sMemDisconnect( &stream );
 +			return( status );
  			}
@@ -246,85 +290,21 @@
 -	else
 -		{
 -		int length;
-+		SET_FLAG( sessionInfoPtr->flags, SESSION_FLAG_ISSECURE_WRITE );
-+		CFI_CHECK_UPDATE( "SSH_MSG_NEWKEYS" );
++		CFI_CHECK_UPDATE( "SSH_MSG_SERVICE_REQUEST" );
  
 -		/* Check the service-accept packet:
-+	#if 0
-+		/*   byte       SSH_MSG_EXT_INFO
-+		     uint32     nr-extensions
-+		       string   extension-name
-+		       string   extension-value (binary) */
-+		status = continuePacketStreamSSH( &stream, SSH_MSG_EXT_INFO, 
-+										  &packetOffset );
-+		if( cryptStatusOK( status ) )
-+			{
-+			writeUint32( &stream, 1 );
-+			writeString32( &stream, "global-requests-ok", 18 );
-+			status = writeUint32( &stream, 0 );
-+			}
-+		if( cryptStatusOK( status ) )
-+			{
-+			status = wrapPacketSSH2( sessionInfoPtr, &stream, packetOffset, 
-+									 FALSE );
-+			}
-+	#endif /* Test handling of trigger for global request after authentication */ 
- 
+-
 -			byte	type = SSH_MSG_SERVICE_ACCEPT
-+		/*	...
-+			byte	type = SSH_MSG_SERVICE_REQUEST
- 			string	service_name = "ssh-userauth".
- 			
+-			string	service_name = "ssh-userauth".
+-			
 -		   This may also be an extension info packet if the server is using 
 -		   extensions: 
--		   
--			byte		type = SSH_MSG_EXT_INFO
--			uint32		no_extensions
--				string	name
--				string	value (binary data) */
--		status = length = \
--			readHSPacketSSH2( sessionInfoPtr, SSH_MSG_SPECIAL_SERVICEACCEPT,
--							  ID_SIZE + UINT32_SIZE );
--		if( cryptStatusError( status ) )
-+		   For some reason SSH requires the use of two authentication messages, 
-+		   an "I'm about to authenticate" packet and an "I'm authenticating" 
-+		   packet, so we have to perform the authentication in two parts (dum 
-+		   loquimur, fugerit invida aetas) */
-+		status = continuePacketStreamSSH( &stream, SSH_MSG_SERVICE_REQUEST,
-+										  &packetOffset );
-+		if( cryptStatusOK( status ) )
-+			status = writeString32( &stream, "ssh-userauth", 12 );
-+		if( cryptStatusOK( status ) )
- 			{
--			/* This is the first message after the change cipherspec, a 
--			   basic packet format error is more likely to be due to an 
--			   incorrect key than an actual format error */
--			retExtErr( CRYPT_ERROR_WRONGKEY,
--					   ( CRYPT_ERROR_WRONGKEY, SESSION_ERRINFO, 
--						 SESSION_ERRINFO, 
--						 "Invalid packet data for SSH_MSG_SERVICE_ACCEPT, "
--						 "probably due to incorrect encryption keys being "
--						 "negotiated during the handshake:" ) );
-+			status = wrapPacketSSH2( sessionInfoPtr, &stream, packetOffset, 
-+									 FALSE );
- 			}
--		if( sessionInfoPtr->sessionSSH->packetType == SSH_MSG_EXT_INFO )
-+		if( cryptStatusError( status ) )
- 			{
--			/* The server sent extension information, process it */
--			sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
--			status = readExtensionsSSH( sessionInfoPtr, &stream );
- 			sMemDisconnect( &stream );
-+			return( status );
-+			}
-+		CFI_CHECK_UPDATE( "SSH_MSG_SERVICE_REQUEST" );
-+
 +		/* Send the whole mess to the server.  This is yet another place where 
-+		   the SSH spec's vagueness over message ordering causes problems.  SSL 
++		   the SSH spec's vagueness over message ordering causes problems.  TLS 
 +		   at this point uses a Finished message in which the client and server 
 +		   do a mutual proof-of-possession of encryption and MAC keys via a 
 +		   pipeline-stalling message that prevents any further (sensitive) data 
-+		   from being exchanged until the PoP has concluded (the SSL Finished 
++		   from being exchanged until the PoP has concluded (the TLS Finished 
 +		   also authenticates the handshake messages) but SSH doesn't have any
 +		   such requirements.  The signed exchange hash from the server proves 
 +		   to the client that the server knows the master secret but not 
@@ -335,7 +315,14 @@
 +		   PoP isn't a design goal of the SSH handshake we do it anyway (as far 
 +		   as we can without a proper Finished message), although this 
 +		   introduces a pipeline stall at this point.
-+		   
+ 		   
+-			byte		type = SSH_MSG_EXT_INFO
+-			uint32		no_extensions
+-				string	name
+-				string	value (binary data) */
+-		status = length = \
+-			readHSPacketSSH2( sessionInfoPtr, SSH_MSG_SPECIAL_SERVICEACCEPT,
+-							  ID_SIZE + UINT32_SIZE );
 +		   In addition because of the aforementioned ambiguity over message 
 +		   ordering we have to send our change cipherspec first because some 
 +		   implementations will stop and wait before they send their one, so if 
@@ -370,11 +357,11 @@
 +		   authentication" to be "Something completely different from what we're 
 +		   doing here" which means that we could send the two packets together 
 +		   without having to wait for the server, but it's probably better to 
-+		   use SSL-tyle Finished semantics at this point even if it adds an 
++		   use TLS-tyle Finished semantics at this point even if it adds an 
 +		   extra RTT delay */
 +		status = sendPacketSSH2( sessionInfoPtr, &stream );
 +		sMemDisconnect( &stream );
-+		if( cryptStatusError( status ) )
+ 		if( cryptStatusError( status ) )
 +			return( status );
 +
 +		/* Wait for the server's change cipherspec message.  From this point
@@ -391,13 +378,21 @@
 +		   check the contents if it's a correctly-formatted packet */
 +		if( TEST_FLAG( sessionInfoPtr->protocolFlags, 
 +					   SSH_PFLAG_EMPTYSVCACCEPT ) )
-+			{
+ 			{
+-			/* This is the first message after the change cipherspec, a 
+-			   basic packet format error is more likely to be due to an 
+-			   incorrect key than an actual format error */
+-			retExtErr( CRYPT_ERROR_WRONGKEY,
+-					   ( CRYPT_ERROR_WRONGKEY, SESSION_ERRINFO, 
+-						 SESSION_ERRINFO, 
+-						 "Invalid packet data for SSH_MSG_SERVICE_ACCEPT, "
+-						 "probably due to incorrect encryption keys being "
+-						 "negotiated during the handshake" ) );
 +			/* It's a buggy implementation, just check for the presence of a 
 +			   packet without looking at the contents */
 +			status = readHSPacketSSH2( sessionInfoPtr, SSH_MSG_SERVICE_ACCEPT, 
 +									   ID_SIZE );
- 			if( cryptStatusError( status ) )
--				return( status );
++			if( cryptStatusError( status ) )
 +				{
 +				/* This is the first message after the change cipherspec, a 
 +				   basic packet format error is more likely to be due to an 
@@ -407,11 +402,18 @@
 +							 SESSION_ERRINFO, 
 +							 "Invalid packet data for SSH_MSG_SERVICE_ACCEPT, "
 +							 "probably due to incorrect encryption keys being "
-+							 "negotiated during the handshake:" ) );
++							 "negotiated during the handshake" ) );
 +				}
-+			}
+ 			}
+-		if( sessionInfoPtr->sessionSSH->packetType == SSH_MSG_EXT_INFO )
 +		else
-+			{
+ 			{
+-			/* The server sent extension information, process it */
+-			sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
+-			status = readExtensionsSSH( sessionInfoPtr, &stream );
+-			sMemDisconnect( &stream );
+-			if( cryptStatusError( status ) )
+-				return( status );
 +			int length;
  
 -			/* Retry the service-accept read */
@@ -443,7 +445,7 @@
 +							 SESSION_ERRINFO, 
 +							 "Invalid packet data for SSH_MSG_SERVICE_ACCEPT, "
 +							 "probably due to incorrect encryption keys being "
-+							 "negotiated during the handshake:" ) );
++							 "negotiated during the handshake" ) );
 +				}
 +			if( sessionInfoPtr->sessionSSH->packetType == SSH_MSG_EXT_INFO )
 +				{
@@ -493,26 +495,23 @@
 -		}
 -	CFI_CHECK_UPDATE( "serviceAccept" );
 +		CFI_CHECK_UPDATE( "serviceAccept" );
- 
 +		REQUIRES( CFI_CHECK_SEQUENCE_5( "initSecurityInfo", "SSH_MSG_NEWKEYS",
-+										"SSH_MSG_SERVICE_REQUEST", 
++										"SSH_MSG_SERVICE_REQUEST",
 +										"readHSPacketSSH2", "serviceAccept") );
 +		CFI_CHECK_VALUE = CFI_CHECK_INIT;
 +	}
-+
+ 
  	/* Try and authenticate ourselves to the server */
  	status = processClientAuth( sessionInfoPtr, handshakeInfo );
- 	if( cryptStatusError( status ) )
-@@ -1210,11 +1218,7 @@
+@@ -1235,10 +1242,7 @@
  		return( status );
  	CFI_CHECK_UPDATE( "sendChannelOpen" );
  
--	REQUIRES( CFI_CHECK_SEQUENCE_7( "initSecurityInfo", "SSH_MSG_NEWKEYS",
--									"SSH_MSG_SERVICE_REQUEST", 
--									"readHSPacketSSH2", "serviceAccept",
--									"processClientAuth", 
--									"sendChannelOpen" ) );
-+	REQUIRES( CFI_CHECK_SEQUENCE_2(  "processClientAuth", "sendChannelOpen" ) );
+-	ENSURES( CFI_CHECK_SEQUENCE_7( "initSecurityInfo", "SSH_MSG_NEWKEYS",
+-								   "SSH_MSG_SERVICE_REQUEST", 
+-								   "readHSPacketSSH2", "serviceAccept",
+-								   "processClientAuth", 
++	ENSURES( CFI_CHECK_SEQUENCE_2( "processClientAuth", 
+ 								   "sendChannelOpen" ) );
  	return( CRYPT_OK );
  #else	/* Test handling of OpenSSH "no-more-sessions@openssh.com" */
- 	status = sendChannelOpen( sessionInfoPtr );
diff --git a/3rdp/build/cl-bn_div.patch b/3rdp/build/cl-bn_div.patch
deleted file mode 100644
index dca72bceae6d1fa49e901706d8a35df47a3419bb..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-bn_div.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- bn/bn_div.c.orig	2019-01-21 13:35:22.583819000 -0500
-+++ bn/bn_div.c	2019-01-21 13:35:27.565846000 -0500
-@@ -112,7 +112,7 @@
- /* End changes for cryptlib - pcg */
- 
- /* The old slow way */
--#if 0
-+#if 1
- int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
-            BN_CTX *ctx)
- {
diff --git a/3rdp/build/cl-bn_div2.patch b/3rdp/build/cl-bn_div2.patch
deleted file mode 100644
index d888e117994ba183be9dfa6c6e38ea00b13da817..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-bn_div2.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- bn/bn_div.c.orig	2017-03-23 01:27:30.000000000 -0400
-+++ bn/bn_div.c	2019-01-21 17:23:06.478306000 -0500
-@@ -229,6 +229,9 @@
- #  endif                        /* __GNUC__ */
- # endif                         /* OPENSSL_NO_ASM */
- 
-+#undef REMAINDER_IS_ALREADY_CALCULATED
-+#undef bn_div_words
-+
- /*-
-  * BN_div computes  dv := num / divisor,  rounding towards
-  * zero, and sets up rm  such that  dv*divisor + rm = num  holds.
diff --git a/3rdp/build/cl-check-before-use.patch b/3rdp/build/cl-check-before-use.patch
deleted file mode 100644
index 56843b7f3040716c33af9def6eb6132a8d25b7cc..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-check-before-use.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff -ur ../cl-old/random/unix.c ./random/unix.c
---- ../cl-old/random/unix.c	2021-03-29 22:36:37.000000000 -0700
-+++ ./random/unix.c	2021-03-29 22:38:03.000000000 -0700
-@@ -505,7 +505,9 @@
- 									   amount of output so typically gets
- 									   truncated at SYSCTL_BUFFER_SIZE */
- #endif /* KERN_PROC2 */
-+#ifdef GPROF_COUNT
- 	{ 3, { CTL_KERN, KERN_PROF, GPROF_COUNT }, 10 },
-+#endif
- 									/* If kernel is compiled for profiling, 
- 									   an array of statistical program 
- 									   counter counts.  This typically isn't
diff --git a/3rdp/build/cl-check-cert-dont-modify.patch b/3rdp/build/cl-check-cert-dont-modify.patch
deleted file mode 100644
index 1a41e3ad1cfb240dfa8045adce2bc4d73c082740..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-check-cert-dont-modify.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-This patch doesn't solve the issue.
---- session/session.c.orig	2023-12-19 14:27:12.836848000 -0500
-+++ session/session.c	2023-12-19 14:29:00.324330000 -0500
-@@ -280,14 +280,19 @@
- 	/* Check whether the certificate is valid at a standard level of 
- 	   compliance, which catches expired certificates and other obvious
- 	   problems */
-+	// Don't mess with the cert!  If the compliance level is crap, do crap checks.
-+#if 0
- 	krnlSendMessage( iServerKey, IMESSAGE_SETATTRIBUTE, 
- 					 ( MESSAGE_CAST ) &complianceLevelStandard, 
- 					 CRYPT_OPTION_CERT_COMPLIANCELEVEL );
-+#endif
- 	status = krnlSendMessage( iServerKey, IMESSAGE_CHECK, NULL, 
- 							  MESSAGE_CHECK_CERT );
-+#if 0
- 	krnlSendMessage( iServerKey, IMESSAGE_SETATTRIBUTE, 
- 					 ( MESSAGE_CAST ) &complianceLevel, 
- 					 CRYPT_OPTION_CERT_COMPLIANCELEVEL );
-+#endif
- 	if( cryptStatusOK( status ) )
- 		return( CRYPT_OK );
- 
diff --git a/3rdp/build/cl-clear-GCM-flag.patch b/3rdp/build/cl-clear-GCM-flag.patch
index 23f3a79ddef17ec05b19eb125997d648d1a1b2df..f9725b7a99806e2d283f6b3ac96411782ed5409c 100644
--- a/3rdp/build/cl-clear-GCM-flag.patch
+++ b/3rdp/build/cl-clear-GCM-flag.patch
@@ -1,10 +1,10 @@
---- ./session/ssl_hs.c.orig	2020-01-24 18:02:09.710811000 -0500
-+++ ./session/ssl_hs.c	2020-01-24 18:02:24.220573000 -0500
+--- ./session/tls_hello.c.orig	2020-01-24 18:02:09.710811000 -0500
++++ ./session/tls_hello.c	2020-01-24 18:02:24.220573000 -0500
 @@ -223,6 +223,7 @@
  		if( cryptStatusError( status ) )
  			return( status );
  		sessionInfoPtr->cryptBlocksize = queryInfo.blockSize;
-+		CLEAR_FLAG( sessionInfoPtr->protocolFlags, SSL_PFLAG_GCM );
++		CLEAR_FLAG( sessionInfoPtr->protocolFlags, TLS_PFLAG_GCM );
  		}
  
  	return( CRYPT_OK );
diff --git a/3rdp/build/cl-cryptodev.patch b/3rdp/build/cl-cryptodev.patch
deleted file mode 100644
index ed489d04ee9bf952eadfeac3e9215fb6f0d87ead..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-cryptodev.patch
+++ /dev/null
@@ -1,23 +0,0 @@
---- ../tmp2/tools/ccopts.sh	2019-03-04 16:32:32.000000000 -0500
-+++ tools/ccopts.sh	2019-06-03 16:22:10.631518000 -0400
-@@ -250,13 +250,13 @@
- 	done
- 
- 	# /dev/crypto support
--	for includepath in $DEVCRYPTOPATHS ; do
--		if [ -f $includepath ] ; then
--			echo "/dev/crypto interface detected, enabling crypto hardware support." >&2 ;
--			CCARGS="$CCARGS -DHAS_DEVCRYPTO -I"$(dirname $includepath)"" ;
--			break ;
--		fi
--	done
-+	#for includepath in $DEVCRYPTOPATHS ; do
-+	#	if [ -f $includepath ] ; then
-+	#		echo "/dev/crypto interface detected, enabling crypto hardware support." >&2 ;
-+	#		CCARGS="$CCARGS -DHAS_DEVCRYPTO -I"$(dirname $includepath)"" ;
-+	#		break ;
-+	#	fi
-+	#done
- 
- fi
- if [ -f /usr/include/zlib.h ] ; then
diff --git a/3rdp/build/cl-do-debug.patch b/3rdp/build/cl-do-debug.patch
index 94c45e591b9a69c275ea581409e42cad706b6026..cd013cad685663982cb763571808e8bdb5b049cc 100644
--- a/3rdp/build/cl-do-debug.patch
+++ b/3rdp/build/cl-do-debug.patch
@@ -1,16 +1,45 @@
-Enables debug and adds a BN check
---- makefile.orig	2023-12-19 16:23:32.026350000 -0500
-+++ makefile	2023-12-19 16:24:02.637389000 -0500
-@@ -90,7 +90,7 @@
- # Further cc flags are gathered dynamically at runtime via the ccopts.sh
- # script.
+--- ./bn/bn.h.orig	2023-12-19 17:54:36.449797000 -0500
++++ ./bn/bn.h	2023-12-19 17:54:46.729612000 -0500
+@@ -13,6 +13,7 @@
+ #else
+   #include "crypt/osconfig.h"
+ #endif /* Compiler-specific includes */
++#include "kernel/thread.h"
+ 
+ /****************************************************************************
+ *																*
+@@ -373,6 +373,7 @@
+ 	   explanation in ctx_bn.c for what this is used for */
+ 	int stack[ BN_CTX_ARRAY_SIZE ];
+ 	int stackPos;
++	THREAD_HANDLE owner;
+ 	} BN_CTX;
+ 
+ /****************************************************************************
+--- context/ctx_bn.c.orig	2019-01-23 22:07:38.000000000 -0500
++++ context/ctx_bn.c	2023-12-19 19:41:45.734499000 -0500
+@@ -655,6 +655,8 @@
+ void BN_CTX_start( INOUT BN_CTX *bnCTX )
+ 	{
+ 	assert( isWritePtr( bnCTX, sizeof( BN_CTX ) ) );
++	assert( bnCTX->stackPos == 0 || bnCTX->owner == THREAD_SELF() );
++	bnCTX->owner = THREAD_SELF();
+ 
+ 	REQUIRES_V( sanityCheckBNCTX( bnCTX ) );
+ 
+ /* Instead of the DIY recursive mutexes above it's also possible to use OS
+--- makefile.orig	2024-01-01 13:49:02.463808000 -0500
++++ makefile	2024-01-01 13:50:55.631910000 -0500
+@@ -94,7 +94,7 @@
+ 
+ DEBUG_FLAGS		= -ggdb3 -fno-omit-frame-pointer -Og
  
 -CFLAGS			= -c -D__UNIX__ -DNDEBUG -I.
 +CFLAGS			= -c -D__UNIX__ -g -I.
- CFLAGS_DEBUG	= -c -D__UNIX__ -I. -g -O1
- CFLAGS_DEBUGGCC	= -c -D__UNIX__ -I. -ggdb3 -fno-omit-frame-pointer -O1
- CFLAGS_ANALYSE	= -c -D__UNIX__ -I.
-@@ -144,12 +144,12 @@
+ CFLAGS_DEBUG	= -c -D__UNIX__ -I. -g -Og
+ CFLAGS_DEBUGGCC	= -c -D__UNIX__ -I. $(DEBUG_FLAGS)
+ 
+@@ -160,12 +160,12 @@
  # removed.  The actual values are explicitly given in the rules for each non-
  # Unix target.
  
@@ -25,7 +54,7 @@ Enables debug and adds a BN check
  XSCFLAGS_DEBUG	= -c -I. -g -O0
  XSDEFINES		= $(SLIBNAME) OBJPATH=$(SHARED_OBJ_PATH) CROSSCOMPILE=1
  XSLDFLAGS		= CROSSCOMPILE=1
-@@ -1934,10 +1934,10 @@
+@@ -2104,10 +2104,10 @@
  #
  # make LDFLAGS='-isysroot /Developer/SDKs/MacOSX10.5.sdk' CFLAGS='-c -isysroot \
  # /Developer/SDKs/MacOSX10.5.sdk -Os -mmacosx-version-min=10.5 -arch ppc -arch \
@@ -38,7 +67,7 @@ Enables debug and adds a BN check
  #
  #			This will also require adding $(LDFLAGS) to the dylib build rule.
  #
-@@ -2362,7 +2362,7 @@
+@@ -2546,7 +2546,7 @@
  		CFLAGS="$(XCFLAGS) -DCONFIG_DATA_LITTLEENDIAN -O2 -D__Android__ \
  		-D_REENTRANT -MMD -MP -MF -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ \
  		-D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -march=armv7-a -mtune=xscale \
@@ -47,7 +76,7 @@ Enables debug and adds a BN check
  		-fno-strict-aliasing -finline-limit=64 \
  		-I$(ANDROID_8D_INCLUDE_SOURCES_PATH)/include \
  		-I$(ANDROID_8D_INCLUDE_SOURCES_PATH)/libs/armeabi-v7a/include \
-@@ -2382,7 +2382,7 @@
+@@ -2566,7 +2566,7 @@
  		CFLAGS="$(XSCFLAGS) -DCONFIG_DATA_LITTLEENDIAN -O2 -D__Android__ \
  		-D_REENTRANT -MMD -MP -MF -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ \
  		-D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -march=armv7-a -mtune=xscale \
@@ -56,7 +85,7 @@ Enables debug and adds a BN check
  		-fno-strict-aliasing -finline-limit=64 \
  		-I$(ANDROID_9_INCLUDE_PATH)/include \
  		-I$(ANDROID_9_INCLUDE_PATH)/libs/armeabi-v7a/include \
-@@ -2396,7 +2396,7 @@
+@@ -2580,7 +2580,7 @@
  		CFLAGS="$(XSCFLAGS) -DCONFIG_DATA_LITTLEENDIAN -O2 -D__Android__ \
  		-D_REENTRANT -MMD -MP -MF -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ \
  		-D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -march=armv7-a -mtune=xscale \
@@ -65,7 +94,7 @@ Enables debug and adds a BN check
  		-fno-strict-aliasing -finline-limit=64 \
  		-I$(ANDROID_9_INCLUDE_PATH)/include \
  		-I$(ANDROID_9_INCLUDE_PATH)/libs/armeabi-v7a/include \
-@@ -2426,7 +2426,7 @@
+@@ -2611,7 +2611,7 @@
  
  # eCOS: Gnu toolchain under Unix.  For a standard install you also need
  # to change the XCFLAGS define at the start of this makefile to
@@ -74,7 +103,7 @@ Enables debug and adds a BN check
  
  target-ecos-arm:
  	@$(MAKE) OSNAME=ecos target-init
-@@ -2979,7 +2979,7 @@
+@@ -3217,7 +3217,7 @@
  							  -mno-implicit-fp -DPPC32_fp60x -DCPU=PPC32
  VXWORKS_GCC_PPC_1_DEFS	= $(VXWORKS_GCC_ARCH_DEFS) -DRW_MULTI_THREAD \
  						  -D_REENTRANT=1 -D_POSIX_THREADS -D__VXWORKS_6_2__ \
@@ -83,7 +112,7 @@ Enables debug and adds a BN check
  						  -DTOOL=gnu -D_WRS_KERNEL -DWITH_NONAMESPACES \
  						  -DRW_MULTI_THREAD -DCONFIG_RANDSEED
  VXWORKS_GCC_PATH	= $(WIND_BASE)/target/h
-@@ -3002,7 +3002,7 @@
+@@ -3240,7 +3240,7 @@
  						 -D_VX_CPU=_VX_PPC32 -D_WRS_VX_SMP -D_WRS_CONFIG_SMP \
  						 -DWITH_NONAMESPACES -DPPC32_fp60x -DTOOL_FAMILY=gnu \
  						 -DTOOL=gnu -DCPU_VARIANT=_ppc603_83xx -D__VXWORKS_6_9__ \
@@ -92,33 +121,21 @@ Enables debug and adds a BN check
  						 -D__powerpc__ -DCONFIG_DATA_BIGENDIAN
  
  target-vxworks-ppc-gnu-2:
---- ./bn/bn.h.orig	2023-12-19 17:54:36.449797000 -0500
-+++ ./bn/bn.h	2023-12-19 17:54:46.729612000 -0500
-@@ -13,6 +13,7 @@
- #else
-   #include "crypt/osconfig.h"
- #endif /* Compiler-specific includes */
-+#include "kernel/thread.h"
- 
- /****************************************************************************
- *																*
-@@ -373,6 +373,7 @@
- 	   explanation in ctx_bn.c for what this is used for */
- 	int stack[ BN_CTX_ARRAY_SIZE ];
- 	int stackPos;
-+	THREAD_HANDLE owner;
- 	} BN_CTX;
+--- session/ssh2_channel.c.orig	2024-01-14 18:46:10.151945000 -0500
++++ session/ssh2_channel.c	2024-01-14 18:52:42.636973000 -0500
+@@ -858,6 +858,7 @@
+ 		return( CRYPT_ERROR_NOTFOUND );
+ 	if( !isActiveChannel( channelInfoPtr ) && channelType != CHANNEL_NONE )
+ 		return( CRYPT_ERROR_NOTINITED );
++fprintf(stderr, "Select channel %d (%d) for %s\n", channelInfoPtr->channelID, channelNo, channelType == CHANNEL_READ ? "Read" : (channelType == CHANNEL_WRITE ? "Write" : (channelType == CHANNEL_BOTH ? "Both" : (channelType == CHANNEL_NONE ? "None" : "Unknown!"))));
+ 	switch( channelType )
+ 		{
+ 		case CHANNEL_READ:
+@@ -1066,6 +1067,7 @@
+ 								 channelInfoPtr->channelID ) ? \
+ 				CRYPT_OK : OK_SPECIAL );
+ 		}
++fprintf(stderr, "Deleting channel info %d (%d)\n", channelID, channelNo);
+ 	deleteSessionInfo( sessionInfoPtr, attributeListPtr );
  
- /****************************************************************************
---- context/ctx_bn.c.orig	2019-01-23 22:07:38.000000000 -0500
-+++ context/ctx_bn.c	2023-12-19 19:41:45.734499000 -0500
-@@ -655,6 +655,8 @@
- void BN_CTX_start( INOUT BN_CTX *bnCTX )
- 	{
- 	assert( isWritePtr( bnCTX, sizeof( BN_CTX ) ) );
-+	assert( bnCTX->stackPos == 0 || bnCTX->owner == THREAD_SELF() );
-+	bnCTX->owner = THREAD_SELF();
- 
- 	REQUIRES_V( sanityCheckBNCTX( bnCTX ) );
- 
- /* Instead of the DIY recursive mutexes above it's also possible to use OS
+ 	/* If we've deleted the current channel, select a null channel until a
diff --git a/3rdp/build/cl-endian.patch b/3rdp/build/cl-endian.patch
index 50d6dcec2e387b7848b8424eff7158e8efbc06d3..57d5e7ea49da5ba218e683df2afa87208972166e 100644
--- a/3rdp/build/cl-endian.patch
+++ b/3rdp/build/cl-endian.patch
@@ -1,12 +1,12 @@
---- ../tmp2/misc/os_detect.h	2019-01-31 14:57:46.000000000 -0500
-+++ misc/os_detect.h	2019-06-03 18:26:42.394038000 -0400
-@@ -566,6 +566,9 @@
- 	#include <machine/endian.h>
-   #elif defined( __NetBSD__ )
- 	#include <sys/endian.h>
-+  #elif defined( __FreeBSD__ )
-+	#include <sys/endian.h>
-+  #elif defined(__MINGW32__)
-   #else
- 	#include <endian.h>
-   #endif /* Apple vs. everyone else */
+--- misc/os_detect.h.orig	2023-12-31 10:15:40.782951000 -0500
++++ misc/os_detect.h	2023-12-31 10:16:40.940469000 -0500
+@@ -658,7 +658,9 @@
+ 	 __GNUC__ is defined but the gcc include files aren't present.  The
+ 	 above checks catch the most common cases, if there are other pretend-
+ 	 gcc's then they'll need to be special-cased before this one */
++#if !defined(__MINGW32__)
+   #include <endian.h>
++#endif
+ #endif /* System-specific endian.h includes */
+ 
+ #if defined( CONFIG_DATA_LITTLEENDIAN ) || defined( CONFIG_DATA_BIGENDIAN )
diff --git a/3rdp/build/cl-fix-ECC-RSA.patch b/3rdp/build/cl-fix-ECC-RSA.patch
deleted file mode 100644
index b6c72d612190a551cf567f9ca05450fafc8181e5..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-fix-ECC-RSA.patch
+++ /dev/null
@@ -1,70 +0,0 @@
---- session/ssl_hs.c.orig	2018-11-14 23:22:26.000000000 -0500
-+++ session/ssl_hs.c	2020-01-23 18:23:41.236235000 -0500
-@@ -240,6 +240,7 @@
- 	const CIPHERSUITE_INFO **cipherSuiteInfo;
- 	const BOOLEAN isServer = isServer( sessionInfoPtr ) ? TRUE : FALSE;
- 	BOOLEAN allowDH = algoAvailable( CRYPT_ALGO_DH ) ? TRUE : FALSE;
-+	BOOLEAN allowECCAuth = TRUE;
- 	BOOLEAN allowECC = ( algoAvailable( CRYPT_ALGO_ECDH ) && \
- 						 algoAvailable( CRYPT_ALGO_ECDSA ) ) ? TRUE : FALSE;
- 	BOOLEAN allowRSA = algoAvailable( CRYPT_ALGO_RSA ) ? TRUE : FALSE;
-@@ -268,7 +269,7 @@
- 			{
- 			/* There's no server private key present, we're limited to PSK
- 			   suites */
--			allowECC = allowRSA = FALSE;
-+			allowECC = allowRSA = allowECCAuth = FALSE;
- 			}
- 		else
- 			{
-@@ -278,7 +279,7 @@
- 			   capable */
- 			if( !checkContextCapability( sessionInfoPtr->privateKey,
- 										 MESSAGE_CHECK_PKC_SIGN ) )
--				allowDH = allowECC = FALSE;
-+				allowDH = allowECC = allowECCAuth = FALSE;
- 
- 			/* To be usable for ECC or RSA the server key has to itself be 
- 			   an ECC or RSA key */
-@@ -286,13 +287,16 @@
- 									  IMESSAGE_GETATTRIBUTE, &pkcAlgo,
- 									  CRYPT_CTXINFO_ALGO );
- 			if( cryptStatusError( status ) )
--				allowECC = allowRSA = FALSE;
-+				allowECC = allowRSA = allowECCAuth = FALSE;
- 			else
- 				{
- 				if( !isEccAlgo( pkcAlgo ) )
- 					allowECC = FALSE;
- 				if( pkcAlgo != CRYPT_ALGO_RSA )
-+					{
- 					allowRSA = FALSE;
-+					allowECCAuth = FALSE;
-+					}
- 				}
- 			}
- 		}
-@@ -443,8 +447,13 @@
- 			( cipherSuiteInfoPtr->flags & CIPHERSUITE_FLAG_DH ) )
- 			continue;
- 		if( !allowECC && \
--			( cipherSuiteInfoPtr->flags & CIPHERSUITE_FLAG_ECC ) )
-+			( cipherSuiteInfoPtr->flags & CIPHERSUITE_FLAG_ECC ) && \
-+			( cipherSuiteInfoPtr->authAlgo != CRYPT_ALGO_RSA) )
- 			continue;
-+		if( !allowECCAuth && \
-+			( cipherSuiteInfoPtr->flags & CIPHERSUITE_FLAG_ECC ) && \
-+			( cipherSuiteInfoPtr->authAlgo == CRYPT_ALGO_RSA) )
-+			continue;
- 		if( !allowTLS12 && \
- 			( cipherSuiteInfoPtr->flags & CIPHERSUITE_FLAG_TLS12 ) )
- 			continue;
-@@ -521,7 +530,7 @@
- 	   find out that we can use it */
- 	if( altSuiteIndex < cipherSuiteInfoSize )
- 		{
--		REQUIRES( allowECC );
-+		REQUIRES( allowECCAuth );
- 
- 		handshakeInfo->eccSuiteInfoPtr = cipherSuiteInfo[ altSuiteIndex ];
- 		}
diff --git a/3rdp/build/cl-fix-ssh-channel-close.patch b/3rdp/build/cl-fix-ssh-channel-close.patch
index a16af75cd848ccc5c0c1416fe113abc66e07d7b7..9ae4adc674cc6eaf3fc8410ed67b6eff96e8af9f 100644
--- a/3rdp/build/cl-fix-ssh-channel-close.patch
+++ b/3rdp/build/cl-fix-ssh-channel-close.patch
@@ -9,6 +9,15 @@
  				}
  			else
  				{
+@@ -527,6 +538,8 @@
+ 	   no more channels left to close */
+ 	status = deleteChannel( sessionInfoPtr, channelNo, channelType,
+ 							closeLastChannel  );
++	if( getChannelStatusByChannelNo( sessionInfoPtr, channelNo ) == CHANNEL_NONE )
++		return CRYPT_OK;
+ 	if( cryptStatusError( status ) )
+ 		{
+ 		if( status != OK_SPECIAL )
 --- cryptlib.h.orig	2023-12-29 15:55:17.717475000 -0500
 +++ cryptlib.h	2023-12-29 15:56:34.124863000 -0500
 @@ -1228,6 +1228,7 @@
@@ -28,54 +37,8 @@
  
  	/* Point at which private-use values start.  Attribute values sometimes
  	   need to be extended with additional pseudo-values in object-specific
---- ./kernel/attr_acl.c	2023-12-29 15:57:31.965603000 -0500
-+++ ./kernel/attr_acl.c.orig	2023-12-29 15:57:21.751654000 -0500
-@@ -3840,6 +3840,12 @@
- 		MKPERM_SSH_EXT( RWx_RWx ),
- 		ROUTE( OBJECT_TYPE_SESSION ),
- 		subACL_SessinfoSSHChannelHeight ),
-+	MKACL_N(
-+		CRYPT_SESSINFO_SSH_CHANNEL_OPEN,
-+		ST_NONE, ST_NONE, ST_SESS_SSH | ST_SESS_SSH_SVR, 
-+		MKPERM_SSL( Rxx_Rxx ),
-+		ROUTE( OBJECT_TYPE_SESSION ),
-+		RANGE( FALSE, TRUE ) ),
- 
- 	MKACL_END(), MKACL_END()
- 	};
-@@ -4707,7 +4713,7 @@
- 	static_assert( CRYPT_CERTINFO_FIRST_EXTENSION == 2200, "Attribute value" );
- 	static_assert( CRYPT_CERTINFO_FIRST_CMS == 2500, "Attribute value" );
- 	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6016, "Attribute value" );
--	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6035, "Attribute value" );
-+	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6036, "Attribute value" );
- 	static_assert( CRYPT_CERTFORMAT_LAST == 12, "Attribute value" );
- 
- 	/* Perform a consistency check on the attribute ACLs.  The ACLs are
---- session/ssh.c.orig	2023-12-29 16:07:09.485094000 -0500
-+++ session/ssh.c	2023-12-29 16:07:52.102633000 -0500
-@@ -993,7 +993,8 @@
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
--			  type == CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL);
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL || \
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_OPEN);
- 
- 	if( type == CRYPT_SESSINFO_SSH_OPTIONS )
- 		{
-@@ -1010,7 +1011,8 @@
- 	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
- 		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
- 		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
--		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT)
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_OPEN)
- 		{
- 		status = getChannelAttribute( sessionInfoPtr, type, data );
- 		}
---- ./session/ssh2_chn.c.orig	2023-12-29 19:50:00.990529000 -0500
-+++ ./session/ssh2_chn.c	2023-12-29 19:51:32.502476000 -0500
+--- ./session/ssh2_channel.c.orig	2023-12-29 19:50:00.990529000 -0500
++++ ./session/ssh2_channel.c	2023-12-29 19:51:32.502476000 -0500
 @@ -24,6 +24,7 @@
  #define CHANNEL_FLAG_NONE		0x00	/* No channel flag */
  #define CHANNEL_FLAG_ACTIVE		0x01	/* Channel is active */
@@ -208,3 +171,47 @@
  		return( isChannelActive( sessionInfoPtr, \
  								 channelInfoPtr->channelID ) ? \
  				CRYPT_OK : OK_SPECIAL );
+--- session/ssh.c.orig	2023-12-31 08:49:41.952161000 -0500
++++ session/ssh.c	2023-12-31 08:50:06.475509000 -0500
+@@ -543,6 +543,7 @@
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL || \
++			  type == CRYPT_SESSINFO_SSH_CHANNEL_OPEN || \
+ 			  type == CRYPT_SESSINFO_SSH_PREAUTH );
+ #else
+ 	REQUIRES( type == CRYPT_SESSINFO_SSH_PREAUTH );
+@@ -567,7 +568,8 @@
+ 	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
+ 		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
+ 		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
+-		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT)
++		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
++		type == CRYPT_SESSINFO_SSH_CHANNEL_OPEN)
+ 		{
+ 		status = getChannelAttribute( sessionInfoPtr, type, data );
+ 		}
+--- kernel/attr_acl.c.orig	2023-12-31 08:49:41.973327000 -0500
++++ kernel/attr_acl.c	2023-12-31 08:51:13.972549000 -0500
+@@ -3943,6 +3943,12 @@
+ 		MKPERM_SSH_EXT( RWx_RWx ),
+ 		ROUTE( OBJECT_TYPE_SESSION ),
+ 		subACL_SessinfoSSHChannelHeight ),
++	MKACL_N(
++		CRYPT_SESSINFO_SSH_CHANNEL_OPEN,
++		ST_NONE, ST_NONE, ST_SESS_SSH | ST_SESS_SSH_SVR, 
++		MKPERM_TLS( Rxx_Rxx ),
++		ROUTE( OBJECT_TYPE_SESSION ),
++		RANGE( FALSE, TRUE ) ),
+ 
+ 	MKACL_END(), MKACL_END()
+ 	};
+@@ -4931,7 +4937,7 @@
+ 	static_assert( CRYPT_CERTINFO_FIRST_EXTENSION == 2200, "Attribute value" );
+ 	static_assert( CRYPT_CERTINFO_FIRST_CMS == 2500, "Attribute value" );
+ 	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6017, "Attribute value" );
+-	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6039, "Attribute value" );
++	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6040, "Attribute value" );
+ 	static_assert( CRYPT_CERTFORMAT_LAST == 13, "Attribute value" );
+ 
+ 	/* Perform a consistency check on the attribute ACLs.  The ACLs are
diff --git a/3rdp/build/cl-fix-test-select.patch b/3rdp/build/cl-fix-test-select.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8f06bae965bbe0966ac729b381f0aa16581a41ef
--- /dev/null
+++ b/3rdp/build/cl-fix-test-select.patch
@@ -0,0 +1,10 @@
+--- test/test.h.orig	2023-12-31 07:11:19.119452000 -0500
++++ test/test.h	2023-12-31 07:11:41.022395000 -0500
+@@ -378,6 +378,7 @@
+   #define THREAD_SLEEP( ms ) Sleep( ms )
+   typedef unsigned ( __stdcall *THREAD_FUNC )( void *arg );
+ #elif defined( UNIX_THREADS )
++  #include <sys/select.h>
+   #define THREAD_HANDLE		pthread_t
+   #define THREAD_EXIT()		pthread_exit( ( void * ) 0 )
+   #define THREAD_SELF()		pthread_self()
diff --git a/3rdp/build/cl-gcc-non-const-time-val.patch b/3rdp/build/cl-gcc-non-const-time-val.patch
deleted file mode 100644
index 81bd85639a53bdfe5d2693551b32286971c9d862..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-gcc-non-const-time-val.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- misc/consts.h.orig	2019-06-20 12:44:22.683319000 -0400
-+++ misc/consts.h	2019-06-20 12:44:53.191660000 -0400
-@@ -346,7 +346,7 @@
- #define MAX_TIME_VALUE			( YEARS_TO_SECONDS( 2036 - 1970 ) )
- 
- #if ( defined( __clang__ ) && ( __clang_major__ > 5 ) ) || \
--	( defined( __GNUC__ ) && ( __GNUC__ > 6 ) ) || \
-+	( defined( __GNUC__ ) && ( __GNUC__ > 11 ) ) || \
- 	( defined( _MSC_VER ) && VC_GE_2017( _MSC_VER ) )
-   #define CURRENT_TIME_VALUE	( ( DATE_YEAR + DATE_MONTH + DATE_DAY - 30 ) * 86400 )
- #else
diff --git a/3rdp/build/cl-getseed64.patch b/3rdp/build/cl-getseed64.patch
deleted file mode 100644
index 765e95e440f50f674b30dd7391e9c58fe69f666f..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-getseed64.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- tools/getseed.sh.orig	2017-07-11 01:19:34.000000000 -0400
-+++ tools/getseed.sh	2018-01-03 02:08:08.240258000 -0500
-@@ -16,7 +16,7 @@
- if [ -e /dev/urandom ] ; then
- 	printf -- "-DFIXED_SEED=0x" ;
- 	if [ $IS64BIT -gt 0 ] ; then
--		printf "%X\n" `od -An -N8 -tu8 < /dev/urandom` ;
-+		printf "%X%X\n" `od -An -N4 -tu4 < /dev/urandom` `od -An -N4 -tu4 < /dev/urandom`;
- 	else
- 		printf "%X\n" `od -An -N4 -tu4 < /dev/urandom` ;
- 	fi ;
diff --git a/3rdp/build/cl-learn-numbers.patch b/3rdp/build/cl-learn-numbers.patch
deleted file mode 100644
index 5706d5631dfbd6b24e9c4df723270eb422ff0837..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-learn-numbers.patch
+++ /dev/null
@@ -1,20 +0,0 @@
---- ./tools/ccopts.sh.orig	2020-05-02 04:05:14.767613000 -0400
-+++ ./tools/ccopts.sh	2020-05-02 04:15:51.301386000 -0400
-@@ -357,7 +357,7 @@
- # tools/getlibs.sh also for clang 4.7 or newer.
- 
- if [ $ISCLANG -gt 0 ] && [ $ISSPECIAL -eq 0 ] ; then
--	CLANG_VER="$($CC -dumpversion | tr -d  '.' | cut -c 1-2)" ;
-+	CLANG_VER="$($CC -dumpversion | sed -E 's/^([0-9]+)$/\1.0/' | sed -E 's/^([0-9]+)\.([0-9]).*$/\1\2/')" ;
- 	if [ $CLANG_VER -gt 42 ] ; then
- 		CCARGS="$CCARGS -fsanitize=safe-stack" ;
- 	fi ;
-@@ -509,7 +509,7 @@
- # apparent version less than 10 we add a trailing zero to the string to make
- # the checks that follow work.
- 
--GCC_VER="$($CC -dumpversion | tr -d  '.' | cut -c 1-2)"
-+GCC_VER="$($CC -dumpversion | sed -E 's/^([0-9]+)$/\1.0/' | sed -E 's/^([0-9]+)\.([0-9]).*$/\1\2/')"
- if [ "$GCC_VER" -lt 10 ] ; then
- 	GCC_VER="${GCC_VER}0" ;
- fi
diff --git a/3rdp/build/cl-linux-yield.patch b/3rdp/build/cl-linux-yield.patch
deleted file mode 100644
index 8cdfc8eafd3fd85f39bf0f8b519f25a31078fee4..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-linux-yield.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- old/thread.h	2021-10-19 12:34:08.766649958 -0700
-+++ kernel/thread.h	2021-10-19 12:34:43.794072316 -0700
-@@ -3005,7 +3005,7 @@
-   #endif /* Slowaris 5.7 / 7.x or newer */
- #elif defined( _AIX ) || defined( __Android__ ) || defined( __CYGWIN__ ) || \
- 	  ( defined( __hpux ) && ( OSVERSION >= 11 ) ) || \
--	  defined( __NetBSD__ ) || defined( __QNX__ ) || defined( __UCLIBC__ )
-+	  defined( __NetBSD__ ) || defined( __QNX__ ) || defined( __UCLIBC__ ) || defined(__linux__)
-   #define THREAD_YIELD()		sched_yield()
- #elif defined( __XMK__ )
-   /* The XMK underlying scheduling object is the process context, for which
diff --git a/3rdp/build/cl-make-channels-work.patch b/3rdp/build/cl-make-channels-work.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3f25f970c03b54e3712804634c8b723e7febbaf0
--- /dev/null
+++ b/3rdp/build/cl-make-channels-work.patch
@@ -0,0 +1,578 @@
+--- ./session/ssh.h.orig	2023-05-06 18:55:50.000000000 -0400
++++ ./session/ssh.h	2024-01-12 23:35:03.804841000 -0500
+@@ -309,9 +309,17 @@
+ 	SSH_ATTRIBUTE_WINDOWCOUNT,				/* Data window count */
+ 	SSH_ATTRIBUTE_WINDOWSIZE,				/* Data window size */
+ 	SSH_ATTRIBUTE_ALTCHANNELNO,				/* Secondary channel no. */
++	SSH_ATTRIBUTE_NEEDWINDOW,				/* Send session open when window opens */
+ 	SSH_ATTRIBUTE_LAST						/* Last channel attribute */
+ 	} SSH_ATTRIBUTE_TYPE;
+ 
++#ifdef USE_SSH_EXTENDED
++typedef enum { SERVICE_NONE, SERVICE_SHELL, SERVICE_PORTFORWARD, 
++			   SERVICE_SUBSYSTEM, SERVICE_EXEC, SERVICE_LAST } SERVICE_TYPE;
++#else
++typedef enum { SERVICE_NONE, SERVICE_SHELL, SERVICE_LAST } SERVICE_TYPE;
++#endif /* USE_SSH_EXTENDED */
++
+ /* Check whether a DH/ECDH value is valid for a given server key size.  The 
+    check is slightly different for the ECC version because the value is
+    a composite ECC point with two coordinates, so we have to divide the 
+@@ -697,6 +705,18 @@
+ 
+ /* Prototypes for functions in ssh2_msgcli.c */
+ 
++CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
++int getServiceType( INOUT_PTR SESSION_INFO *sessionInfoPtr, 
++						   OUT_ENUM_OPT( SERVICE ) SERVICE_TYPE *serviceType );
++						   CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
++int createSessionOpenRequest( INOUT_PTR SESSION_INFO *sessionInfoPtr,
++									 INOUT_PTR STREAM *stream,
++									 IN_ENUM( SERVICE ) \
++										const SERVICE_TYPE serviceType );
++CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
++int processChannelOpenFailure( INOUT_PTR SESSION_INFO *sessionInfoPtr, INOUT_PTR STREAM *stream );
++CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
++int processChannelOpenConfirmation( INOUT_PTR SESSION_INFO *sessionInfoPtr, INOUT_PTR STREAM *stream );
+ CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
+ int sendChannelOpen( INOUT_PTR SESSION_INFO *sessionInfoPtr );
+ 
+--- session/sess_rd.c.orig	2023-05-06 19:14:10.000000000 -0400
++++ session/sess_rd.c	2024-01-13 01:40:38.360167000 -0500
+@@ -739,7 +739,7 @@
+ 		/* Remember how much we've copied and, if we've satisfied the 
+ 		   request, exit */
+ 		*bytesCopied = bytesToCopy;
+-		if( bytesToCopy >= length )
++		if( bytesToCopy >= 0 )
+ 			{
+ 			ENSURES( sanityCheckSessionRead( sessionInfoPtr ) );
+ 
+@@ -929,6 +929,22 @@
+ 			dataPtr += byteCount;
+ 			dataLength -= byteCount;
+ 			}
++		/*
++		 * SyncTERM hack for SSH channels... after a full packet has been received, *and*
++		 * some data has been received, always return.
++		 *
++		 * This ensures that we can never return data from two different channels in the
++		 * same cryptPopData() response.
++		 */
++		if (*bytesCopied > 0) {
++			if (sessionInfoPtr->type == CRYPT_SESSION_SSH || sessionInfoPtr->type == CRYPT_SESSION_SSH_SERVER)
++				{
++				if (sessionInfoPtr->pendingPacketLength <= 0)
++					{
++					status = OK_SPECIAL;
++					}
++				}
++		}
+ 		if( status == OK_SPECIAL )
+ 			{
+ 			/* That was the last of the data, exit */
+--- session/ssh2_msg.c.orig	2024-01-13 01:45:16.168554000 -0500
++++ session/ssh2_msg.c	2024-01-13 01:46:42.971186000 -0500
+@@ -319,7 +319,10 @@
+ 					}
+ 				}
+ 			break;
+-
++		case SSH_MSG_CHANNEL_OPEN_FAILURE:
++			return processChannelOpenFailure(sessionInfoPtr, stream);
++		case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
++			return processChannelOpenConfirmation(sessionInfoPtr, stream);
+ 		default:
+ 			{
+ #ifdef USE_ERRMSGS
+@@ -444,10 +447,18 @@
+ 			return( OK_SPECIAL );
+ 
+ 		case SSH_MSG_CHANNEL_WINDOW_ADJUST:
++			{
++			int value;
+ 			/* Another noop-equivalent (but a very performance-affecting
+ 			   one) */
+ 			DEBUG_PUTS(( "Processing window adjust message" ));
++			status = getChannelExtAttribute(sessionInfoPtr, SSH_ATTRIBUTE_NEEDWINDOW, &value);
++			if (cryptStatusOK(status) && value)
++				{
++				status = setChannelExtAttribute(sessionInfoPtr, SSH_ATTRIBUTE_NEEDWINDOW, FALSE);
++				}
+ 			return( OK_SPECIAL );
++			}
+ 
+ 		case SSH_MSG_CHANNEL_EOF:
+ 			/* According to the SSH docs the EOF packet is a courtesy 
+--- session/ssh2_msgcli.c.orig	2024-01-14 13:50:16.921501000 -0500
++++ session/ssh2_msgcli.c	2024-01-14 13:50:34.230994000 -0500
+@@ -27,13 +27,6 @@
+ 			   OPENREQUEST_CHANNELONLY, OPENREQUEST_SESSION,
+ 			   OPENREQUEST_LAST } OPENREQUEST_TYPE;
+ 
+-#ifdef USE_SSH_EXTENDED
+-typedef enum { SERVICE_NONE, SERVICE_SHELL, SERVICE_PORTFORWARD, 
+-			   SERVICE_SUBSYSTEM, SERVICE_EXEC, SERVICE_LAST } SERVICE_TYPE;
+-#else
+-typedef enum { SERVICE_NONE, SERVICE_SHELL, SERVICE_LAST } SERVICE_TYPE;
+-#endif /* USE_SSH_EXTENDED */
+-
+ /****************************************************************************
+ *																			*
+ *								Utility Functions							*
+@@ -45,7 +38,7 @@
+ /* Determine which type of service the caller requested */
+ 
+ CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
+-static int getServiceType( INOUT_PTR SESSION_INFO *sessionInfoPtr, 
++int getServiceType( INOUT_PTR SESSION_INFO *sessionInfoPtr, 
+ 						   OUT_ENUM_OPT( SERVICE ) SERVICE_TYPE *serviceType )
+ 	{
+ 	BYTE typeString[ CRYPT_MAX_TEXTSIZE + 8 ];
+@@ -441,7 +434,7 @@
+ #endif /* USE_SSH_EXTENDED */
+ 
+ CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
+-static int createSessionOpenRequest( INOUT_PTR SESSION_INFO *sessionInfoPtr,
++int createSessionOpenRequest( INOUT_PTR SESSION_INFO *sessionInfoPtr,
+ 									 INOUT_PTR STREAM *stream,
+ 									 IN_ENUM( SERVICE ) \
+ 										const SERVICE_TYPE serviceType )
+@@ -595,121 +588,54 @@
+ 	return( status );
+ 	}
+ 
+-/* Send a channel open */
++CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
++int processChannelOpenFailure( INOUT_PTR SESSION_INFO *sessionInfoPtr, INOUT_PTR STREAM *stream )
++	{
++	int status;
++	status = getOpenFailInfo( sessionInfoPtr, stream );
++	return( status );
++	}
+ 
+-CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
+-int sendChannelOpen( INOUT_PTR SESSION_INFO *sessionInfoPtr )
++CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
++int processChannelOpenConfirmation( INOUT_PTR SESSION_INFO *sessionInfoPtr, INOUT_PTR STREAM *stream )
+ 	{
+-	STREAM stream;
++	int status;
++	long currentChannelNo;
++	long channelNo;
++	long origWriteChannelNo;
+ 	SERVICE_TYPE serviceType;
+-	OPENREQUEST_TYPE requestType;
+-	BOOLEAN waitforWindow = FALSE;
++	long windowSize;
++	STREAM sendStream;
+ 	BYTE buffer[ UINT32_SIZE + 8 ];
+-	const long channelNo = getCurrentChannelNo( sessionInfoPtr,
+-												CHANNEL_READ );
+-	long currentChannelNo, windowSize;
+-	int length, value, status;
++	BOOLEAN waitforWindow = FALSE;
++	int length;
+ 
+-	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
+-
+-	REQUIRES( sanityCheckSessionSSH( sessionInfoPtr ) );
+-
+-	/* Make sure that there's channel data available to activate and
+-	   that it doesn't correspond to an already-active channel */
+-	if( channelNo == UNUSED_CHANNEL_NO )
+-		{
+-		retExt( CRYPT_ERROR_NOTINITED,
+-				( CRYPT_ERROR_NOTINITED, SESSION_ERRINFO, 
+-				  "No current channel information available to activate "
+-				  "channel" ) );
+-		}
+-	status = getChannelAttribute( sessionInfoPtr,
+-								  CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE,
+-								  &value );
+-	if( cryptStatusError( status ) || value )
+-		{
+-		retExt( CRYPT_ERROR_INITED,
+-				( CRYPT_ERROR_INITED, SESSION_ERRINFO, 
+-				  "Current channel has already been activated" ) );
+-		}
+-
+-	/* Determine the service type that we'll be using */
+ 	status = getServiceType( sessionInfoPtr, &serviceType );
+-	if( cryptStatusError( status ) )
++	if( cryptStatusError( status ) ) {
+ 		return( status );
++	}
+ 
+-	/* Create a request for the appropriate type of service */
+-	status = createOpenRequest( sessionInfoPtr, &stream, serviceType, 
+-								&requestType );
+-	if( cryptStatusError( status ) )
+-		return( status );
++	origWriteChannelNo = sessionInfoPtr->sessionSSH->currWriteChannel;
++	status = currentChannelNo = readUint32( stream );
+ 
+-	/* Send the open request to the server.  The SSH spec doesn't really
+-	   explain the semantics of the server's response to the channel open
+-	   command, in particular whether the returned data size parameters are
+-	   merely a confirmation of the client's requested values or whether the
+-	   server is allowed to further modify them to suit its own requirements
+-	   (or perhaps one is for send and the other for receive?).  In the
+-	   absence of any further guidance we just ignore the returned values,
+-	   which seems to work for all deployed servers */
+-	status = wrapSendPacketSSH2( sessionInfoPtr, &stream );
+-	sMemDisconnect( &stream );
+-	if( cryptStatusError( status ) )
++	// Find channel by number...
++	if (!cryptStatusError(status))
++		status = selectChannel( sessionInfoPtr, currentChannelNo, CHANNEL_NONE );
++	if( cryptStatusError( status ) ) {
+ 		return( status );
++	}
++	channelNo = currentChannelNo;
+ 
+-#if 0	/* Never used, see comment in createOpenRequest() for 
+-		   "tcpip-forward" type */
+-	/* If it's a request-only message that doesn't open a channel then
+-	   we're done */
+-	if( requestType == OPENREQUEST_STANDALONE )
+-		return( CRYPT_OK );
+-#endif /* 0 */
+-
+-	/* Wait for the server's ack of the channel open request:
+-
+-		byte	SSH_MSG_CHANNEL_OPEN_CONFIRMATION
+-		uint32	recipient_channel
+-		uint32	sender_channel
+-		uint32	initial_window_size
+-		uint32	maximum_packet_size
+-		... 
+-		
+-	   Quite a number of implementations use the same approach that we do to 
+-	   the windowing problem and advertise a maximum-size window, since this 
+-	   is typically INT_MAX (used by e.g. PSFTP, WinSCP, and FileZilla) we 
+-	   have to use an sread() rather than the range-checking readUint32() 
+-	   to read this */
+-	status = length = \
+-		readAuthPacketSSH2( sessionInfoPtr, SSH_MSG_SPECIAL_CHANNEL,
+-							ID_SIZE + UINT32_SIZE + UINT32_SIZE + \
+-								UINT32_SIZE + UINT32_SIZE );
+-	if( cryptStatusError( status ) )
+-		return( status );
+-	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
+-	if( sessionInfoPtr->sessionSSH->packetType == SSH_MSG_CHANNEL_OPEN_FAILURE )
+-		{
+-		/* The open failed, report the details to the user */
+-		status = getOpenFailInfo( sessionInfoPtr, &stream );
+-		sMemDisconnect( &stream );
+-		return( status );
+-		}
+-	status = currentChannelNo = readUint32( &stream );
+-	if( !cryptStatusError( status ) && currentChannelNo != channelNo )
+-		{
+-		/* We got back a different channel number than we sent */
+-		status = CRYPT_ERROR_BADDATA;
+-		}
+ 	if( !cryptStatusError( status ) )
+-		status = currentChannelNo = readUint32( &stream );
++		status = currentChannelNo = readUint32( stream );
+ 	if( cryptStatusError( status ) )
+ 		{
+-		sMemDisconnect( &stream );
+ 		retExt( CRYPT_ERROR_BADDATA,
+ 				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
+ 				  "Invalid channel information in channel open "
+ 				  "confirmation for channel %lX", channelNo ) );
+ 		}
+-	status = sread( &stream, buffer, UINT32_SIZE );
++	status = sread( stream, buffer, UINT32_SIZE );
+ 	if( !cryptStatusError( status ) && \
+ 		!memcmp( buffer, "\x00\x00\x00\x00", UINT32_SIZE ) )
+ 		{
+@@ -720,8 +646,15 @@
+ 		DEBUG_PRINT(( "Peer advertised window size 0 in channel open, will "
+ 					  "wait for window adjust in order to send data.\n" ));
+ 		waitforWindow = TRUE;
++		status = setChannelExtAttribute(sessionInfoPtr, SSH_ATTRIBUTE_NEEDWINDOW, TRUE);
++		if( cryptStatusError( status ) )
++			{
++			retExt( CRYPT_ERROR_INTERNAL,
++					( CRYPT_ERROR_INTERNAL, SESSION_ERRINFO,
++					  "Unable to set NEEDWINDOW for "
++					  "channel %lX", channelNo ) );
++			}
+ 		}
+-	sMemDisconnect( &stream );
+ 	if( cryptStatusError( status ) )
+ 		{
+ 		retExt( CRYPT_ERROR_BADDATA,
+@@ -757,63 +690,178 @@
+ 											 windowSize );
+ 			}
+ 		}
+-	if( cryptStatusOK( status ) )
+-		status = selectChannel( sessionInfoPtr, channelNo, CHANNEL_BOTH );
+-	if( cryptStatusError( status ) )
++	if (cryptStatusOK(status))
++		status = selectChannel( sessionInfoPtr, currentChannelNo, CHANNEL_BOTH );
++	if( cryptStatusError( status ) ) {
++		selectChannel( sessionInfoPtr, origWriteChannelNo, CHANNEL_WRITE );
+ 		return( status );
++	}
+ 
+ 	/* If we're just opening a new channel in an existing session then we're 
+ 	   done */
+-	if( requestType == OPENREQUEST_CHANNELONLY )
++	if( serviceType == SERVICE_PORTFORWARD ) {
++		selectChannel( sessionInfoPtr, origWriteChannelNo, CHANNEL_WRITE );
+ 		return( CRYPT_OK );
++	}
+ 
+-	REQUIRES( requestType == OPENREQUEST_SESSION );
++	if ( TRUE || channelNo == 0 || !waitforWindow )
++		{
++		/* It's a session open request that requires additional messages to do
++		   anything useful, create and send the extra packets.  Unlike the 
++		   overall open request, we can't wrap and send the packets in one go
++		   because serviceType == SERVICE_SHELL has to send multiple packets,
++		   which are wrapped in createSessionOpenRequest() */
++		status = createSessionOpenRequest( sessionInfoPtr, &sendStream, 
++										   serviceType );
++		if( cryptStatusOK( status ) )
++			{
++			/* serviceType == SERVICE_SHELL creates two packets */
++			status = sendPacketSSH2( sessionInfoPtr, &sendStream );
++			}
++		sMemDisconnect( &sendStream );
++		if( cryptStatusError( status ) )
++			selectChannel( sessionInfoPtr, origWriteChannelNo, CHANNEL_WRITE );
++			return( status );
++		}
+ 
+-	/* It's a session open request that requires additional messages to do
+-	   anything useful, create and send the extra packets.  Unlike the 
+-	   overall open request, we can't wrap and send the packets in one go
+-	   because serviceType == SERVICE_SHELL has to send multiple packets,
+-	   which are wrapped in createSessionOpenRequest() */
+-	status = createSessionOpenRequest( sessionInfoPtr, &stream, 
+-									   serviceType );
+-	if( cryptStatusOK( status ) )
++	/* If the peer advertised a zero-length window, we have to wait for a
++	   window adjust before we can send any data.  We know that this is what
++	   will (or at least should) arrive next because we've set want_reply =
++	   FALSE in the session open request */
++	if( waitforWindow )
+ 		{
+-		/* serviceType == SERVICE_SHELL creates two packets */
+-		status = sendPacketSSH2( sessionInfoPtr, &stream );
++		if ( channelNo == 0 )
++			{
++			/* This isn't really an auth packet any more but to read further
++			   packets we would have to get into the data-read state machine via
++			   readHeaderFunction()/processBodyFunction() which would be quite
++			   difficult, so we read it as a (pseudo-)auth packet */
++			status = length = \
++				readAuthPacketSSH2( sessionInfoPtr, SSH_MSG_CHANNEL_WINDOW_ADJUST,
++									ID_SIZE + UINT32_SIZE + UINT32_SIZE );
++			if( cryptStatusError( status ) ) {
++				selectChannel( sessionInfoPtr, origWriteChannelNo, CHANNEL_WRITE );
++				return( status );
++			}
++			sMemConnect( &sendStream, sessionInfoPtr->receiveBuffer, length );
++			status = currentChannelNo = readUint32( &sendStream );
++			if( !cryptStatusError( status ) && currentChannelNo != channelNo )
++				status = CRYPT_ERROR_BADDATA;
++			sMemDisconnect( &sendStream );
++			if( cryptStatusError( status ) )
++				{
++				retExt( CRYPT_ERROR_BADDATA,
++						( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
++						  "Invalid channel information in window adjust for "
++						  "channel %lX", channelNo ) );
++				}
++			}
+ 		}
++
++	selectChannel( sessionInfoPtr, origWriteChannelNo, CHANNEL_WRITE );
++	return( CRYPT_OK );
++	}
++
++/* Send a channel open */
++
++CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
++int sendChannelOpen( INOUT_PTR SESSION_INFO *sessionInfoPtr )
++	{
++	STREAM stream;
++	SERVICE_TYPE serviceType;
++	OPENREQUEST_TYPE requestType;
++	const long channelNo = getCurrentChannelNo( sessionInfoPtr,
++												CHANNEL_READ );
++	int length, value, status;
++
++	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
++
++	REQUIRES( sanityCheckSessionSSH( sessionInfoPtr ) );
++
++	/* Make sure that there's channel data available to activate and
++	   that it doesn't correspond to an already-active channel */
++	if( channelNo == UNUSED_CHANNEL_NO )
++		{
++		retExt( CRYPT_ERROR_NOTINITED,
++				( CRYPT_ERROR_NOTINITED, SESSION_ERRINFO, 
++				  "No current channel information available to activate "
++				  "channel" ) );
++		}
++	status = getChannelAttribute( sessionInfoPtr,
++								  CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE,
++								  &value );
++	if( cryptStatusError( status ) || value )
++		{
++		retExt( CRYPT_ERROR_INITED,
++				( CRYPT_ERROR_INITED, SESSION_ERRINFO, 
++				  "Current channel has already been activated" ) );
++		}
++
++	/* Determine the service type that we'll be using */
++	status = getServiceType( sessionInfoPtr, &serviceType );
++	if( cryptStatusError( status ) )
++		return( status );
++
++	/* Create a request for the appropriate type of service */
++	status = createOpenRequest( sessionInfoPtr, &stream, serviceType, 
++								&requestType );
++	if( cryptStatusError( status ) )
++		return( status );
++
++	/* Send the open request to the server.  The SSH spec doesn't really
++	   explain the semantics of the server's response to the channel open
++	   command, in particular whether the returned data size parameters are
++	   merely a confirmation of the client's requested values or whether the
++	   server is allowed to further modify them to suit its own requirements
++	   (or perhaps one is for send and the other for receive?).  In the
++	   absence of any further guidance we just ignore the returned values,
++	   which seems to work for all deployed servers */
++	status = wrapSendPacketSSH2( sessionInfoPtr, &stream );
+ 	sMemDisconnect( &stream );
+ 	if( cryptStatusError( status ) )
+ 		return( status );
+-	
+-	/* If the peer advertised a zero-length window, we have to wait for a 
+-	   window adjust before we can send any data.  We know that this is what
+-	   will (or at least should) arrive next because we've set want_reply = 
+-	   FALSE in the session open request */
+-	if( waitforWindow )
++
++#if 0	/* Never used, see comment in createOpenRequest() for 
++		   "tcpip-forward" type */
++	/* If it's a request-only message that doesn't open a channel then
++	   we're done */
++	if( requestType == OPENREQUEST_STANDALONE )
++		return( CRYPT_OK );
++#endif /* 0 */
++
++	if (channelNo == 0)
+ 		{
+-		/* This isn't really an auth packet any more but to read further 
+-		   packets we would have to get into the data-read state machine via
+-		   readHeaderFunction()/processBodyFunction() which would be quite
+-		   difficult, so we read it as a (pseudo-)auth packet */
++		/* Wait for the server's ack of the channel open request:
++
++			byte	SSH_MSG_CHANNEL_OPEN_CONFIRMATION
++			uint32	recipient_channel
++			uint32	sender_channel
++			uint32	initial_window_size
++			uint32	maximum_packet_size
++			... 
++			
++		   Quite a number of implementations use the same approach that we do to 
++		   the windowing problem and advertise a maximum-size window, since this 
++		   is typically INT_MAX (used by e.g. PSFTP, WinSCP, and FileZilla) we 
++		   have to use an sread() rather than the range-checking readUint32() 
++		   to read this */
+ 		status = length = \
+-			readAuthPacketSSH2( sessionInfoPtr, SSH_MSG_CHANNEL_WINDOW_ADJUST,
+-								ID_SIZE + UINT32_SIZE + UINT32_SIZE );
++			readAuthPacketSSH2( sessionInfoPtr, SSH_MSG_SPECIAL_CHANNEL,
++								ID_SIZE + UINT32_SIZE + UINT32_SIZE + \
++									UINT32_SIZE + UINT32_SIZE );
+ 		if( cryptStatusError( status ) )
+ 			return( status );
+ 		sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
+-		status = currentChannelNo = readUint32( &stream );
+-		if( !cryptStatusError( status ) && currentChannelNo != channelNo )
+-			status = CRYPT_ERROR_BADDATA;
+-		sMemDisconnect( &stream );
+-		if( cryptStatusError( status ) )
++		if( sessionInfoPtr->sessionSSH->packetType == SSH_MSG_CHANNEL_OPEN_FAILURE )
+ 			{
+-			retExt( CRYPT_ERROR_BADDATA,
+-					( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
+-					  "Invalid channel information in window adjust for "
+-					  "channel %lX", channelNo ) );
++			status = processChannelOpenFailure(sessionInfoPtr, &stream);
++			sMemDisconnect( &stream );
++			return status;
+ 			}
++		status = processChannelOpenConfirmation(sessionInfoPtr, &stream);
++		sMemDisconnect( &stream );
++		return status;
+ 		}
+-
+-	return( CRYPT_OK );
++	return (CRYPT_ENVELOPE_RESOURCE);
+ 	}
+ #endif /* USE_SSH */
+--- session/ssh2_channel.c.orig	2024-01-14 18:43:50.796652000 -0500
++++ session/ssh2_channel.c	2024-01-14 18:45:50.515008000 -0500
+@@ -25,6 +25,7 @@
+ #define CHANNEL_FLAG_ACTIVE		0x01	/* Channel is active */
+ #define CHANNEL_FLAG_WRITECLOSED 0x02	/* Write-side of ch.closed */
+ #define CHANNEL_FLAG_READCLOSED 0x04	/* Read-side of ch.closed */
++#define CHANNEL_FLAG_NEEDWINDOW 0x08	/* Needs open session */
+ 
+ /* Per-channel information.  SSH channel IDs are 32-bit/4 byte data values
+    and can be reused during sessions so we provide our own guaranteed-unique
+@@ -506,7 +507,7 @@
+ 		case CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE:
+ 			if( isNullChannel( writeChannelInfoPtr ) )
+ 				return( CRYPT_ERROR_NOTFOUND );
+-			*value = isActiveChannel( writeChannelInfoPtr ) ? TRUE : FALSE;
++			*value = isActiveChannel( writeChannelInfoPtr ) ? (writeChannelInfoPtr->flags & CHANNEL_FLAG_NEEDWINDOW ? FALSE : TRUE) : FALSE;
+ 			return( CRYPT_OK );
+ 
+ 		case CRYPT_SESSINFO_SSH_CHANNEL_OPEN:
+@@ -629,6 +630,10 @@
+ 		case SSH_ATTRIBUTE_WINDOWSIZE:
+ 			*value = channelInfoPtr->windowSize;
+ 			return( CRYPT_OK );
++
++		case SSH_ATTRIBUTE_NEEDWINDOW:
++			*value = (channelInfoPtr->flags & CHANNEL_FLAG_NEEDWINDOW) ? TRUE : FALSE;
++			return( CRYPT_OK );
+ 		}
+ 
+ 	retIntError();
+@@ -748,6 +753,8 @@
+ 		{
+ 		case SSH_ATTRIBUTE_ACTIVE:
+ 			channelInfoPtr->flags |= CHANNEL_FLAG_ACTIVE;
++			if( channelInfoPtr->flags & CHANNEL_FLAG_READCLOSED )
++				deleteChannel(sessionInfoPtr, channelInfoPtr->writeChannelNo, CHANNEL_BOTH, FALSE);
+ 			return( CRYPT_OK );
+ 
+ 		case SSH_ATTRIBUTE_WINDOWCOUNT:
+@@ -760,6 +767,13 @@
+ 
+ 		case SSH_ATTRIBUTE_ALTCHANNELNO:
+ 			channelInfoPtr->writeChannelNo = value;
++			return( CRYPT_OK );
++
++		case SSH_ATTRIBUTE_NEEDWINDOW:
++			if (value)
++				channelInfoPtr->flags |= (CHANNEL_FLAG_NEEDWINDOW);
++			else
++				channelInfoPtr->flags &= ~(CHANNEL_FLAG_NEEDWINDOW);
+ 			return( CRYPT_OK );
+ 		}
+ 
diff --git a/3rdp/build/cl-more-RSA-ECC-fixes.patch b/3rdp/build/cl-more-RSA-ECC-fixes.patch
deleted file mode 100644
index c69b1b2534451cf6bc5c017b7f25dd9ffdf2b770..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-more-RSA-ECC-fixes.patch
+++ /dev/null
@@ -1,13 +0,0 @@
---- session/ssl_ext.c.orig	2020-01-23 15:25:30.640683000 -0500
-+++ session/ssl_ext.c	2020-01-23 15:25:40.141297000 -0500
-@@ -607,8 +607,8 @@
- #endif /* CONFIG_SUITEB */
- 
- 		/* Make sure that the curve matches the server's signing key */
--		if( curveSize != keySize )
--			continue;
-+		//if( curveSize != keySize )
-+		//	continue;
- 
- 		/* We've got a matching curve, remember it.  In theory we could exit
- 		   at this point but we continue anyway to clear the remainder of 
diff --git a/3rdp/build/cl-no-RSA-suites.patch b/3rdp/build/cl-no-RSA-suites.patch
deleted file mode 100644
index 1506fe47a9d21dd90198240c7a9da4832b144682..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-no-RSA-suites.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- misc/config.h.orig	2020-01-23 12:03:27.741075000 -0500
-+++ misc/config.h	2020-01-23 12:03:27.806947000 -0500
-@@ -684,7 +684,7 @@
-    64-bit systems, which by definition are going to be fairly recent */
- 
- #ifndef SYSTEM_64BIT
--  #define USE_RSA_SUITES 
-+//  #define USE_RSA_SUITES 
- #endif /* SYSTEM_64BIT */
- 
- /* This now leads to a second problem, as of 2018 many public web servers 
diff --git a/3rdp/build/cl-no-odbc.patch b/3rdp/build/cl-no-odbc.patch
index 8ef855c07d4f60cd7ba5e20c8e15b6da54439c87..e8eff1f1628913b70e1006af7778e255c4780f86 100644
--- a/3rdp/build/cl-no-odbc.patch
+++ b/3rdp/build/cl-no-odbc.patch
@@ -1,12 +1,45 @@
---- tools/ccopts.sh.orig	2019-06-20 12:51:38.118150000 -0400
-+++ tools/ccopts.sh	2019-06-20 12:52:34.479052000 -0400
-@@ -210,7 +210,8 @@
- 	for includepath in $ODBCPATHS ; do
- 		if [ -f $includepath ] ; then
- 			echo "ODBC interface detected, enabling ODBC support." >&2 ;
--			CCARGS="$CCARGS -DHAS_ODBC -I"$(dirname $includepath)"" ;
-+			#CCARGS="$CCARGS -DHAS_ODBC -I"$(dirname $includepath)"" ;
-+			echo "Hah ha ha, no. fuck off." >&2 ;
- 			break ;
- 		fi
- 	done
+--- tools/ccopts.sh.orig	2023-12-31 07:18:39.570162000 -0500
++++ tools/ccopts.sh	2023-12-31 07:19:32.075029000 -0500
+@@ -369,25 +369,25 @@
+ esac
+ if [ -z "$DISABLE_AUTODETECT" ] && [ $HASDYNLOAD -gt 0 ] ; then
+ 	# ODBC support
+-	for includepath in $ODBCPATHS ; do
+-		if [ -f $includepath ] ; then
+-			echo "ODBC interface detected, enabling ODBC support." >&2 ;
+-			CCARGS="$CCARGS -DHAS_ODBC" ;
+-			if [ "$(dirname $includepath)" != "/usr/include" ] ; then
+-				CCARGS="$CCARGS -I$(dirname $includepath)" ;
+-			fi ;
+-			break ;
+-		fi ;
+-	done
++	#for includepath in $ODBCPATHS ; do
++	#	if [ -f $includepath ] ; then
++	#		echo "ODBC interface detected, enabling ODBC support." >&2 ;
++	#		CCARGS="$CCARGS -DHAS_ODBC" ;
++	#		if [ "$(dirname $includepath)" != "/usr/include" ] ; then
++	#			CCARGS="$CCARGS -I$(dirname $includepath)" ;
++	#		fi ;
++	#		break ;
++	#	fi ;
++	#done
+ 
+ 	# LDAP support
+-	if [ -f /usr/include/ldap.h ] ; then
+-		echo "LDAP interface detected, enabling LDAP support" >&2 ;
+-		CCARGS="$CCARGS -DHAS_LDAP" ;
+-		if [ $ISDEVELOPMENT -gt 0 ] ; then
+-			CCARGS="$CCARGS -DUSE_LDAP" ;
+-		fi ;
+-	fi
++	#if [ -f /usr/include/ldap.h ] ; then
++	#	echo "LDAP interface detected, enabling LDAP support" >&2 ;
++	#	CCARGS="$CCARGS -DHAS_LDAP" ;
++	#	if [ $ISDEVELOPMENT -gt 0 ] ; then
++	#		CCARGS="$CCARGS -DUSE_LDAP" ;
++	#	fi ;
++	#fi
+ 
+ 	# PKCS #11 support
+ 	for includepath in $PKCS11PATHS ; do
diff --git a/3rdp/build/cl-no-pie.patch b/3rdp/build/cl-no-pie.patch
new file mode 100644
index 0000000000000000000000000000000000000000..98716086c833abe7ad2628c84a4b3ff8f2d1600a
--- /dev/null
+++ b/3rdp/build/cl-no-pie.patch
@@ -0,0 +1,15 @@
+--- tools/ccopts.sh.orig	2023-12-31 11:49:24.760461000 -0500
++++ tools/ccopts.sh	2023-12-31 11:49:32.686744000 -0500
+@@ -1253,9 +1253,9 @@
+ # Enable ASLR.  We only do this for static libs, for shared libs it's
+ # already been handled via -fpic.
+ 
+-if [ "$COMPILER_VER" -ge 42 ] && [ $SHARED -le 0 ] ; then
+-	CCARGS="$CCARGS -fpie -Wl,-pie" ;
+-fi
++#if [ "$COMPILER_VER" -ge 42 ] && [ $SHARED -le 0 ] ; then
++#	CCARGS="$CCARGS -fpie -Wl,-pie" ;
++#fi
+ 
+ # Newer versions of gcc support marking the stack as nonexecutable (e.g.
+ # using the x86-64 NX bit), so if it's available we enable it.  This is
diff --git a/3rdp/build/cl-no-safe-stack.patch b/3rdp/build/cl-no-safe-stack.patch
index bbeb3cb1cda1d2d267abef8b1043718a859e4c37..020c1b763e190a530454fcf6d0eb67a1e60321ab 100644
--- a/3rdp/build/cl-no-safe-stack.patch
+++ b/3rdp/build/cl-no-safe-stack.patch
@@ -1,31 +1,47 @@
---- tools/getlibs.sh.orig	2021-01-24 07:40:21.569115000 -0500
-+++ tools/getlibs.sh	2021-01-24 07:40:42.823333000 -0500
-@@ -59,9 +59,9 @@
+--- tools/ccopts.sh.orig	2023-12-31 07:57:24.600204000 -0500
++++ tools/ccopts.sh	2023-12-31 07:59:35.674830000 -0500
+@@ -601,25 +601,25 @@
+ 	return $RESULT ;
+ 	}
  
- if hasSubstring "$BUILDOPTS" "sanitize=safe-stack" ; then
- 	CLANG_VER="$(clang -dumpversion | tr -d  '.' | cut -c 1-2)" ;
--	if [ $CLANG_VER -gt 47 ] ; then
--		LDARGS="$LDARGS -fsanitize=safe-stack" ;
+-if [ $ISCLANG -gt 0 ] && [ $ISSPECIAL -eq 0 ] ; then
+-	if [ $COMPILER_VER -ge 47 ] ; then
+-		if [ "$OSNAME" = "Darwin" ] || [ "$OSNAME" = "OpenBSD" ] ; then
+-			# The versions of clang shipped with OS X or OpenBSD don't
+-			# support -fsanitize=safe-stack even as late as clang 12, so
+-			# there's not much that we can do.
+-			CCARGS="$CCARGS" ;
+-		elif ! hasSafeStackLibs ; then
+-			echo "  " >&2 ;
+-			echo "  (This system supports clang stack sanitization via -fsanitize=safe-stack" >&2 ;
+-			echo "   in $0, however the necessary libclang_rt isn't installed." >&2 ;
+-			echo "   If you can install the required library then consider enabling" >&2 ;
+-			echo "   -fsanitize=safe-stack in $0)." >&2 ;
+-			echo "  " >&2 ;
+-		else
+-			CCARGS="$CCARGS -fsanitize=safe-stack" ;
+-		fi ;
 -	fi ;
-+	#if [ $CLANG_VER -gt 47 ] ; then
-+	#	LDARGS="$LDARGS -fsanitize=safe-stack" ;
-+	#fi ;
- fi
- 
- # Add any libraries needed by optional components.  In the case of zlib use
---- tools/ccopts.sh.orig	2020-11-26 02:40:05.222021000 -0500
-+++ tools/ccopts.sh	2021-01-24 07:41:02.126230000 -0500
-@@ -358,9 +358,9 @@
- # tools/getlibs.sh also for clang 4.7 or newer.
- 
- if [ $ISCLANG -gt 0 ] && [ $ISSPECIAL -eq 0 ] ; then
- 	CLANG_VER="$($CC -dumpversion | sed -E 's/^([0-9]+)$/\1.0/' | sed -E 's/^([0-9]+)\.([0-9]).*$/\1\2/')" ;
--	if [ $CLANG_VER -gt 42 ] ; then
--		CCARGS="$CCARGS -fsanitize=safe-stack" ;
--	fi ;
-+	#if [ $CLANG_VER -gt 42 ] ; then
-+	#	CCARGS="$CCARGS -fsanitize=safe-stack" ;
-+	#fi ;
- fi
+-fi
++#if [ $ISCLANG -gt 0 ] && [ $ISSPECIAL -eq 0 ] ; then
++#	if [ $COMPILER_VER -ge 47 ] ; then
++#		if [ "$OSNAME" = "Darwin" ] || [ "$OSNAME" = "OpenBSD" ] ; then
++#			# The versions of clang shipped with OS X or OpenBSD don't
++#			# support -fsanitize=safe-stack even as late as clang 12, so
++#			# there's not much that we can do.
++#			CCARGS="$CCARGS" ;
++#		elif ! hasSafeStackLibs ; then
++#			echo "  " >&2 ;
++#			echo "  (This system supports clang stack sanitization via -fsanitize=safe-stack" >&2 ;
++#			echo "   in $0, however the necessary libclang_rt isn't installed." >&2 ;
++#			echo "   If you can install the required library then consider enabling" >&2 ;
++#			echo "   -fsanitize=safe-stack in $0)." >&2 ;
++#			echo "  " >&2 ;
++#		else
++#			CCARGS="$CCARGS -fsanitize=safe-stack" ;
++#		fi ;
++#	fi ;
++#fi
  
  # The Sun compiler has its own set of problems, the biggest of which is
+ # determining where it is and what it is (see comments elsewhere), but
diff --git a/3rdp/build/cl-no-testobjs.patch b/3rdp/build/cl-no-testobjs.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7f1b1d11b580e35fde2521eb5478a0e414239647
--- /dev/null
+++ b/3rdp/build/cl-no-testobjs.patch
@@ -0,0 +1,11 @@
+--- makefile.orig	2023-12-31 12:09:41.982826000 -0500
++++ makefile	2023-12-31 12:10:05.682180000 -0500
+@@ -1784,7 +1784,7 @@
+ # than the system tools and libraries for the build, so we special-case this
+ # step based on the $(OSNAME) setting supplied to the build script.
+ 
+-$(ALIBNAME):	$(OBJS) $(EXTRAOBJS) $(TESTOBJS)
++$(ALIBNAME):	$(OBJS) $(EXTRAOBJS)
+ 				@./tools/buildlib.sh $(ALIBNAME) $(OSNAME) $(AR) \
+ 					$(OBJS) $(EXTRAOBJS)
+ 
diff --git a/3rdp/build/cl-no-tpm.patch b/3rdp/build/cl-no-tpm.patch
index 78393b077249512633f98f0bcaa2fa8a09d00523..faf719fa5830164a4f97412095eb1247889b87ee 100644
--- a/3rdp/build/cl-no-tpm.patch
+++ b/3rdp/build/cl-no-tpm.patch
@@ -1,27 +1,53 @@
---- tools/ccopts.sh.orig	2020-04-01 20:03:19.115301000 -0400
-+++ tools/ccopts.sh	2020-04-01 20:04:10.160695000 -0400
-@@ -242,15 +242,15 @@
- 	done
+--- tools/ccopts.sh.orig	2023-12-31 07:50:46.349349000 -0500
++++ tools/ccopts.sh	2023-12-31 07:51:14.307725000 -0500
+@@ -411,30 +411,30 @@
+ 	# TPM support.  The use of the doubled-up dirname is required because
+ 	# the TPM header is in a subdirectory tss2/tss2_fapi.h so we have to
+ 	# remove first the tss2_fapi.h and then the tss2 from the path.
+-	for includepath in $TPMPATHS ; do
+-		if [ -f $includepath ] ; then
+-			echo "TPM interface detected, enabling TPM support." >&2 ;
+-			CCARGS="$CCARGS -DHAS_TPM" ;
+-			if [ "$(dirname $includepath)" != "/usr/include/tss2" ] ; then
+-				CCARGS="$CCARGS -I$(dirname $(dirname $includepath))" ;
+-			fi ;
+-			break ;
+-		fi ;
+-	done
++	#for includepath in $TPMPATHS ; do
++	#	if [ -f $includepath ] ; then
++	#		echo "TPM interface detected, enabling TPM support." >&2 ;
++	#		CCARGS="$CCARGS -DHAS_TPM" ;
++	#		if [ "$(dirname $includepath)" != "/usr/include/tss2" ] ; then
++	#			CCARGS="$CCARGS -I$(dirname $(dirname $includepath))" ;
++	#		fi ;
++	#		break ;
++	#	fi ;
++	#done
  
- 	# TPM support
--	if [ "$(uname -s)" = "Linux" ] ; then
--		for includepath in $TPMPATHS ; do
--			if [ -f $includepath ] ; then
--				echo "TPM interface detected, enabling TPM support." >&2 ;
--				CCARGS="$CCARGS -DHAS_TPM -I"$(dirname $includepath)"" ;
--				break ;
--			fi
--		done
--	fi
-+	#if [ "$(uname -s)" = "Linux" ] ; then
-+	#	for includepath in $TPMPATHS ; do
-+	#		if [ -f $includepath ] ; then
-+	#			echo "TPM interface detected, enabling TPM support." >&2 ;
-+	#			CCARGS="$CCARGS -DHAS_TPM -I"$(dirname $includepath)"" ;
-+	#			break ;
-+	#		fi
-+	#	done
-+	#fi
+ 	# TPM RNG support.  The use of the doubled-up dirname is required because
+ 	# the TPM header is in a subdirectory tss/tspi.h so we have to remove
+ 	# first the tspi.h and then the tss from the path.
+-	for includepath in $TPMRNGPATHS ; do
+-		if [ -f $includepath ] ; then
+-			echo "TPM RNG interface detected, enabling TPM RNG support." >&2 ;
+-			CCARGS="$CCARGS -DHAS_TPM_RNG" ;
+-			if [ "$(dirname $includepath)" != "/usr/include/tss" ] ; then
+-				CCARGS="$CCARGS -I$(dirname $(dirname $includepath))" ;
+-			fi ;
+-			break ;
+-		fi ;
+-	done
++	#for includepath in $TPMRNGPATHS ; do
++	#	if [ -f $includepath ] ; then
++	#		echo "TPM RNG interface detected, enabling TPM RNG support." >&2 ;
++	#		CCARGS="$CCARGS -DHAS_TPM_RNG" ;
++	#		if [ "$(dirname $includepath)" != "/usr/include/tss" ] ; then
++	#			CCARGS="$CCARGS -I$(dirname $(dirname $includepath))" ;
++	#		fi ;
++	#		break ;
++	#	fi ;
++	#done
  
- 	# /dev/crypto support
- 	#for includepath in $DEVCRYPTOPATHS ; do
+ 	# /dev/crypto support.  The use of the doubled-up dirname is required
+ 	# because the /dev/crypto header is in a subdirectory crypto/cryptodev.h
diff --git a/3rdp/build/cl-noasm-defines.patch b/3rdp/build/cl-noasm-defines.patch
index d0849f461f3628b4f9b3bd30e91cdbd1ca3cdfb1..fa92ba3b6076d08d445867fb09f5c4097c9372c4 100644
--- a/3rdp/build/cl-noasm-defines.patch
+++ b/3rdp/build/cl-noasm-defines.patch
@@ -1,5 +1,5 @@
---- crypt.h.orig	2019-07-15 16:20:43.204006000 -0400
-+++ crypt.h	2019-07-15 16:21:06.812752000 -0400
+--- crypt.h.orig	2023-02-26 02:45:18.000000000 -0500
++++ crypt.h	2023-12-31 07:21:16.146850000 -0500
 @@ -9,6 +9,10 @@
  
  #define _CRYPT_DEFINED
@@ -8,6 +8,6 @@
 +#define OPENSSL_NO_INLINE_ASM
 +#define NO_ASM
 +
- /* Various compilers handle includes in subdirectories differently.  Most
-    will work with paths from a root directory.  Non-OS X Macintoshes don't
-    recognise '/'s as path delimiters, but work around it by scanning all
+ /* The overall cryptlib header file, which pulls in all other universally-
+    used header files.  The include order is:
+ 
diff --git a/3rdp/build/cl-pass-after-pubkey.patch b/3rdp/build/cl-pass-after-pubkey.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8e444fbf191044af82da5da3a5a20d8d74c9a242
--- /dev/null
+++ b/3rdp/build/cl-pass-after-pubkey.patch
@@ -0,0 +1,18 @@
+--- session/ssh2_authcli.c.orig	2024-01-19 12:15:13.314932000 -0500
++++ session/ssh2_authcli.c	2024-01-19 12:15:26.674148000 -0500
+@@ -597,6 +597,7 @@
+ 	   and return some sort of useful information to the caller */
+ 	if( providedAuthType == SSH_AUTHTYPE_PUBKEY )
+ 		{
++#if 0
+ 		if( needsPW )
+ 			{
+ 			setObjectErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_PASSWORD,
+@@ -606,6 +607,7 @@
+ 					  "Server requested password authentication but only a "
+ 					  "public/private key was available" ) );
+ 			}
++#endif
+ 		return CRYPT_ENVELOPE_RESOURCE;
+ 		}
+ 	if( requiredAuthType == SSH_AUTHTYPE_PUBKEY )
diff --git a/3rdp/build/cl-poll-not-select.patch b/3rdp/build/cl-poll-not-select.patch
index 35e5ca0228fe0b7936d9c35da880a06556904aad..5762f87ea5557ce12dca87f8b0995bf4085ea3b2 100644
--- a/3rdp/build/cl-poll-not-select.patch
+++ b/3rdp/build/cl-poll-not-select.patch
@@ -1,5 +1,5 @@
---- io/tcp_rw.c.orig	2019-02-05 18:16:32.000000000 -0500
-+++ io/tcp_rw.c	2021-12-07 15:16:54.161874000 -0500
+--- io/tcp_rw.c.orig	2023-02-26 03:33:50.000000000 -0500
++++ io/tcp_rw.c	2023-12-31 08:12:00.663053000 -0500
 @@ -20,6 +20,10 @@
  
  #ifdef USE_TCP
@@ -19,7 +19,7 @@
  	struct timeval tv;
  	fd_set readfds, writefds, exceptfds;
  	fd_set *readFDPtr = ( type == IOWAIT_READ || \
-@@ -81,6 +86,10 @@
+@@ -81,6 +86,11 @@
  						  type == IOWAIT_ACCEPT ) ? &readfds : NULL;
  	fd_set *writeFDPtr = ( type == IOWAIT_WRITE || \
  						   type == IOWAIT_CONNECT ) ? &writefds : NULL;
@@ -27,11 +27,12 @@
 +	struct pollfd fds;
 +	int ptimeout;
 +#endif
- 	int selectIterations, status, LOOP_ITERATOR;
++
+ 	LOOP_INDEX selectIterations;
+ 	int status;
  
- 	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
-@@ -90,26 +99,6 @@
- 	REQUIRES( previousDataRead == TRUE || previousDataRead == FALSE );
+@@ -91,26 +101,6 @@
+ 	REQUIRES( isBooleanValue( previousDataRead ) );
  	REQUIRES( isEnumRange( type, IOWAIT ) );
  
 -	/* Check for overflows in FD_SET().  This is an ugly implementation 
@@ -57,7 +58,7 @@
  	/* Set up the information needed to handle timeouts and wait on the
  	   socket.  If there's no timeout then we wait 5ms on the theory that it 
  	   isn't noticeable to the caller but ensures that we at least get a 
-@@ -152,6 +141,20 @@
+@@ -153,6 +143,20 @@
  	status = setMonoTimer( &timerInfo, timeout );
  	if( cryptStatusError( status ) )
  		return( status );
@@ -78,15 +79,15 @@
  	LOOP_MED( ( selectIterations = 0, status = SOCKET_ERROR ), \
  			  isSocketError( status ) && \
  				( selectIterations <= 0 || \
-@@ -159,6 +162,7 @@
- 				selectIterations < 20, 
- 			  selectIterations++ )
+@@ -162,6 +166,7 @@
  		{
+ 		ENSURES( LOOP_INVARIANT_MED( selectIterations, 0, 19 ) );
+ 
 +#ifdef __WINDOWS__
  		if( readFDPtr != NULL )
  			{
  			FD_ZERO( readFDPtr );
-@@ -186,6 +190,10 @@
+@@ -189,6 +194,10 @@
  		clearErrorState();
  		status = select( ( int ) netStream->netSocket + 1, readFDPtr, 
  						 writeFDPtr, &exceptfds, &tv );
@@ -97,7 +98,7 @@
  
  		/* If there's a problem and it's not something transient like an
  		   interrupted system call, exit.  For a transient problem, we just
-@@ -269,7 +277,11 @@
+@@ -272,7 +281,11 @@
  	   false and an indicator to receive SIGURG's not set, the OOB data byte 
  	   just languishes in a side-buffer), however we shouldn't be receiving 
  	   OOB data so we treat that as an error too */
@@ -109,7 +110,7 @@
  		{
  		int socketErrorCode;
  
-@@ -323,6 +335,7 @@
+@@ -326,6 +339,7 @@
  
  	/* The socket is read for reading or writing */
  	ENSURES( status > 0 );
@@ -117,7 +118,7 @@
  	ENSURES( ( type == IOWAIT_READ && \
  			   FD_ISSET( netStream->netSocket, &readfds ) ) || \
  			 ( type == IOWAIT_WRITE && \
-@@ -331,6 +344,13 @@
+@@ -334,6 +348,13 @@
  			   ( FD_ISSET( netStream->netSocket, &readfds ) || \
  				 FD_ISSET( netStream->netSocket, &writefds ) ) ) || \
  			 ( type == IOWAIT_ACCEPT ) );
diff --git a/3rdp/build/cl-posix-me-gently.patch b/3rdp/build/cl-posix-me-gently.patch
index 3e9441f914555d9a7eed870acd6964c581ed889e..1e55f4910002050b5c8d9cb31a4bb90ddeeafb25 100644
--- a/3rdp/build/cl-posix-me-gently.patch
+++ b/3rdp/build/cl-posix-me-gently.patch
@@ -1,11 +1,11 @@
---- ../tmp2/crypt.h	2019-01-31 14:52:00.000000000 -0500
-+++ crypt.h	2019-06-03 16:26:35.672044000 -0400
-@@ -79,7 +79,7 @@
+--- misc/os_spec.h.orig	2023-12-31 06:48:03.815555000 -0500
++++ misc/os_spec.h	2023-12-31 06:48:27.417919000 -0500
+@@ -103,7 +103,7 @@
  #ifndef _POSIX_C_SOURCE 
    #if defined( __xlc__ ) || defined( __IBMC__ )
  	#define _POSIX_C_SOURCE			200112L		/* Posix 2001 */
 -  #elif defined( __GNUC__ )
-+  #elif defined( __GNUC__ ) && defined( __linux__ )
++  #elif defined( __GNUC__ ) && defined(__linux__)
  	#define _POSIX_C_SOURCE			200809L		/* Posix 2008 */
  	#define _DEFAULT_SOURCE			1			/* See note above */
  	#define _BSD_SOURCE				1			/* Undo breakage */
diff --git a/3rdp/build/cl-prefer-ECC-harder.patch b/3rdp/build/cl-prefer-ECC-harder.patch
index 4d44f5e439618aa39f390b7fb5fcc84b954a68b5..51ac35a7f1ef8e7723b2a975e50580e9f108f818 100644
--- a/3rdp/build/cl-prefer-ECC-harder.patch
+++ b/3rdp/build/cl-prefer-ECC-harder.patch
@@ -1,8 +1,8 @@
---- session/ssl_suites.c.orig	2020-01-23 14:12:41.131472000 -0500
-+++ session/ssl_suites.c	2020-01-23 14:12:59.980267000 -0500
-@@ -357,12 +357,12 @@
- static const CIPHERSUITES_LIST cipherSuitesList[] = {
- 	{ cipherSuitePSK, FAILSAFE_ARRAYSIZE( cipherSuitePSK, CIPHERSUITE_INFO ) },
+--- session/tls_suites.c.orig	2023-02-28 02:55:06.000000000 -0500
++++ session/tls_suites.c	2023-12-31 07:30:02.368446000 -0500
+@@ -414,12 +414,12 @@
+ 
+ 	/* ECC suites if these are preferred */
  #ifdef PREFER_ECC
 -  #ifdef USE_GCM
 -	{ cipherSuiteGCM, FAILSAFE_ARRAYSIZE( cipherSuiteGCM, CIPHERSUITE_INFO ) },
@@ -13,6 +13,6 @@
 +  #ifdef USE_GCM
 +	{ cipherSuiteGCM, FAILSAFE_ARRAYSIZE( cipherSuiteGCM, CIPHERSUITE_INFO ) },
 +  #endif /* USE_GCM */
- #endif /* PREFER_ECC */
- 	{ cipherSuiteDH, FAILSAFE_ARRAYSIZE( cipherSuiteDH, CIPHERSUITE_INFO ) },
- #ifdef USE_RSA_SUITES 
+   #ifdef USE_CHACHA20
+ 	{ cipherSuiteBernstein, FAILSAFE_ARRAYSIZE( cipherSuiteBernstein, CIPHERSUITE_INFO ) },
+   #endif /* USE_CHACH20 */
diff --git a/3rdp/build/cl-pthread_yield.patch b/3rdp/build/cl-pthread_yield.patch
deleted file mode 100644
index 50b889858b1961c2f3ee3d0cf14ec19828cac096..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-pthread_yield.patch
+++ /dev/null
@@ -1,14 +0,0 @@
---- kernel/thread.h.orig	2023-12-13 12:08:02.174014000 -0500
-+++ kernel/thread.h	2023-12-13 12:08:24.634971000 -0500
-@@ -3013,10 +3013,7 @@
- 	 underlying process context should yield the associated thread */
-   #define THREAD_YIELD()		yield()
- #else
--  #if defined( __linux__ ) && !defined( __USE_GNU )
--	void pthread_yield( void );
--  #endif /* Present but not prototyped unless GNU extensions are enabled */
--  #define  THREAD_YIELD()		pthread_yield()
-+  #define  THREAD_YIELD()		sched_yield()
- #endif /* Not-very-portable Posix portability */
- #define THREAD_SLEEP( ms )		{ \
- 								struct timeval tv = { 0 }; \
diff --git a/3rdp/build/cl-random-openbsd.patch b/3rdp/build/cl-random-openbsd.patch
deleted file mode 100644
index 05c0c97a2e80e2b4f8b150e633759bd71f97207c..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-random-openbsd.patch
+++ /dev/null
@@ -1,35 +0,0 @@
---- random/unix.c.orig	2021-03-15 18:02:42.743073000 -0400
-+++ random/unix.c	2021-03-15 18:04:17.393934000 -0400
-@@ -398,7 +398,7 @@
-   #include <net/route.h>			/* For CTL_NET:AF_ROUTE:0:AF_INET:\
- 									   NET_RT_FLAGS idents */
-   #include <sys/gmon.h>				/* For CTL_KERN:KERN_PROF identifiers */
--  #if defined( __NetBSD__ )
-+  #if defined( __NetBSD__ ) || defined( __OpenBSD__ )
- 	#include <uvm/uvm_param.h>		/* For CTL_VM identifiers */
-   #else
- 	#include <vm/vm_param.h>		/* For CTL_VM identifiers */
-@@ -414,7 +414,9 @@
- static const SYSCTL_INFO sysctlInfo[] = {
- 	/* Hardware info */
- 	{ 2, { CTL_HW, HW_MACHINE } },	/* Machine class */
-+#ifdef HW_MACHINE_ARCH
- 	{ 2, { CTL_HW, HW_MACHINE_ARCH } }, /* Machine architecture */
-+#endif
- 	{ 2, { CTL_HW, HW_MODEL } },	/* Machine model */
- #ifdef HW_IOSTATS
- 	{ 2, { CTL_HW, HW_IOSTATS } },	/* struct io_sysctl for each device 
-@@ -517,11 +519,13 @@
- 									/* Terminal chars sent/received */
- #endif /* KERN_TKSTAT */
- 	{ 2, { CTL_KERN, KERN_VERSION } }, /* System version string  */
-+#ifdef KERN_VNODE
- 	{ 2, { CTL_KERN, KERN_VNODE }, 15 }, 
- 									/* struct xvnode for each vnode, see 
- 									   /sys/sys/vnode.h.  Produces a huge 
- 									   amount of output so typically gets
- 									   truncated at SYSCTL_BUFFER_SIZE */
-+#endif
- 
- 	/* Networking info */
- 	{ 6, { CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0 }, 5 },
diff --git a/3rdp/build/cl-read-timeout-every-time.patch b/3rdp/build/cl-read-timeout-every-time.patch
new file mode 100644
index 0000000000000000000000000000000000000000..09243ae3ddda557d4314555c77604255c412380d
--- /dev/null
+++ b/3rdp/build/cl-read-timeout-every-time.patch
@@ -0,0 +1,50 @@
+--- ./session/sess_rd.c.orig	2024-01-14 19:55:23.556519000 -0500
++++ ./session/sess_rd.c	2024-01-14 19:55:55.611225000 -0500
+@@ -884,28 +884,28 @@
+ 		return( status );
+ 		}
+ 
+-	/* Update the stream read timeout to the current user-selected read 
+-	   timeout in case the user has changed the timeout setting.
+-	   
+-	   This isn't perfect in the case of the extremely chatty SSH protocol 
+-	   because what looks like a read to the user can involve several reads 
+-	   and writes under the hood, and what gets used for those is the 
+-	   overall high-level timeout for the operation as a whole, with the 
+-	   hidden internal reads and writes using that as their shared setting.  
+-	   
+-	   For example if the code performs a read and hits an SSH channel 
+-	   command it has to send back a response, leading possibly to further 
+-	   reads and writes, before it can actually read any data.  So the top-
+-	   level read command sets a read timeout and then the much lower-level 
+-	   code ends up in a hidden long exchange with the other side using the
+-	   same timeout that was set for the overall read before the higher-
+-	   level read code gets to complete the actual read */
+-	sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_READTIMEOUT, 
+-			   sessionInfoPtr->readTimeout );
+-
+ 	LOOP_MAX_REV_INITCHECK( dataLength = dataMaxLength, dataLength > 0 )
+ 		{
+ 		int byteCount;
++
++		/* Update the stream read timeout to the current user-selected read 
++		   timeout in case the user has changed the timeout setting.
++	   
++		   This isn't perfect in the case of the extremely chatty SSH protocol 
++		   because what looks like a read to the user can involve several reads 
++		   and writes under the hood, and what gets used for those is the 
++		   overall high-level timeout for the operation as a whole, with the 
++		   hidden internal reads and writes using that as their shared setting.  
++	   
++		   For example if the code performs a read and hits an SSH channel 
++		   command it has to send back a response, leading possibly to further 
++		   reads and writes, before it can actually read any data.  So the top-
++		   level read command sets a read timeout and then the much lower-level 
++		   code ends up in a hidden long exchange with the other side using the
++		   same timeout that was set for the overall read before the higher-
++		   level read code gets to complete the actual read */
++		sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_READTIMEOUT, 
++				   sessionInfoPtr->readTimeout );
+ 
+ 		ENSURES( LOOP_INVARIANT_MAX_REV_XXX( dataLength, 1, dataMaxLength ) );
+ 				 /* dataLength is decremented by the number of bytes read */
diff --git a/3rdp/build/cl-remove-march.patch b/3rdp/build/cl-remove-march.patch
index f22fbac6391897a42acc349ec0621141631fdcda..6908ee0a65ac8b6ffaa15f1fa3bee961db31dea2 100644
--- a/3rdp/build/cl-remove-march.patch
+++ b/3rdp/build/cl-remove-march.patch
@@ -1,11 +1,66 @@
---- tools/ccopts.sh.sbbs	2022-02-25 13:17:06.665485787 +1100
-+++ tools/ccopts.sh	2022-02-25 13:03:43.969689324 +1100
-@@ -591,7 +591,7 @@
+--- tools/ccopts.sh.orig	2023-12-31 08:25:17.141687000 -0500
++++ tools/ccopts.sh	2023-12-31 08:33:58.559121000 -0500
+@@ -1055,34 +1055,35 @@
+ # -march=native.  As a result we have to use the pretty bad -march=x86-64
+ # for most gcc versions, which doesn't even get us native AES support.
  
- if [ "$ARCH" = "i586" ] || [ "$ARCH" = "i686" ] || [ "$ARCH" = "x86_64" ] ; then
- 	if [ "$GCC_VER" -ge 45 ] ; then
--		CCARGS="$CCARGS -march=native -mtune=generic" ;
-+		CCARGS="$CCARGS -mtune=generic" ;
- 		if [ "$ARCH" = "x86_64" ] ; then
- 			CCARGS="$CCARGS -fPIC" ;
- 		fi ;
+-if [ "$ARCH" = "i586" ] || [ "$ARCH" = "i686" ] || [ "$ARCH" = "x86_64" ] ; then
+-	if [ "$COMPILER_VER" -ge 110 ] ; then
+-		if [ $GENERICBUILD -gt 0 ] ; then
+-			echo "  (Enabling lowest-common-denominator build options for cross-platform library)." >&2 ;
+-		else
+-			CCARGS="$CCARGS -march=x86-64-v3" ;
+-		fi
+-	elif [ "$COMPILER_VER" -ge 45 ] ; then
+-		if [ $GENERICBUILD -gt 0 ] ; then
+-			echo "  (Enabling lowest-common-denominator build options for cross-platform library)." >&2 ;
+-		else
+-			CCARGS="$CCARGS -march=x86-64" ;
+-		fi
+-	elif [ "$COMPILER_VER" -ge 30 ] ; then
+-		case $ARCH in
+-			'x86_64')
+-				CCARGS="$CCARGS -march=opteron -fPIC" ;;
+-
+-			'i686')
+-				CCARGS="$CCARGS -march=pentiumpro" ;;
+-
+-			*)
+-				CCARGS="$CCARGS -march=pentium" ;;
+-		esac ;
+-	else
+-		CCARGS="$CCARGS -mcpu=pentium" ;
+-	fi ;
+-fi
++# We can't use the generic target because we use an explcit target for mingw
++#if [ "$ARCH" = "i586" ] || [ "$ARCH" = "i686" ] || [ "$ARCH" = "x86_64" ] ; then
++#	if [ "$COMPILER_VER" -ge 110 ] ; then
++#		if [ $GENERICBUILD -gt 0 ] ; then
++#			echo "  (Enabling lowest-common-denominator build options for cross-platform library)." >&2 ;
++#		else
++#			CCARGS="$CCARGS -march=x86-64-v3" ;
++#		fi
++#	elif [ "$COMPILER_VER" -ge 45 ] ; then
++#		if [ $GENERICBUILD -gt 0 ] ; then
++#			echo "  (Enabling lowest-common-denominator build options for cross-platform library)." >&2 ;
++#		else
++#			CCARGS="$CCARGS -march=x86-64" ;
++#		fi
++#	elif [ "$COMPILER_VER" -ge 30 ] ; then
++#		case $ARCH in
++#			'x86_64')
++#				CCARGS="$CCARGS -march=opteron -fPIC" ;;
++#
++#			'i686')
++#				CCARGS="$CCARGS -march=pentiumpro" ;;
++#
++#			*)
++#				CCARGS="$CCARGS -march=pentium" ;;
++#		esac ;
++#	else
++#		CCARGS="$CCARGS -mcpu=pentium" ;
++#	fi ;
++#fi
+ 
+ # gcc 4.x for 64-bit architectures has an optimiser bug that removes an
+ # empty-list check in cryptlib's list-management code (this has been
diff --git a/3rdp/build/cl-select-fix.patch b/3rdp/build/cl-select-fix.patch
deleted file mode 100644
index 874a3fc905db03a331f1bd7264ce465024e2baf7..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-select-fix.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- io/tcp.c.orig	2018-03-12 13:47:37.385998000 -0400
-+++ io/tcp.c	2018-03-12 13:48:12.696032000 -0400
-@@ -402,7 +402,7 @@
- 		return( status );
- 	LOOP_MED( ( selectIterations = 0, status = SOCKET_ERROR ), \
- 			  isSocketError( status ) && \
--				!checkMonoTimerExpired( &timerInfo ) && \
-+				(selectIterations == 0 || !checkMonoTimerExpired( &timerInfo )) && \
- 				selectIterations < 20, 
- 			  selectIterations++ )
- 		{
diff --git a/3rdp/build/cl-server-term-support.patch b/3rdp/build/cl-server-term-support.patch
index 4d4e62cfc4b6b686b9561b4e3f65eb8c1585eaa0..354af6b22cc576053f3e0f975c26da5af2a2a306 100644
--- a/3rdp/build/cl-server-term-support.patch
+++ b/3rdp/build/cl-server-term-support.patch
@@ -1,5 +1,5 @@
---- session/ssh2_chn.c.orig	2019-02-05 18:18:26.000000000 -0500
-+++ session/ssh2_chn.c	2023-12-24 08:09:36.669204000 -0500
+--- session/ssh2_channel.c.orig	2019-02-05 18:18:26.000000000 -0500
++++ session/ssh2_channel.c	2023-12-24 08:09:36.669204000 -0500
 @@ -59,6 +59,9 @@
  
  	/* Channel extra data.  This contains encoded oddball protocol-specific
@@ -99,64 +99,8 @@
  										 data, dataLength ) );
  		}
  
---- session/ssh.c.orig	2023-12-24 07:59:01.180636000 -0500
-+++ session/ssh.c	2023-12-24 08:11:02.562401000 -0500
-@@ -978,7 +978,10 @@
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_TYPE || \
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG1 || \
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
--			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE );
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL);
- 
- 	if( type == CRYPT_SESSINFO_SSH_OPTIONS )
- 		{
-@@ -993,7 +996,9 @@
- 		}
- 
- 	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
--		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE )
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT)
- 		{
- 		status = getChannelAttribute( sessionInfoPtr, type, data );
- 		}
-@@ -1023,12 +1028,17 @@
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG1 || \
- 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
- 			  type == CRYPT_SESSINFO_SSH_OPTIONS || \
--			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE );
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
-+			  type == CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL);
- 
- 	/* Get the data value if it's an integer parameter */
- 	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
- 		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
--		type == CRYPT_SESSINFO_SSH_OPTIONS)
-+		type == CRYPT_SESSINFO_SSH_OPTIONS || \
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH) 
- 		value = *( ( int * ) data );
- 
- 	/* If we're selecting a channel and there's unwritten data from a
-@@ -1069,7 +1079,9 @@
- 		return( closeChannel( sessionInfoPtr, FALSE ) );
- 		}
- 
--	if( type == CRYPT_SESSINFO_SSH_CHANNEL )
-+	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
-+		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT)
- 		status = setChannelAttribute( sessionInfoPtr, type, value );
- 	else
- 		{
---- session/ssh2_msgc.c.orig	2023-12-24 07:59:00.803690000 -0500
-+++ session/ssh2_msgc.c	2023-12-24 08:12:21.955372000 -0500
+--- session/ssh2_msgcli.c.orig	2023-12-24 07:59:00.803690000 -0500
++++ session/ssh2_msgcli.c	2023-12-24 08:12:21.955372000 -0500
 @@ -553,15 +553,15 @@
  	writeUint32( stream, channelNo );
  	writeString32( stream, "pty-req", 7 );
@@ -176,8 +120,8 @@
  		writeUint32( stream, 48 );		/* 48 x 80 (24 x 80 is so 1970s) */
  	else
  		writeUint32( stream, value);
---- session/ssh2_msgs.c.orig	2019-02-05 18:18:26.000000000 -0500
-+++ session/ssh2_msgs.c	2023-12-24 08:15:19.887857000 -0500
+--- session/ssh2_msgsvr.c.orig	2019-02-05 18:18:26.000000000 -0500
++++ session/ssh2_msgsvr.c	2023-12-24 08:15:19.887857000 -0500
 @@ -655,8 +655,20 @@
  	   problem but just deny the request */
  	switch( requestInfoPtr->requestType )
@@ -275,9 +219,9 @@
  		case CRYPT_SESSINFO_USERNAME:
  		case CRYPT_SESSINFO_PASSWORD:
  		case CRYPT_SESSINFO_SERVER_NAME:
---- kernel/attr_acl.c.orig	2023-12-24 08:27:15.033674000 -0500
-+++ kernel/attr_acl.c	2023-12-24 08:30:04.633826000 -0500
-@@ -3564,6 +3564,49 @@
+--- kernel/attr_acl.c.orig	2023-12-31 08:42:47.250931000 -0500
++++ kernel/attr_acl.c	2023-12-31 08:43:02.362902000 -0500
+@@ -3648,6 +3648,49 @@
  	MKACL_END_SUBACL(), MKACL_END_SUBACL()
  	};
  
@@ -327,7 +271,7 @@
  /* Session attributes */
  
  static const ATTRIBUTE_ACL sessionACL[] = {
-@@ -3774,24 +3817,24 @@
+@@ -3877,24 +3920,24 @@
  		MKPERM_TSP( xWD_xWD ),
  		ROUTE( OBJECT_TYPE_SESSION ), &objectCtxHash ),
  
@@ -335,7 +279,7 @@
 -		CRYPT_SESSINFO_SSH_TERMINAL,
 -		ST_NONE, ST_NONE, ST_SESS_SSH, 
 -		0xffffffff /*MKPERM_SSH_EXT( RWD_RWD )*/,
-+	MKACL_X(	/* SSH client: Read/write */
++	MKACL_ST(	/* SSH client: Read/write */
 +		CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL,
 +		ST_NONE, ST_NONE, ST_SESS_SSH | ST_SESS_SSH_SVR, 
 +		MKPERM_SSH_EXT( RWx_RWx ),
@@ -346,7 +290,7 @@
 -		ST_NONE, ST_NONE, ST_SESS_SSH, 
 -		0xffffffff /*MKPERM_SSH_EXT( RWD_RWD )*/,
 +		subACL_SessinfoSSHChannelTerminal ),
-+	MKACL_X(	/* SSH client: Read/write */
++	MKACL_ST(	/* SSH client: Read/write */
 +		CRYPT_SESSINFO_SSH_CHANNEL_WIDTH,
 +		ST_NONE, ST_NONE, ST_SESS_SSH | ST_SESS_SSH_SVR, 
 +		MKPERM_SSH_EXT( RWx_RWx ),
@@ -357,7 +301,7 @@
 -		ST_NONE, ST_NONE, ST_SESS_SSH, 
 -		0xffffffff /*MKPERM_SSH_EXT( RWD_RWD )*/,
 +		subACL_SessinfoSSHChannelWidth ),
-+	MKACL_X(	/* SSH client: Read/write */
++	MKACL_ST(	/* SSH client: Read/write */
 +		CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT,
 +		ST_NONE, ST_NONE, ST_SESS_SSH | ST_SESS_SSH_SVR, 
 +		MKPERM_SSH_EXT( RWx_RWx ),
@@ -367,12 +311,67 @@
  
  	MKACL_END(), MKACL_END()
  	};
-@@ -4659,7 +4702,7 @@
+@@ -4883,7 +4926,7 @@
  	static_assert( CRYPT_CERTINFO_FIRST_EXTENSION == 2200, "Attribute value" );
  	static_assert( CRYPT_CERTINFO_FIRST_CMS == 2500, "Attribute value" );
- 	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6016, "Attribute value" );
--	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6032, "Attribute value" );
-+	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6035, "Attribute value" );
- 	static_assert( CRYPT_CERTFORMAT_LAST == 12, "Attribute value" );
+ 	static_assert( CRYPT_SESSINFO_FIRST_SPECIFIC == 6017, "Attribute value" );
+-	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6036, "Attribute value" );
++	static_assert( CRYPT_SESSINFO_LAST_SPECIFIC == 6039, "Attribute value" );
+ 	static_assert( CRYPT_CERTFORMAT_LAST == 13, "Attribute value" );
  
  	/* Perform a consistency check on the attribute ACLs.  The ACLs are
+--- ./session/ssh.c.orig	2024-01-07 21:24:52.912681000 -0500
++++ ./session/ssh.c	2024-01-07 21:25:24.857224000 -0500
+@@ -541,6 +541,9 @@
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
+ 			  type == CRYPT_SESSINFO_SSH_OPTIONS || \
++			  type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
++			  type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
++			  type == CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL || \
+ 			  type == CRYPT_SESSINFO_SSH_PREAUTH );
+ #else
+ 	REQUIRES( type == CRYPT_SESSINFO_SSH_PREAUTH );
+@@ -576,7 +579,9 @@
+ 
+ 
+ 	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
+-		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE )
++		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
++		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
++		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT)
+ 		{
+ 		status = getChannelAttribute( sessionInfoPtr, type, data );
+ 		}
+@@ -611,6 +616,9 @@
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
+ 			  type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
+ 			  type == CRYPT_SESSINFO_SSH_OPTIONS || \
++			  type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
++			  type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
++			  type == CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL || \
+ 			  type == CRYPT_SESSINFO_SSH_PREAUTH );
+ #else
+ 	REQUIRES( type == CRYPT_SESSINFO_SSH_PREAUTH );
+@@ -629,7 +637,9 @@
+ 	/* Get the data value if it's an integer parameter */
+ 	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
+ 		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE || \
+-		type == CRYPT_SESSINFO_SSH_OPTIONS )
++		type == CRYPT_SESSINFO_SSH_OPTIONS || \
++		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT || \
++		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH) 
+ 		value = *( ( int * ) data );
+ 
+ 	/* If we're selecting a channel and there's unwritten data from a
+@@ -680,7 +690,9 @@
+ 		return( closeChannel( sessionInfoPtr, FALSE ) );
+ 		}
+ 
+-	if( type == CRYPT_SESSINFO_SSH_CHANNEL )
++	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
++		type == CRYPT_SESSINFO_SSH_CHANNEL_WIDTH || \
++		type == CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT)
+ 		status = setChannelAttribute( sessionInfoPtr, type, value );
+ 	else
+ 		{
diff --git a/3rdp/build/cl-short-client-name.patch b/3rdp/build/cl-short-client-name.patch
deleted file mode 100644
index b2f70bbe6f5fdaf126e4cd1e79eee372025640b9..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-short-client-name.patch
+++ /dev/null
@@ -1,13 +0,0 @@
---- session/ssh.c.orig	2018-03-12 21:28:40.049142000 -0400
-+++ session/ssh.c	2018-03-12 21:28:57.425639000 -0400
-@@ -306,8 +306,8 @@
- 
- 	/* Make sure that we got enough data to work with.  We need at least 
- 	   "SSH-" (ID, size SSH_ID_SIZE) + "x.y-" (protocol version) + "xxxxx" 
--	   (software version/ID, of which the shortest-known is "ConfD") */
--	if( length < SSH_ID_SIZE + 9 || length > SSH_ID_MAX_SIZE )
-+	   (software version/ID, of which the shortest-known is "Go") */
-+	if( length < SSH_ID_SIZE + 6 || length > SSH_ID_MAX_SIZE )
- 		{
- 		retExt( CRYPT_ERROR_BADDATA,
- 				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
diff --git a/3rdp/build/cl-ssh-incCtr.patch b/3rdp/build/cl-ssh-incCtr.patch
deleted file mode 100644
index 3c0d9b1490d05ad52e599bf6104a6e23a79c56d2..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-ssh-incCtr.patch
+++ /dev/null
@@ -1,26 +0,0 @@
---- session/ssh2_crypt.c.orig	2019-01-21 16:56:04.000000000 -0500
-+++ session/ssh2_crypt.c	2020-02-14 14:15:11.144585000 -0500
-@@ -55,12 +55,12 @@
- 	/* Walk along the counter incrementing each byte if required */
- 	LOOP_MED( i = blockSize - 1, i >= 0, i-- )
- 		{
--		if( ctrPtr[ i ]++ != 0 )
-+		if( ++ctrPtr[ i ] != 0 )
- 			break;
- 		}
- 	ENSURES( LOOP_BOUND_OK );
- 	ENSURES( ctrMSB != ctrPtr[ blockSize - 1 ] );
--	ENSURES( ctrMSB != 0 || ctrMSBnext != ctrPtr[ blockSize - 2 ] );
-+	ENSURES( (ctrPtr[ blockSize - 1 ] != 0 || ctrMSBnext != ctrPtr[ blockSize - 2 ]) );
- 
- 	return( CRYPT_OK );
- 	}
-@@ -388,7 +388,7 @@
- 		memcpy( sshInfo->writeCTR, buffer, sessionInfoPtr->cryptBlocksize );
- 	else
- 		memcpy( sshInfo->readCTR, buffer, sessionInfoPtr->cryptBlocksize );
--	zeroise( buffer, CRYPT_MAX_KEYSIZE );
-+	zeroise( buffer, CRYPT_MAX_HASHSIZE );
- 
- 	return( CRYPT_OK );
- 	}
diff --git a/3rdp/build/cl-ssh-list-ctr-modes.patch b/3rdp/build/cl-ssh-list-ctr-modes.patch
index 930b14d7c522a96869c7ba2957915cd9a131741c..4180bb56d3d2e60cf1135fc7715d0a5de402999d 100644
--- a/3rdp/build/cl-ssh-list-ctr-modes.patch
+++ b/3rdp/build/cl-ssh-list-ctr-modes.patch
@@ -1,6 +1,6 @@
---- session/ssh2.c.orig	2019-01-26 20:39:00.000000000 -0500
-+++ session/ssh2.c	2020-02-14 02:31:35.785792000 -0500
-@@ -851,6 +851,7 @@
+--- ./session/ssh2_algo.c.orig	2024-01-20 16:21:25.993730000 -0500
++++ ./session/ssh2_algo.c	2024-01-20 16:21:59.153489000 -0500
+@@ -837,6 +837,7 @@
  
  		/* Make sure that any required sub-algorithms are available */
  		if( algoStringInfo->subAlgo != CRYPT_ALGO_NONE && \
diff --git a/3rdp/build/cl-ssl-suite-blocksizes.patch b/3rdp/build/cl-ssl-suite-blocksizes.patch
index 2c6599dc71b91ad385928687393080f4e2366f06..c34cb1b519313b555acebd988605c60c147054a9 100644
--- a/3rdp/build/cl-ssl-suite-blocksizes.patch
+++ b/3rdp/build/cl-ssl-suite-blocksizes.patch
@@ -1,47 +1,11 @@
---- session/ssl_suites.c.orig	2020-02-17 15:42:41.411268000 -0500
-+++ session/ssl_suites.c	2020-02-17 16:05:59.563026000 -0500
-@@ -135,7 +135,7 @@
+--- session/tls_suites.c.orig	2023-12-31 07:45:33.902489000 -0500
++++ session/tls_suites.c	2023-12-31 07:49:12.514913000 -0500
+@@ -129,7 +129,7 @@
  	{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 
  	  DESCRIPTION( "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" )
  	  CRYPT_ALGO_ECDH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES,
--	  CRYPT_ALGO_HMAC_SHA2, 0, 32, SHA2MAC_SIZE, 
-+	  CRYPT_ALGO_HMAC_SHA2, 0, 16, SHA2MAC_SIZE, 
- 	  CIPHERSUITE_FLAG_ECC | CIPHERSUITE_FLAG_TLS12 },
- /*	{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 
+-	  CRYPT_ALGO_HMAC_SHA2, 0, 32, SHA2MAC_SIZE, CIPHERSUITE_FLAG_TLS12 },
++	  CRYPT_ALGO_HMAC_SHA2, 0, 16, SHA2MAC_SIZE, CIPHERSUITE_FLAG_TLS12 },
+   #ifdef CONFIG_SUITEB
+ 	{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 
  	  DESCRIPTION( "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" )
-@@ -187,11 +187,11 @@
- 	  CRYPT_ALGO_ECDH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES,
- 	  CRYPT_ALGO_HMAC_SHA2, 0, 16, GCMICV_SIZE, 
- 	  CIPHERSUITE_FLAG_ECC | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 },
--	{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 
-+/*	{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 
- 	  DESCRIPTION( "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" )
- 	  CRYPT_ALGO_ECDH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES,
--	  CRYPT_ALGO_HMAC_SHA2, 48, 16, GCMICV_SIZE, 
--	  CIPHERSUITE_FLAG_ECC | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 },
-+	  CRYPT_ALGO_HMAC_SHA2, 48, 32, GCMICV_SIZE, 
-+	  CIPHERSUITE_FLAG_ECC | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 },*/
- 
- 	/* AES-GCM with DH */
- 	{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
-@@ -200,9 +200,9 @@
- 	  CRYPT_ALGO_HMAC_SHA2, 0, 16, GCMICV_SIZE, 
- 	  CIPHERSUITE_FLAG_DH | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 },
- /*	{ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
--	  DESCRIPTION( "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" )
-+	  DESCRIPTION( "TLS_DHE_RSA_WITH_AES_256_GCM_SHA256" )
- 	  CRYPT_ALGO_DH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES,
--	  CRYPT_ALGO_HMAC_SHA2, 0, 16, GCMICV_SIZE, 
-+	  CRYPT_ALGO_HMAC_SHA2, 0, 32, GCMICV_SIZE, 
- 	  CIPHERSUITE_FLAG_DH | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 }, */
- 
- 	/* AES-GCM with RSA */
-@@ -214,7 +214,7 @@
- /*	{ TLS_RSA_WITH_AES_256_GCM_SHA384,
- 	  DESCRIPTION( "TLS_RSA_WITH_AES_256_GCM_SHA384" )
- 	  CRYPT_ALGO_RSA, CRYPT_ALGO_RSA, CRYPT_ALGO_AES,
--	  CRYPT_ALGO_HMAC_SHA2, 48, 16, GCMICV_SIZE, 
-+	  CRYPT_ALGO_HMAC_SHA2, 48, 32, GCMICV_SIZE, 
- 	  CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 }, */
- 
- 	/* End-of-list marker */
diff --git a/3rdp/build/cl-suites.patch b/3rdp/build/cl-suites.patch
deleted file mode 100644
index afe1b847c04fb249f675d1261cc54b72753d5bd5..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-suites.patch
+++ /dev/null
@@ -1,16 +0,0 @@
---- ./session/ssl_suites.c.orig	2019-07-03 13:16:53.917656000 -0400
-+++ ./session/ssl_suites.c	2019-07-03 13:17:06.390635000 -0400
-@@ -187,11 +187,11 @@
- 	  CRYPT_ALGO_ECDH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES,
- 	  CRYPT_ALGO_HMAC_SHA2, 0, 16, GCMICV_SIZE, 
- 	  CIPHERSUITE_FLAG_ECC | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 },
--	{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 
-+/*	{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 
- 	  DESCRIPTION( "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" )
- 	  CRYPT_ALGO_ECDH, CRYPT_ALGO_RSA, CRYPT_ALGO_AES,
- 	  CRYPT_ALGO_HMAC_SHA2, 48, 16, GCMICV_SIZE, 
--	  CIPHERSUITE_FLAG_ECC | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 },
-+	  CIPHERSUITE_FLAG_ECC | CIPHERSUITE_FLAG_GCM | CIPHERSUITE_FLAG_TLS12 },*/
- 
- 	/* AES-GCM with DH */
- 	{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
diff --git a/3rdp/build/terminal-params.patch b/3rdp/build/cl-terminal-params.patch
similarity index 95%
rename from 3rdp/build/terminal-params.patch
rename to 3rdp/build/cl-terminal-params.patch
index 000fdebcd5a0155f9d7c2728cc10cd1bb4087a43..908ccdcf488152d9ead8ea7484aa3068934dafd9 100644
--- a/3rdp/build/terminal-params.patch
+++ b/3rdp/build/cl-terminal-params.patch
@@ -94,9 +94,9 @@ diff -ur ../tmp2/session/sess_attr.c ./session/sess_attr.c
  		case CRYPT_SESSINFO_USERNAME:
  		case CRYPT_SESSINFO_PASSWORD:
  		case CRYPT_SESSINFO_SERVER_NAME:
-diff -ur ../tmp2/session/ssh2_msgc.c ./session/ssh2_msgc.c
---- ../tmp2/session/ssh2_msgc.c	2021-03-13 02:55:27.112993000 -0500
-+++ ./session/ssh2_msgc.c	2021-03-13 02:56:03.671662000 -0500
+diff -ur ../tmp2/session/ssh2_msgcli.c ./session/ssh2_msgcli.c
+--- ../tmp2/session/ssh2_msgcli.c	2021-03-13 02:55:27.112993000 -0500
++++ ./session/ssh2_msgcli.c	2021-03-13 02:56:03.671662000 -0500
 @@ -448,6 +448,12 @@
  												CHANNEL_WRITE );
  	int packetOffset, status;
diff --git a/3rdp/build/cl-thats-not-asm.patch b/3rdp/build/cl-thats-not-asm.patch
new file mode 100644
index 0000000000000000000000000000000000000000..478a9078ee7e19bb3898448d6b44d86aabd1d8e9
--- /dev/null
+++ b/3rdp/build/cl-thats-not-asm.patch
@@ -0,0 +1,11 @@
+--- bn/bn_lcl.h.orig	2024-01-07 22:16:23.377711000 -0500
++++ bn/bn_lcl.h	2024-01-07 22:16:36.330481000 -0500
+@@ -232,7 +232,7 @@
+ #  define PTR_SIZE_INT size_t
+ # endif                         /* defined(OPENSSL_SYS_VMS) [else] */
+ 
+-# if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) && !defined(PEDANTIC)
++# if !defined(PEDANTIC)
+ 
+ /* The original OpenSSL code has a mass of inline asm to handle 64-bit 
+    multiplies across different architectures, however if the compiler 
diff --git a/3rdp/build/cl-tls-psk-userfix.patch b/3rdp/build/cl-tls-psk-userfix.patch
deleted file mode 100644
index d0bfe6321fad46e3ed92836f48fba6e486a6c085..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-tls-psk-userfix.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- session/ssl_cli.c.orig	2014-08-22 03:20:26.000000000 -0700
-+++ session/ssl_cli.c	2014-08-22 03:20:53.000000000 -0700
-@@ -1342,7 +1342,7 @@
- 										 CRYPT_SESSINFO_PASSWORD );
- 			const ATTRIBUTE_LIST *userNamePtr = \
- 						findSessionInfo( sessionInfoPtr->attributeList,
--										 CRYPT_SESSINFO_PASSWORD );
-+										 CRYPT_SESSINFO_USERNAME );
- 
- 			REQUIRES( passwordPtr != NULL );
- 			REQUIRES( userNamePtr != NULL );
diff --git a/3rdp/build/cl-tpm-linux.patch b/3rdp/build/cl-tpm-linux.patch
deleted file mode 100644
index e6f3d817b4b81469bf0b69bf84b67fe0df37e3b7..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-tpm-linux.patch
+++ /dev/null
@@ -1,25 +0,0 @@
---- ../tmp2/tools/ccopts.sh	2019-03-04 16:32:32.000000000 -0500
-+++ tools/ccopts.sh	2019-06-03 16:30:45.060050000 -0400
-@@ -241,13 +241,15 @@
- 	done
- 
- 	# TPM support
--	for includepath in $TPMPATHS ; do
--		if [ -f $includepath ] ; then
--			echo "TPM interface detected, enabling TPM support." >&2 ;
--			CCARGS="$CCARGS -DHAS_TPM -I"$(dirname $includepath)"" ;
--			break ;
--		fi
--	done
-+	if [ "$(uname -s)" = "Linux" ] ; then
-+		for includepath in $TPMPATHS ; do
-+			if [ -f $includepath ] ; then
-+				echo "TPM interface detected, enabling TPM support." >&2 ;
-+				CCARGS="$CCARGS -DHAS_TPM -I"$(dirname $includepath)"" ;
-+				break ;
-+			fi
-+		done
-+	fi
- 
- 	# /dev/crypto support
- 	for includepath in $DEVCRYPTOPATHS ; do
diff --git a/3rdp/build/cl-uint64_t-redefine.patch b/3rdp/build/cl-uint64_t-redefine.patch
deleted file mode 100644
index e9acb7380936225cb50dbe017ebedfb9a6cc3340..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-uint64_t-redefine.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- crypt/brg_types.h.orig	2021-03-15 17:59:00.031496000 -0400
-+++ crypt/brg_types.h	2021-03-15 17:59:49.685028000 -0400
-@@ -133,7 +133,7 @@
- #    if ULONG_MAX == 18446744073709551615ul
- #      define BRG_UI64
- #      define li_64(h) 0x##h##ul
--	#ifndef _UINT64_T	/* Apple define their own version - pcg */
-+	#if !defined(_UINT64_T) && !defined(_UINT64_T_DEFINED_)	/* Apple define their own version - pcg */
- 	   typedef unsigned long uint64_t;		/* AES-GCM - pcg */
- 	#endif /* !_UINT64_T */
- #    endif
diff --git a/3rdp/build/cl-use-tls-1.3.patch b/3rdp/build/cl-use-tls-1.3.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c5b11bd6bb73c039dbbbd902a1aac5fa64c022ed
--- /dev/null
+++ b/3rdp/build/cl-use-tls-1.3.patch
@@ -0,0 +1,11 @@
+--- misc/config.h.orig	2024-01-14 23:08:30.593591000 -0500
++++ misc/config.h	2024-01-14 23:10:25.859020000 -0500
+@@ -33,6 +33,8 @@
+ #define PREFER_ECC
+ #define USE_SSH_CTR
+ #define CONFIG_NUM_OBJECTS 16384
++#define USE_TLS13
++#define USE_PSS
+ /****************************************************************************
+ *																			*
+ *						Custom Configuration Profiles						*
diff --git a/3rdp/build/cl-vcxproj.patch b/3rdp/build/cl-vcxproj.patch
index 43066f19f8f697e6ba8c8e9722c8d4705c2da0cf..2fe7369bb05b9a0ea33939f72c749430a266e026 100644
--- a/3rdp/build/cl-vcxproj.patch
+++ b/3rdp/build/cl-vcxproj.patch
@@ -1,6 +1,40 @@
---- crypt32.vcxproj.orig	2018-01-03 01:05:54.648617000 -0500
-+++ crypt32.vcxproj	2018-01-03 01:14:08.964397000 -0500
-@@ -109,6 +109,8 @@
+--- crypt32.vcxproj.orig	2023-06-14 23:54:56.000000000 -0400
++++ crypt32.vcxproj	2023-12-31 06:32:59.386199000 -0500
+@@ -208,6 +208,8 @@
+       <ControlFlowGuard>false</ControlFlowGuard>
+       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+       <BasicRuntimeChecks>UninitializedLocalUsageCheck</BasicRuntimeChecks>
++      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
++      <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
+     </ClCompile>
+     <Link>
+       <SubSystem>Windows</SubSystem>
+@@ -216,6 +218,7 @@
+       <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+       <ManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</ManifestFile>
+       <ModuleDefinitionFile>.\crypt32.def</ModuleDefinitionFile>
++      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+       <Profile>false</Profile>
+     </Link>
+   </ItemDefinitionGroup>
+@@ -232,6 +235,8 @@
+       <ControlFlowGuard>false</ControlFlowGuard>
+       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
++      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
++      <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
+     </ClCompile>
+     <Link>
+       <SubSystem>Windows</SubSystem>
+@@ -240,6 +245,7 @@
+       <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+       <ManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</ManifestFile>
+       <ModuleDefinitionFile>.\crypt32.def</ModuleDefinitionFile>
++      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+       <Profile>false</Profile>
+     </Link>
+   </ItemDefinitionGroup>
+@@ -254,6 +260,8 @@
        <SmallerTypeCheck>false</SmallerTypeCheck>
        <AdditionalIncludeDirectories>.\</AdditionalIncludeDirectories>
        <ControlFlowGuard>false</ControlFlowGuard>
@@ -9,16 +43,50 @@
      </ClCompile>
      <Link>
        <SubSystem>Windows</SubSystem>
-@@ -117,6 +119,7 @@
+@@ -262,6 +270,7 @@
        <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
        <ManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</ManifestFile>
-       <ModuleDefinitionFile>.\crypt32.def</ModuleDefinitionFile>
+       <ModuleDefinitionFile>.\crypt32_fuzz.def</ModuleDefinitionFile>
++      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+       <Profile>false</Profile>
+     </Link>
+   </ItemDefinitionGroup>
+@@ -276,6 +285,8 @@
+       <SmallerTypeCheck>false</SmallerTypeCheck>
+       <AdditionalIncludeDirectories>.\</AdditionalIncludeDirectories>
+       <ControlFlowGuard>false</ControlFlowGuard>
++      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
++      <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
+     </ClCompile>
+     <Link>
+       <SubSystem>Windows</SubSystem>
+@@ -284,6 +295,7 @@
+       <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+       <ManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</ManifestFile>
+       <ModuleDefinitionFile>.\crypt32_fuzz.def</ModuleDefinitionFile>
 +      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
        <Profile>false</Profile>
      </Link>
    </ItemDefinitionGroup>
-@@ -131,6 +134,8 @@
-       <SmallerTypeCheck>true</SmallerTypeCheck>
+@@ -300,6 +312,8 @@
+       <ControlFlowGuard>false</ControlFlowGuard>
+       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+       <BasicRuntimeChecks>UninitializedLocalUsageCheck</BasicRuntimeChecks>
++      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
++      <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
+     </ClCompile>
+     <Link>
+       <SubSystem>Windows</SubSystem>
+@@ -309,6 +323,7 @@
+       <ManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</ManifestFile>
+       <ModuleDefinitionFile>
+       </ModuleDefinitionFile>
++      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+       <Profile>false</Profile>
+     </Link>
+     <ResourceCompile>
+@@ -326,6 +341,8 @@
+       <SmallerTypeCheck>false</SmallerTypeCheck>
        <AdditionalIncludeDirectories>.\</AdditionalIncludeDirectories>
        <ControlFlowGuard>false</ControlFlowGuard>
 +      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -26,7 +94,15 @@
      </ClCompile>
      <Link>
        <SubSystem>Windows</SubSystem>
-@@ -160,6 +165,8 @@
+@@ -335,6 +352,7 @@
+       <ManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</ManifestFile>
+       <ModuleDefinitionFile>
+       </ModuleDefinitionFile>
++      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+       <Profile>false</Profile>
+     </Link>
+     <ResourceCompile>
+@@ -355,6 +373,8 @@
        <ExceptionHandling>false</ExceptionHandling>
        <ControlFlowGuard>Guard</ControlFlowGuard>
        <WholeProgramOptimization>true</WholeProgramOptimization>
@@ -35,7 +111,24 @@
      </ClCompile>
      <Link>
        <SubSystem>Windows</SubSystem>
-@@ -187,6 +194,8 @@
+@@ -367,6 +387,7 @@
+       <ModuleDefinitionFile>.\crypt32.def</ModuleDefinitionFile>
+       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+       <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
++      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+     </Link>
+   </ItemDefinitionGroup>
+   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+@@ -383,6 +404,8 @@
+       <ExceptionHandling>false</ExceptionHandling>
+       <ControlFlowGuard>Guard</ControlFlowGuard>
+       <WholeProgramOptimization>true</WholeProgramOptimization>
++      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
++      <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
+     </ClCompile>
+     <Link>
+       <SubSystem>Windows</SubSystem>
+@@ -410,6 +433,8 @@
        <ExceptionHandling>false</ExceptionHandling>
        <StringPooling>true</StringPooling>
        <ControlFlowGuard>Guard</ControlFlowGuard>
@@ -44,7 +137,15 @@
      </ClCompile>
      <Link>
        <SubSystem>Windows</SubSystem>
-@@ -607,4 +616,4 @@
+@@ -422,6 +447,7 @@
+       <ModuleDefinitionFile>
+       </ModuleDefinitionFile>
+       <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
++      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+     </Link>
+     <ResourceCompile>
+       <PreprocessorDefinitions>_WIN64</PreprocessorDefinitions>
+@@ -896,4 +922,4 @@
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
    <ImportGroup Label="ExtensionTargets">
    </ImportGroup>
diff --git a/3rdp/build/cl-vt-lt-2005-always-defined.patch b/3rdp/build/cl-vt-lt-2005-always-defined.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c1263f686f0de83f60de08cfd1916dfd7a744fbe
--- /dev/null
+++ b/3rdp/build/cl-vt-lt-2005-always-defined.patch
@@ -0,0 +1,11 @@
+--- io/file.c.orig	2023-12-31 10:28:41.818647000 -0500
++++ io/file.c	2023-12-31 10:28:56.618717000 -0500
+@@ -5226,7 +5226,7 @@
+ CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
+ static BOOLEAN isSpecialSID( INOUT_PTR SID *pUserSid )
+ 	{
+-#if defined( _MSC_VER ) && VC_LT_2005( _MSC_VER )
++#if VC_LT_2005( _MSC_VER )
+ 	BYTE sidBuffer[ SID_BUFFER_SIZE + 8 ];
+ 	SID *pSid = ( PSID ) sidBuffer;
+ 	SID_IDENTIFIER_AUTHORITY identifierAuthority = SECURITY_NT_AUTHORITY;
diff --git a/3rdp/build/cl-win32-compile.patch b/3rdp/build/cl-win32-compile.patch
deleted file mode 100644
index 823a8705b80197aacadbe062a9334bdb274de285..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-win32-compile.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- test/certs.c.orig	2018-01-03 02:46:59.742613000 -0500
-+++ test/certs.c	2018-01-03 02:47:14.150003000 -0500
-@@ -17,7 +17,7 @@
-   #define _OSSPEC_DEFINED
-   #if !defined( __WIN32__ ) && ( defined( WIN32 ) || defined( _WIN32 ) )
- 	#define __WIN32__
--  #elif !defined( __WIN64__ ) defined( _M_X64 )
-+  #elif !defined( __WIN64__ ) && defined( _M_X64 )
- 	#define __WIN64__
-   #endif /* Win32/Win64 */
-   #define VC_LT_2005( version )		( version < 1400 )
diff --git a/3rdp/build/cl-win32-compile2.patch b/3rdp/build/cl-win32-compile2.patch
deleted file mode 100644
index f90066578d63ad6c464b2e2e866c1f9b01411e8b..0000000000000000000000000000000000000000
--- a/3rdp/build/cl-win32-compile2.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- test/ssh.c.orig	2018-01-03 02:55:55.133827000 -0500
-+++ test/ssh.c	2018-01-03 02:56:03.891978000 -0500
-@@ -17,7 +17,7 @@
-   #define _OSSPEC_DEFINED
-   #if !defined( __WIN32__ ) && ( defined( WIN32 ) || defined( _WIN32 ) )
- 	#define __WIN32__
--  #elif !defined( __WIN64__ ) defined( _M_X64 )
-+  #elif !defined( __WIN64__ ) && defined( _M_X64 )
- 	#define __WIN64__
-   #endif /* Win32/Win64 */
-   #define VC_16BIT( version )		( version <= 800 )
diff --git a/3rdp/build/cl-win32-lean-and-mean.patch b/3rdp/build/cl-win32-lean-and-mean.patch
new file mode 100644
index 0000000000000000000000000000000000000000..517c47a60a3b3475b3d399fcf686571291bcdf54
--- /dev/null
+++ b/3rdp/build/cl-win32-lean-and-mean.patch
@@ -0,0 +1,10 @@
+--- cryptlib.h.orig	2023-12-31 12:30:58.153233000 -0500
++++ cryptlib.h	2023-12-31 12:31:23.642069000 -0500
+@@ -41,6 +41,7 @@
+   #pragma warning( push )
+   #pragma warning( disable: 4255 )	/* No function prototype given */
+   #pragma warning( disable: 4514 )	/* Unreferenced inline function has been removed */
++  #define WIN32_LEAN_AND_MEAN
+   #include <windows.h>
+   #pragma warning( pop )
+ 
diff --git a/3rdp/build/cl-zz-country.patch b/3rdp/build/cl-zz-country.patch
index 1449cc167a0f861432a643abc364f103d6e4a581..b052cb53c2327823b5498d7cf328551f32ab4a26 100644
--- a/3rdp/build/cl-zz-country.patch
+++ b/3rdp/build/cl-zz-country.patch
@@ -1,11 +1,11 @@
 --- cert/dn.c.orig	2018-02-15 01:13:14.949502000 -0500
 +++ cert/dn.c	2018-02-15 01:13:55.474689000 -0500
 @@ -204,7 +204,7 @@
-   /*W*/				   xF|									  xS,
-   /*X*/	0,
-   /*Y*/				xE|											 xT|xU,
--  /*Z*/	xA|									xM|							  xW,
-+  /*Z*/	xA|									xM|							  xW|	   xZ,
+   /*W*/				   xF|									  xS,					   /*W*/
+   /*X*/	0,																			   /*X*/
+   /*Y*/				xE|											 xT,				   /*Y*/
+-  /*Z*/	xA|									xM|							  xW,		   /*Z*/
++  /*Z*/	xA|									xM|							  xW|	   xZ, /*Z*/
+ 	/*	 A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z */
  		0, 0	/* Catch overflows */
  		};
- 	const int cc0 = countryCode[ 0 ] - 'A';
diff --git a/3rdp/dist/cryptlib.zip b/3rdp/dist/cryptlib.zip
index e4e5b02a8c33694a1a0b96748aaed01c1049ec76..8a5c8e0326783bd2b0cb332890043009bc74c654 100644
Binary files a/3rdp/dist/cryptlib.zip and b/3rdp/dist/cryptlib.zip differ
diff --git a/3rdp/win32.release/cryptlib/bin/cl32.dll b/3rdp/win32.release/cryptlib/bin/cl32.dll
index 4c407df722f31a18802ccf3f6bea294923666b8c..bdf5a02c40af988e2054e9e1e4df30b7072e9084 100644
Binary files a/3rdp/win32.release/cryptlib/bin/cl32.dll and b/3rdp/win32.release/cryptlib/bin/cl32.dll differ
diff --git a/3rdp/win32.release/cryptlib/bin/cl32.lib b/3rdp/win32.release/cryptlib/bin/cl32.lib
index 1c705391f977366f840cbc48b72794f1d40a9aac..849abcb0c3f220fd794b2b23e717435d28c7ff82 100644
Binary files a/3rdp/win32.release/cryptlib/bin/cl32.lib and b/3rdp/win32.release/cryptlib/bin/cl32.lib differ
diff --git a/3rdp/win32.release/cryptlib/include/cryptlib.h b/3rdp/win32.release/cryptlib/include/cryptlib.h
index cdb35b5b2eb93f8ec7d511efa3dcdfefe2dd50e5..55f499a56c5303cafe2759800d571de829130515 100644
--- a/3rdp/win32.release/cryptlib/include/cryptlib.h
+++ b/3rdp/win32.release/cryptlib/include/cryptlib.h
@@ -1,7 +1,7 @@
 /****************************************************************************
 *																			*
 *							  cryptlib Header File							*
-*						Copyright Peter Gutmann 1992-2019					*
+*						Copyright Peter Gutmann 1992-2022					*
 *																			*
 ****************************************************************************/
 
@@ -9,13 +9,13 @@
 
 #define _CRYPTLIB_DEFINED
 
-/* The current cryptlib version: 3.4.5 */
+/* The current cryptlib version: 3.4.7 */
 
-#define CRYPTLIB_VERSION	345
+#define CRYPTLIB_VERSION	347
 
 /* Fixup for Windows support.  We need to include windows.h for various types
-   and prototypes needed for DLLs.  In addition wincrypt.h defines some
-   values with the same names as cryptlib ones, so we need to check for this
+   and prototypes needed for DLLs, but this pulls in wincrypt.h which defines 
+   values with the same names as cryptlib ones so we need to check for this
    and issue a warning not to mix cryptlib with CryptoAPI (that's like taking
    a bank vault and making one side out of papier mache).
 
@@ -25,7 +25,7 @@
    if they ignore this convention.  The NOCRYPT doesn't fix this since
    wincrypt.h can be pulled in indirectly and unconditionally, for example
    via winldap.h -> schnlsp.h -> schannel.h -> wincrypt.h.  To fix this, we
-   create a redundant define for CRYPT_MODE_ECB which produces a compile
+   create a redundant define for CRYPT_MODE_ECB that produces a compile
    error if wincrypt.h is included after cryptlib.h.  Since thie will
    conflict with the enum, we have to place it after the CRYPT_MODE_xxx
    enums */
@@ -33,11 +33,17 @@
 #if ( defined( _WINDOWS ) || defined( WIN32 ) || defined( _WIN32 ) || \
 	  defined( __WIN32__ ) || defined( _WIN32_WCE ) ) && \
 	  !defined( _SCCTK ) && !defined( _CVI_ )
-  #ifndef WIN32_LEAN_AND_MEAN
-	#define WIN32_LEAN_AND_MEAN	/* Skip RPC, OLE, Multimedia, etc */
-  #endif /* WIN32_LEAN_AND_MEAN */
   #define NOCRYPT				/* Disable include of wincrypt.h */
+
+  /* The Windows headers are riddled with errors which are turned up at 
+     warning level 4.  To deal with this we disable some of the noisier 
+	 ones */
+  #pragma warning( push )
+  #pragma warning( disable: 4255 )	/* No function prototype given */
+  #pragma warning( disable: 4514 )	/* Unreferenced inline function has been removed */
+  #define WIN32_LEAN_AND_MEAN
   #include <windows.h>
+  #pragma warning( pop )
 
   /* Catch use of CryptoAPI and cryptlib at the same time.  wxWidgets 
      includes wincrypt.h by default so we undefine the conflicting values 
@@ -202,10 +208,11 @@ typedef enum {						/* Algorithms */
 	CRYPT_ALGO_IDEA,				/* IDEA (only used for PGP 2.x) */
 	CRYPT_ALGO_CAST,				/* CAST-128 (only used for OpenPGP) */
 	CRYPT_ALGO_RC2,					/* RC2 (disabled by default, used for PKCS #12) */
-	CRYPT_ALGO_RC4,					/* RC4 (insecure, deprecated) */
+	CRYPT_ALGO_RC4,					/* RC4 (insecure, disabled by default) */
 	CRYPT_ALGO_RESERVED1,			/* Formerly RC5 */
 	CRYPT_ALGO_AES,					/* AES */
 	CRYPT_ALGO_RESERVED2,			/* Formerly Blowfish */
+	CRYPT_ALGO_CHACHA20,			/* ChaCha20 */
 
 	/* Public-key encryption */
 	CRYPT_ALGO_DH = 100,			/* Diffie-Hellman */
@@ -215,11 +222,13 @@ typedef enum {						/* Algorithms */
 	CRYPT_ALGO_RESERVED3,			/* Formerly KEA */
 	CRYPT_ALGO_ECDSA,				/* ECDSA */
 	CRYPT_ALGO_ECDH,				/* ECDH */
+	CRYPT_ALGO_EDDSA,				/* EDDSA */
+	CRYPT_ALGO_25519,				/* X25519/X448 */
 
 	/* Hash algorithms */
 	CRYPT_ALGO_RESERVED4 = 200,		/* Formerly MD2 */
 	CRYPT_ALGO_RESERVED5,			/* Formerly MD4 */
-	CRYPT_ALGO_MD5,					/* MD5 (only used for TLS 1.0/1.1) */
+	CRYPT_ALGO_MD5,					/* MD5 (only used internally for TLS 1.0/1.1) */
 	CRYPT_ALGO_SHA1,				/* SHA/SHA1 */
 	CRYPT_ALGO_RESERVED6,			/* Formerly RIPE-MD 160 */
 	CRYPT_ALGO_SHA2,				/* SHA-256 */
@@ -227,11 +236,12 @@ typedef enum {						/* Algorithms */
 	CRYPT_ALGO_SHAng,				/* Future SHA-nextgen standard */
 
 	/* MACs */
-	CRYPT_ALGO_RESREVED_7 = 300,	/* Formerly HMAC-MD5 */
+	CRYPT_ALGO_RESERVED7 = 300,		/* Formerly HMAC-MD5 */
 	CRYPT_ALGO_HMAC_SHA1,			/* HMAC-SHA */
-	CRYPT_ALGO_RESERVED8,			/* Formerly HMAC-RIPEMD-160 */
+	CRYPT_ALGO_RESERVED8,			/* Formerly HMAC-RIPEMD 160 */
 	CRYPT_ALGO_HMAC_SHA2,			/* HMAC-SHA2 */
-	CRYPT_ALGO_HMAC_SHAng,			/* HMAC-future-SHA-nextgen */
+	CRYPT_ALGO_HMAC_SHAng,			/* HMAC-SHA-nextgen */
+	CRYPT_ALGO_POLY1305,			/* Poly1305 */
 
 #ifdef _CRYPT_DEFINED
 	/* Alongside the usual types we also need a generic secret-key store
@@ -273,8 +283,8 @@ typedef enum {						/* Block cipher modes */
 	CRYPT_MODE_NONE,				/* No encryption mode */
 	CRYPT_MODE_ECB,					/* ECB */
 	CRYPT_MODE_CBC,					/* CBC */
-	CRYPT_MODE_CFB,					/* CFB */
-	CRYPT_MODE_GCM,					/* GCM */
+	CRYPT_MODE_CFB,					/* CFB, needed for PGP */
+	CRYPT_MODE_GCM,					/* GCM, needed for SSH and TLS */
 	CRYPT_MODE_LAST					/* Last possible crypt mode value */
 	} CRYPT_MODE_TYPE;
 
@@ -285,6 +295,17 @@ typedef enum {						/* Block cipher modes */
   #define CRYPT_MODE_ECB	1
 #endif /* Windows other than a cross-development environment */
 
+/* PKC format subtypes */
+
+typedef enum {
+	CRYPT_PKCFORMAT_NONE,			/* No PKC format type */
+	CRYPT_PKCFORMAT_PKCS1,			/* PKCS #1 */
+		CRYPT_PKCFORMAT_DEFAULT = CRYPT_PKCFORMAT_PKCS1,
+	CRYPT_PKCFORMAT_OAEP,			/* RSA-OAEP */
+	CRYPT_PKCFORMAT_PSS,			/* RSA-PSS */
+	CRYPT_PKCFORMAT_LAST			/* Last possible PKC format type */
+	} CRYPT_PKCFORMAT_TYPE;
+
 /* Keyset subtypes */
 
 typedef enum {						/* Keyset types */
@@ -292,15 +313,15 @@ typedef enum {						/* Keyset types */
 	CRYPT_KEYSET_FILE,				/* Generic flat file keyset */
 	CRYPT_KEYSET_HTTP,				/* Web page containing cert/CRL */
 	CRYPT_KEYSET_LDAP,				/* LDAP directory service */
-	CRYPT_KEYSET_ODBC,				/* Generic ODBC interface */
-	CRYPT_KEYSET_DATABASE,			/* Generic RDBMS interface */
-	CRYPT_KEYSET_ODBC_STORE,		/* ODBC certificate store */
-	CRYPT_KEYSET_DATABASE_STORE,	/* Database certificate store */
+	CRYPT_KEYSET_DATABASE,			/* ODBC database interface */
+		CRYPT_KEYSET_ODBC = CRYPT_KEYSET_DATABASE,	/* Backwards compatibility */
+	CRYPT_KEYSET_DATABASE_STORE,		/* ODBC certificate store */
+		CRYPT_KEYSET_ODBC_STORE = CRYPT_KEYSET_DATABASE_STORE,
 	CRYPT_KEYSET_LAST				/* Last possible keyset type */
 
 #ifdef _CRYPT_DEFINED
 	/* Useful defines used internally for range checking */
-	, CRYPT_FIRST_RDBMS = CRYPT_KEYSET_ODBC,
+	, CRYPT_FIRST_RDBMS = CRYPT_KEYSET_DATABASE,
 	CRYPT_LAST_RDBMS = CRYPT_KEYSET_DATABASE_STORE
 #endif /* _CRYPT_DEFINED */
 	} CRYPT_KEYSET_TYPE;
@@ -309,7 +330,7 @@ typedef enum {						/* Keyset types */
 
 typedef enum {						/* Crypto device types */
 	CRYPT_DEVICE_NONE,				/* No crypto device */
-	CRYPT_DEVICE_FORTEZZA,			/* Fortezza card - Placeholder only */
+	CRYPT_DEVICE_TPM,				/* TPM, formerly Fortezza */
 	CRYPT_DEVICE_PKCS11,			/* PKCS #11 crypto token */
 	CRYPT_DEVICE_CRYPTOAPI,			/* Microsoft CryptoAPI */
 	CRYPT_DEVICE_HARDWARE,			/* Generic crypo HW plugin */
@@ -338,9 +359,16 @@ typedef enum {						/* Certificate object types */
 	   certificate-bagging schemes such as cert chains and sequences that
 	   can't be exported in this format and therefore aren't visible to the
 	   user, but that need to be distinguished internally.  The following
-	   types are only visible internally */
+	   types are only visible internally.  
+	   
+	   These types are only used on import where we need to provide a format 
+	   hint alongside the type, so the types below encode both the format, 
+	   for example SET OF Certificate, and the underlying type, certificate 
+	   chain */
 	CRYPT_ICERTTYPE_CMS_CERTSET,	/* CMS SET OF Certificate = cert chain */
-	CRYPT_ICERTTYPE_SSL_CERTCHAIN,	/* SSL certificate chain = cert chain */
+	CRYPT_ICERTTYPE_CMP_CERTSEQUENCE,/* CMP SEQUENCE OF Certificate = cert chain */
+	CRYPT_ICERTTYPE_TLS_CERTCHAIN,	/* TLS certificate chain = cert chain */
+	CRYPT_ICERTTYPE_TLS13_CERTCHAIN,/* TLS 1.3 certificate chain = cert chain */
 	CRYPT_ICERTTYPE_REVINFO,		/* Revocation info/single CRL entry */
 #endif /* _CRYPT_DEFINED */
 	CRYPT_CERTTYPE_LAST				/* Last possible cert.type */
@@ -361,10 +389,11 @@ typedef enum {
 	CRYPT_FORMAT_PGP,				/* PGP format */
 #ifdef _CRYPT_DEFINED
 	/* Alongside the usual types we can also wind up with various protocol-
-	   specific format types such as SSL and SSH.  The following types are
+	   specific format types such as TLS and SSH.  The following types are
 	   only visible internally */
-	CRYPT_IFORMAT_SSL,				/* SSL/TLS format */
+	CRYPT_IFORMAT_TLS,				/* TLS format */
 	CRYPT_IFORMAT_TLS12,			/* TLS 1.2 format */
+	CRYPT_IFORMAT_TLS13,			/* TLS 1.3 format */
 	CRYPT_IFORMAT_SSH,				/* SSH format */
 #endif /* _CRYPT_DEFINED */
 	CRYPT_FORMAT_LAST				/* Last possible format type */
@@ -379,12 +408,14 @@ typedef enum {
 	CRYPT_SESSION_NONE,				/* No session type */
 	CRYPT_SESSION_SSH,				/* SSH */
 	CRYPT_SESSION_SSH_SERVER,		/* SSH server */
-	CRYPT_SESSION_SSL,				/* SSL/TLS */
-		CRYPT_SESSION_TLS = CRYPT_SESSION_SSL,
-	CRYPT_SESSION_SSL_SERVER,		/* SSL/TLS server */
-		CRYPT_SESSION_TLS_SERVER = CRYPT_SESSION_SSL_SERVER,
+	CRYPT_SESSION_TLS,				/* TLS */
+		CRYPT_SESSION_SSL = CRYPT_SESSION_TLS,
+	CRYPT_SESSION_TLS_SERVER,		/* TLS server */
+		CRYPT_SESSION_SSL_SERVER = CRYPT_SESSION_TLS_SERVER,
 	CRYPT_SESSION_RTCS,				/* RTCS */
 	CRYPT_SESSION_RTCS_SERVER,		/* RTCS server */
+	CRYPT_SESSION_SCVP,				/* SCVP */
+	CRYPT_SESSION_SCVP_SERVER,		/* SCVP server */
 	CRYPT_SESSION_OCSP,				/* OCSP */
 	CRYPT_SESSION_OCSP_SERVER,		/* OCSP server */
 	CRYPT_SESSION_TSP,				/* TSP */
@@ -473,17 +504,17 @@ typedef enum {
 	CRYPT_OPTION_INFO_STEPPING,		/* Release stepping */
 
 	/* Encryption options */
-	CRYPT_OPTION_ENCR_ALGO,			/* Conventional ncryption algorithm */
+	CRYPT_OPTION_ENCR_ALGO,			/* Conventional encryption algorithm */
 	CRYPT_OPTION_ENCR_HASH,			/* Hash algorithm */
 	CRYPT_OPTION_ENCR_MAC,			/* MAC algorithm */
 
 	/* PKC options */
 	CRYPT_OPTION_PKC_ALGO,			/* PKC algorithm */
 	CRYPT_OPTION_PKC_KEYSIZE,		/* PKC key size */
+	CRYPT_OPTION_PKC_FORMAT,		/* PKC format */
 
-	/* Placeholder for obsolete options */
-	CRYPT_OPTION_DUMMY1,
-	CRYPT_OPTION_DUMMY2,
+	/* Additional encryption options, replacing an obsolete option */
+	CRYPT_OPTION_ENCR_HASHPARAM,	/* Hash/MAC parameter */
 
 	/* Keying options */
 	CRYPT_OPTION_KEYING_ALGO,		/* Key processing algorithm */
@@ -771,8 +802,16 @@ typedef enum {
 
 	/* 2 5 29 9 subjectDirectoryAttributes */
 	CRYPT_CERTINFO_SUBJECTDIRECTORYATTRIBUTES,
+#ifdef USE_CUSTOM_CONFIG_1
+	CRYPT_CERTINFO_SUBJECTDIR_OBJECTCLASS,	/* objectClass */
+	CRYPT_CERTINFO_SUBJECTDIR_CLEARANCE_POLICY,		/* clearance.policy */
+	CRYPT_CERTINFO_SUBJECTDIR_CLEARANCE_CLASSLIST,	/* clearance.classList */
+	CRYPT_CERTINFO_SUBJECTDIR_CLEARANCE_CATEGORY_POLICY1,	/* clearance.secCategories.category.policy1 */
+	CRYPT_CERTINFO_SUBJECTDIR_CLEARANCE_CATEGORY_POLICY2,	/* clearance.secCategories.category.policy2 */
+#else
 	CRYPT_CERTINFO_SUBJECTDIR_TYPE,			/* attribute.type */
 	CRYPT_CERTINFO_SUBJECTDIR_VALUES,		/* attribute.values */
+#endif /* USE_CUSTOM_CONFIG_1 */
 
 	/* 2 5 29 14 subjectKeyIdentifier */
 	CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
@@ -1084,6 +1123,12 @@ typedef enum {
 	/* 1 2 840 113549 1 9 25 3 randomNonce */
 	CRYPT_CERTINFO_CMS_NONCE,				/* randomNonce */
 
+	/* 1 2 840 113549 1 9 52 cmsAlgorithmProtection */
+	CRYPT_CERTINFO_CMS_ALGORITHMPROTECTION,
+	CRYPT_CERTINFO_CMS_ALGORITHMPROTECTION_HASH,/* Signer hash algorithm */
+	CRYPT_CERTINFO_CMS_ALGORITHMPROTECTION_SIG,	/* Signer sig.algorithm */
+	CRYPT_CERTINFO_CMS_ALGORITHMPROTECTION_MAC,	/* Signer MAC algorithm */
+
 	/* SCEP attributes:
 	   2 16 840 1 113733 1 9 2 messageType
 	   2 16 840 1 113733 1 9 3 pkiStatus
@@ -1189,7 +1234,9 @@ typedef enum {
 	/* Security-related information */
 	CRYPT_SESSINFO_USERNAME,		/* User name */
 	CRYPT_SESSINFO_PASSWORD,		/* Password */
+	CRYPT_SESSINFO_AUTHTOKEN,		/* Authentication token, e.g. TOTP */
 	CRYPT_SESSINFO_PRIVATEKEY,		/* Server/client private key */
+	CRYPT_SESSINFO_PUBLICKEY,		/* Other sides public key */
 	CRYPT_SESSINFO_KEYSET,			/* Certificate store */
 	CRYPT_SESSINFO_AUTHRESPONSE,	/* Session authorisation OK */
 
@@ -1211,17 +1258,21 @@ typedef enum {
 	/* Protocol-specific information */
 	CRYPT_SESSINFO_CMP_REQUESTTYPE,	/* Request type */
 	CRYPT_SESSINFO_CMP_PRIVKEYSET,	/* Private-key keyset */
+	CRYPT_SESSINFO_CMP_OPTIONS,		/* CMP protocol options */
 	CRYPT_SESSINFO_SSH_CHANNEL,		/* SSH current channel */
 	CRYPT_SESSINFO_SSH_CHANNEL_TYPE,/* SSH channel type */
 	CRYPT_SESSINFO_SSH_CHANNEL_ARG1,/* SSH channel argument 1 */
 	CRYPT_SESSINFO_SSH_CHANNEL_ARG2,/* SSH channel argument 2 */
 	CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE,/* SSH channel active */
+	CRYPT_SESSINFO_SSH_PREAUTH,		/* SSH pre-authentication value */
 	CRYPT_SESSINFO_SSH_OPTIONS,		/* SSH protocol options */
-	CRYPT_SESSINFO_SSL_OPTIONS,		/* SSL/TLS protocol options */
-	CRYPT_SESSINFO_SSL_SUBPROTOCOL,	/* SSL/TLS additional sub-protocol */
-	CRYPT_SESSINFO_SSL_WSPROTOCOL,	/* SSL/TLS WebSockets sub-protocol */
-	CRYPT_SESSINFO_SSL_EAPCHALLENGE,/* SSL/TLS EAP challenge */
-	CRYPT_SESSINFO_SSL_EAPKEY,		/* SSL/TLS EAP key */
+	CRYPT_SESSINFO_TLS_OPTIONS,		/* SSL/TLS protocol options */
+		CRYPT_SESSINFO_SSL_OPTIONS = CRYPT_SESSINFO_TLS_OPTIONS,
+	CRYPT_SESSINFO_TLS_SUBPROTOCOL,	/* SSL/TLS additional sub-protocol */
+	CRYPT_SESSINFO_TLS_WSPROTOCOL,	/* SSL/TLS WebSockets sub-protocol */
+	CRYPT_SESSINFO_TLS_EAPCHALLENGE,/* TLS EAP challenge */
+	CRYPT_SESSINFO_TLS_EAPKEY,		/* TLS EAP key */
+	CRYPT_SESSINFO_TLS_EAPDATA,		/* TLS EAP additional data */
 	CRYPT_SESSINFO_TSP_MSGIMPRINT,	/* TSP message imprint */
 
 	/* Terminal attributes */
@@ -1256,19 +1307,29 @@ typedef enum {
 
 	/* The following attributes are only visible internally and are protected
 	   from any external access by the kernel (and for good measure by checks
-	   in other places as well).  The two attributes CRYPT_IATTRIBUTE_KEY_SPKI
-	   and CRYPT_IATTRIBUTE_SPKI are actually the same thing, the difference
-	   is that the former is write-only for contexts and the latter is read-
-	   only for certificates (the former is used when loading a context from
-	   a key contained in a device, where the actual key components aren't
-	   directly available in the context but may be needed in the future for
-	   things like cert requests).  Because a single object can act as both a
-	   context and a cert, having two explicitly different attribute names
-	   makes things less confusing.  In addition, some public-key attributes
-	   have _PARTIAL variants that load the public-key components but don't
-	   initialise the key/move the context into the high state.  This is
-	   used for formats in which public and private-key components are loaded
-	   separately */
+	   in other places as well).  
+	   
+	   The CRYPT_IATTRIBUTE_COMPLETEINIT attribute is used to complete the
+	   initialisation process for system objects like the default user 
+	   object, these are created early on in the boot process but their
+	   initialisation can't be completed at that point because higher-level
+	   functionality that's required to complete the intialisation isn't
+	   available yet, see cryptlib.c for details.
+
+	   The two attributes CRYPT_IATTRIBUTE_KEY_SPKI and CRYPT_IATTRIBUTE_SPKI 
+	   are actually the same thing, the difference is that the former is 
+	   write-only for contexts in low mode (read-only in high mode) and the 
+	   latter is read-only for certificates (the former is used when loading 
+	   a context from a key contained in a device, where the actual key 
+	   components aren't directly available in the context but may be needed 
+	   in the future for things like cert requests).  Because a single object 
+	   can act as both a context and a cert, having two explicitly different 
+	   attribute names makes things less confusing.  
+	   
+	   In addition, some public-key attributes have _PARTIAL variants that 
+	   load the public-key components but don't initialise the key/move the 
+	   context into the high state.  This is used for formats in which 
+	   public and private-key components are loaded separately */
 	, CRYPT_IATTRIBUTE_FIRST = 8000,
 	CRYPT_IATTRIBUTE_TYPE,			/* Object type */
 	CRYPT_IATTRIBUTE_SUBTYPE,		/* Object subtype */
@@ -1277,6 +1338,7 @@ typedef enum {
 	CRYPT_IATTRIBUTE_ACTIONPERMS,	/* Object action permissions */
 	CRYPT_IATTRIBUTE_LOCKED,		/* Object locked for exclusive use */
 	CRYPT_IATTRIBUTE_INITIALISED,	/* Object inited (in high state) */
+	CRYPT_IATTRIBUTE_COMPLETEINIT,	/* Complete init of system objects */
 
 	/* Context internal attributes */
 	CRYPT_IATTRIBUTE_KEYSIZE,		/* Key size (written to non-native ctxs) */
@@ -1287,22 +1349,23 @@ typedef enum {
 	CRYPT_IATTRIBUTE_KEY_SPKI,		/* SubjectPublicKeyInfo */
 	CRYPT_IATTRIBUTE_KEY_PGP,		/* PGP-format public key */
 	CRYPT_IATTRIBUTE_KEY_SSH,		/* SSHv2-format public key */
-	CRYPT_IATTRIBUTE_KEY_SSL,		/* SSL-format public key */
-	CRYPT_IATTRIBUTE_KEY_SSL_EXT,	/* TLS-extended-format public key */
+	CRYPT_IATTRIBUTE_KEY_TLS,		/* TLS-format public key */
+	CRYPT_IATTRIBUTE_KEY_TLS_EXT,	/* TLS-extended-format public key */
 	CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL,/* SubjectPublicKeyInfo w/o trigger */
 	CRYPT_IATTRIBUTE_KEY_PGP_PARTIAL,/* PGP public key w/o trigger */
 	CRYPT_IATTRIBUTE_KEY_DLPPARAM,	/* DLP domain parameters */
 	CRYPT_IATTRIBUTE_KEY_ECCPARAM,	/* ECC domain parameters */
 	CRYPT_IATTRIBUTE_PGPVALIDITY,	/* PGP key validity */
-	CRYPT_IATTRIBUTE_DEVICEOBJECT,	/* Device object handle */
+	CRYPT_IATTRIBUTE_DEVICEOBJECT,	/* Handle for object in device */
 	CRYPT_IATTRIBUTE_DEVICESTORAGEID,/* Storage ID for data in device */
 	CRYPT_IATTRIBUTE_EXISTINGLABEL,	/* Existing label for object in device */
 	CRYPT_IATTRIBUTE_KEYING_ALGO_PARAM,/* Opt.params for C_C_KEYING_ALGO */
 	CRYPT_IATTRIBUTE_KDFPARAMS,		/* Opt.KDF params for generic-secret */
 	CRYPT_IATTRIBUTE_ENCPARAMS,		/* Encryption params for generic-secret */
 	CRYPT_IATTRIBUTE_MACPARAMS,		/* MAC params for generic-secret */
-	CRYPT_IATTRIBUTE_AAD,			/* AAD for authenticated-encr.modes */
-	CRYPT_IATTRIBUTE_ICV,			/* ICV for authenticated-encr.modes */
+	CRYPT_IATTRIBUTE_AAD,			/* AAD for AEAD modes */
+	CRYPT_IATTRIBUTE_ICV,			/* ICV for AEAD modes */
+	CRYPT_IATTRIBUTE_REKEY,			/* Rekey for AEAD modes */
 
 	/* Certificate internal attributes */
 	CRYPT_IATTRIBUTE_SUBJECT,		/* SubjectName */
@@ -1311,8 +1374,7 @@ typedef enum {
 	CRYPT_IATTRIBUTE_HOLDERNAME,	/* Best approximation to cert.owner name */
 	CRYPT_IATTRIBUTE_HOLDERURI,		/* Best approximation to cert.owner URI */
 	CRYPT_IATTRIBUTE_SPKI,			/* Encoded SubjectPublicKeyInfo */
-	CRYPT_IATTRIBUTE_CERTKEYALGO,	/* PKC algo.used for certificate */
-	CRYPT_IATTRIBUTE_CERTHASHALGO,	/* Hash algo.used for certificate */
+	CRYPT_IATTRIBUTE_CERTHASHALGO,	/* Certificate hash algorithm */
 	CRYPT_IATTRIBUTE_CERTCOLLECTION,/* Certs added to cert chain */
 	CRYPT_IATTRIBUTE_CRLENTRY,		/* Individual entry from CRL */
 	CRYPT_IATTRIBUTE_RESPONDERURL,	/* RTCS/OCSP responder name */
@@ -1337,10 +1399,15 @@ typedef enum {
 	CRYPT_IATTRIBUTE_RANDOM_HIPICKET,/* High picket for random data attrs.*/
 	CRYPT_IATTRIBUTE_RANDOM_NONCE,	/* Basic nonce */
 	CRYPT_IATTRIBUTE_TIME,			/* Reliable (hardware-based) time value */
+	CRYPT_IATTRIBUTE_HWSTORAGE,		/* Associated keyset for priv.key data */
+	CRYPT_IATTRIBUTE_COMMITNOTIFY,	/* Commit notification for device data */
+	CRYPT_IATTRIBUTE_RESETNOTIFY,	/* Reset notification for device data */
 
 	/* Envelope internal attributes */
 	CRYPT_IATTRIBUTE_INCLUDESIGCERT,/* Whether to include signing cert(s) */
 	CRYPT_IATTRIBUTE_ATTRONLY,		/* Signed data contains only CMS attrs.*/
+	CRYPT_IATTRIBUTE_ENVFORMAT,		/* Envelope format type */
+	CRYPT_IATTRIBUTE_ENVUSAGE,		/* Envelope usage as content-type */
 
 	/* Keyset internal attributes */
 	CRYPT_IATTRIBUTE_CONFIGDATA,	/* Config information */
@@ -1349,7 +1416,7 @@ typedef enum {
 	CRYPT_IATTRIBUTE_USERINFO,		/* User information */
 	CRYPT_IATTRIBUTE_TRUSTEDCERT,	/* First trusted cert */
 	CRYPT_IATTRIBUTE_TRUSTEDCERT_NEXT,	/* Successive trusted certs */
-	CRYPT_IATTRIBUTE_HWSTORAGE,		/* Associated device for priv.key data */
+	CRYPT_IATTRIBUTE_HWDEVICE,		/* Associated device for priv.key data */
 
 	/* Session internal attributes */
 	CRYPT_IATTRIBUTE_ENC_TIMESTAMP,	/* Encoded TSA timestamp */
@@ -1491,7 +1558,11 @@ typedef enum { CRYPT_CONTENT_NONE, CRYPT_CONTENT_DATA,
 			   CRYPT_CONTENT_AUTHENVDATA, CRYPT_CONTENT_TSTINFO,
 			   CRYPT_CONTENT_SPCINDIRECTDATACONTEXT,
 			   CRYPT_CONTENT_RTCSREQUEST, CRYPT_CONTENT_RTCSRESPONSE,
-			   CRYPT_CONTENT_RTCSRESPONSE_EXT, CRYPT_CONTENT_MRTD, 
+			   CRYPT_CONTENT_RTCSRESPONSE_EXT, 
+			   CRYPT_CONTENT_SCVPCERTVALREQUEST,
+			   CRYPT_CONTENT_SCVPCERTVALRESPONSE, 
+			   CRYPT_CONTENT_SCVPVALPOLREQUEST,
+			   CRYPT_CONTENT_SCVPVALPOLRESPONSE, CRYPT_CONTENT_MRTD, 
 			   CRYPT_CONTENT_LAST
 			 } CRYPT_CONTENT_TYPE;
 
@@ -1540,7 +1611,9 @@ typedef enum {
 	} CRYPT_INTEGRITY_TYPE;
 
 /* The certificate export format type, which defines the format in which a
-   certificate object is exported */
+   certificate object is exported.  For example a basic certificate type can 
+   be exported as a certificate, certificate chain, SET OF certificate, 
+   SEQUENCE OF certificate, or TLS or TLS 1.3 certificate collection */
 
 typedef enum {
 	CRYPT_CERTFORMAT_NONE,			/* No certificate format */
@@ -1553,7 +1626,8 @@ typedef enum {
 #ifdef _CRYPT_DEFINED
 	CRYPT_ICERTFORMAT_CERTSET,		/* SET OF Certificate */
 	CRYPT_ICERTFORMAT_CERTSEQUENCE,	/* SEQUENCE OF Certificate */
-	CRYPT_ICERTFORMAT_SSL_CERTCHAIN,/* SSL certificate chain */
+	CRYPT_ICERTFORMAT_TLS_CERTCHAIN,/* TLS certificate chain */
+	CRYPT_ICERTFORMAT_TLS13_CERTCHAIN,/* TLS 1.3 certificate chain */
 	CRYPT_ICERTFORMAT_DATA,			/* Non-signed object data */
 	CRYPT_ICERTFORMAT_SMIME_CERTIFICATE,/* S/MIME cert.request or cert chain */
 			/* Used as an internal format specifier when the format is 
@@ -1663,26 +1737,36 @@ typedef enum {
 	CRYPT_SUBPROTOCOL_NONE,			/* No sub-protocol type */
 	CRYPT_SUBPROTOCOL_WEBSOCKETS,	/* Websockets */
 	CRYPT_SUBPROTOCOL_EAPTTLS,		/* EAP-TTLS */
+	CRYPT_SUBPROTOCOL_PEAP,			/* PEAP */
 	CRYPT_SUBPROTOCOL_LAST			/* Last possible sub-protocol type */
 	} CRYPT_SUBPROTOCOL_TYPE;
 
-/* SSL/TLS protocol options.  CRYPT_SSLOPTION_MINVER_SSLV3 is the same as 
-   CRYPT_SSLOPTION_NONE since this is the baseline, although it'll never be
+/* CMP protocol options */
+
+#define CRYPT_CMPOPTION_NONE				0x000
+#define CRYPT_CMPOPTION_3GPP				0x001	/* Peer is following 33.310 */
+#ifdef _CRYPT_DEFINED
+#define CRYPT_CMPOPTION_MAX					0x07F	/* Defines for range checking */
+#endif /* _CRYPT_DEFINED */
+
+/* TLS protocol options.  CRYPT_TLSOPTION_MINVER_SSLV3 is the same as 
+   CRYPT_TLSOPTION_NONE since this is the baseline, although it'll never be
    encountered since SSLv3 is disabled */
 
-#define CRYPT_SSLOPTION_NONE				0x000
-#define CRYPT_SSLOPTION_MINVER_SSLV3		0x000	/* Min.protocol version */
-#define CRYPT_SSLOPTION_MINVER_TLS10		0x001
-#define CRYPT_SSLOPTION_MINVER_TLS11		0x002
-#define CRYPT_SSLOPTION_MINVER_TLS12		0x003
-#define CRYPT_SSLOPTION_MINVER_TLS13		0x004
-#define CRYPT_SSLOPTION_MANUAL_CERTCHECK	0x008	/* Require manual cert.verif.*/
-#define CRYPT_SSLOPTION_DISABLE_NAMEVERIFY	0x010	/* Disable cert hostname check */
-#define CRYPT_SSLOPTION_DISABLE_CERTVERIFY	0x020	/* Disable certificate check */
-#define CRYPT_SSLOPTION_SUITEB_128			0x100	/* SuiteB security levels (may */
-#define CRYPT_SSLOPTION_SUITEB_256			0x200	/*  vanish in future releases) */
+#define CRYPT_TLSOPTION_NONE				0x000
+#define CRYPT_TLSOPTION_MINVER_SSLV3		0x000	/* Min.protocol version */
+#define CRYPT_TLSOPTION_MINVER_TLS10		0x001
+#define CRYPT_TLSOPTION_MINVER_TLS11		0x002
+#define CRYPT_TLSOPTION_MINVER_TLS12		0x003
+#define CRYPT_TLSOPTION_MINVER_TLS13		0x004
+#define CRYPT_TLSOPTION_MANUAL_CERTCHECK	0x008	/* Require manual cert.verif.*/
+#define CRYPT_TLSOPTION_DISABLE_NAMEVERIFY	0x010	/* Disable cert hostname check */
+#define CRYPT_TLSOPTION_DISABLE_CERTVERIFY	0x020	/* Disable certificate check */
+#define CRYPT_TLSOPTION_SERVER_SNI			0x040	/* Enable SNI-based key selection */
+#define CRYPT_TLSOPTION_SUITEB_128			0x100	/* SuiteB security levels (will */
+#define CRYPT_TLSOPTION_SUITEB_256			0x200	/*  vanish in future releases) */
 #ifdef _CRYPT_DEFINED
-#define CRYPT_SSLOPTION_MAX					0x7F	/* Defines for range checking */
+#define CRYPT_TLSOPTION_MAX					0x07F	/* Defines for range checking */
 #endif /* _CRYPT_DEFINED */
 
 /* SSH protocol options. */
@@ -1699,18 +1783,24 @@ typedef enum {
 *																			*
 ****************************************************************************/
 
-/* The maximum user key size - 2048 bits */
+/* The maximum user key size - 512 bits */
 
-#define CRYPT_MAX_KEYSIZE		256
+#define CRYPT_MAX_KEYSIZE		64
 
 /* The maximum IV/cipher block size - 256 bits */
 
 #define CRYPT_MAX_IVSIZE		32
 
 /* The maximum public-key component size - 4096 bits, and maximum component
-   size for ECCs - 576 bits (to handle the P521 curve) */
+   size for ECCs - 576 bits (to handle the P521 curve).  This is a bit 
+   complex to set up because it can be overridden via the 
+   CONFIG_PKC_ALLOCSIZE define in order to conserve memory */
 
-#define CRYPT_MAX_PKCSIZE		512
+#ifdef CONFIG_PKC_ALLOCSIZE
+  #define CRYPT_MAX_PKCSIZE		CONFIG_PKC_ALLOCSIZE
+#else
+  #define CRYPT_MAX_PKCSIZE		512
+#endif /* CRYPT_MAX_PKCSIZE */
 #define CRYPT_MAX_PKCSIZE_ECC	72
 
 /* The maximum hash size - 512 bits.  Before 3.4 this was 256 bits, in the 
@@ -1884,6 +1974,8 @@ typedef enum {
 	CRYPT_ECCCURVE_BRAINPOOL_P256, /* Brainpool p256r1 */
 	CRYPT_ECCCURVE_BRAINPOOL_P384, /* Brainpool p384r1 */
 	CRYPT_ECCCURVE_BRAINPOOL_P512, /* Brainpool p512r1 */
+	CRYPT_ECCCURVE_25519,		/* X25519/Ed25519 */
+	CRYPT_ECCCURVE_448,			/* X448/Ed448 */
 	CRYPT_ECCCURVE_LAST			/* Last valid ECC curve type */
 	} CRYPT_ECCCURVE_TYPE;
 
@@ -1997,10 +2089,14 @@ typedef struct {
 
 #define CRYPT_ENVELOPE_RESOURCE	( -50 )	/* Need resource to proceed */
 
-/* Macros to examine return values */
+/* Macros to examine return values.  These may have more complex definitions 
+   via internal headers, so we only define them if they're not already
+   defined */
 
-#define cryptStatusError( status )	( ( status ) < CRYPT_OK )
-#define cryptStatusOK( status )		( ( status ) == CRYPT_OK )
+#ifndef cryptStatusError
+  #define cryptStatusError( status )	( ( status ) < CRYPT_OK )
+  #define cryptStatusOK( status )		( ( status ) == CRYPT_OK )
+#endif /* cryptStatusError */
 
 /****************************************************************************
 *																			*
diff --git a/src/conio/SDL_win32_main.c b/src/conio/SDL_win32_main.c
index fe6f83ab37f0bee1088d84a1a5f93d4add6ce117..42a3860ad98a27a30642e065c32a66d21310bf76 100644
--- a/src/conio/SDL_win32_main.c
+++ b/src/conio/SDL_win32_main.c
@@ -9,6 +9,7 @@
 #include <ctype.h>
 #include <stdlib.h>
 
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <malloc.h>			/* For _alloca() */
 
diff --git a/src/conio/win32cio.c b/src/conio/win32cio.c
index 44a5ed70dfd8883c2a5561acc7a436489faa73aa..eb2e83bba962fc87b075a80cf39e016a9003f2be 100644
--- a/src/conio/win32cio.c
+++ b/src/conio/win32cio.c
@@ -17,6 +17,7 @@
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>	/* INPUT_RECORD, etc. */
 #include <genwrap.h>
 #include <stdio.h>		/* stdin */
diff --git a/src/conio/win32gdi.c b/src/conio/win32gdi.c
index 6687e1137a851122889e902bc4c82c72ead489ad..53dfb9623c80d02dbcb7d829e6b2fdc151b1b8af 100644
--- a/src/conio/win32gdi.c
+++ b/src/conio/win32gdi.c
@@ -1,3 +1,4 @@
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
 #include <math.h>
diff --git a/src/sbbs3/answer.cpp b/src/sbbs3/answer.cpp
index 9420a6548b6b0dd35ccdac6dd4fc45aecffb9c97..8d25637de1ff9d0d216969e96cc5f1a552d15abe 100644
--- a/src/sbbs3/answer.cpp
+++ b/src/sbbs3/answer.cpp
@@ -19,6 +19,8 @@
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
+#include <stddef.h> // size_t for base64.h
+#include "base64.h"
 #include "sbbs.h"
 #include "telnet.h"
 #include "ssl.h"
@@ -39,11 +41,67 @@ sbbs_t::set_authresponse(bool activate_ssh)
 	return true;
 }
 
+static bool
+check_pubkey(scfg_t *cfg, ushort unum, char *pkey, size_t pksz)
+{
+	// 2048 is enough bytes for anyone!
+	// I would absolutely prefer a getline() here. :(
+	char path[MAX_PATH + 1];
+	char keyline[2048 + 1];
+	FILE *sshkeys;
+	char *brkb;
+	char *tok;
+
+	// Obviously not valid...
+	if (pksz < 16)
+		return false;
+	SAFEPRINTF2(path, "%suser/%04d.sshkeys", cfg->data_dir, unum);
+	sshkeys = fopen(path, "rb");
+	if (sshkeys != NULL) {
+		while (fgets(keyline, sizeof(keyline), sshkeys) != NULL) {
+			size_t len = strlen(keyline);
+
+			if (keyline[len - 1] != '\n') {
+				// Ignore the rest of the line...
+				while (keyline[len - 1] != '\n') {
+					lprintf(LOG_ERR, "keyline not large enough for key in %s (or missing newline)\n", path);
+					if (fgets(keyline, sizeof(keyline), sshkeys) == NULL)
+						break;
+					len = strlen(keyline);
+				}
+			}
+			else {
+				tok = strtok_r(keyline, " \t", &brkb);
+				if (tok) {
+					tok = strtok_r(NULL, " \t", &brkb);
+					if (tok) {
+						char pk[2048];
+						int pklen;
+						pklen = b64_decode(pk, sizeof(pk), tok, 0);
+						if (pklen != -1) {
+							if ((pksz - 4) == pklen) {
+								if (memcmp(&pkey[4], pk, pklen) == 0) {
+									fclose(sshkeys);
+									return true;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		fclose(sshkeys);
+	}
+	return false;
+}
+
 bool sbbs_t::answer()
 {
 	char	str[MAX_PATH+1],str2[MAX_PATH+1],c;
 	char 	tmp[MAX_PATH];
 	char 	*ctmp;
+	char 	*pubkey;
+	size_t  pubkeysz;
 	char 	path[MAX_PATH+1];
 	int		i,l,in;
 	struct tm tm;
@@ -218,6 +276,9 @@ bool sbbs_t::answer()
 					SAFECOPY(tmp, ctmp);
 					free_crypt_attrstr(ctmp);
 				}
+				else {
+					pubkey = get_binary_crypt_attribute(ssh_session, CRYPT_SESSINFO_PUBLICKEY, &pubkeysz);
+				}
 				lprintf(LOG_DEBUG,"SSH login: '%s'", rlogin_name);
 			}
 			else {
@@ -226,21 +287,33 @@ bool sbbs_t::answer()
 			}
 			useron.number = find_login_id(&cfg, rlogin_name);
 			if(useron.number) {
-				getuserdat(&cfg,&useron);
-				if (stricmp(tmp, useron.pass) == 0) {
-					SAFECOPY(rlogin_pass, tmp);
-					activate_ssh = set_authresponse(true);
+				if (getuserdat(&cfg,&useron) == 0) {
+					if (pubkey) {
+						if (check_pubkey(&cfg, useron.number, pubkey, pubkeysz)) {
+							SAFECOPY(rlogin_pass, tmp);
+							activate_ssh = set_authresponse(true);
+						}
+					}
+					else {
+						if (stricmp(tmp, useron.pass) == 0) {
+							SAFECOPY(rlogin_pass, tmp);
+							activate_ssh = set_authresponse(true);
+						}
+						else if(ssh_failed) {
+							if(cfg.sys_misc&SM_ECHO_PW)
+								safe_snprintf(str,sizeof(str),"(%04u)  %-25s  FAILED Password attempt: '%s'"
+									,useron.number,useron.alias,tmp);
+							else
+								safe_snprintf(str,sizeof(str),"(%04u)  %-25s  FAILED Password attempt"
+									,useron.number,useron.alias);
+							logline(LOG_NOTICE,"+!",str);
+							badlogin(useron.alias, tmp);
+							useron.number=0;
+						}
+					}
 				}
-				else if(ssh_failed) {
-					if(cfg.sys_misc&SM_ECHO_PW)
-						safe_snprintf(str,sizeof(str),"(%04u)  %-25s  FAILED Password attempt: '%s'"
-							,useron.number,useron.alias,tmp);
-					else
-						safe_snprintf(str,sizeof(str),"(%04u)  %-25s  FAILED Password attempt"
-							,useron.number,useron.alias);
-					logline(LOG_NOTICE,"+!",str);
-					badlogin(useron.alias, tmp);
-					useron.number=0;
+				else {
+					lprintf(LOG_NOTICE, "SSH failed to read user data for %s", rlogin_name);
 				}
 			}
 			else {
@@ -252,6 +325,10 @@ bool sbbs_t::answer()
 				// Enable SSH so we can create a new user...
 				activate_ssh = set_authresponse(true);
 			}
+			if (pubkey)
+				free_crypt_attrstr(pubkey);
+			if (!activate_ssh)
+				set_authresponse(false);
 		}
 		if (activate_ssh) {
 			int cid;
diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index 308a7829223d8b6efbf075bd96a54b1ec8fc5c71..55892108e23cb9876b7b576c1a6ae521bb328520 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -1163,13 +1163,13 @@ static BOOL start_tls(SOCKET *sock, CRYPT_SESSION *sess, BOOL resp)
 			sockprintf(*sock, *sess, "431 TLS not available");
 		return FALSE;
 	}
-	if ((status = cryptCreateSession(sess, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) {
+	if ((status = cryptCreateSession(sess, CRYPT_UNUSED, CRYPT_SESSION_TLS_SERVER)) != CRYPT_OK) {
 		GCES(status, *sock, CRYPT_UNUSED, estr, "creating session");
 		if (resp)
 			sockprintf(*sock, *sess, "431 TLS not available");
 		return FALSE;
 	}
-	if ((status = cryptSetAttribute(*sess, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
+	if ((status = cryptSetAttribute(*sess, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
 		GCES(status, *sock, *sess, estr, "disabling certificate verification");
 		cryptDestroySession(*sess);
 		*sess = -1;
diff --git a/src/sbbs3/js_socket.c b/src/sbbs3/js_socket.c
index d47867f18f371682a7e3b387b4e45f2c76a7bf6c..e6429e6250c11980af52911f2eeda7b06bd35470 100644
--- a/src/sbbs3/js_socket.c
+++ b/src/sbbs3/js_socket.c
@@ -2349,7 +2349,7 @@ static JSBool js_socket_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict
 					scfg = JS_GetRuntimePrivate(JS_GetRuntime(cx));
 
 					if(ssl_sync(scfg, lprintf)) {
-						if((ret=cryptCreateSession(&p->session, CRYPT_UNUSED, tiny == SOCK_PROP_SSL_SESSION ? CRYPT_SESSION_SSL: CRYPT_SESSION_SSL_SERVER))==CRYPT_OK) {
+						if((ret=cryptCreateSession(&p->session, CRYPT_UNUSED, tiny == SOCK_PROP_SSL_SESSION ? CRYPT_SESSION_TLS: CRYPT_SESSION_TLS_SERVER))==CRYPT_OK) {
 							ulong nb=0;
 							ioctlsocket(p->sock,FIONBIO,&nb);
 							nb=1;
@@ -2359,7 +2359,7 @@ static JSBool js_socket_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict
 								do_cryptAttribute(p->session, CRYPT_OPTION_CERT_COMPLIANCELEVEL, CRYPT_COMPLIANCELEVEL_REDUCED);
 								if (tiny == SOCK_PROP_SSL_SESSION) {
 									// TODO: Make this configurable
-									do_cryptAttribute(p->session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_NAMEVERIFY);
+									do_cryptAttribute(p->session, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_NAMEVERIFY);
 									ret=do_cryptAttributeString(p->session, CRYPT_SESSINFO_SERVER_NAME, p->hostname, strlen(p->hostname));
 									p->tls_server = false;
 								}
diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c
index 123f802ae4c54b3d0c1540f80281b256c6b783da..3e0aeec8d4419f4b5f1367d4e5e6228317aa7ec9 100644
--- a/src/sbbs3/mailsrvr.c
+++ b/src/sbbs3/mailsrvr.c
@@ -1078,11 +1078,11 @@ static bool pop3_client_thread(pop3_t* pop3)
 		if (!do_cryptInit(lprintf)) {
 			return false;
 		}
-		if ((stat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) {
+		if ((stat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_TLS_SERVER)) != CRYPT_OK) {
 			GCESH(stat, client.protocol, socket, host_ip, CRYPT_UNUSED, "creating session");
 			return false;
 		}
-		if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
+		if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
 			cryptDestroySession(session);
 			GCESH(stat, client.protocol, socket, host_ip, session, "disabling certificate verification");
 			return false;
@@ -1192,12 +1192,12 @@ static bool pop3_client_thread(pop3_t* pop3)
 					continue;
 				}
 				sockprintf(socket,client.protocol,session,"+OK Begin TLS negotiation");
-				if ((stat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) {
+				if ((stat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_TLS_SERVER)) != CRYPT_OK) {
 					GCESH(stat, client.protocol, socket, host_ip, CRYPT_UNUSED, "creating session");
 					buf[0] = 0;
 					break;
 				}
-				if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
+				if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
 					cryptDestroySession(session);
 					GCESH(stat, client.protocol, socket, host_ip, session, "disabling certificate verification");
 					buf[0] = 0;
@@ -2970,11 +2970,11 @@ static bool smtp_client_thread(smtp_t* smtp)
 		if (!do_cryptInit(lprintf)) {
 			return false;
 		}
-		if ((cstat = cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) {
+		if ((cstat = cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_TLS_SERVER)) != CRYPT_OK) {
 			GCESH(cstat, client.protocol, socket, host_ip, CRYPT_UNUSED, "creating session");
 			return false;
 		}
-		if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
+		if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
 			cryptDestroySession(session);
 			GCESH(cstat, client.protocol, socket, host_ip, session, "disabling certificate verification");
 			return false;
@@ -4949,12 +4949,12 @@ static bool smtp_client_thread(smtp_t* smtp)
 				sockprintf(socket, client.protocol, session, "454 TLS not available");
 				continue;
 			}
-			if ((cstat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) {
+			if ((cstat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_TLS_SERVER)) != CRYPT_OK) {
 				GCESH(cstat, "SMTPS", socket, host_ip, CRYPT_UNUSED, "creating TLS session");
 				sockprintf(socket, client.protocol, session, "454 TLS not available");
 				continue;
 			}
-			if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
+			if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
 				GCESH(cstat, "SMTPS", socket, host_ip, session, "disabling certificate verification");
 				cryptDestroySession(session);
 				session = -1;
@@ -5373,11 +5373,11 @@ static SOCKET sendmail_negotiate(CRYPT_SESSION *session, smb_t *smb, smbmsg_t *m
 					const char* prot = "SEND/TLS";
 					sockprintf(sock, prot, *session, "STARTTLS");
 					if (sockgetrsp(sock, prot, *session, "220", buf, sizeof(buf))) {
-						if ((status=cryptCreateSession(session, CRYPT_UNUSED, CRYPT_SESSION_SSL)) != CRYPT_OK) {
+						if ((status=cryptCreateSession(session, CRYPT_UNUSED, CRYPT_SESSION_TLS)) != CRYPT_OK) {
 							GCESH(status, prot, sock, server, CRYPT_UNUSED, "creating TLS session");
 							continue;
 						}
-						if ((status=cryptSetAttribute(*session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
+						if ((status=cryptSetAttribute(*session, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
 							cryptDestroySession(*session);
 							*session = -1;
 							GCESH(status, prot, sock, server, *session, "disabling certificate verification");
diff --git a/src/sbbs3/sbbs.version b/src/sbbs3/sbbs.version
index 9527b8a0673d04de56ec6998df3c80ebfba08bc2..8262a0bc5857d86cdf574e5fb9a66faddcdf6ca3 100644
--- a/src/sbbs3/sbbs.version
+++ b/src/sbbs3/sbbs.version
@@ -1,4 +1,3 @@
 SBBS {
 	local: BN_*;  # hide cryptlib BigNum functions, prevent collision with OpenSSL
 };
-
diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index a4679a2db7136acb0f1b149581430395402e4394..29cc542ae99b639ef25095153ac2c9b1f53bd68d 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -1093,7 +1093,7 @@ static void js_service_thread(void* arg)
 	service_client.tls_sess = -1;
 	if (service_client.service->options & SERVICE_OPT_TLS) {
 		/* Create and initialize the TLS session */
-		if (!HANDLE_CRYPT_CALL(cryptCreateSession(&service_client.tls_sess, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER), &service_client, "creating session")) {
+		if (!HANDLE_CRYPT_CALL(cryptCreateSession(&service_client.tls_sess, CRYPT_UNUSED, CRYPT_SESSION_TLS_SERVER), &service_client, "creating session")) {
 			js_service_failure_cleanup(service, socket);
 			return;
 		}
diff --git a/src/sbbs3/ssl.c b/src/sbbs3/ssl.c
index 9a1adba1259818245628e50328ca8b5bc08afec4..3d91f7a1fee5b17245681f35f57041c1a6ae3fad 100644
--- a/src/sbbs3/ssl.c
+++ b/src/sbbs3/ssl.c
@@ -36,7 +36,7 @@ void free_crypt_attrstr(char *attr)
 	free(attr);
 }
 
-char* get_crypt_attribute(CRYPT_HANDLE sess, C_IN CRYPT_ATTRIBUTE_TYPE attr)
+char* get_binary_crypt_attribute(CRYPT_HANDLE sess, C_IN CRYPT_ATTRIBUTE_TYPE attr, size_t *sz)
 {
 	int   len = 0;
 	char *estr = NULL;
@@ -46,17 +46,25 @@ char* get_crypt_attribute(CRYPT_HANDLE sess, C_IN CRYPT_ATTRIBUTE_TYPE attr)
 	if (cryptStatusOK(status)) {
 		estr = malloc(len + 1);
 		if (estr) {
-			if (cryptStatusError(cryptGetAttributeString(sess, attr, estr, &len))) {
-				free(estr);
-				return NULL;
+			if (cryptStatusOK(cryptGetAttributeString(sess, attr, estr, &len))) {
+				if (len >= 0) {
+					estr[len] = 0;
+					if (sz)
+						*sz = len;
+					return estr;
+				}
 			}
-			estr[len] = 0;
-			return estr;
+			free(estr);
 		}
 	}
 	return NULL;
 }
 
+char* get_crypt_attribute(CRYPT_HANDLE sess, C_IN CRYPT_ATTRIBUTE_TYPE attr)
+{
+	return get_binary_crypt_attribute(sess, attr, NULL);
+}
+
 char* get_crypt_error(CRYPT_HANDLE sess)
 {
 	return get_crypt_attribute(sess, CRYPT_ATTRIBUTE_ERRORMESSAGE);
@@ -423,7 +431,7 @@ static struct cert_list * get_ssl_cert(scfg_t *cfg, int (*lprintf)(int level, co
 	}
 	else {
 		/* Couldn't do that... create a new context and use the cert from there... */
-		if(!DO("creating SSL context", CRYPT_UNUSED,cryptCreateContext(&cert_entry->cert, CRYPT_UNUSED, CRYPT_ALGO_RSA))) {
+		if(!DO("creating TLS context", CRYPT_UNUSED,cryptCreateContext(&cert_entry->cert, CRYPT_UNUSED, CRYPT_ALGO_RSA))) {
 			pthread_mutex_unlock(&get_ssl_cert_mutex);
 			free(cert_entry);
 			return NULL;
diff --git a/src/sbbs3/ssl.h b/src/sbbs3/ssl.h
index 15261d58d2d78250da79526c95f2621f91d59631..7b0d47d7c3b28351df9d025c6f3cd644b250a611 100644
--- a/src/sbbs3/ssl.h
+++ b/src/sbbs3/ssl.h
@@ -34,6 +34,7 @@ extern "C" {
 #endif
 
 DLLEXPORT void DLLCALL free_crypt_attrstr(char *attr);
+DLLEXPORT char* DLLCALL get_binary_crypt_attribute(CRYPT_HANDLE sess, C_IN CRYPT_ATTRIBUTE_TYPE attr, size_t *sz);
 DLLEXPORT char* DLLCALL get_crypt_attribute(CRYPT_HANDLE sess, C_IN CRYPT_ATTRIBUTE_TYPE attr);
 DLLEXPORT char* DLLCALL get_crypt_error(CRYPT_HANDLE sess);
 DLLEXPORT bool DLLCALL do_cryptInit(int (*lprintf)(int level, const char* fmt, ...));
diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c
index e0eb6fa8e87cd37bfe8114ce23b7e324c394f901..6298b04d129bc03f0c07cc880170c7e2d8eb005c 100644
--- a/src/sbbs3/websrvr.c
+++ b/src/sbbs3/websrvr.c
@@ -6615,7 +6615,7 @@ void http_session_thread(void* arg)
 	if (session.is_tls) {
 		BOOL looking_good;
 		/* Create and initialize the TLS session */
-		if (!HANDLE_CRYPT_CALL(cryptCreateSession(&session.tls_sess, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER), &session, "creating session")) {
+		if (!HANDLE_CRYPT_CALL(cryptCreateSession(&session.tls_sess, CRYPT_UNUSED, CRYPT_SESSION_TLS_SERVER), &session, "creating session")) {
 			close_session_no_rb(&session);
 			thread_down();
 			return;
@@ -6637,7 +6637,7 @@ void http_session_thread(void* arg)
 
 		looking_good = do_cryptInit(lprintf);
 		if (looking_good)
-			looking_good = HANDLE_CRYPT_CALL(cryptSetAttribute(session.tls_sess, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY), &session, "disabling certificate verification");
+			looking_good = HANDLE_CRYPT_CALL(cryptSetAttribute(session.tls_sess, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_DISABLE_CERTVERIFY), &session, "disabling certificate verification");
 		if (looking_good)
 			looking_good = HANDLE_CRYPT_CALL(add_private_key(&scfg, lprintf, session.tls_sess), &session, "setting private key");
 		if (!looking_good) {
@@ -6650,7 +6650,8 @@ void http_session_thread(void* arg)
 		bool nodelay=true;
 		setsockopt(session.socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
 
-		//HANDLE_CRYPT_CALL(cryptSetAttribute(session.tls_sess, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_MINVER_TLS12), &session, "setting TLS minver to 1.2");
+		if (looking_good)
+			looking_good = HANDLE_CRYPT_CALL(cryptSetAttribute(session.tls_sess, CRYPT_SESSINFO_TLS_OPTIONS, CRYPT_TLSOPTION_MINVER_TLS12), &session, "setting TLS minver to 1.2");
 		if (looking_good)
 			looking_good = HANDLE_CRYPT_CALL(cryptSetAttribute(session.tls_sess, CRYPT_SESSINFO_NETWORKSOCKET, session.socket), &session, "setting network socket");
 		if (looking_good)
diff --git a/src/syncterm/bbslist.c b/src/syncterm/bbslist.c
index 5a9dafad3cbe78a90d6a6b420b04806cd966fc1b..5de046d37907ed8745640de6ada52abe8df342c3 100644
--- a/src/syncterm/bbslist.c
+++ b/src/syncterm/bbslist.c
@@ -784,6 +784,7 @@ read_item(str_list_t listfile, struct bbslist *entry, char *bbsname, int id, int
 	else {
 		entry->has_fingerprint = false;
 	}
+	entry->sftp_public_key = iniGetBool(section, NULL, "SFTPPublicKey", true);
 	iniGetString(section, NULL, "DownloadPath", home, entry->dldir);
 	iniGetString(section, NULL, "UploadPath", home, entry->uldir);
 
@@ -1051,7 +1052,7 @@ get_rip_version(int oldver, int *changed)
 int
 edit_list(struct bbslist **list, struct bbslist *item, char *listpath, int isdefault)
 {
-	char       opt[21][69]; /* 21=Holds number of menu items, 80=Number of columns */
+	char       opt[22][69]; /* 21=Holds number of menu items, 80=Number of columns */
 	char      *opts[(sizeof(opt) / sizeof(opt[0])) + 1];
 	int        changed = 0;
 	int        copt = 0, i, j;
@@ -1137,6 +1138,7 @@ edit_list(struct bbslist **list, struct bbslist *item, char *listpath, int isdef
 		sprintf(opt[i++], "RIP               %s", rip_versions[item->rip]);
 		sprintf(opt[i++], "Force LCF Mode    %s", item->force_lcf ? "Yes" : "No");
 		sprintf(opt[i++], "Yellow is Yellow  %s", item->yellow_is_yellow ? "Yes" : "No");
+		sprintf(opt[i++], "SFTP Public Key   %s", item->sftp_public_key ? "Yes" : "No");
 		opt[i][0] = 0;
 		uifc.changes = 0;
 
@@ -1670,6 +1672,11 @@ edit_list(struct bbslist **list, struct bbslist *item, char *listpath, int isdef
 				changed = 1;
 				iniSetBool(&inifile, itemname, "YellowIsYellow", item->yellow_is_yellow, &ini_style);
 				break;
+			case 20:
+				item->sftp_public_key = !item->sftp_public_key;
+				changed = 1;
+				iniSetBool(&inifile, itemname, "SFTPPublicKey", item->sftp_public_key, &ini_style);
+				break;
 		}
 		if (uifc.changes)
 			changed = 1;
@@ -1733,6 +1740,7 @@ add_bbs(char *listpath, struct bbslist *bbs)
 		}
 		iniSetString(&inifile, bbs->name, "SSHFingerprint", fp, &ini_style);
 	}
+	iniSetBool(&inifile, bbs->name, "SFTPPublicKey", bbs->sftp_public_key, &ini_style);
 	if ((listfile = fopen(listpath, "w")) != NULL) {
 		iniWriteFile(listfile, inifile);
 		fclose(listfile);
diff --git a/src/syncterm/bbslist.h b/src/syncterm/bbslist.h
index 02a7e84b143d01d02aa962a3e051cc09d5c1e7b8..e1c9406e44814c2025dfaa6598571db8b40ce17a 100644
--- a/src/syncterm/bbslist.h
+++ b/src/syncterm/bbslist.h
@@ -142,6 +142,7 @@ struct bbslist {
 	bool               yellow_is_yellow;
 	bool               has_fingerprint;
 	uint8_t            ssh_fingerprint[20];
+	bool               sftp_public_key;
 };
 
 extern char *music_names[];
diff --git a/src/syncterm/ssh.c b/src/syncterm/ssh.c
index 7a91fed4031f1d7371dd6f583d3453ae040c03fd..a854a0f476e16a5f0a6dc577bf7355513530955a 100644
--- a/src/syncterm/ssh.c
+++ b/src/syncterm/ssh.c
@@ -27,9 +27,11 @@ CRYPT_SESSION   ssh_session;
 int             ssh_channel;
 int             ssh_active = true;
 pthread_mutex_t ssh_mutex;
+pthread_mutex_t ssh_tx_mutex;
 int             sftp_channel = -1;
 bool            sftp_active;
 sftpc_state_t   sftp_state;
+bool            pubkey_thread_running;
 
 static void
 FlushData(CRYPT_SESSION sess)
@@ -60,17 +62,17 @@ cryptlib_error_message(int status, const char *msg)
 }
 
 static void
-close_sftp_channel(void)
+close_sftp_channel(int chan)
 {
 	sftpc_state_t oldstate;
 	pthread_mutex_lock(&ssh_mutex);
-	if (sftp_channel != -1) {
+	if (chan != -1) {
 		FlushData(ssh_session);
-		if (cryptStatusOK(cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, sftp_channel))) {
+		if (cryptStatusOK(cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, chan))) {
 			cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 0);
 		}
-		sftp_channel = -1;
 	}
+	sftp_channel = -1;
 	oldstate = sftp_state;
 	sftp_state = NULL;
 	pthread_mutex_unlock(&ssh_mutex);
@@ -106,9 +108,9 @@ check_channel_open(int *chan)
 		if (cryptStatusError(status)) {
 			open = 0;
 		}
-	}
-	if (!open) {
-		cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 0);
+		if (!open) {
+			cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 0);
+		}
 	}
 	return open;
 }
@@ -246,7 +248,7 @@ ssh_input_thread(void *args)
 				 */
 				if (rd > 0 && !sftpc_recv(sftp_state, conn_api.rd_buf, rd)) {
 					pthread_mutex_unlock(&ssh_mutex);
-					close_sftp_channel();
+					close_sftp_channel(sftp_channel);
 					pthread_mutex_lock(&ssh_mutex);
 					FlushData(ssh_session);
 					pthread_mutex_unlock(&ssh_mutex);
@@ -295,6 +297,7 @@ ssh_output_thread(void *args)
 			wr = conn_buf_get(&conn_outbuf, conn_api.wr_buf, conn_api.wr_buf_size);
 			pthread_mutex_unlock(&(conn_outbuf.mutex));
 			sent = 0;
+			pthread_mutex_lock(&ssh_tx_mutex);
 			while (ssh_active && sent < wr) {
 				ret = 0;
 				pthread_mutex_lock(&ssh_mutex);
@@ -320,6 +323,7 @@ ssh_output_thread(void *args)
 				}
 				sent += ret;
 			}
+			pthread_mutex_unlock(&ssh_tx_mutex);
 		}
 		else {
 			pthread_mutex_unlock(&(conn_outbuf.mutex));
@@ -328,7 +332,6 @@ ssh_output_thread(void *args)
 	conn_api.output_thread_running = 2;
 }
 
-#if NOTYET
 static bool
 sftp_send(uint8_t *buf, size_t sz, void *cb_data)
 {
@@ -337,6 +340,7 @@ sftp_send(uint8_t *buf, size_t sz, void *cb_data)
 
 	if (sz == 0)
 		return true;
+	pthread_mutex_lock(&ssh_tx_mutex);
 	while (ssh_active && sent < sz) {
 		int status;
 		int ret = 0;
@@ -359,6 +363,7 @@ sftp_send(uint8_t *buf, size_t sz, void *cb_data)
 		}
 		sent += ret;
 	}
+	pthread_mutex_unlock(&ssh_tx_mutex);
 	return sent == sz;
 }
 
@@ -465,14 +470,28 @@ add_public_key(void *vpriv)
 {
 	int status;
 	int active;
+	int new_sftp_channel = -1;
 	char *priv = vpriv;
 
-	/*
-	 * TODO: We need to wait until the session is established.
-	 *       Best way to do this is a channel property that indicates
-	 *       what type of channel it is.
-	 */
-	SLEEP(1000);
+	// Wait for at most five seconds for channel to be fully active
+	active = 0;
+	for (unsigned sleep_count = 0; sleep_count < 500 && conn_api.terminate == 0; sleep_count++) {
+		pthread_mutex_lock(&ssh_mutex);
+		if (ssh_channel != -1) {
+			status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, ssh_channel);
+			if (cryptStatusOK(status))
+				status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, &active);
+		}
+		pthread_mutex_unlock(&ssh_mutex);
+		if (cryptStatusOK(status) && active)
+			break;
+		SLEEP(10);
+	};
+	if (!active) {
+		pubkey_thread_running = false;
+		return;
+	}
+	pthread_mutex_lock(&ssh_tx_mutex);
 	pthread_mutex_lock(&ssh_mutex);
 	FlushData(ssh_session);
 	status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED);
@@ -490,7 +509,7 @@ add_public_key(void *vpriv)
 				pthread_mutex_unlock(&ssh_mutex);
 				cryptlib_error_message(status, "setting subsystem");
 			} else {
-				status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, &sftp_channel);
+				status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, &new_sftp_channel);
 				if (cryptStatusError(status)) {
 					sftp_channel = -1;
 					pthread_mutex_unlock(&ssh_mutex);
@@ -499,27 +518,73 @@ add_public_key(void *vpriv)
 			}
 		}
 	}
-	if (sftp_channel != -1) {
+	if (new_sftp_channel != -1) {
 		status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_OPEN, &active);
 		if (cryptStatusError(status) || !active) {
 			cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 0);
-			sftp_channel = -1;
 			pthread_mutex_unlock(&ssh_mutex);
+			pthread_mutex_unlock(&ssh_tx_mutex);
 			free(priv);
+			pubkey_thread_running = false;
 			return;
 		}
 		status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 1);
-		if (cryptStatusError(status)) {
+		if (cryptStatusError(status) && status != CRYPT_ENVELOPE_RESOURCE) {
+			pthread_mutex_unlock(&ssh_mutex);
+			pthread_mutex_unlock(&ssh_tx_mutex);
+			close_sftp_channel(new_sftp_channel);
+			free(priv);
+			pubkey_thread_running = false;
+			return;
+		}
+		pthread_mutex_unlock(&ssh_mutex);
+		pthread_mutex_unlock(&ssh_tx_mutex);
+		active = 0;
+		for (unsigned sleep_count = 0; sleep_count < 500 && conn_api.terminate == 0; sleep_count++) {
+			pthread_mutex_lock(&ssh_mutex);
+			status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, new_sftp_channel);
+			if (cryptStatusOK(status))
+				status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, &active);
+			pthread_mutex_unlock(&ssh_mutex);
+			if (cryptStatusOK(status) && active)
+				break;
+			SLEEP(10);
+		}
+		if (!active) {
+			close_sftp_channel(sftp_channel);
+			free(priv);
+			pubkey_thread_running = false;
+			return;
+		}
+		/*
+		 * Old version of Synchronet will accept the channel, then
+		 * immediately close it.  If we then send data on the channel,
+		 * it will get mixed in with the first channels data because
+		 * it doesn't have the channel patches.
+		 * 
+		 * To avoid that, we'll sleep for a second to allow
+		 * the remote to close the channel if it wants to.
+		 */
+		for (unsigned sleep_count = 0; sleep_count < 100 && conn_api.terminate == 0; sleep_count++) {
+			SLEEP(10);
+		}
+		pthread_mutex_lock(&ssh_tx_mutex);
+		pthread_mutex_lock(&ssh_mutex);
+		if (conn_api.terminate || !check_channel_open(&new_sftp_channel)) {
+			pthread_mutex_unlock(&ssh_tx_mutex);
 			pthread_mutex_unlock(&ssh_mutex);
-			close_sftp_channel();
 			free(priv);
+			pubkey_thread_running = false;
 			return;
 		}
+		sftp_channel = new_sftp_channel;
 		sftp_state = sftpc_begin(sftp_send, NULL);
 		pthread_mutex_unlock(&ssh_mutex);
+		pthread_mutex_unlock(&ssh_tx_mutex);
 		if (sftp_state == NULL) {
-			close_sftp_channel();
+			close_sftp_channel(sftp_channel);
 			free(priv);
+			pubkey_thread_running = false;
 			return;
 		}
 		if (sftpc_init(sftp_state)) {
@@ -544,25 +609,14 @@ add_public_key(void *vpriv)
 			pthread_mutex_unlock(&ssh_mutex);
 			sftpc_finish(oldstate);
 		}
-		close_sftp_channel();
+		close_sftp_channel(sftp_channel);
 	}
 	else {
 		pthread_mutex_unlock(&ssh_mutex);
 	}
 	free(priv);
+	pubkey_thread_running = false;
 }
-#else
-static void
-add_public_key(void *vpriv)
-{
-}
-
-static char *
-get_public_key(CRYPT_CONTEXT ctx)
-{
-	return NULL;
-}
-#endif
 
 static void
 error_popup(struct bbslist *bbs, const char *blurb, int status)
@@ -597,6 +651,7 @@ ssh_connect(struct bbslist *bbs)
 	if (!bbs->hidepopups)
 		init_uifc(true, true);
 	pthread_mutex_init(&ssh_mutex, NULL);
+	pthread_mutex_init(&ssh_tx_mutex, NULL);
 
 	if (!crypt_loaded) {
 		if (!bbs->hidepopups) {
@@ -913,7 +968,10 @@ ssh_connect(struct bbslist *bbs)
 
 	_beginthread(ssh_output_thread, 0, NULL);
 	_beginthread(ssh_input_thread, 0, NULL);
-	_beginthread(add_public_key, 0, pubkey);
+	if (bbs->sftp_public_key) {
+		pubkey_thread_running = true;
+		_beginthread(add_public_key, 0, pubkey);
+	}
 
 	if (!bbs->hidepopups)
 		uifc.pop(NULL); // TODO: Why is this called twice?
@@ -927,10 +985,10 @@ ssh_close(void)
 	char garbage[1024];
 
 	conn_api.terminate = 1;
-	close_sftp_channel();
+	close_sftp_channel(sftp_channel);
 	close_ssh_channel();
 	ssh_active = false;
-	while (conn_api.input_thread_running == 1 || conn_api.output_thread_running == 1) {
+	while (conn_api.input_thread_running == 1 || conn_api.output_thread_running == 1 || pubkey_thread_running) {
 		conn_recv_upto(garbage, sizeof(garbage), 0);
 		SLEEP(1);
 	}
diff --git a/src/uifc/uifc32.c b/src/uifc/uifc32.c
index f5a0bf688bb7452ef9a2288fd72bf40c00d7151b..f4d6df1abc8851f172e42ecabeda92e7f8099526 100644
--- a/src/uifc/uifc32.c
+++ b/src/uifc/uifc32.c
@@ -27,6 +27,7 @@
 	#endif
     #define mswait(x) delay(x)
 #elif defined(_WIN32)
+	#define WIN32_LEAN_AND_MEAN
 	#include <share.h>
 	#include <windows.h>
 	#define mswait(x) Sleep(x)
diff --git a/src/xpdev/dirwrap.c b/src/xpdev/dirwrap.c
index a13036614a0164c3c71269b0ba539ca16333d21e..5cdb57222147ec2cf25fb2d17a3dbe043b430b58 100644
--- a/src/xpdev/dirwrap.c
+++ b/src/xpdev/dirwrap.c
@@ -23,6 +23,7 @@
 
 #if defined(_WIN32)
 
+	#define WIN32_LEAN_AND_MEAN
 	#include <windows.h>	/* WINAPI, etc */
 	#include <io.h>			/* _findfirst */
 
diff --git a/src/xpdev/xp_dl.h b/src/xpdev/xp_dl.h
index 70779a662898d26795101ad4b2a1c85d0bf10dcc..30fb2532708351ccbfe095bde137891683e7d22d 100644
--- a/src/xpdev/xp_dl.h
+++ b/src/xpdev/xp_dl.h
@@ -12,7 +12,9 @@
 	#define xp_dlsym(handle, name)				dlsym(handle, #name)
 	#define xp_dlclose(handle)					dlclose(handle)
 #elif defined(_WIN32)
+	#define WIN32_LEAN_AND_MEAN
 	#include <windows.h>
+	#undef WIN32_LEAN_AND_MEAN
 
 	typedef HMODULE dll_handle;
 	DLLEXPORT dll_handle xp_dlopen(const char **name, int mode, int major);
diff --git a/src/xpdev/xpbeep.c b/src/xpdev/xpbeep.c
index 2f4d72091acceec8748b11c0fabc12a5e75971be..7e703df46ec71c75a9ce026f7cd526174e2d3f08 100644
--- a/src/xpdev/xpbeep.c
+++ b/src/xpdev/xpbeep.c
@@ -8,6 +8,7 @@
 #include "xp_dl.h"
 
 #if defined(_WIN32)
+	#define WIN32_LEAN_AND_MEAN
 	#include <windows.h>
 	#include <mmsystem.h>
 #elif defined(__unix__)