Patch: Ciphers, MACs and KexAlgorithms on Match

Armin Wolfermann aw at osn.de
Mon Jun 9 02:15:29 EST 2014


* Darren Tucker <dtucker at zip.com.au> [08.06.2014 16:56]:
> (although I'd call it "Implementation" or some other neutral name so the
> same keyword could be used on both client and server).

I called it "Version" (the RFC calls it softwareversion) and prepared a
rough patch that handles my use case with:

Match Version TrileadSSH2Java_213
  Ciphers aes128-cbc
  MACs hmac-sha1
  KexAlgorithms diffie-hellman-group-exchange-sha1

If there is enough interest I will polish it up and resubmit later.

Index: servconf.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.c,v
retrieving revision 1.249
diff -u -p -u -r1.249 servconf.c
--- servconf.c	29 Jan 2014 06:18:35 -0000	1.249
+++ servconf.c	8 Jun 2014 15:58:36 -0000
@@ -57,6 +57,7 @@ static void add_one_listen_addr(ServerOp
 /* Use of privilege separation or not */
 extern int use_privsep;
 extern Buffer cfg;
+extern char *remote_version_string;
 
 /* Initializes the server options to their default values. */
 
@@ -399,8 +400,8 @@ static struct {
 	{ "denyusers", sDenyUsers, SSHCFG_ALL },
 	{ "allowgroups", sAllowGroups, SSHCFG_ALL },
 	{ "denygroups", sDenyGroups, SSHCFG_ALL },
-	{ "ciphers", sCiphers, SSHCFG_GLOBAL },
-	{ "macs", sMacs, SSHCFG_GLOBAL },
+	{ "ciphers", sCiphers, SSHCFG_ALL },
+	{ "macs", sMacs, SSHCFG_ALL },
 	{ "protocol", sProtocol, SSHCFG_GLOBAL },
 	{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
 	{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
@@ -415,7 +416,7 @@ static struct {
 	{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
 	{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
 	{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL },
-	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
+	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
 	{ "acceptenv", sAcceptEnv, SSHCFG_ALL },
 	{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
 	{ "permittty", sPermitTTY, SSHCFG_ALL },
@@ -427,7 +428,7 @@ static struct {
 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
-	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
+	{ "kexalgorithms", sKexAlgorithms, SSHCFG_ALL },
 	{ "ipqos", sIPQoS, SSHCFG_ALL },
 	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
 	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
@@ -532,6 +533,7 @@ get_connection_info(int populate, int us
 	ci.address = get_remote_ipaddr();
 	ci.laddress = get_local_ipaddr(packet_get_connection_in());
 	ci.lport = get_local_port();
+	ci.version = remote_version_string;
 	return &ci;
 }
 
@@ -612,10 +614,13 @@ match_cfg_line(char **condition, int lin
 		debug3("checking syntax for 'Match %s'", cp);
 	else
 		debug3("checking match for '%s' user %s host %s addr %s "
-		    "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
+		    "laddr %s lport %d version '%s'", cp,
+		    ci->user ? ci->user : "(null)",
 		    ci->host ? ci->host : "(null)",
 		    ci->address ? ci->address : "(null)",
-		    ci->laddress ? ci->laddress : "(null)", ci->lport);
+		    ci->laddress ? ci->laddress : "(null)",
+		    ci->lport,
+		    ci->version ? ci->version : "(null)");
 
 	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
 		attributes++;
@@ -717,6 +722,16 @@ match_cfg_line(char **condition, int lin
 				    ci->laddress, port, line);
 			else
 				result = 0;
+		} else if (strcasecmp(attrib, "version") == 0) {
+			if (ci == NULL || ci->version == NULL) {
+				result = 0;
+				continue;
+			}
+			if (strcasecmp(ci->version, arg) != 0)
+				result = 0;
+			else
+				debug("connection from %.100s matched 'Version "
+				    "%.100s' at line %d", ci->version, arg, line);
 		} else {
 			error("Unsupported Match attribute %s", attrib);
 			return -1;
@@ -1239,7 +1254,7 @@ process_server_config_line(ServerOptions
 		if (!ciphers_valid(arg))
 			fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
 			    filename, linenum, arg ? arg : "<NONE>");
-		if (options->ciphers == NULL)
+		if (*activep && options->ciphers == NULL)
 			options->ciphers = xstrdup(arg);
 		break;
 
@@ -1250,7 +1265,7 @@ process_server_config_line(ServerOptions
 		if (!mac_valid(arg))
 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
 			    filename, linenum, arg ? arg : "<NONE>");
-		if (options->macs == NULL)
+		if (*activep && options->macs == NULL)
 			options->macs = xstrdup(arg);
 		break;
 
@@ -1262,7 +1277,7 @@ process_server_config_line(ServerOptions
 		if (!kex_names_valid(arg))
 			fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
 			    filename, linenum, arg ? arg : "<NONE>");
-		if (options->kex_algorithms == NULL)
+		if (*activep && options->kex_algorithms == NULL)
 			options->kex_algorithms = xstrdup(arg);
 		break;
 
@@ -1663,6 +1678,8 @@ int parse_server_match_testspec(struct c
 				   " specification %s\n", p+6, p);
 				return -1;
 			}
+		} else if (strncmp(p, "version=", 8) == 0) {
+			ci->version = xstrdup(p + 8);
 		} else {
 			fprintf(stderr, "Invalid test mode specification %s\n",
 			   p);
Index: servconf.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.h,v
retrieving revision 1.112
diff -u -p -u -r1.112 servconf.h
--- servconf.h	29 Jan 2014 06:18:35 -0000	1.112
+++ servconf.h	8 Jun 2014 15:58:36 -0000
@@ -190,6 +190,7 @@ struct connection_info {
 	const char *address; 	/* remote address */
 	const char *laddress;	/* local address */
 	int lport;		/* local port */
+	const char *version;	/* remote version string */
 };
 
 
@@ -209,6 +210,9 @@ struct connection_info {
 		M_CP_STROPT(authorized_principals_file); \
 		M_CP_STROPT(authorized_keys_command); \
 		M_CP_STROPT(authorized_keys_command_user); \
+		M_CP_STROPT(ciphers); \
+		M_CP_STROPT(macs); \
+		M_CP_STROPT(kex_algorithms); \
 		M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \
 		M_CP_STRARRAYOPT(allow_users, num_allow_users); \
 		M_CP_STRARRAYOPT(deny_users, num_deny_users); \
Index: sshd.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sshd.c,v
retrieving revision 1.426
diff -u -p -u -r1.426 sshd.c
--- sshd.c	29 Apr 2014 18:01:49 -0000	1.426
+++ sshd.c	8 Jun 2014 15:58:36 -0000
@@ -166,6 +166,7 @@ int num_listen_socks = 0;
  */
 char *client_version_string = NULL;
 char *server_version_string = NULL;
+char *remote_version_string = NULL;
 
 /* for rekeying XXX fixme */
 Kex *xxx_kex;
@@ -460,6 +461,7 @@ sshd_exchange_identification(int sock_in
 		close(sock_out);
 		cleanup_exit(255);
 	}
+	remote_version_string = xstrdup(remote_version);
 	debug("Client protocol version %d.%d; client software version %.100s",
 	    remote_major, remote_minor, remote_version);
 
@@ -1933,6 +1935,10 @@ main(int ac, char **av)
 		alarm(options.login_grace_time);
 
 	sshd_exchange_identification(sock_in, sock_out);
+
+	/* Match configuration against the connection */
+	connection_info = get_connection_info(1, options.use_dns);
+	parse_server_match_config(&options, connection_info);
 
 	/* In inetd mode, generate ephemeral key only for proto 1 connections */
 	if (!compat20 && inetd_flag && sensitive_data.server_key == NULL)


Regards,
Armin Wolfermann


More information about the openssh-unix-dev mailing list