*/
#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.182 2001/03/28 20:50:45 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.191 2001/04/05 10:42:57 markus Exp $");
#include <openssl/dh.h>
#include <openssl/bn.h>
#include "canohost.h"
#include "auth.h"
#include "misc.h"
+#include "dispatch.h"
#ifdef LIBWRAP
#include <tcpd.h>
char *client_version_string = NULL;
char *server_version_string = NULL;
+/* for rekeying XXX fixme */
+Kex *xxx_kex;
+
/*
* Any really sensitive data in the application is contained in this
* structure. The idea is that this structure could be locked into memory so
u_int32_t rand = 0;
int i;
- log("Generating %s%d bit RSA key.", sensitive_data.server_key ? "new " : "",
- options.server_key_bits);
+ verbose("Generating %s%d bit RSA key.",
+ sensitive_data.server_key ? "new " : "", options.server_key_bits);
if (sensitive_data.server_key != NULL)
key_free(sensitive_data.server_key);
- sensitive_data.server_key = key_generate(KEY_RSA1, options.server_key_bits);
- log("RSA key generation complete.");
+ sensitive_data.server_key = key_generate(KEY_RSA1,
+ options.server_key_bits);
+ verbose("RSA key generation complete.");
for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
if (i % 4 == 0)
}
/* Read other side's version identification. */
- memset(buf, 0, sizeof(buf));
+ memset(buf, 0, sizeof(buf));
for (i = 0; i < sizeof(buf) - 1; i++) {
if (atomicio(read, sock_in, &buf[i], 1) != 1) {
log("Did not receive identification string from %s.",
void
do_ssh2_kex(void)
{
- Buffer *server_kexinit;
- Buffer *client_kexinit;
- int payload_len;
- int i;
Kex *kex;
- char *cprop[PROPOSAL_MAX];
-
-/* KEXINIT */
if (options.ciphers != NULL) {
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
}
+ myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+ compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
+ myproposal[PROPOSAL_ENC_ALGS_STOC] =
+ compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
+
if (options.macs != NULL) {
myproposal[PROPOSAL_MAC_ALGS_CTOS] =
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
}
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
- myproposal[PROPOSAL_ENC_ALGS_STOC] =
- compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
+ /* start key exchange */
+ kex = kex_setup(myproposal);
+ kex->server = 1;
+ kex->client_version_string=client_version_string;
+ kex->server_version_string=server_version_string;
+ kex->load_host_key=&get_hostkey_by_type;
- server_kexinit = kex_init(myproposal);
- client_kexinit = xmalloc(sizeof(*client_kexinit));
- buffer_init(client_kexinit);
+ xxx_kex = kex;
- /* algorithm negotiation */
- kex_exchange_kexinit(server_kexinit, client_kexinit, cprop);
- kex = kex_choose_conf(cprop, myproposal, 1);
- for (i = 0; i < PROPOSAL_MAX; i++)
- xfree(cprop[i]);
+ dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
- switch (kex->kex_type) {
- case DH_GRP1_SHA1:
- ssh_dh1_server(kex, client_kexinit, server_kexinit);
- break;
- case DH_GEX_SHA1:
- ssh_dhgex_server(kex, client_kexinit, server_kexinit);
- break;
- default:
- fatal("Unsupported key exchange %d", kex->kex_type);
- }
-
- debug("send SSH2_MSG_NEWKEYS.");
- packet_start(SSH2_MSG_NEWKEYS);
- packet_send();
- packet_write_wait();
- debug("done: send SSH2_MSG_NEWKEYS.");
-
- debug("Wait SSH2_MSG_NEWKEYS.");
- packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
- debug("GOT SSH2_MSG_NEWKEYS.");
+ session_id2 = kex->session_id;
+ session_id2_len = kex->session_id_len;
#ifdef DEBUG_KEXDH
/* send 1st encrypted/maced/compressed message */
packet_send();
packet_write_wait();
#endif
-
- debug("done: KEX2.");
-}
-
-/*
- * SSH2 key exchange
- */
-
-/* diffie-hellman-group1-sha1 */
-
-void
-ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
-{
-#ifdef DEBUG_KEXDH
- int i;
-#endif
- int payload_len, dlen;
- int slen;
- u_char *signature = NULL;
- u_char *server_host_key_blob = NULL;
- u_int sbloblen;
- u_int klen, kout;
- u_char *kbuf;
- u_char *hash;
- BIGNUM *shared_secret = 0;
- DH *dh;
- BIGNUM *dh_client_pub = 0;
- Key *hostkey;
-
- hostkey = get_hostkey_by_type(kex->hostkey_type);
- if (hostkey == NULL)
- fatal("Unsupported hostkey type %d", kex->hostkey_type);
-
-/* KEXDH */
- /* generate DH key */
- dh = dh_new_group1(); /* XXX depends on 'kex' */
- dh_gen_key(dh, kex->we_need * 8);
-
- debug("Wait SSH2_MSG_KEXDH_INIT.");
- packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT);
-
- /* key, cert */
- dh_client_pub = BN_new();
- if (dh_client_pub == NULL)
- fatal("dh_client_pub == NULL");
- packet_get_bignum2(dh_client_pub, &dlen);
-
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "\ndh_client_pub= ");
- BN_print_fp(stderr, dh_client_pub);
- fprintf(stderr, "\n");
- debug("bits %d", BN_num_bits(dh_client_pub));
-#endif
-
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "\np= ");
- BN_print_fp(stderr, dh->p);
- fprintf(stderr, "\ng= ");
- bn_print(dh->g);
- fprintf(stderr, "\npub= ");
- BN_print_fp(stderr, dh->pub_key);
- fprintf(stderr, "\n");
- DHparams_print_fp(stderr, dh);
-#endif
- if (!dh_pub_is_valid(dh, dh_client_pub))
- packet_disconnect("bad client public DH value");
-
- klen = DH_size(dh);
- kbuf = xmalloc(klen);
- kout = DH_compute_key(kbuf, dh_client_pub, dh);
-
-#ifdef DEBUG_KEXDH
- debug("shared secret: len %d/%d", klen, kout);
- fprintf(stderr, "shared secret == ");
- for (i = 0; i< kout; i++)
- fprintf(stderr, "%02x", (kbuf[i])&0xff);
- fprintf(stderr, "\n");
-#endif
- shared_secret = BN_new();
-
- BN_bin2bn(kbuf, kout, shared_secret);
- memset(kbuf, 0, klen);
- xfree(kbuf);
-
- /* XXX precompute? */
- key_to_blob(hostkey, &server_host_key_blob, &sbloblen);
-
- /* calc H */ /* XXX depends on 'kex' */
- hash = kex_hash(
- client_version_string,
- server_version_string,
- buffer_ptr(client_kexinit), buffer_len(client_kexinit),
- buffer_ptr(server_kexinit), buffer_len(server_kexinit),
- (char *)server_host_key_blob, sbloblen,
- dh_client_pub,
- dh->pub_key,
- shared_secret
- );
- buffer_free(client_kexinit);
- buffer_free(server_kexinit);
- xfree(client_kexinit);
- xfree(server_kexinit);
- BN_free(dh_client_pub);
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "hash == ");
- for (i = 0; i< 20; i++)
- fprintf(stderr, "%02x", (hash[i])&0xff);
- fprintf(stderr, "\n");
-#endif
- /* save session id := H */
- /* XXX hashlen depends on KEX */
- session_id2_len = 20;
- session_id2 = xmalloc(session_id2_len);
- memcpy(session_id2, hash, session_id2_len);
-
- /* sign H */
- /* XXX hashlen depends on KEX */
- key_sign(hostkey, &signature, &slen, hash, 20);
-
- destroy_sensitive_data();
-
- /* send server hostkey, DH pubkey 'f' and singed H */
- packet_start(SSH2_MSG_KEXDH_REPLY);
- packet_put_string((char *)server_host_key_blob, sbloblen);
- packet_put_bignum2(dh->pub_key); /* f */
- packet_put_string((char *)signature, slen);
- packet_send();
- xfree(signature);
- xfree(server_host_key_blob);
- packet_write_wait();
-
- kex_derive_keys(kex, hash, shared_secret);
- BN_clear_free(shared_secret);
- packet_set_kex(kex);
-
- /* have keys, free DH */
- DH_free(dh);
-}
-
-/* diffie-hellman-group-exchange-sha1 */
-
-void
-ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit)
-{
-#ifdef DEBUG_KEXDH
- int i;
-#endif
- int payload_len, dlen;
- int slen, nbits, type, min, max;
- u_char *signature = NULL;
- u_char *server_host_key_blob = NULL;
- u_int sbloblen;
- u_int klen, kout;
- u_char *kbuf;
- u_char *hash;
- BIGNUM *shared_secret = 0;
- DH *dh;
- BIGNUM *dh_client_pub = 0;
- Key *hostkey;
-
- hostkey = get_hostkey_by_type(kex->hostkey_type);
- if (hostkey == NULL)
- fatal("Unsupported hostkey type %d", kex->hostkey_type);
-
-/* KEXDHGEX */
- debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST.");
- type = packet_read(&payload_len);
- if (type != SSH2_MSG_KEX_DH_GEX_REQUEST_OLD &&
- type != SSH2_MSG_KEX_DH_GEX_REQUEST)
- packet_disconnect("Protocol error: expected type %d or %d, got %d",
- SSH2_MSG_KEX_DH_GEX_REQUEST_OLD,
- SSH2_MSG_KEX_DH_GEX_REQUEST,
- type);
- if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) {
- nbits = packet_get_int();
- min = DH_GRP_MIN;
- max = DH_GRP_MAX;
- } else {
- min = packet_get_int();
- nbits = packet_get_int();
- max = packet_get_int();
-
- min = MAX(DH_GRP_MIN, min);
- max = MIN(DH_GRP_MAX, max);
- }
-
- if (max < min || nbits < min || max < nbits)
- fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
- min, nbits, max);
-
- dh = choose_dh(min, nbits, max);
- if (dh == NULL)
- packet_disconnect("Protocol error: no matching DH grp found");
-
- debug("Sending SSH2_MSG_KEX_DH_GEX_GROUP.");
- packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
- packet_put_bignum2(dh->p);
- packet_put_bignum2(dh->g);
- packet_send();
- packet_write_wait();
-
- /* Compute our exchange value in parallel with the client */
-
- dh_gen_key(dh, kex->we_need * 8);
-
- debug("Wait SSH2_MSG_KEX_DH_GEX_INIT.");
- packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_INIT);
-
- /* key, cert */
- dh_client_pub = BN_new();
- if (dh_client_pub == NULL)
- fatal("dh_client_pub == NULL");
- packet_get_bignum2(dh_client_pub, &dlen);
-
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "\ndh_client_pub= ");
- BN_print_fp(stderr, dh_client_pub);
- fprintf(stderr, "\n");
- debug("bits %d", BN_num_bits(dh_client_pub));
-#endif
-
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "\np= ");
- BN_print_fp(stderr, dh->p);
- fprintf(stderr, "\ng= ");
- bn_print(dh->g);
- fprintf(stderr, "\npub= ");
- BN_print_fp(stderr, dh->pub_key);
- fprintf(stderr, "\n");
- DHparams_print_fp(stderr, dh);
-#endif
- if (!dh_pub_is_valid(dh, dh_client_pub))
- packet_disconnect("bad client public DH value");
-
- klen = DH_size(dh);
- kbuf = xmalloc(klen);
- kout = DH_compute_key(kbuf, dh_client_pub, dh);
-
-#ifdef DEBUG_KEXDH
- debug("shared secret: len %d/%d", klen, kout);
- fprintf(stderr, "shared secret == ");
- for (i = 0; i< kout; i++)
- fprintf(stderr, "%02x", (kbuf[i])&0xff);
- fprintf(stderr, "\n");
-#endif
- shared_secret = BN_new();
-
- BN_bin2bn(kbuf, kout, shared_secret);
- memset(kbuf, 0, klen);
- xfree(kbuf);
-
- /* XXX precompute? */
- key_to_blob(hostkey, &server_host_key_blob, &sbloblen);
-
- /* calc H */ /* XXX depends on 'kex' */
- hash = kex_hash_gex(
- client_version_string,
- server_version_string,
- buffer_ptr(client_kexinit), buffer_len(client_kexinit),
- buffer_ptr(server_kexinit), buffer_len(server_kexinit),
- (char *)server_host_key_blob, sbloblen,
- nbits, dh->p, dh->g,
- dh_client_pub,
- dh->pub_key,
- shared_secret
- );
- buffer_free(client_kexinit);
- buffer_free(server_kexinit);
- xfree(client_kexinit);
- xfree(server_kexinit);
- BN_free(dh_client_pub);
-#ifdef DEBUG_KEXDH
- fprintf(stderr, "hash == ");
- for (i = 0; i< 20; i++)
- fprintf(stderr, "%02x", (hash[i])&0xff);
- fprintf(stderr, "\n");
-#endif
- /* save session id := H */
- /* XXX hashlen depends on KEX */
- session_id2_len = 20;
- session_id2 = xmalloc(session_id2_len);
- memcpy(session_id2, hash, session_id2_len);
-
- /* sign H */
- /* XXX hashlen depends on KEX */
- key_sign(hostkey, &signature, &slen, hash, 20);
-
- destroy_sensitive_data();
-
- /* send server hostkey, DH pubkey 'f' and singed H */
- packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
- packet_put_string((char *)server_host_key_blob, sbloblen);
- packet_put_bignum2(dh->pub_key); /* f */
- packet_put_string((char *)signature, slen);
- packet_send();
- xfree(signature);
- xfree(server_host_key_blob);
- packet_write_wait();
-
- kex_derive_keys(kex, hash, shared_secret);
- BN_clear_free(shared_secret);
- packet_set_kex(kex);
-
- /* have keys, free DH */
- DH_free(dh);
+ debug("KEX done");
}