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