xref: /netbsd-src/crypto/external/bsd/openssh/dist/compat.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: compat.c,v 1.18 2018/04/06 18:59:00 christos Exp $	*/
2 /* $OpenBSD: compat.c,v 1.106 2018/02/16 04:43:11 dtucker Exp $ */
3 /*
4  * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "includes.h"
28 __RCSID("$NetBSD: compat.c,v 1.18 2018/04/06 18:59:00 christos Exp $");
29 #include <sys/types.h>
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 
35 #include "xmalloc.h"
36 #include "buffer.h"
37 #include "packet.h"
38 #include "compat.h"
39 #include "log.h"
40 #include "match.h"
41 #include "kex.h"
42 
43 int datafellows = 0;
44 
45 /* datafellows bug compatibility */
46 u_int
47 compat_datafellows(const char *version)
48 {
49 	int i;
50 	static struct {
51 		const char	*pat;
52 		int	bugs;
53 	} check[] = {
54 		{ "OpenSSH_2.*,"
55 		  "OpenSSH_3.0*,"
56 		  "OpenSSH_3.1*",	SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
57 		{ "OpenSSH_3.*",	SSH_OLD_FORWARD_ADDR },
58 		{ "Sun_SSH_1.0*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
59 		{ "OpenSSH_2*,"
60 		  "OpenSSH_3*,"
61 		  "OpenSSH_4*",		0 },
62 		{ "OpenSSH_5*",		SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT},
63 		{ "OpenSSH_6.6.1*",	SSH_NEW_OPENSSH},
64 		{ "OpenSSH_6.5*,"
65 		  "OpenSSH_6.6*",	SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD},
66 		{ "OpenSSH*",		SSH_NEW_OPENSSH },
67 		{ "*MindTerm*",		0 },
68 		{ "3.0.*",		SSH_BUG_DEBUG },
69 		{ "3.0 SecureCRT*",	SSH_OLD_SESSIONID },
70 		{ "1.7 SecureFX*",	SSH_OLD_SESSIONID },
71 		{ "1.2.18*,"
72 		  "1.2.19*,"
73 		  "1.2.20*,"
74 		  "1.2.21*,"
75 		  "1.2.22*",		SSH_BUG_IGNOREMSG },
76 		{ "1.3.2*",		/* F-Secure */
77 					SSH_BUG_IGNOREMSG },
78 		{ "Cisco-1.*",		SSH_BUG_DHGEX_LARGE|
79 					SSH_BUG_HOSTKEYS },
80 		{ "*SSH Compatible Server*",			/* Netscreen */
81 					SSH_BUG_PASSWORDPAD },
82 		{ "*OSU_0*,"
83 		  "OSU_1.0*,"
84 		  "OSU_1.1*,"
85 		  "OSU_1.2*,"
86 		  "OSU_1.3*,"
87 		  "OSU_1.4*,"
88 		  "OSU_1.5alpha1*,"
89 		  "OSU_1.5alpha2*,"
90 		  "OSU_1.5alpha3*",	SSH_BUG_PASSWORDPAD },
91 		{ "*SSH_Version_Mapper*",
92 					SSH_BUG_SCANNER },
93 		{ "PuTTY_Local:*,"	/* dev versions < Sep 2014 */
94 		  "PuTTY-Release-0.5*," /* 0.50-0.57, DH-GEX in >=0.52 */
95 		  "PuTTY_Release_0.5*,"	/* 0.58-0.59 */
96 		  "PuTTY_Release_0.60*,"
97 		  "PuTTY_Release_0.61*,"
98 		  "PuTTY_Release_0.62*,"
99 		  "PuTTY_Release_0.63*,"
100 		  "PuTTY_Release_0.64*",
101 					SSH_OLD_DHGEX },
102 		{ "FuTTY*",		SSH_OLD_DHGEX }, /* Putty Fork */
103 		{ "Probe-*",
104 					SSH_BUG_PROBE },
105 		{ "TeraTerm SSH*,"
106 		  "TTSSH/1.5.*,"
107 		  "TTSSH/2.1*,"
108 		  "TTSSH/2.2*,"
109 		  "TTSSH/2.3*,"
110 		  "TTSSH/2.4*,"
111 		  "TTSSH/2.5*,"
112 		  "TTSSH/2.6*,"
113 		  "TTSSH/2.70*,"
114 		  "TTSSH/2.71*,"
115 		  "TTSSH/2.72*",	SSH_BUG_HOSTKEYS },
116 		{ "WinSCP_release_4*,"
117 		  "WinSCP_release_5.0*,"
118 		  "WinSCP_release_5.1,"
119 		  "WinSCP_release_5.1.*,"
120 		  "WinSCP_release_5.5,"
121 		  "WinSCP_release_5.5.*,"
122 		  "WinSCP_release_5.6,"
123 		  "WinSCP_release_5.6.*,"
124 		  "WinSCP_release_5.7,"
125 		  "WinSCP_release_5.7.1,"
126 		  "WinSCP_release_5.7.2,"
127 		  "WinSCP_release_5.7.3,"
128 		  "WinSCP_release_5.7.4",
129 					SSH_OLD_DHGEX },
130 		{ "ConfD-*",
131 					SSH_BUG_UTF8TTYMODE },
132 		{ NULL,			0 }
133 	};
134 
135 	/* process table, return first match */
136 	for (i = 0; check[i].pat; i++) {
137 		if (match_pattern_list(version, check[i].pat, 0) == 1) {
138 			debug("match: %s pat %s compat 0x%08x",
139 			    version, check[i].pat, check[i].bugs);
140 			datafellows = check[i].bugs;	/* XXX for now */
141 			/* Check to see if the remote side is OpenSSH and not HPN */
142 			if(strstr(version,"OpenSSH") != NULL)
143 			{
144 				if (strstr(version,"hpn") == NULL)
145 				{
146 					datafellows |= SSH_BUG_LARGEWINDOW;
147 					debug("Remote is NON-HPN aware");
148 				}
149 			}
150 			return check[i].bugs;
151 		}
152 	}
153 	debug("no match: %s", version);
154 	return 0;
155 }
156 
157 #define	SEP	","
158 int
159 proto_spec(const char *spec)
160 {
161 	char *s, *p, *q;
162 	int ret = SSH_PROTO_UNKNOWN;
163 
164 	if (spec == NULL)
165 		return ret;
166 	q = s = strdup(spec);
167 	if (s == NULL)
168 		return ret;
169 	for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
170 		switch (atoi(p)) {
171 		case 2:
172 			ret |= SSH_PROTO_2;
173 			break;
174 		default:
175 			logit("ignoring bad proto spec: '%s'.", p);
176 			break;
177 		}
178 	}
179 	free(s);
180 	return ret;
181 }
182 
183 const char *
184 compat_cipher_proposal(const char *cipher_prop)
185 {
186 	if (!(datafellows & SSH_BUG_BIGENDIANAES))
187 		return cipher_prop;
188 	debug2("%s: original cipher proposal: %s", __func__, cipher_prop);
189 	if ((cipher_prop = match_filter_list(cipher_prop, "aes*")) == NULL)
190 		fatal("match_filter_list failed");
191 	debug2("%s: compat cipher proposal: %s", __func__, cipher_prop);
192 	if (*cipher_prop == '\0')
193 		fatal("No supported ciphers found");
194 	return cipher_prop;
195 }
196 
197 char *
198 compat_pkalg_proposal(char *pkalg_prop)
199 {
200 	if (!(datafellows & SSH_BUG_RSASIGMD5))
201 		return pkalg_prop;
202 	debug2("%s: original public key proposal: %s", __func__, pkalg_prop);
203 	if ((pkalg_prop = match_filter_list(pkalg_prop, "ssh-rsa")) == NULL)
204 		fatal("match_filter_list failed");
205 	debug2("%s: compat public key proposal: %s", __func__, pkalg_prop);
206 	if (*pkalg_prop == '\0')
207 		fatal("No supported PK algorithms found");
208 	return pkalg_prop;
209 }
210 
211 const char *
212 compat_kex_proposal(const char *p)
213 {
214 	if ((datafellows & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
215 		return p;
216 	debug2("%s: original KEX proposal: %s", __func__, p);
217 	if ((datafellows & SSH_BUG_CURVE25519PAD) != 0)
218 		if ((p = match_filter_list(p,
219 		    "curve25519-sha256@libssh.org")) == NULL)
220 			fatal("match_filter_list failed");
221 	if ((datafellows & SSH_OLD_DHGEX) != 0) {
222 		if ((p = match_filter_list(p,
223 		    "diffie-hellman-group-exchange-sha256,"
224 		    "diffie-hellman-group-exchange-sha1")) == NULL)
225 			fatal("match_filter_list failed");
226 	}
227 	debug2("%s: compat KEX proposal: %s", __func__, p);
228 	if (*p == '\0')
229 		fatal("No supported key exchange algorithms found");
230 	return p;
231 }
232 
233