xref: /netbsd-src/crypto/external/bsd/openssh/dist/compat.c (revision 796c32c94f6e154afc9de0f63da35c91bb739b45)
1 /*	$NetBSD: compat.c,v 1.17 2017/10/07 19:39:19 christos Exp $	*/
2 /* $OpenBSD: compat.c,v 1.104 2017/07/25 09:22:25 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.17 2017/10/07 19:39:19 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.0*,"
55 		  "OpenSSH-2.1*,"
56 		  "OpenSSH_2.1*,"
57 		  "OpenSSH_2.2*",	SSH_OLD_SESSIONID|SSH_BUG_BANNER|
58 					SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
59 					SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
60 		{ "OpenSSH_2.3.0*",	SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
61 					SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
62 					SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
63 		{ "OpenSSH_2.3.*",	SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
64 					SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
65 					SSH_OLD_FORWARD_ADDR},
66 		{ "OpenSSH_2.5.0p1*,"
67 		  "OpenSSH_2.5.1p1*",
68 					SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
69 					SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
70 					SSH_OLD_FORWARD_ADDR},
71 		{ "OpenSSH_2.5.0*,"
72 		  "OpenSSH_2.5.1*,"
73 		  "OpenSSH_2.5.2*",	SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
74 					SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
75 		{ "OpenSSH_2.5.3*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
76 					SSH_OLD_FORWARD_ADDR},
77 		{ "OpenSSH_2.*,"
78 		  "OpenSSH_3.0*,"
79 		  "OpenSSH_3.1*",	SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
80 		{ "OpenSSH_3.*",	SSH_OLD_FORWARD_ADDR },
81 		{ "Sun_SSH_1.0*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
82 		{ "OpenSSH_4*",		0 },
83 		{ "OpenSSH_5*",		SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT},
84 		{ "OpenSSH_6.6.1*",	SSH_NEW_OPENSSH},
85 		{ "OpenSSH_6.5*,"
86 		  "OpenSSH_6.6*",	SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD},
87 		{ "OpenSSH*",		SSH_NEW_OPENSSH },
88 		{ "*MindTerm*",		0 },
89 		{ "2.1.0*",		SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
90 					SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
91 					SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE|
92 					SSH_BUG_FIRSTKEX },
93 		{ "2.1 *",		SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
94 					SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
95 					SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE|
96 					SSH_BUG_FIRSTKEX },
97 		{ "2.0.13*,"
98 		  "2.0.14*,"
99 		  "2.0.15*,"
100 		  "2.0.16*,"
101 		  "2.0.17*,"
102 		  "2.0.18*,"
103 		  "2.0.19*",		SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
104 					SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
105 					SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
106 					SSH_BUG_PKOK|SSH_BUG_RSASIGMD5|
107 					SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE|
108 					SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX },
109 		{ "2.0.11*,"
110 		  "2.0.12*",		SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
111 					SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
112 					SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
113 					SSH_BUG_PKAUTH|SSH_BUG_PKOK|
114 					SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
115 					SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX },
116 		{ "2.0.*",		SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
117 					SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
118 					SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
119 					SSH_BUG_PKAUTH|SSH_BUG_PKOK|
120 					SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE|
121 					SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN|
122 					SSH_BUG_FIRSTKEX },
123 		{ "2.2.0*,"
124 		  "2.3.0*",		SSH_BUG_HMAC|SSH_BUG_DEBUG|
125 					SSH_BUG_RSASIGMD5|SSH_BUG_FIRSTKEX },
126 		{ "2.3.*",		SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5|
127 					SSH_BUG_FIRSTKEX },
128 		{ "2.4",		SSH_OLD_SESSIONID },	/* Van Dyke */
129 		{ "2.*",		SSH_BUG_DEBUG|SSH_BUG_FIRSTKEX|
130 					SSH_BUG_RFWD_ADDR },
131 		{ "3.0.*",		SSH_BUG_DEBUG },
132 		{ "3.0 SecureCRT*",	SSH_OLD_SESSIONID },
133 		{ "1.7 SecureFX*",	SSH_OLD_SESSIONID },
134 		{ "1.2.18*,"
135 		  "1.2.19*,"
136 		  "1.2.20*,"
137 		  "1.2.21*,"
138 		  "1.2.22*",		SSH_BUG_IGNOREMSG },
139 		{ "1.3.2*",		/* F-Secure */
140 					SSH_BUG_IGNOREMSG },
141 		{ "Cisco-1.*",		SSH_BUG_DHGEX_LARGE|
142 					SSH_BUG_HOSTKEYS },
143 		{ "*SSH Compatible Server*",			/* Netscreen */
144 					SSH_BUG_PASSWORDPAD },
145 		{ "*OSU_0*,"
146 		  "OSU_1.0*,"
147 		  "OSU_1.1*,"
148 		  "OSU_1.2*,"
149 		  "OSU_1.3*,"
150 		  "OSU_1.4*,"
151 		  "OSU_1.5alpha1*,"
152 		  "OSU_1.5alpha2*,"
153 		  "OSU_1.5alpha3*",	SSH_BUG_PASSWORDPAD },
154 		{ "*SSH_Version_Mapper*",
155 					SSH_BUG_SCANNER },
156 		{ "PuTTY_Local:*,"	/* dev versions < Sep 2014 */
157 		  "PuTTY-Release-0.5*," /* 0.50-0.57, DH-GEX in >=0.52 */
158 		  "PuTTY_Release_0.5*,"	/* 0.58-0.59 */
159 		  "PuTTY_Release_0.60*,"
160 		  "PuTTY_Release_0.61*,"
161 		  "PuTTY_Release_0.62*,"
162 		  "PuTTY_Release_0.63*,"
163 		  "PuTTY_Release_0.64*",
164 					SSH_OLD_DHGEX },
165 		{ "FuTTY*",		SSH_OLD_DHGEX }, /* Putty Fork */
166 		{ "Probe-*",
167 					SSH_BUG_PROBE },
168 		{ "TeraTerm SSH*,"
169 		  "TTSSH/1.5.*,"
170 		  "TTSSH/2.1*,"
171 		  "TTSSH/2.2*,"
172 		  "TTSSH/2.3*,"
173 		  "TTSSH/2.4*,"
174 		  "TTSSH/2.5*,"
175 		  "TTSSH/2.6*,"
176 		  "TTSSH/2.70*,"
177 		  "TTSSH/2.71*,"
178 		  "TTSSH/2.72*",	SSH_BUG_HOSTKEYS },
179 		{ "WinSCP_release_4*,"
180 		  "WinSCP_release_5.0*,"
181 		  "WinSCP_release_5.1,"
182 		  "WinSCP_release_5.1.*,"
183 		  "WinSCP_release_5.5,"
184 		  "WinSCP_release_5.5.*,"
185 		  "WinSCP_release_5.6,"
186 		  "WinSCP_release_5.6.*,"
187 		  "WinSCP_release_5.7,"
188 		  "WinSCP_release_5.7.1,"
189 		  "WinSCP_release_5.7.2,"
190 		  "WinSCP_release_5.7.3,"
191 		  "WinSCP_release_5.7.4",
192 					SSH_OLD_DHGEX },
193 		{ NULL,			0 }
194 	};
195 
196 	/* process table, return first match */
197 	for (i = 0; check[i].pat; i++) {
198 		if (match_pattern_list(version, check[i].pat, 0) == 1) {
199 			debug("match: %s pat %s compat 0x%08x",
200 			    version, check[i].pat, check[i].bugs);
201 			datafellows = check[i].bugs;	/* XXX for now */
202 			/* Check to see if the remote side is OpenSSH and not HPN */
203 			if(strstr(version,"OpenSSH") != NULL)
204 			{
205 				if (strstr(version,"hpn") == NULL)
206 				{
207 					datafellows |= SSH_BUG_LARGEWINDOW;
208 					debug("Remote is NON-HPN aware");
209 				}
210 			}
211 			return check[i].bugs;
212 		}
213 	}
214 	debug("no match: %s", version);
215 	return 0;
216 }
217 
218 #define	SEP	","
219 int
220 proto_spec(const char *spec)
221 {
222 	char *s, *p, *q;
223 	int ret = SSH_PROTO_UNKNOWN;
224 
225 	if (spec == NULL)
226 		return ret;
227 	q = s = strdup(spec);
228 	if (s == NULL)
229 		return ret;
230 	for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
231 		switch (atoi(p)) {
232 		case 2:
233 			ret |= SSH_PROTO_2;
234 			break;
235 		default:
236 			logit("ignoring bad proto spec: '%s'.", p);
237 			break;
238 		}
239 	}
240 	free(s);
241 	return ret;
242 }
243 
244 const char *
245 compat_cipher_proposal(const char *cipher_prop)
246 {
247 	if (!(datafellows & SSH_BUG_BIGENDIANAES))
248 		return cipher_prop;
249 	debug2("%s: original cipher proposal: %s", __func__, cipher_prop);
250 	if ((cipher_prop = match_filter_list(cipher_prop, "aes*")) == NULL)
251 		fatal("match_filter_list failed");
252 	debug2("%s: compat cipher proposal: %s", __func__, cipher_prop);
253 	if (*cipher_prop == '\0')
254 		fatal("No supported ciphers found");
255 	return cipher_prop;
256 }
257 
258 char *
259 compat_pkalg_proposal(char *pkalg_prop)
260 {
261 	if (!(datafellows & SSH_BUG_RSASIGMD5))
262 		return pkalg_prop;
263 	debug2("%s: original public key proposal: %s", __func__, pkalg_prop);
264 	if ((pkalg_prop = match_filter_list(pkalg_prop, "ssh-rsa")) == NULL)
265 		fatal("match_filter_list failed");
266 	debug2("%s: compat public key proposal: %s", __func__, pkalg_prop);
267 	if (*pkalg_prop == '\0')
268 		fatal("No supported PK algorithms found");
269 	return pkalg_prop;
270 }
271 
272 const char *
273 compat_kex_proposal(const char *p)
274 {
275 	if ((datafellows & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
276 		return p;
277 	debug2("%s: original KEX proposal: %s", __func__, p);
278 	if ((datafellows & SSH_BUG_CURVE25519PAD) != 0)
279 		if ((p = match_filter_list(p,
280 		    "curve25519-sha256@libssh.org")) == NULL)
281 			fatal("match_filter_list failed");
282 	if ((datafellows & SSH_OLD_DHGEX) != 0) {
283 		if ((p = match_filter_list(p,
284 		    "diffie-hellman-group-exchange-sha256,"
285 		    "diffie-hellman-group-exchange-sha1")) == NULL)
286 			fatal("match_filter_list failed");
287 	}
288 	debug2("%s: compat KEX proposal: %s", __func__, p);
289 	if (*p == '\0')
290 		fatal("No supported key exchange algorithms found");
291 	return p;
292 }
293 
294