1323124Sdes/* $OpenBSD: compat.c,v 1.99 2016/05/24 02:31:57 dtucker Exp $ */ 257429Smarkm/* 392559Sdes * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 457429Smarkm * 557429Smarkm * Redistribution and use in source and binary forms, with or without 657429Smarkm * modification, are permitted provided that the following conditions 757429Smarkm * are met: 857429Smarkm * 1. Redistributions of source code must retain the above copyright 957429Smarkm * notice, this list of conditions and the following disclaimer. 1057429Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157429Smarkm * notice, this list of conditions and the following disclaimer in the 1257429Smarkm * documentation and/or other materials provided with the distribution. 1357429Smarkm * 1457429Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1557429Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1657429Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1757429Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1857429Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1957429Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2057429Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2157429Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2257429Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2357429Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2457429Smarkm */ 2557429Smarkm 2657429Smarkm#include "includes.h" 2757429Smarkm 28162856Sdes#include <sys/types.h> 29162856Sdes 30162856Sdes#include <stdlib.h> 31162856Sdes#include <string.h> 32162856Sdes#include <stdarg.h> 33162856Sdes 34162856Sdes#include "xmalloc.h" 3592559Sdes#include "buffer.h" 3660573Skris#include "packet.h" 3760573Skris#include "compat.h" 3876262Sgreen#include "log.h" 3992559Sdes#include "match.h" 4057429Smarkm 4157429Smarkmint compat13 = 0; 4260573Skrisint compat20 = 0; 4360573Skrisint datafellows = 0; 4457429Smarkm 4560573Skrisvoid 4660573Skrisenable_compat20(void) 4760573Skris{ 48248619Sdes if (compat20) 49248619Sdes return; 50106130Sdes debug("Enabling compatibility mode for protocol 2.0"); 5160573Skris compat20 = 1; 5260573Skris} 5360573Skrisvoid 5457429Smarkmenable_compat13(void) 5557429Smarkm{ 56106130Sdes debug("Enabling compatibility mode for protocol 1.3"); 5757429Smarkm compat13 = 1; 5857429Smarkm} 5960573Skris/* datafellows bug compatibility */ 60295367Sdesu_int 6160573Skriscompat_datafellows(const char *version) 6260573Skris{ 6392559Sdes int i; 6469587Sgreen static struct { 6569587Sgreen char *pat; 6660573Skris int bugs; 6760573Skris } check[] = { 6892559Sdes { "OpenSSH-2.0*," 6992559Sdes "OpenSSH-2.1*," 7092559Sdes "OpenSSH_2.1*," 7192559Sdes "OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER| 7298684Sdes SSH_OLD_DHGEX|SSH_BUG_NOREKEY| 73147005Sdes SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, 7492559Sdes { "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES| 7598684Sdes SSH_OLD_DHGEX|SSH_BUG_NOREKEY| 76147005Sdes SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, 7792559Sdes { "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| 78147005Sdes SSH_BUG_NOREKEY|SSH_BUG_EXTEOF| 79147005Sdes SSH_OLD_FORWARD_ADDR}, 8092559Sdes { "OpenSSH_2.5.0p1*," 8192559Sdes "OpenSSH_2.5.1p1*", 8276262Sgreen SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| 83147005Sdes SSH_BUG_NOREKEY|SSH_BUG_EXTEOF| 84147005Sdes SSH_OLD_FORWARD_ADDR}, 8592559Sdes { "OpenSSH_2.5.0*," 8692559Sdes "OpenSSH_2.5.1*," 8798684Sdes "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY| 88147005Sdes SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, 89147005Sdes { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF| 90147005Sdes SSH_OLD_FORWARD_ADDR}, 9198684Sdes { "OpenSSH_2.*," 9298684Sdes "OpenSSH_3.0*," 93147005Sdes "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, 94147005Sdes { "OpenSSH_3.*", SSH_OLD_FORWARD_ADDR }, 9598684Sdes { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, 96192595Sdes { "OpenSSH_4*", 0 }, 97240075Sdes { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT}, 98264692Sdes { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH}, 99264692Sdes { "OpenSSH_6.5*," 100264692Sdes "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD}, 101192595Sdes { "OpenSSH*", SSH_NEW_OPENSSH }, 10292559Sdes { "*MindTerm*", 0 }, 10392559Sdes { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 10476262Sgreen SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 105113911Sdes SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE| 106113911Sdes SSH_BUG_FIRSTKEX }, 10792559Sdes { "2.1 *", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 10876262Sgreen SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 109113911Sdes SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE| 110113911Sdes SSH_BUG_FIRSTKEX }, 11192559Sdes { "2.0.13*," 11292559Sdes "2.0.14*," 11392559Sdes "2.0.15*," 11492559Sdes "2.0.16*," 11592559Sdes "2.0.17*," 11692559Sdes "2.0.18*," 11792559Sdes "2.0.19*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 11876262Sgreen SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 11976262Sgreen SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| 12076262Sgreen SSH_BUG_PKOK|SSH_BUG_RSASIGMD5| 12192559Sdes SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE| 122113911Sdes SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX }, 12392559Sdes { "2.0.11*," 12492559Sdes "2.0.12*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 12576262Sgreen SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 12676262Sgreen SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| 12776262Sgreen SSH_BUG_PKAUTH|SSH_BUG_PKOK| 12892559Sdes SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE| 129113911Sdes SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX }, 13092559Sdes { "2.0.*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 13192559Sdes SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 13292559Sdes SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| 13392559Sdes SSH_BUG_PKAUTH|SSH_BUG_PKOK| 13492559Sdes SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE| 135113911Sdes SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN| 136113911Sdes SSH_BUG_FIRSTKEX }, 13792559Sdes { "2.2.0*," 13892559Sdes "2.3.0*", SSH_BUG_HMAC|SSH_BUG_DEBUG| 139113911Sdes SSH_BUG_RSASIGMD5|SSH_BUG_FIRSTKEX }, 140113911Sdes { "2.3.*", SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5| 141113911Sdes SSH_BUG_FIRSTKEX }, 14292559Sdes { "2.4", SSH_OLD_SESSIONID }, /* Van Dyke */ 143181111Sdes { "2.*", SSH_BUG_DEBUG|SSH_BUG_FIRSTKEX| 144181111Sdes SSH_BUG_RFWD_ADDR }, 14592559Sdes { "3.0.*", SSH_BUG_DEBUG }, 14692559Sdes { "3.0 SecureCRT*", SSH_OLD_SESSIONID }, 14792559Sdes { "1.7 SecureFX*", SSH_OLD_SESSIONID }, 14892559Sdes { "1.2.18*," 14992559Sdes "1.2.19*," 15092559Sdes "1.2.20*," 15192559Sdes "1.2.21*," 152124211Sdes "1.2.22*", SSH_BUG_IGNOREMSG }, 15398684Sdes { "1.3.2*", /* F-Secure */ 154124211Sdes SSH_BUG_IGNOREMSG }, 155295367Sdes { "Cisco-1.*", SSH_BUG_DHGEX_LARGE| 156295367Sdes SSH_BUG_HOSTKEYS }, 15792559Sdes { "*SSH Compatible Server*", /* Netscreen */ 15876262Sgreen SSH_BUG_PASSWORDPAD }, 15992559Sdes { "*OSU_0*," 16092559Sdes "OSU_1.0*," 16192559Sdes "OSU_1.1*," 16292559Sdes "OSU_1.2*," 16392559Sdes "OSU_1.3*," 16492559Sdes "OSU_1.4*," 16592559Sdes "OSU_1.5alpha1*," 16692559Sdes "OSU_1.5alpha2*," 16792559Sdes "OSU_1.5alpha3*", SSH_BUG_PASSWORDPAD }, 16892559Sdes { "*SSH_Version_Mapper*", 16976262Sgreen SSH_BUG_SCANNER }, 170295367Sdes { "PuTTY_Local:*," /* dev versions < Sep 2014 */ 171295367Sdes "PuTTY-Release-0.5*," /* 0.50-0.57, DH-GEX in >=0.52 */ 172295367Sdes "PuTTY_Release_0.5*," /* 0.58-0.59 */ 173295367Sdes "PuTTY_Release_0.60*," 174295367Sdes "PuTTY_Release_0.61*," 175295367Sdes "PuTTY_Release_0.62*," 176295367Sdes "PuTTY_Release_0.63*," 177295367Sdes "PuTTY_Release_0.64*", 178295367Sdes SSH_OLD_DHGEX }, 179295367Sdes { "FuTTY*", SSH_OLD_DHGEX }, /* Putty Fork */ 180106130Sdes { "Probe-*", 181106130Sdes SSH_BUG_PROBE }, 182295367Sdes { "TeraTerm SSH*," 183295367Sdes "TTSSH/1.5.*," 184295367Sdes "TTSSH/2.1*," 185295367Sdes "TTSSH/2.2*," 186295367Sdes "TTSSH/2.3*," 187295367Sdes "TTSSH/2.4*," 188295367Sdes "TTSSH/2.5*," 189295367Sdes "TTSSH/2.6*," 190295367Sdes "TTSSH/2.70*," 191295367Sdes "TTSSH/2.71*," 192295367Sdes "TTSSH/2.72*", SSH_BUG_HOSTKEYS }, 193295367Sdes { "WinSCP_release_4*," 194295367Sdes "WinSCP_release_5.0*," 195295367Sdes "WinSCP_release_5.1*," 196295367Sdes "WinSCP_release_5.5*," 197295367Sdes "WinSCP_release_5.6*," 198295367Sdes "WinSCP_release_5.7," 199295367Sdes "WinSCP_release_5.7.1," 200295367Sdes "WinSCP_release_5.7.2," 201295367Sdes "WinSCP_release_5.7.3," 202295367Sdes "WinSCP_release_5.7.4", 203295367Sdes SSH_OLD_DHGEX }, 20469587Sgreen { NULL, 0 } 20560573Skris }; 20692559Sdes 20765668Skris /* process table, return first match */ 20869587Sgreen for (i = 0; check[i].pat; i++) { 209295367Sdes if (match_pattern_list(version, check[i].pat, 0) == 1) { 210262566Sdes debug("match: %s pat %s compat 0x%08x", 211295367Sdes version, check[i].pat, check[i].bugs); 212295367Sdes datafellows = check[i].bugs; /* XXX for now */ 213295367Sdes return check[i].bugs; 21460573Skris } 21560573Skris } 21669587Sgreen debug("no match: %s", version); 217295367Sdes return 0; 21860573Skris} 21960573Skris 22060573Skris#define SEP "," 22160573Skrisint 22260573Skrisproto_spec(const char *spec) 22360573Skris{ 22465668Skris char *s, *p, *q; 22560573Skris int ret = SSH_PROTO_UNKNOWN; 22660573Skris 22761209Skris if (spec == NULL) 22861209Skris return ret; 229295367Sdes q = s = strdup(spec); 230295367Sdes if (s == NULL) 231295367Sdes return ret; 23265668Skris for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) { 23392559Sdes switch (atoi(p)) { 23460573Skris case 1: 235295367Sdes#ifdef WITH_SSH1 23660573Skris if (ret == SSH_PROTO_UNKNOWN) 23760573Skris ret |= SSH_PROTO_1_PREFERRED; 23860573Skris ret |= SSH_PROTO_1; 239295367Sdes#endif 24060573Skris break; 24160573Skris case 2: 24260573Skris ret |= SSH_PROTO_2; 24360573Skris break; 24460573Skris default: 245124211Sdes logit("ignoring bad proto spec: '%s'.", p); 24660573Skris break; 24760573Skris } 24860573Skris } 249255767Sdes free(s); 25060573Skris return ret; 25160573Skris} 25276262Sgreen 253262566Sdes/* 254262566Sdes * Filters a proposal string, excluding any algorithm matching the 'filter' 255262566Sdes * pattern list. 256262566Sdes */ 257262566Sdesstatic char * 258262566Sdesfilter_proposal(char *proposal, const char *filter) 25976262Sgreen{ 26092559Sdes Buffer b; 261262566Sdes char *orig_prop, *fix_prop; 26276262Sgreen char *cp, *tmp; 26376262Sgreen 26492559Sdes buffer_init(&b); 265262566Sdes tmp = orig_prop = xstrdup(proposal); 26692559Sdes while ((cp = strsep(&tmp, ",")) != NULL) { 267295367Sdes if (match_pattern_list(cp, filter, 0) != 1) { 26892559Sdes if (buffer_len(&b) > 0) 26992559Sdes buffer_append(&b, ",", 1); 27092559Sdes buffer_append(&b, cp, strlen(cp)); 271262566Sdes } else 272262566Sdes debug2("Compat: skipping algorithm \"%s\"", cp); 27376262Sgreen } 27492559Sdes buffer_append(&b, "\0", 1); 275295367Sdes fix_prop = xstrdup((char *)buffer_ptr(&b)); 27692559Sdes buffer_free(&b); 277255767Sdes free(orig_prop); 27876262Sgreen 279262566Sdes return fix_prop; 28076262Sgreen} 281262566Sdes 282262566Sdeschar * 283262566Sdescompat_cipher_proposal(char *cipher_prop) 284262566Sdes{ 285262566Sdes if (!(datafellows & SSH_BUG_BIGENDIANAES)) 286262566Sdes return cipher_prop; 287262566Sdes debug2("%s: original cipher proposal: %s", __func__, cipher_prop); 288262566Sdes cipher_prop = filter_proposal(cipher_prop, "aes*"); 289262566Sdes debug2("%s: compat cipher proposal: %s", __func__, cipher_prop); 290262566Sdes if (*cipher_prop == '\0') 291262566Sdes fatal("No supported ciphers found"); 292262566Sdes return cipher_prop; 293262566Sdes} 294262566Sdes 295262566Sdeschar * 296262566Sdescompat_pkalg_proposal(char *pkalg_prop) 297262566Sdes{ 298262566Sdes if (!(datafellows & SSH_BUG_RSASIGMD5)) 299262566Sdes return pkalg_prop; 300262566Sdes debug2("%s: original public key proposal: %s", __func__, pkalg_prop); 301262566Sdes pkalg_prop = filter_proposal(pkalg_prop, "ssh-rsa"); 302262566Sdes debug2("%s: compat public key proposal: %s", __func__, pkalg_prop); 303262566Sdes if (*pkalg_prop == '\0') 304262566Sdes fatal("No supported PK algorithms found"); 305262566Sdes return pkalg_prop; 306262566Sdes} 307262566Sdes 308264692Sdeschar * 309295367Sdescompat_kex_proposal(char *p) 310264692Sdes{ 311295367Sdes if ((datafellows & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0) 312295367Sdes return p; 313295367Sdes debug2("%s: original KEX proposal: %s", __func__, p); 314295367Sdes if ((datafellows & SSH_BUG_CURVE25519PAD) != 0) 315295367Sdes p = filter_proposal(p, "curve25519-sha256@libssh.org"); 316295367Sdes if ((datafellows & SSH_OLD_DHGEX) != 0) { 317295367Sdes p = filter_proposal(p, "diffie-hellman-group-exchange-sha256"); 318295367Sdes p = filter_proposal(p, "diffie-hellman-group-exchange-sha1"); 319295367Sdes } 320295367Sdes debug2("%s: compat KEX proposal: %s", __func__, p); 321295367Sdes if (*p == '\0') 322264692Sdes fatal("No supported key exchange algorithms found"); 323295367Sdes return p; 324264692Sdes} 325264692Sdes 326