[Patch] TCP MD5SIG for OpenSSH

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



The intent of this option is similar to "tls-auth" in openvpn[1]: To
refuse to talk to anyone who doesn't know the shared secret.

You could compare this to port knocking, in that it solves a similar
problem.

This also prevents RST attacks from killing an existing connection,
even when attacker can sniff sequence numbers.

This feature doesn't work through NAT, since the source and
destination are signed. As IPv6 becomes more and more prevalent it'll
become possible to use this in more and more deployments.

The socket option is enabled *after* connection establishment, thus
doesn't protect against SYN floods. This is because server doesn't
know (in userspace) what the address of the peer is until they
connect. Again because signed addresses.

Setting up:
* Add "TCPMD5 foorbarSecret" to sshd_config
* SSH with "-oTCPMD5=foobarSecret"

Patch attached, but it's an ugly patch for 7.1p. I didn't want to put
too much effort into cleaning up and documenting everything if the
concept itself would rejected outright.

It needs formatting, portability, apply to CVS HEAD, and include file
changes at
least. But it works on Linux as is.

Everything signed from fourth packet:

16:32:40.902764 IP 127.0.0.1.51216 > 127.0.0.1.2222: Flags [S], seq
2342692369, win 43690, options [mss 65495,sackOK,TS val 51101999 ecr
0,nop,wscale 7], length 0

16:32:40.902777 IP 127.0.0.1.2222 > 127.0.0.1.51216: Flags [S.], seq
514139093, ack 2342692370, win 43690, options [mss 65495,sackOK,TS val
51101999 ecr 51101999,nop,wscale 7], length 0

16:32:40.902789 IP 127.0.0.1.51216 > 127.0.0.1.2222: Flags [.], ack 1, win
342, options [nop,nop,TS val 51101999 ecr 51101999], length 0

16:32:40.903480 IP 127.0.0.1.51216 > 127.0.0.1.2222: Flags [P.], seq 1:22,
ack 1, win 342, options [nop,nop,md5shared secret not supplied with -M,
can't check - 2daa171c0c342b041da3cb79ecd1d11b,nop,nop,TS val 51101999 ecr
51101999], length 21

So, how about it? Worth cleaning up?

[1] https://community.openvpn.net/openvpn/wiki/Hardening#Useof--tls-auth


-- 
☢ Thomas ☢
From: Thomas Habets <habets@xxxxxxxxxx>
Date: Wed, 13 Jan 2016 16:31:09 +0000
Subject: [PATCH 1/1] TCP MD5SIG for OpenSSH

The intent of this option is similar to "tls-auth" in openvpn[1]: To
refuse to talk to anyone who doesn't know the shared secret.

You could compare this to port knocking, in that it solves a similar problem.

This also prevents RST attacks from killing an existing connection,
even when attacker can sniff sequence numbers.

The socket option is enabled *after* connection establishment, thus
doesn't protect against SYN floods. This is because server doesn't
know (in userspace) what the address of the peer is until they
connect.

This feature doesn't work through NAT, since the source and
destination are signed. As IPv6 becomes more and more prevalent it'll
become possible to use this in more and more deployments.

Setting up:
* Add "TCPMD5 foorbarSecret" to sshd_config
* SSH with "-oTCPMD5=foobarSecret"

Patch attached, but it's an ugly patch for 7.1p. I didn't want to put
too much effort into cleaning up and documenting everything if the
concept itself would rejected outright.

It needs formatting, portability, and include file changes at
least. But it works on Linux as is.

[1] https://community.openvpn.net/openvpn/wiki/Hardening#Useof--tls-auth


---
 readconf.c   |  9 ++++++++-
 readconf.h   |  1 +
 servconf.c   | 15 ++++++++++++++-
 servconf.h   |  1 +
 sshconnect.c | 25 +++++++++++++++++++++++++
 sshd.c       | 26 ++++++++++++++++++++++++++
 6 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/readconf.c b/readconf.c
index 1d03bdf..5233b95 100644
--- a/readconf.c
+++ b/readconf.c
@@ -143,7 +143,7 @@ typedef enum {
 	oPubkeyAuthentication,
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
-	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
+	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, oTCPMD5,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
@@ -234,6 +234,7 @@ static struct {
 	{ "preferredauthentications", oPreferredAuthentications },
 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
 	{ "bindaddress", oBindAddress },
+        { "tcpmd5", oTCPMD5 },
 #ifdef ENABLE_PKCS11
 	{ "smartcarddevice", oPKCS11Provider },
 	{ "pkcs11provider", oPKCS11Provider },
@@ -1038,6 +1039,10 @@ parse_char_array:
 		charptr = &options->pkcs11_provider;
 		goto parse_string;
 
+	case oTCPMD5:
+		charptr = &options->tcpmd5;
+		goto parse_string;
+
 	case oProxyCommand:
 		charptr = &options->proxy_command;
 parse_command:
@@ -1641,6 +1646,7 @@ initialize_options(Options * options)
 	options->preferred_authentications = NULL;
 	options->bind_address = NULL;
 	options->pkcs11_provider = NULL;
+	options->tcpmd5 = NULL;
 	options->enable_ssh_keysign = - 1;
 	options->no_host_authentication_for_localhost = - 1;
 	options->identities_only = - 1;
@@ -2312,6 +2318,7 @@ dump_client_config(Options *o, const char *host)
 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
 	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
+	dump_cfg_string(oTCPMD5, o->tcpmd5);
 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
 	dump_cfg_string(oProxyCommand, o->proxy_command);
 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
diff --git a/readconf.h b/readconf.h
index bb2d552..41d2b64 100644
--- a/readconf.h
+++ b/readconf.h
@@ -88,6 +88,7 @@ typedef struct {
 	char   *preferred_authentications;
 	char   *bind_address;	/* local socket address for connection to sshd */
 	char   *pkcs11_provider; /* PKCS#11 provider */
+  char *tcpmd5;
 	int	verify_host_key_dns;	/* Verify host key using DNS */
 
 	int     num_identity_files;	/* Number of files for RSA/DSA identities. */
diff --git a/servconf.c b/servconf.c
index 6c7a91e..6da77cb 100644
--- a/servconf.c
+++ b/servconf.c
@@ -149,6 +149,7 @@ initialize_server_options(ServerOptions *options)
 	options->max_authtries = -1;
 	options->max_sessions = -1;
 	options->banner = NULL;
+        options->tcpmd5 = NULL;
 	options->use_dns = -1;
 	options->client_alive_interval = -1;
 	options->client_alive_count_max = -1;
@@ -423,7 +424,7 @@ typedef enum {
 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
 	sAllowStreamLocalForwarding, sFingerprintHash,
-	sDeprecated, sUnsupported
+	sDeprecated, sTCPMD5, sUnsupported
 } ServerOpCodes;
 
 #define SSHCFG_GLOBAL	0x01	/* allowed in main section of sshd_config */
@@ -538,6 +539,7 @@ static struct {
 	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
 	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
 	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
+        { "tcpmd5", sTCPMD5, SSHCFG_GLOBAL},
 	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
 	{ "permittty", sPermitTTY, SSHCFG_ALL },
 	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
@@ -1555,6 +1557,17 @@ process_server_config_line(ServerOptions *options, char *line,
 		charptr = &options->banner;
 		goto parse_filename;
 
+          case sTCPMD5:
+		charptr = &options->tcpmd5;
+
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%s line %d: missing file name.",
+			    filename, linenum);
+		if (*activep && *charptr == NULL)
+			*charptr = xstrdup(arg);
+		break;
+
 	/*
 	 * These options can contain %X options expanded at
 	 * connect time, so that you can specify paths like:
diff --git a/servconf.h b/servconf.h
index f4137af..18295c7 100644
--- a/servconf.h
+++ b/servconf.h
@@ -155,6 +155,7 @@ typedef struct {
 	int	max_authtries;
 	int	max_sessions;
 	char   *banner;			/* SSH-2 banner message */
+  char *tcpmd5;
 	int	use_dns;
 	int	client_alive_interval;	/*
 					 * poke the client this often to
diff --git a/sshconnect.c b/sshconnect.c
index 17fbe39..d13f005 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -42,6 +42,12 @@
 #include <string.h>
 #include <unistd.h>
 
+#include<fcntl.h>
+#include<netinet/in.h>
+#include<netinet/tcp.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+
 #include "xmalloc.h"
 #include "key.h"
 #include "hostfile.h"
@@ -479,6 +485,25 @@ ssh_connect_direct(const char *host, struct addrinfo *aitop,
 			break;	/* Successful connection. */
 	}
 
+        if (sock != -1 && options.tcpmd5) {
+          struct tcp_md5sig md5sig;
+          socklen_t t = sizeof(struct sockaddr_storage);
+
+          memset(&md5sig, 0, sizeof(md5sig));
+          strlcpy(md5sig.tcpm_key, options.tcpmd5, TCP_MD5SIG_MAXKEYLEN);
+
+          if (getpeername(sock,
+                          (struct sockaddr*)&md5sig.tcpm_addr, &t)) {
+            error("getpeername(): %.100s", strerror(errno));
+          }
+          md5sig.tcpm_keylen = strlen(md5sig.tcpm_key);
+          if (-1 == setsockopt(sock,
+                               IPPROTO_TCP, TCP_MD5SIG,
+                               &md5sig, sizeof(md5sig))) {
+            error("setsockopt(TCP_MD5SIG): %.100s", strerror(errno));
+          }
+        }
+
 	/* Return failure if we didn't get a successful connection. */
 	if (sock == -1) {
 		error("ssh: connect to host %s port %s: %s",
diff --git a/sshd.c b/sshd.c
index 65ef7e8..7128527 100644
--- a/sshd.c
+++ b/sshd.c
@@ -85,6 +85,13 @@
 #include <prot.h>
 #endif
 
+#include<fcntl.h>
+#include<netinet/in.h>
+#include<netinet/tcp.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+
+
 #include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
@@ -1310,6 +1317,25 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
 					usleep(100 * 1000);
 				continue;
 			}
+                        if (options.tcpmd5) {
+                          struct tcp_md5sig md5sig;
+                          socklen_t t = sizeof(struct sockaddr_storage);
+
+                          memset(&md5sig, 0, sizeof(md5sig));
+                          strlcpy(md5sig.tcpm_key, options.tcpmd5, TCP_MD5SIG_MAXKEYLEN);
+
+                          if (getpeername(*newsock,
+                                          (struct sockaddr*)&md5sig.tcpm_addr, &t)) {
+                            error("getpeername(): %.100s", strerror(errno));
+                          }
+                          md5sig.tcpm_keylen = strlen(md5sig.tcpm_key);
+                          if (-1 == setsockopt(*newsock,
+                                               IPPROTO_TCP, TCP_MD5SIG,
+                                               &md5sig, sizeof(md5sig))) {
+                            error("setsockopt(TCP_MD5SIG): %.100s", strerror(errno));
+                          }
+                        }
+
 			if (unset_nonblock(*newsock) == -1) {
 				close(*newsock);
 				continue;
-- 
2.6.0.rc2.230.g3dd15c0

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux