kexgexs.c revision 221420
1139749Simp/* $OpenBSD: kexgexs.c,v 1.14 2010/11/10 01:33:07 djm Exp $ */ 259743Sgroudier/* 359743Sgroudier * Copyright (c) 2000 Niels Provos. All rights reserved. 459743Sgroudier * Copyright (c) 2001 Markus Friedl. All rights reserved. 586266Sgroudier * 659743Sgroudier * Redistribution and use in source and binary forms, with or without 759743Sgroudier * modification, are permitted provided that the following conditions 859743Sgroudier * are met: 959743Sgroudier * 1. Redistributions of source code must retain the above copyright 1059743Sgroudier * notice, this list of conditions and the following disclaimer. 1159743Sgroudier * 2. Redistributions in binary form must reproduce the above copyright 1259743Sgroudier * notice, this list of conditions and the following disclaimer in the 1359743Sgroudier * documentation and/or other materials provided with the distribution. 1459743Sgroudier * 1559743Sgroudier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1659743Sgroudier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1759743Sgroudier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1859743Sgroudier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1959743Sgroudier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2059743Sgroudier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2159743Sgroudier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2259743Sgroudier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2359743Sgroudier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2459743Sgroudier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2559743Sgroudier */ 2659743Sgroudier 2759743Sgroudier#include "includes.h" 2859743Sgroudier 2959743Sgroudier#include <sys/param.h> 3059743Sgroudier 3159743Sgroudier#include <stdarg.h> 3259743Sgroudier#include <stdio.h> 3359743Sgroudier#include <string.h> 3459743Sgroudier#include <signal.h> 3559743Sgroudier 3659743Sgroudier#include <openssl/dh.h> 3759743Sgroudier 3859743Sgroudier#include "xmalloc.h" 3959743Sgroudier#include "buffer.h" 4059743Sgroudier#include "key.h" 4159743Sgroudier#include "cipher.h" 4259743Sgroudier#include "kex.h" 4359743Sgroudier#include "log.h" 4459743Sgroudier#include "packet.h" 4559743Sgroudier#include "dh.h" 4659743Sgroudier#include "ssh2.h" 4759743Sgroudier#include "compat.h" 4859743Sgroudier#ifdef GSSAPI 4959743Sgroudier#include "ssh-gss.h" 5059743Sgroudier#endif 5159743Sgroudier#include "monitor_wrap.h" 5259743Sgroudier 5359743Sgroudiervoid 5459743Sgroudierkexgex_server(Kex *kex) 5559743Sgroudier{ 5659743Sgroudier BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; 5759743Sgroudier Key *server_host_public, *server_host_private; 5859743Sgroudier DH *dh; 5959743Sgroudier u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; 6059743Sgroudier u_int sbloblen, klen, slen, hashlen; 6159743Sgroudier int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; 6259743Sgroudier int type, kout; 6359743Sgroudier 6459743Sgroudier if (kex->load_host_public_key == NULL || 6559743Sgroudier kex->load_host_private_key == NULL) 6659743Sgroudier fatal("Cannot load hostkey"); 6759743Sgroudier server_host_public = kex->load_host_public_key(kex->hostkey_type); 6859743Sgroudier if (server_host_public == NULL) 6959743Sgroudier fatal("Unsupported hostkey type %d", kex->hostkey_type); 7059743Sgroudier server_host_private = kex->load_host_private_key(kex->hostkey_type); 7159743Sgroudier if (server_host_private == NULL) 7259743Sgroudier fatal("Missing private key for hostkey type %d", 7359743Sgroudier kex->hostkey_type); 7459743Sgroudier 7559743Sgroudier 7659743Sgroudier type = packet_read(); 7759743Sgroudier switch (type) { 7859743Sgroudier case SSH2_MSG_KEX_DH_GEX_REQUEST: 7959743Sgroudier debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); 8059743Sgroudier omin = min = packet_get_int(); 8159743Sgroudier onbits = nbits = packet_get_int(); 8259743Sgroudier omax = max = packet_get_int(); 8359743Sgroudier min = MAX(DH_GRP_MIN, min); 8459743Sgroudier max = MIN(DH_GRP_MAX, max); 8559743Sgroudier nbits = MAX(DH_GRP_MIN, nbits); 8659743Sgroudier nbits = MIN(DH_GRP_MAX, nbits); 8759743Sgroudier break; 8859743Sgroudier case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: 8959743Sgroudier debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); 9059743Sgroudier onbits = nbits = packet_get_int(); 9159743Sgroudier /* unused for old GEX */ 9259743Sgroudier omin = min = DH_GRP_MIN; 9359743Sgroudier omax = max = DH_GRP_MAX; 9459743Sgroudier break; 9559743Sgroudier default: 9659743Sgroudier fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); 9759743Sgroudier } 9859743Sgroudier packet_check_eom(); 9959743Sgroudier 10059743Sgroudier if (omax < omin || onbits < omin || omax < onbits) 10159743Sgroudier fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", 10259743Sgroudier omin, onbits, omax); 10359743Sgroudier 10459743Sgroudier /* Contact privileged parent */ 10559743Sgroudier dh = PRIVSEP(choose_dh(min, nbits, max)); 10659743Sgroudier if (dh == NULL) 10759743Sgroudier packet_disconnect("Protocol error: no matching DH grp found"); 10859743Sgroudier 10959743Sgroudier debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 11059743Sgroudier packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); 11159743Sgroudier packet_put_bignum2(dh->p); 11259743Sgroudier packet_put_bignum2(dh->g); 11359743Sgroudier packet_send(); 11459743Sgroudier 11559743Sgroudier /* flush */ 11659743Sgroudier packet_write_wait(); 11759743Sgroudier 11859743Sgroudier /* Compute our exchange value in parallel with the client */ 11959743Sgroudier dh_gen_key(dh, kex->we_need * 8); 12059743Sgroudier 12159743Sgroudier debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); 12259743Sgroudier packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); 12359743Sgroudier 12459743Sgroudier /* key, cert */ 12559743Sgroudier if ((dh_client_pub = BN_new()) == NULL) 12659743Sgroudier fatal("dh_client_pub == NULL"); 12759743Sgroudier packet_get_bignum2(dh_client_pub); 12859743Sgroudier packet_check_eom(); 12959743Sgroudier 13059743Sgroudier#ifdef DEBUG_KEXDH 13159743Sgroudier fprintf(stderr, "dh_client_pub= "); 13259743Sgroudier BN_print_fp(stderr, dh_client_pub); 13359743Sgroudier fprintf(stderr, "\n"); 13459743Sgroudier debug("bits %d", BN_num_bits(dh_client_pub)); 13559743Sgroudier#endif 13659743Sgroudier 13759743Sgroudier#ifdef DEBUG_KEXDH 13859743Sgroudier DHparams_print_fp(stderr, dh); 13959743Sgroudier fprintf(stderr, "pub= "); 14059743Sgroudier BN_print_fp(stderr, dh->pub_key); 14159743Sgroudier fprintf(stderr, "\n"); 14259743Sgroudier#endif 14359743Sgroudier if (!dh_pub_is_valid(dh, dh_client_pub)) 14459743Sgroudier packet_disconnect("bad client public DH value"); 14559743Sgroudier 14659743Sgroudier klen = DH_size(dh); 14759743Sgroudier kbuf = xmalloc(klen); 14859743Sgroudier if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) 14959743Sgroudier fatal("DH_compute_key: failed"); 15059743Sgroudier#ifdef DEBUG_KEXDH 15159743Sgroudier dump_digest("shared secret", kbuf, kout); 15259743Sgroudier#endif 15359743Sgroudier if ((shared_secret = BN_new()) == NULL) 15459743Sgroudier fatal("kexgex_server: BN_new failed"); 15559743Sgroudier if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 15659743Sgroudier fatal("kexgex_server: BN_bin2bn failed"); 15759743Sgroudier memset(kbuf, 0, klen); 15859743Sgroudier xfree(kbuf); 15959743Sgroudier 16059743Sgroudier key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); 16159743Sgroudier 16259743Sgroudier if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) 16359743Sgroudier omin = min = omax = max = -1; 16459743Sgroudier 16559743Sgroudier /* calc H */ 16659743Sgroudier kexgex_hash( 16759743Sgroudier kex->evp_md, 16859743Sgroudier kex->client_version_string, 16959743Sgroudier kex->server_version_string, 17059743Sgroudier buffer_ptr(&kex->peer), buffer_len(&kex->peer), 17159743Sgroudier buffer_ptr(&kex->my), buffer_len(&kex->my), 17259743Sgroudier server_host_key_blob, sbloblen, 17359743Sgroudier omin, onbits, omax, 17459743Sgroudier dh->p, dh->g, 17559743Sgroudier dh_client_pub, 17659743Sgroudier dh->pub_key, 17759743Sgroudier shared_secret, 17859743Sgroudier &hash, &hashlen 17959743Sgroudier ); 18059743Sgroudier BN_clear_free(dh_client_pub); 18159743Sgroudier 18259743Sgroudier /* save session id := H */ 18359743Sgroudier if (kex->session_id == NULL) { 18459743Sgroudier kex->session_id_len = hashlen; 18559743Sgroudier kex->session_id = xmalloc(kex->session_id_len); 18659743Sgroudier memcpy(kex->session_id, hash, kex->session_id_len); 18759743Sgroudier } 18859743Sgroudier 18959743Sgroudier /* sign H */ 19059743Sgroudier if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash, 19159743Sgroudier hashlen)) < 0) 19259743Sgroudier fatal("kexgex_server: key_sign failed"); 19359743Sgroudier 19459743Sgroudier /* destroy_sensitive_data(); */ 19559743Sgroudier 19659743Sgroudier /* send server hostkey, DH pubkey 'f' and singed H */ 19759743Sgroudier debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); 19859743Sgroudier packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); 19959743Sgroudier packet_put_string(server_host_key_blob, sbloblen); 20059743Sgroudier packet_put_bignum2(dh->pub_key); /* f */ 20159743Sgroudier packet_put_string(signature, slen); 20259743Sgroudier packet_send(); 20359743Sgroudier 20459743Sgroudier xfree(signature); 20559743Sgroudier xfree(server_host_key_blob); 20659743Sgroudier /* have keys, free DH */ 20759743Sgroudier DH_free(dh); 20859743Sgroudier 20959743Sgroudier kex_derive_keys(kex, hash, hashlen, shared_secret); 21059743Sgroudier BN_clear_free(shared_secret); 21159743Sgroudier 21259743Sgroudier kex_finish(kex); 21359743Sgroudier} 21459743Sgroudier