+ if (cfg.cipher == CIPHER_BLOWFISH) {
+ ciphers[0] = &ssh_blowfish_ssh2;
+ } else if (cfg.cipher == CIPHER_DES) {
+ logevent("Single DES not supported in SSH2; using 3DES");
+ ciphers[0] = &ssh_3des_ssh2;
+ } else if (cfg.cipher == CIPHER_3DES) {
+ ciphers[0] = &ssh_3des_ssh2;
+ } else {
+ /* Shouldn't happen, but we do want to initialise to _something_. */
+ ciphers[0] = &ssh_3des_ssh2;
+ }
+
+ begin_key_exchange:
+ /*
+ * Construct and send our key exchange packet.
+ */
+ ssh2_pkt_init(SSH2_MSG_KEXINIT);
+ for (i = 0; i < 16; i++)
+ ssh2_pkt_addbyte((unsigned char)random_byte());
+ /* List key exchange algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(kex_algs); i++) {
+ ssh2_pkt_addstring_str(kex_algs[i]->name);
+ if (i < lenof(kex_algs)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List server host key algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(hostkey_algs); i++) {
+ ssh2_pkt_addstring_str(hostkey_algs[i]->name);
+ if (i < lenof(hostkey_algs)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List client->server encryption algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(ciphers); i++) {
+ ssh2_pkt_addstring_str(ciphers[i]->name);
+ if (i < lenof(ciphers)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List server->client encryption algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(ciphers); i++) {
+ ssh2_pkt_addstring_str(ciphers[i]->name);
+ if (i < lenof(ciphers)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List client->server MAC algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(macs); i++) {
+ ssh2_pkt_addstring_str(macs[i]->name);
+ if (i < lenof(macs)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List server->client MAC algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(macs); i++) {
+ ssh2_pkt_addstring_str(macs[i]->name);
+ if (i < lenof(macs)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List client->server compression algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(compressions); i++) {
+ ssh2_pkt_addstring_str(compressions[i]->name);
+ if (i < lenof(compressions)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List server->client compression algorithms. */
+ ssh2_pkt_addstring_start();
+ for (i = 0; i < lenof(compressions); i++) {
+ ssh2_pkt_addstring_str(compressions[i]->name);
+ if (i < lenof(compressions)-1)
+ ssh2_pkt_addstring_str(",");
+ }
+ /* List client->server languages. Empty list. */
+ ssh2_pkt_addstring_start();
+ /* List server->client languages. Empty list. */
+ ssh2_pkt_addstring_start();
+ /* First KEX packet does _not_ follow, because we're not that brave. */
+ ssh2_pkt_addbool(FALSE);
+ /* Reserved. */
+ ssh2_pkt_adduint32(0);
+ sha_string(&exhash, pktout.data+5, pktout.length-5);
+ ssh2_pkt_send();
+
+ if (!ispkt) crWaitUntil(ispkt);
+ sha_string(&exhash, pktin.data+5, pktin.length-5);
+
+ /*
+ * Now examine the other side's KEXINIT to see what we're up
+ * to.
+ */
+ if (pktin.type != SSH2_MSG_KEXINIT) {
+ bombout(("expected key exchange packet from server"));
+ crReturn(0);
+ }
+ kex = NULL; hostkey = NULL; cscipher_tobe = NULL; sccipher_tobe = NULL;
+ csmac_tobe = NULL; scmac_tobe = NULL; cscomp_tobe = NULL; sccomp_tobe = NULL;
+ pktin.savedpos += 16; /* skip garbage cookie */
+ ssh2_pkt_getstring(&str, &len); /* key exchange algorithms */
+ for (i = 0; i < lenof(kex_algs); i++) {
+ if (in_commasep_string(kex_algs[i]->name, str, len)) {
+ kex = kex_algs[i];
+ break;
+ }
+ }
+ ssh2_pkt_getstring(&str, &len); /* host key algorithms */
+ for (i = 0; i < lenof(hostkey_algs); i++) {
+ if (in_commasep_string(hostkey_algs[i]->name, str, len)) {
+ hostkey = hostkey_algs[i];
+ break;
+ }
+ }
+ ssh2_pkt_getstring(&str, &len); /* client->server cipher */
+ for (i = 0; i < lenof(ciphers); i++) {
+ if (in_commasep_string(ciphers[i]->name, str, len)) {
+ cscipher_tobe = ciphers[i];
+ break;
+ }
+ }
+ ssh2_pkt_getstring(&str, &len); /* server->client cipher */
+ for (i = 0; i < lenof(ciphers); i++) {
+ if (in_commasep_string(ciphers[i]->name, str, len)) {
+ sccipher_tobe = ciphers[i];
+ break;
+ }
+ }
+ ssh2_pkt_getstring(&str, &len); /* client->server mac */
+ for (i = 0; i < lenof(macs); i++) {
+ if (in_commasep_string(macs[i]->name, str, len)) {
+ csmac_tobe = macs[i];
+ break;
+ }
+ }
+ ssh2_pkt_getstring(&str, &len); /* server->client mac */
+ for (i = 0; i < lenof(macs); i++) {
+ if (in_commasep_string(macs[i]->name, str, len)) {
+ scmac_tobe = macs[i];
+ break;
+ }
+ }
+ ssh2_pkt_getstring(&str, &len); /* client->server compression */
+ for (i = 0; i < lenof(compressions); i++) {
+ if (in_commasep_string(compressions[i]->name, str, len)) {
+ cscomp_tobe = compressions[i];
+ break;
+ }
+ }
+ ssh2_pkt_getstring(&str, &len); /* server->client compression */
+ for (i = 0; i < lenof(compressions); i++) {
+ if (in_commasep_string(compressions[i]->name, str, len)) {
+ sccomp_tobe = compressions[i];
+ break;
+ }
+ }
+
+ /*
+ * Currently we only support Diffie-Hellman and DSS, so let's
+ * bomb out if those aren't selected.
+ */
+ if (kex != &ssh_diffiehellman || hostkey != &ssh_dss) {
+ bombout(("internal fault: chaos in SSH 2 transport layer"));
+ crReturn(0);
+ }
+
+ /*
+ * Now we begin the fun. Generate and send e for Diffie-Hellman.
+ */
+ e = dh_create_e();
+ ssh2_pkt_init(SSH2_MSG_KEXDH_INIT);
+ ssh2_pkt_addmp(e);
+ ssh2_pkt_send();
+
+ crWaitUntil(ispkt);
+ if (pktin.type != SSH2_MSG_KEXDH_REPLY) {
+ bombout(("expected key exchange packet from server"));
+ crReturn(0);
+ }
+ ssh2_pkt_getstring(&hostkeydata, &hostkeylen);
+ f = ssh2_pkt_getmp();
+ ssh2_pkt_getstring(&sigdata, &siglen);
+
+ K = dh_find_K(f);
+
+ sha_string(&exhash, hostkeydata, hostkeylen);
+ sha_mpint(&exhash, e);
+ sha_mpint(&exhash, f);
+ sha_mpint(&exhash, K);
+ SHA_Final(&exhash, exchange_hash);
+
+#if 0
+ debug(("Exchange hash is:\r\n"));
+ for (i = 0; i < 20; i++)
+ debug((" %02x", exchange_hash[i]));
+ debug(("\r\n"));