verstring.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * Code to handle the initial SSH version string exchange.
  3. */
  4. #include <assert.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include "putty.h"
  8. #include "ssh.h"
  9. #include "bpp.h"
  10. #include "sshcr.h"
  11. #define PREFIX_MAXLEN 64
  12. struct ssh_verstring_state {
  13. int crState;
  14. Conf *conf;
  15. ptrlen prefix_wanted;
  16. char *our_protoversion;
  17. struct ssh_version_receiver *receiver;
  18. bool send_early;
  19. bool found_prefix;
  20. int major_protoversion;
  21. int remote_bugs;
  22. char prefix[PREFIX_MAXLEN];
  23. char *impl_name;
  24. strbuf *vstring;
  25. char *protoversion;
  26. const char *softwareversion;
  27. char *our_vstring;
  28. int i;
  29. BinaryPacketProtocol bpp;
  30. };
  31. static void ssh_verstring_free(BinaryPacketProtocol *bpp);
  32. static void ssh_verstring_handle_input(BinaryPacketProtocol *bpp);
  33. static void ssh_verstring_handle_output(BinaryPacketProtocol *bpp);
  34. static PktOut *ssh_verstring_new_pktout(int type);
  35. static void ssh_verstring_queue_disconnect(BinaryPacketProtocol *bpp,
  36. const char *msg, int category);
  37. static const BinaryPacketProtocolVtable ssh_verstring_vtable = {
  38. // WINSCP
  39. /*.free =*/ ssh_verstring_free,
  40. /*.handle_input =*/ ssh_verstring_handle_input,
  41. /*.handle_output =*/ ssh_verstring_handle_output,
  42. /*.new_pktout =*/ ssh_verstring_new_pktout,
  43. /*.queue_disconnect =*/ ssh_verstring_queue_disconnect,
  44. /*.packet_size_limit =*/ 0xFFFFFFFF, /* no special limit for this bpp */
  45. };
  46. static void ssh_detect_bugs(struct ssh_verstring_state *s);
  47. static bool ssh_version_includes_v1(const char *ver);
  48. static bool ssh_version_includes_v2(const char *ver);
  49. BinaryPacketProtocol *ssh_verstring_new(
  50. Conf *conf, LogContext *logctx, bool bare_connection_mode,
  51. const char *protoversion, struct ssh_version_receiver *rcv,
  52. bool server_mode, const char *impl_name)
  53. {
  54. struct ssh_verstring_state *s = snew(struct ssh_verstring_state);
  55. memset(s, 0, sizeof(struct ssh_verstring_state));
  56. if (!bare_connection_mode) {
  57. s->prefix_wanted = PTRLEN_LITERAL("SSH-");
  58. } else {
  59. /*
  60. * Ordinary SSH begins with the banner "SSH-x.y-...". Here,
  61. * we're going to be speaking just the ssh-connection
  62. * subprotocol, extracted and given a trivial binary packet
  63. * protocol, so we need a new banner.
  64. *
  65. * The new banner is like the ordinary SSH banner, but
  66. * replaces the prefix 'SSH-' at the start with a new name. In
  67. * proper SSH style (though of course this part of the proper
  68. * SSH protocol _isn't_ subject to this kind of
  69. * DNS-domain-based extension), we define the new name in our
  70. * extension space.
  71. */
  72. s->prefix_wanted = PTRLEN_LITERAL(
  73. "[email protected]");
  74. }
  75. assert(s->prefix_wanted.len <= PREFIX_MAXLEN);
  76. s->conf = conf_copy(conf);
  77. s->bpp.logctx = logctx;
  78. s->our_protoversion = dupstr(protoversion);
  79. s->receiver = rcv;
  80. s->impl_name = dupstr(impl_name);
  81. s->vstring = strbuf_new();
  82. /*
  83. * We send our version string early if we can. But if it includes
  84. * SSH-1, we can't, because we have to take the other end into
  85. * account too (see below).
  86. *
  87. * In server mode, we do send early.
  88. */
  89. s->send_early = server_mode || !ssh_version_includes_v1(protoversion);
  90. /*
  91. * Override: we don't send our version string early if the server
  92. * has a bug that will make it discard it. See for example
  93. * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=991958
  94. */
  95. if (conf_get_int(s->conf, CONF_sshbug_dropstart) == FORCE_ON)
  96. s->send_early = false;
  97. s->bpp.vt = &ssh_verstring_vtable;
  98. ssh_bpp_common_setup(&s->bpp);
  99. return &s->bpp;
  100. }
  101. void ssh_verstring_free(BinaryPacketProtocol *bpp)
  102. {
  103. struct ssh_verstring_state *s =
  104. container_of(bpp, struct ssh_verstring_state, bpp);
  105. conf_free(s->conf);
  106. sfree(s->impl_name);
  107. strbuf_free(s->vstring);
  108. sfree(s->protoversion);
  109. sfree(s->our_vstring);
  110. sfree(s->our_protoversion);
  111. sfree(s);
  112. }
  113. static int ssh_versioncmp(const char *a, const char *b)
  114. {
  115. char *ae, *be;
  116. unsigned long av, bv;
  117. av = strtoul(a, &ae, 10);
  118. bv = strtoul(b, &be, 10);
  119. if (av != bv)
  120. return (av < bv ? -1 : +1);
  121. if (*ae == '.')
  122. ae++;
  123. if (*be == '.')
  124. be++;
  125. av = strtoul(ae, &ae, 10);
  126. bv = strtoul(be, &be, 10);
  127. if (av != bv)
  128. return (av < bv ? -1 : +1);
  129. return 0;
  130. }
  131. static bool ssh_version_includes_v1(const char *ver)
  132. {
  133. return ssh_versioncmp(ver, "2.0") < 0;
  134. }
  135. static bool ssh_version_includes_v2(const char *ver)
  136. {
  137. return ssh_versioncmp(ver, "1.99") >= 0;
  138. }
  139. static void ssh_verstring_send(struct ssh_verstring_state *s)
  140. {
  141. BinaryPacketProtocol *bpp = &s->bpp; /* for bpp_logevent */
  142. char *p;
  143. int sv_pos;
  144. /*
  145. * Construct our outgoing version string.
  146. */
  147. s->our_vstring = dupprintf(
  148. "%.*s%s-%s%s",
  149. (int)s->prefix_wanted.len, (const char *)s->prefix_wanted.ptr,
  150. s->our_protoversion, s->impl_name, sshver);
  151. sv_pos = s->prefix_wanted.len + strlen(s->our_protoversion) + 1;
  152. /* Convert minus signs and spaces in the software version string
  153. * into underscores. */
  154. for (p = s->our_vstring + sv_pos; *p; p++) {
  155. if (*p == '-' || *p == ' ')
  156. *p = '_';
  157. }
  158. #ifdef FUZZING
  159. /*
  160. * Replace the first character of the string with an "I" if we're
  161. * compiling this code for fuzzing - i.e. the protocol prefix
  162. * becomes "ISH-" instead of "SSH-".
  163. *
  164. * This is irrelevant to any real client software (the only thing
  165. * reading the output of PuTTY built for fuzzing is the fuzzer,
  166. * which can adapt to whatever it sees anyway). But it's a safety
  167. * precaution making it difficult to accidentally run such a
  168. * version of PuTTY (which would be hugely insecure) against a
  169. * live peer implementation.
  170. *
  171. * (So the replacement prefix "ISH" notionally stands for
  172. * 'Insecure Shell', of course.)
  173. */
  174. s->our_vstring[0] = 'I';
  175. #endif
  176. /*
  177. * Now send that version string, plus trailing \r\n or just \n
  178. * (the latter in SSH-1 mode).
  179. */
  180. bufchain_add(s->bpp.out_raw, s->our_vstring, strlen(s->our_vstring));
  181. if (ssh_version_includes_v2(s->our_protoversion))
  182. bufchain_add(s->bpp.out_raw, "\015", 1);
  183. bufchain_add(s->bpp.out_raw, "\012", 1);
  184. bpp_logevent("We claim version: %s", s->our_vstring);
  185. }
  186. #define BPP_WAITFOR(minlen) do \
  187. { \
  188. bool success; \
  189. crMaybeWaitUntilV( \
  190. (success = (bufchain_size(s->bpp.in_raw) >= (minlen))) || \
  191. s->bpp.input_eof); \
  192. if (!success) \
  193. goto eof; \
  194. } while (0)
  195. void ssh_verstring_handle_input(BinaryPacketProtocol *bpp)
  196. {
  197. struct ssh_verstring_state *s =
  198. container_of(bpp, struct ssh_verstring_state, bpp);
  199. crBegin(s->crState);
  200. /*
  201. * If we're sending our version string up front before seeing the
  202. * other side's, then do it now.
  203. */
  204. if (s->send_early)
  205. ssh_verstring_send(s);
  206. /*
  207. * Search for a line beginning with the protocol name prefix in
  208. * the input.
  209. */
  210. s->i = 0;
  211. while (1) {
  212. /*
  213. * Every time round this loop, we're at the start of a new
  214. * line, so look for the prefix.
  215. */
  216. BPP_WAITFOR(s->prefix_wanted.len);
  217. bufchain_fetch(s->bpp.in_raw, s->prefix, s->prefix_wanted.len);
  218. if (!memcmp(s->prefix, s->prefix_wanted.ptr, s->prefix_wanted.len)) {
  219. bufchain_consume(s->bpp.in_raw, s->prefix_wanted.len);
  220. ssh_check_frozen(s->bpp.ssh);
  221. break;
  222. }
  223. /*
  224. * If we didn't find it, consume data until we see a newline.
  225. */
  226. while (1) {
  227. ptrlen data;
  228. char *nl;
  229. /* Wait to receive at least 1 byte, but then consume more
  230. * than that if it's there. */
  231. BPP_WAITFOR(1);
  232. data = bufchain_prefix(s->bpp.in_raw);
  233. if ((nl = memchr(data.ptr, '\012', data.len)) != NULL) {
  234. bufchain_consume(s->bpp.in_raw, nl - (char *)data.ptr + 1);
  235. ssh_check_frozen(s->bpp.ssh);
  236. break;
  237. } else {
  238. bufchain_consume(s->bpp.in_raw, data.len);
  239. ssh_check_frozen(s->bpp.ssh);
  240. }
  241. }
  242. }
  243. s->found_prefix = true;
  244. /*
  245. * Copy the greeting line so far into vstring.
  246. */
  247. put_data(s->vstring, s->prefix_wanted.ptr, s->prefix_wanted.len);
  248. /*
  249. * Now read the rest of the greeting line.
  250. */
  251. s->i = 0;
  252. do {
  253. ptrlen data;
  254. char *nl;
  255. BPP_WAITFOR(1);
  256. data = bufchain_prefix(s->bpp.in_raw);
  257. if ((nl = memchr(data.ptr, '\012', data.len)) != NULL) {
  258. data.len = nl - (char *)data.ptr + 1;
  259. }
  260. put_datapl(s->vstring, data);
  261. bufchain_consume(s->bpp.in_raw, data.len);
  262. ssh_check_frozen(s->bpp.ssh);
  263. } while (s->vstring->s[s->vstring->len-1] != '\012');
  264. /*
  265. * Trim \r and \n from the version string, and replace them with
  266. * a NUL terminator.
  267. */
  268. while (s->vstring->len > 0 &&
  269. (s->vstring->s[s->vstring->len-1] == '\015' ||
  270. s->vstring->s[s->vstring->len-1] == '\012'))
  271. strbuf_shrink_by(s->vstring, 1);
  272. bpp_logevent("Remote version: %s", s->vstring->s);
  273. /*
  274. * Pick out the protocol version and software version. The former
  275. * goes in a separately allocated string, so that s->vstring
  276. * remains intact for later use in key exchange; the latter is the
  277. * tail of s->vstring, so it doesn't need to be allocated.
  278. */
  279. {
  280. const char *pv_start = s->vstring->s + s->prefix_wanted.len;
  281. int pv_len = strcspn(pv_start, "-");
  282. s->protoversion = dupprintf("%.*s", pv_len, pv_start);
  283. s->softwareversion = pv_start + pv_len;
  284. if (*s->softwareversion) {
  285. assert(*s->softwareversion == '-');
  286. s->softwareversion++;
  287. }
  288. }
  289. ssh_detect_bugs(s);
  290. /*
  291. * Figure out what actual SSH protocol version we're speaking.
  292. */
  293. if (ssh_version_includes_v2(s->our_protoversion) &&
  294. ssh_version_includes_v2(s->protoversion)) {
  295. /*
  296. * We're doing SSH-2.
  297. */
  298. s->major_protoversion = 2;
  299. } else if (ssh_version_includes_v1(s->our_protoversion) &&
  300. ssh_version_includes_v1(s->protoversion)) {
  301. /*
  302. * We're doing SSH-1.
  303. */
  304. s->major_protoversion = 1;
  305. /*
  306. * There are multiple minor versions of SSH-1, and the
  307. * protocol does not specify that the minimum of client
  308. * and server versions is used. So we must adjust our
  309. * outgoing protocol version to be no higher than that of
  310. * the other side.
  311. */
  312. if (!s->send_early &&
  313. ssh_versioncmp(s->our_protoversion, s->protoversion) > 0) {
  314. sfree(s->our_protoversion);
  315. s->our_protoversion = dupstr(s->protoversion);
  316. }
  317. } else {
  318. /*
  319. * Unable to agree on a major protocol version at all.
  320. */
  321. if (!ssh_version_includes_v2(s->our_protoversion)) {
  322. ssh_sw_abort(s->bpp.ssh,
  323. "SSH protocol version 1 required by our "
  324. "configuration but not provided by remote");
  325. } else {
  326. ssh_sw_abort(s->bpp.ssh,
  327. "SSH protocol version 2 required by our "
  328. "configuration but remote only provides "
  329. "(old, insecure) SSH-1");
  330. }
  331. crStopV;
  332. }
  333. bpp_logevent("Using SSH protocol version %d", s->major_protoversion);
  334. if (!s->send_early) {
  335. /*
  336. * If we didn't send our version string early, construct and
  337. * send it now, because now we know what it is.
  338. */
  339. ssh_verstring_send(s);
  340. }
  341. /*
  342. * And we're done. Notify our receiver that we now know our
  343. * protocol version. This will cause it to disconnect us from the
  344. * input stream and ultimately free us, because our job is now
  345. * done.
  346. */
  347. s->receiver->got_ssh_version(s->receiver, s->major_protoversion);
  348. return;
  349. eof:
  350. ssh_remote_error(s->bpp.ssh,
  351. "Remote side unexpectedly closed network connection");
  352. return; /* avoid touching s now it's been freed */
  353. crFinishV;
  354. }
  355. static PktOut *ssh_verstring_new_pktout(int type)
  356. {
  357. unreachable("Should never try to send packets during SSH version "
  358. "string exchange");
  359. }
  360. static void ssh_verstring_handle_output(BinaryPacketProtocol *bpp)
  361. {
  362. if (pq_peek(&bpp->out_pq)) {
  363. unreachable("Should never try to send packets during SSH version "
  364. "string exchange");
  365. }
  366. }
  367. /*
  368. * Examine the remote side's version string, and compare it against a
  369. * list of known buggy implementations.
  370. */
  371. static void ssh_detect_bugs(struct ssh_verstring_state *s)
  372. {
  373. BinaryPacketProtocol *bpp = &s->bpp; /* for bpp_logevent */
  374. const char *imp = s->softwareversion;
  375. s->remote_bugs = 0;
  376. /*
  377. * General notes on server version strings:
  378. * - Not all servers reporting "Cisco-1.25" have all the bugs listed
  379. * here -- in particular, we've heard of one that's perfectly happy
  380. * with SSH1_MSG_IGNOREs -- but this string never seems to change,
  381. * so we can't distinguish them.
  382. */
  383. if (conf_get_int(s->conf, CONF_sshbug_ignore1) == FORCE_ON ||
  384. (conf_get_int(s->conf, CONF_sshbug_ignore1) == AUTO &&
  385. (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||
  386. !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||
  387. !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") ||
  388. !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) {
  389. /*
  390. * These versions don't support SSH1_MSG_IGNORE, so we have
  391. * to use a different defence against password length
  392. * sniffing.
  393. */
  394. s->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE;
  395. bpp_logevent("We believe remote version has SSH-1 ignore bug");
  396. }
  397. if (conf_get_int(s->conf, CONF_sshbug_plainpw1) == FORCE_ON ||
  398. (conf_get_int(s->conf, CONF_sshbug_plainpw1) == AUTO &&
  399. (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) {
  400. /*
  401. * These versions need a plain password sent; they can't
  402. * handle having a null and a random length of data after
  403. * the password.
  404. */
  405. s->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD;
  406. bpp_logevent("We believe remote version needs a "
  407. "plain SSH-1 password");
  408. }
  409. if (conf_get_int(s->conf, CONF_sshbug_rsa1) == FORCE_ON ||
  410. (conf_get_int(s->conf, CONF_sshbug_rsa1) == AUTO &&
  411. (!strcmp(imp, "Cisco-1.25")))) {
  412. /*
  413. * These versions apparently have no clue whatever about
  414. * RSA authentication and will panic and die if they see
  415. * an AUTH_RSA message.
  416. */
  417. s->remote_bugs |= BUG_CHOKES_ON_RSA;
  418. bpp_logevent("We believe remote version can't handle SSH-1 "
  419. "RSA authentication");
  420. }
  421. if (conf_get_int(s->conf, CONF_sshbug_hmac2) == FORCE_ON ||
  422. (conf_get_int(s->conf, CONF_sshbug_hmac2) == AUTO &&
  423. !wc_match("* VShell", imp) &&
  424. (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) ||
  425. wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) ||
  426. wc_match("2.1 *", imp)))) {
  427. /*
  428. * These versions have the HMAC bug.
  429. */
  430. s->remote_bugs |= BUG_SSH2_HMAC;
  431. bpp_logevent("We believe remote version has SSH-2 HMAC bug");
  432. }
  433. if (conf_get_int(s->conf, CONF_sshbug_derivekey2) == FORCE_ON ||
  434. (conf_get_int(s->conf, CONF_sshbug_derivekey2) == AUTO &&
  435. !wc_match("* VShell", imp) &&
  436. (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) {
  437. /*
  438. * These versions have the key-derivation bug (failing to
  439. * include the literal shared secret in the hashes that
  440. * generate the keys).
  441. */
  442. s->remote_bugs |= BUG_SSH2_DERIVEKEY;
  443. bpp_logevent("We believe remote version has SSH-2 "
  444. "key-derivation bug");
  445. }
  446. if (conf_get_int(s->conf, CONF_sshbug_rsapad2) == FORCE_ON ||
  447. (conf_get_int(s->conf, CONF_sshbug_rsapad2) == AUTO &&
  448. (wc_match("OpenSSH_2.[5-9]*", imp) ||
  449. wc_match("OpenSSH_3.[0-2]*", imp) ||
  450. wc_match("mod_sftp/0.[0-8]*", imp) ||
  451. wc_match("mod_sftp/0.9.[0-8]", imp)))) {
  452. /*
  453. * These versions have the SSH-2 RSA padding bug.
  454. */
  455. s->remote_bugs |= BUG_SSH2_RSA_PADDING;
  456. bpp_logevent("We believe remote version has SSH-2 RSA padding bug");
  457. }
  458. if (conf_get_int(s->conf, CONF_sshbug_pksessid2) == FORCE_ON ||
  459. (conf_get_int(s->conf, CONF_sshbug_pksessid2) == AUTO &&
  460. wc_match("OpenSSH_2.[0-2]*", imp))) {
  461. /*
  462. * These versions have the SSH-2 session-ID bug in
  463. * public-key authentication.
  464. */
  465. s->remote_bugs |= BUG_SSH2_PK_SESSIONID;
  466. bpp_logevent("We believe remote version has SSH-2 "
  467. "public-key-session-ID bug");
  468. }
  469. if (conf_get_int(s->conf, CONF_sshbug_rekey2) == FORCE_ON ||
  470. (conf_get_int(s->conf, CONF_sshbug_rekey2) == AUTO &&
  471. (wc_match("DigiSSH_2.0", imp) ||
  472. wc_match("OpenSSH_2.[0-4]*", imp) ||
  473. wc_match("OpenSSH_2.5.[0-3]*", imp) ||
  474. wc_match("Sun_SSH_1.0", imp) ||
  475. wc_match("Sun_SSH_1.0.1", imp) ||
  476. /* All versions <= 1.2.6 (they changed their format in 1.2.7) */
  477. wc_match("WeOnlyDo-*", imp)))) {
  478. /*
  479. * These versions have the SSH-2 rekey bug.
  480. */
  481. s->remote_bugs |= BUG_SSH2_REKEY;
  482. bpp_logevent("We believe remote version has SSH-2 rekey bug");
  483. }
  484. if (conf_get_int(s->conf, CONF_sshbug_maxpkt2) == FORCE_ON ||
  485. (conf_get_int(s->conf, CONF_sshbug_maxpkt2) == AUTO &&
  486. (wc_match("1.36_sshlib GlobalSCAPE", imp) ||
  487. wc_match("1.36 sshlib: GlobalScape", imp)))) {
  488. /*
  489. * This version ignores our makpkt and needs to be throttled.
  490. */
  491. s->remote_bugs |= BUG_SSH2_MAXPKT;
  492. bpp_logevent("We believe remote version ignores SSH-2 "
  493. "maximum packet size");
  494. }
  495. if (conf_get_int(s->conf, CONF_sshbug_ignore2) == FORCE_ON) {
  496. /*
  497. * Servers that don't support SSH2_MSG_IGNORE. Currently,
  498. * none detected automatically.
  499. */
  500. s->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE;
  501. bpp_logevent("We believe remote version has SSH-2 ignore bug");
  502. }
  503. if (conf_get_int(s->conf, CONF_sshbug_oldgex2) == FORCE_ON ||
  504. (conf_get_int(s->conf, CONF_sshbug_oldgex2) == AUTO &&
  505. (wc_match("OpenSSH_2.[235]*", imp)))) {
  506. /*
  507. * These versions only support the original (pre-RFC4419)
  508. * SSH-2 GEX request, and disconnect with a protocol error if
  509. * we use the newer version.
  510. */
  511. s->remote_bugs |= BUG_SSH2_OLDGEX;
  512. bpp_logevent("We believe remote version has outdated SSH-2 GEX");
  513. }
  514. if (conf_get_int(s->conf, CONF_sshbug_winadj) == FORCE_ON) {
  515. /*
  516. * Servers that don't support our winadj request for one
  517. * reason or another. Currently, none detected automatically.
  518. */
  519. s->remote_bugs |= BUG_CHOKES_ON_WINADJ;
  520. bpp_logevent("We believe remote version has winadj bug");
  521. }
  522. if (conf_get_int(s->conf, CONF_sshbug_chanreq) == FORCE_ON ||
  523. (conf_get_int(s->conf, CONF_sshbug_chanreq) == AUTO &&
  524. (wc_match("OpenSSH_[2-5].*", imp) ||
  525. wc_match("OpenSSH_6.[0-6]*", imp) ||
  526. wc_match("dropbear_0.[2-4][0-9]*", imp) ||
  527. wc_match("dropbear_0.5[01]*", imp)))) {
  528. /*
  529. * These versions have the SSH-2 channel request bug.
  530. * OpenSSH 6.7 and above do not:
  531. * https://bugzilla.mindrot.org/show_bug.cgi?id=1818
  532. * dropbear_0.52 and above do not:
  533. * https://secure.ucc.asn.au/hg/dropbear/rev/cd02449b709c
  534. */
  535. s->remote_bugs |= BUG_SENDS_LATE_REQUEST_REPLY;
  536. bpp_logevent("We believe remote version has SSH-2 "
  537. "channel request bug");
  538. }
  539. if (conf_get_int(s->conf, CONF_sshbug_filter_kexinit) == FORCE_ON) {
  540. s->remote_bugs |= BUG_REQUIRES_FILTERED_KEXINIT;
  541. bpp_logevent("We believe remote version requires us to "
  542. "filter our KEXINIT");
  543. }
  544. if (conf_get_int(s->conf, CONF_sshbug_rsa_sha2_cert_userauth) == FORCE_ON ||
  545. (conf_get_int(s->conf, CONF_sshbug_rsa_sha2_cert_userauth) == AUTO &&
  546. (wc_match("OpenSSH_7.[2-7]*", imp)))) {
  547. /*
  548. * These versions have the bug in which using RSA/SHA-2
  549. * authentication with a certified key requires the key
  550. * algorithm to be sent as ssh-rsa-cert-... instead of
  551. * rsa-sha2-NNN-cert-...
  552. *
  553. * OpenSSH 7.8 wants rsa-sha2-NNN-cert-...:
  554. * https://github.com/openssh/openssh-portable/commit/4ba0d54794814ec0de1ec87987d0c3b89379b436
  555. * (also labelled "OpenBSD-Commit-ID:
  556. * c6e9f6d45eed8962ad502d315d7eaef32c419dde")
  557. *
  558. * OpenSSH 7.2 was the first release supporting RSA/SHA-2
  559. * at all, so this bug is irrelevant to anything before that.
  560. */
  561. s->remote_bugs |= BUG_RSA_SHA2_CERT_USERAUTH;
  562. bpp_logevent("We believe remote version has SSH-2 "
  563. "RSA/SHA-2/certificate userauth bug");
  564. }
  565. }
  566. const char *ssh_verstring_get_remote(BinaryPacketProtocol *bpp)
  567. {
  568. struct ssh_verstring_state *s =
  569. container_of(bpp, struct ssh_verstring_state, bpp);
  570. return s->vstring->s;
  571. }
  572. const char *ssh_verstring_get_local(BinaryPacketProtocol *bpp)
  573. {
  574. struct ssh_verstring_state *s =
  575. container_of(bpp, struct ssh_verstring_state, bpp);
  576. return s->our_vstring;
  577. }
  578. int ssh_verstring_get_bugs(BinaryPacketProtocol *bpp)
  579. {
  580. struct ssh_verstring_state *s =
  581. container_of(bpp, struct ssh_verstring_state, bpp);
  582. return s->remote_bugs;
  583. }
  584. static void ssh_verstring_queue_disconnect(BinaryPacketProtocol *bpp,
  585. const char *msg, int category)
  586. {
  587. /* No way to send disconnect messages at this stage of the protocol! */
  588. }