diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2015-01-19 20:16:16 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2015-01-19 20:16:16 +0000 |
commit | 002124f10b6efe41acf62100a28f8d9fad5cafa1 (patch) | |
tree | 68c430a276ba8885606f7fe642ac62ddb1e7222d /usr.bin/ssh/kexdhs.c | |
parent | 42d3f66770b2d25d3ec4b397e2b3fd37cdb1740b (diff) |
adapt kex to sshbuf and struct ssh; ok djm@
Diffstat (limited to 'usr.bin/ssh/kexdhs.c')
-rw-r--r-- | usr.bin/ssh/kexdhs.c | 186 |
1 files changed, 119 insertions, 67 deletions
diff --git a/usr.bin/ssh/kexdhs.c b/usr.bin/ssh/kexdhs.c index 121134c44ed..1ac5a4e16d1 100644 --- a/usr.bin/ssh/kexdhs.c +++ b/usr.bin/ssh/kexdhs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexdhs.c,v 1.19 2015/01/19 19:52:16 markus Exp $ */ +/* $OpenBSD: kexdhs.c,v 1.20 2015/01/19 20:16:15 markus Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -30,55 +30,88 @@ #include <openssl/dh.h> -#include "xmalloc.h" -#include "buffer.h" -#include "key.h" +#include "sshkey.h" #include "cipher.h" +#include "digest.h" #include "kex.h" #include "log.h" #include "packet.h" #include "dh.h" #include "ssh2.h" -void -kexdh_server(Kex *kex) +#include "dispatch.h" +#include "compat.h" +#include "ssherr.h" +#include "sshbuf.h" + +static int input_kex_dh_init(int, u_int32_t, void *); + +int +kexdh_server(struct ssh *ssh) { - BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; - DH *dh; - Key *server_host_public, *server_host_private; - u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; - u_int sbloblen, klen, hashlen, slen; - int kout; + struct kex *kex = ssh->kex; + int r; /* generate server DH public key */ switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: - dh = dh_new_group1(); + kex->dh = dh_new_group1(); break; case KEX_DH_GRP14_SHA1: - dh = dh_new_group14(); + kex->dh = dh_new_group14(); break; default: - fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + r = SSH_ERR_INVALID_ARGUMENT; + goto out; } - dh_gen_key(dh, kex->we_need * 8); + if (kex->dh == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) + goto out; debug("expecting SSH2_MSG_KEXDH_INIT"); - packet_read_expect(SSH2_MSG_KEXDH_INIT); + ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init); + r = 0; + out: + return r; +} + +int +input_kex_dh_init(int type, u_int32_t seq, void *ctxt) +{ + struct ssh *ssh = ctxt; + struct kex *kex = ssh->kex; + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + struct sshkey *server_host_public, *server_host_private; + u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; + u_char hash[SSH_DIGEST_MAX_LENGTH]; + size_t sbloblen, slen; + size_t klen = 0, hashlen; + int kout, r; if (kex->load_host_public_key == NULL || - kex->load_host_private_key == NULL) - fatal("Cannot load hostkey"); - server_host_public = kex->load_host_public_key(kex->hostkey_type); - if (server_host_public == NULL) - fatal("Unsupported hostkey type %d", kex->hostkey_type); - server_host_private = kex->load_host_private_key(kex->hostkey_type); + kex->load_host_private_key == NULL) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } + if ((server_host_public = kex->load_host_public_key(kex->hostkey_type, + ssh)) == NULL || + (server_host_private = kex->load_host_private_key(kex->hostkey_type, + ssh)) == NULL) { + r = SSH_ERR_NO_HOSTKEY_LOADED; + goto out; + } /* key, cert */ - if ((dh_client_pub = BN_new()) == NULL) - fatal("dh_client_pub == NULL"); - packet_get_bignum2(dh_client_pub); - packet_check_eom(); + if ((dh_client_pub = BN_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + goto out; #ifdef DEBUG_KEXDH fprintf(stderr, "dh_client_pub= "); @@ -88,70 +121,89 @@ kexdh_server(Kex *kex) #endif #ifdef DEBUG_KEXDH - DHparams_print_fp(stderr, dh); + DHparams_print_fp(stderr, kex->dh); fprintf(stderr, "pub= "); - BN_print_fp(stderr, dh->pub_key); + BN_print_fp(stderr, kex->dh->pub_key); fprintf(stderr, "\n"); #endif - if (!dh_pub_is_valid(dh, dh_client_pub)) - packet_disconnect("bad client public DH value"); + if (!dh_pub_is_valid(kex->dh, dh_client_pub)) { + sshpkt_disconnect(ssh, "bad client public DH value"); + r = SSH_ERR_MESSAGE_INCOMPLETE; + goto out; + } - klen = DH_size(dh); - kbuf = xmalloc(klen); - if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) - fatal("DH_compute_key: failed"); + klen = DH_size(kex->dh); + if ((kbuf = malloc(klen)) == NULL || + (shared_secret = BN_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 || + BN_bin2bn(kbuf, kout, shared_secret) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, kout); #endif - if ((shared_secret = BN_new()) == NULL) - fatal("kexdh_server: BN_new failed"); - if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) - fatal("kexdh_server: BN_bin2bn failed"); - explicit_bzero(kbuf, klen); - free(kbuf); - - key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); - + if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, + &sbloblen)) != 0) + goto out; /* calc H */ - kex_dh_hash( + hashlen = sizeof(hash); + if ((r = kex_dh_hash( kex->client_version_string, kex->server_version_string, - buffer_ptr(kex->peer), buffer_len(kex->peer), - buffer_ptr(kex->my), buffer_len(kex->my), + sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), + sshbuf_ptr(kex->my), sshbuf_len(kex->my), server_host_key_blob, sbloblen, dh_client_pub, - dh->pub_key, + kex->dh->pub_key, shared_secret, - &hash, &hashlen - ); - BN_clear_free(dh_client_pub); + hash, &hashlen)) != 0) + goto out; /* save session id := H */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; - kex->session_id = xmalloc(kex->session_id_len); + kex->session_id = malloc(kex->session_id_len); + if (kex->session_id == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } memcpy(kex->session_id, hash, kex->session_id_len); } /* sign H */ - kex->sign(server_host_private, server_host_public, &signature, &slen, - hash, hashlen); + if ((r = kex->sign(server_host_private, server_host_public, + &signature, &slen, hash, hashlen, ssh->compat)) < 0) + goto out; /* destroy_sensitive_data(); */ /* send server hostkey, DH pubkey 'f' and singed H */ - packet_start(SSH2_MSG_KEXDH_REPLY); - packet_put_string(server_host_key_blob, sbloblen); - packet_put_bignum2(dh->pub_key); /* f */ - packet_put_string(signature, slen); - packet_send(); - - free(signature); + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 || + (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || + (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ + (r = sshpkt_put_string(ssh, signature, slen)) != 0 || + (r = sshpkt_send(ssh)) != 0) + goto out; + + if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); + out: + explicit_bzero(hash, sizeof(hash)); + DH_free(kex->dh); + kex->dh = NULL; + if (dh_client_pub) + BN_clear_free(dh_client_pub); + if (kbuf) { + explicit_bzero(kbuf, klen); + free(kbuf); + } + if (shared_secret) + BN_clear_free(shared_secret); free(server_host_key_blob); - /* have keys, free DH */ - DH_free(dh); - - kex_derive_keys_bn(kex, hash, hashlen, shared_secret); - BN_clear_free(shared_secret); - kex_finish(kex); + free(signature); + return r; } |