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