kexgexs.c revision 164146
1112918Sjeff/* $OpenBSD: kexgexs.c,v 1.10 2006/11/06 21:25:28 markus Exp $ */ 2112918Sjeff/* 3112918Sjeff * Copyright (c) 2000 Niels Provos. All rights reserved. 4112918Sjeff * Copyright (c) 2001 Markus Friedl. All rights reserved. 5112918Sjeff * 6112918Sjeff * Redistribution and use in source and binary forms, with or without 7112918Sjeff * modification, are permitted provided that the following conditions 8112918Sjeff * are met: 9112918Sjeff * 1. Redistributions of source code must retain the above copyright 10112918Sjeff * notice, this list of conditions and the following disclaimer. 11112918Sjeff * 2. Redistributions in binary form must reproduce the above copyright 12112918Sjeff * notice, this list of conditions and the following disclaimer in the 13112918Sjeff * documentation and/or other materials provided with the distribution. 14112918Sjeff * 15112918Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16112918Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17112918Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18112918Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19112918Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20112918Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21112918Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22112918Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23112918Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24112918Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25112918Sjeff */ 26112918Sjeff 27112918Sjeff#include "includes.h" 28112918Sjeff 29112918Sjeff#include <sys/param.h> 30112918Sjeff 31112918Sjeff#include <stdarg.h> 32112918Sjeff#include <stdio.h> 33112918Sjeff#include <string.h> 34112918Sjeff#include <signal.h> 35112918Sjeff 36112918Sjeff#include "xmalloc.h" 37112918Sjeff#include "buffer.h" 38112918Sjeff#include "key.h" 39112918Sjeff#include "cipher.h" 40112918Sjeff#include "kex.h" 41112918Sjeff#include "log.h" 42112918Sjeff#include "packet.h" 43112918Sjeff#include "dh.h" 44112918Sjeff#include "ssh2.h" 45112918Sjeff#include "compat.h" 46115035Smtm#ifdef GSSAPI 47115035Smtm#include "ssh-gss.h" 48112918Sjeff#endif 49112918Sjeff#include "monitor_wrap.h" 50112918Sjeff 51112918Sjeffvoid 52112918Sjeffkexgex_server(Kex *kex) 53112918Sjeff{ 54112918Sjeff BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; 55112918Sjeff Key *server_host_key; 56112918Sjeff DH *dh; 57112918Sjeff u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; 58112918Sjeff u_int sbloblen, klen, slen, hashlen; 59112918Sjeff int min = -1, max = -1, nbits = -1, type, kout; 60112918Sjeff 61112918Sjeff if (kex->load_host_key == NULL) 62112918Sjeff fatal("Cannot load hostkey"); 63112918Sjeff server_host_key = kex->load_host_key(kex->hostkey_type); 64112918Sjeff if (server_host_key == NULL) 65112918Sjeff fatal("Unsupported hostkey type %d", kex->hostkey_type); 66112918Sjeff 67112918Sjeff type = packet_read(); 68112918Sjeff switch (type) { 69112918Sjeff case SSH2_MSG_KEX_DH_GEX_REQUEST: 70112918Sjeff debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); 71112918Sjeff min = packet_get_int(); 72112918Sjeff nbits = packet_get_int(); 73112918Sjeff max = packet_get_int(); 74112918Sjeff min = MAX(DH_GRP_MIN, min); 75112918Sjeff max = MIN(DH_GRP_MAX, max); 76112918Sjeff break; 77112918Sjeff case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: 78112918Sjeff debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); 79112918Sjeff nbits = packet_get_int(); 80112918Sjeff min = DH_GRP_MIN; 81112918Sjeff max = DH_GRP_MAX; 82112918Sjeff /* unused for old GEX */ 83112918Sjeff break; 84112918Sjeff default: 85112918Sjeff fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); 86112918Sjeff } 87112918Sjeff packet_check_eom(); 88112918Sjeff 89112918Sjeff if (max < min || nbits < min || max < nbits) 90112918Sjeff fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", 91112918Sjeff min, nbits, max); 92112918Sjeff 93112918Sjeff /* Contact privileged parent */ 94112918Sjeff dh = PRIVSEP(choose_dh(min, nbits, max)); 95112918Sjeff if (dh == NULL) 96112918Sjeff packet_disconnect("Protocol error: no matching DH grp found"); 97112918Sjeff 98112918Sjeff debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 99112918Sjeff packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); 100112918Sjeff packet_put_bignum2(dh->p); 101112918Sjeff packet_put_bignum2(dh->g); 102112918Sjeff packet_send(); 103112918Sjeff 104112918Sjeff /* flush */ 105112918Sjeff packet_write_wait(); 106112918Sjeff 107112918Sjeff /* Compute our exchange value in parallel with the client */ 108112918Sjeff dh_gen_key(dh, kex->we_need * 8); 109112918Sjeff 110112918Sjeff debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); 111112918Sjeff packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); 112112918Sjeff 113112918Sjeff /* key, cert */ 114112918Sjeff if ((dh_client_pub = BN_new()) == NULL) 115112918Sjeff fatal("dh_client_pub == NULL"); 116112918Sjeff packet_get_bignum2(dh_client_pub); 117112918Sjeff packet_check_eom(); 118112918Sjeff 119112918Sjeff#ifdef DEBUG_KEXDH 120112918Sjeff fprintf(stderr, "dh_client_pub= "); 121112918Sjeff BN_print_fp(stderr, dh_client_pub); 122112918Sjeff fprintf(stderr, "\n"); 123112918Sjeff debug("bits %d", BN_num_bits(dh_client_pub)); 124112918Sjeff#endif 125112918Sjeff 126112918Sjeff#ifdef DEBUG_KEXDH 127112918Sjeff DHparams_print_fp(stderr, dh); 128112918Sjeff fprintf(stderr, "pub= "); 129112918Sjeff BN_print_fp(stderr, dh->pub_key); 130112918Sjeff fprintf(stderr, "\n"); 131112918Sjeff#endif 132112918Sjeff if (!dh_pub_is_valid(dh, dh_client_pub)) 133112918Sjeff packet_disconnect("bad client public DH value"); 134112918Sjeff 135112918Sjeff klen = DH_size(dh); 136112918Sjeff kbuf = xmalloc(klen); 137112918Sjeff if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) 138112918Sjeff fatal("DH_compute_key: failed"); 139112918Sjeff#ifdef DEBUG_KEXDH 140112918Sjeff dump_digest("shared secret", kbuf, kout); 141112918Sjeff#endif 142112918Sjeff if ((shared_secret = BN_new()) == NULL) 143112918Sjeff fatal("kexgex_server: BN_new failed"); 144112918Sjeff if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 145112918Sjeff fatal("kexgex_server: BN_bin2bn failed"); 146112918Sjeff memset(kbuf, 0, klen); 147112918Sjeff xfree(kbuf); 148112918Sjeff 149112918Sjeff key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); 150112918Sjeff 151112918Sjeff if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) 152112918Sjeff min = max = -1; 153112918Sjeff 154112918Sjeff /* calc H */ 155112918Sjeff kexgex_hash( 156112918Sjeff kex->evp_md, 157112918Sjeff kex->client_version_string, 158112918Sjeff kex->server_version_string, 159112918Sjeff buffer_ptr(&kex->peer), buffer_len(&kex->peer), 160112918Sjeff buffer_ptr(&kex->my), buffer_len(&kex->my), 161112918Sjeff server_host_key_blob, sbloblen, 162112918Sjeff min, nbits, max, 163112918Sjeff dh->p, dh->g, 164112918Sjeff dh_client_pub, 165112918Sjeff dh->pub_key, 166112918Sjeff shared_secret, 167115035Smtm &hash, &hashlen 168112918Sjeff ); 169112918Sjeff BN_clear_free(dh_client_pub); 170112918Sjeff 171112918Sjeff /* save session id := H */ 172112918Sjeff if (kex->session_id == NULL) { 173112918Sjeff kex->session_id_len = hashlen; 174112918Sjeff kex->session_id = xmalloc(kex->session_id_len); 175112918Sjeff memcpy(kex->session_id, hash, kex->session_id_len); 176112918Sjeff } 177112918Sjeff 178112918Sjeff /* sign H */ 179112918Sjeff PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, hashlen)); 180115035Smtm 181115035Smtm /* destroy_sensitive_data(); */ 182115035Smtm 183115035Smtm /* send server hostkey, DH pubkey 'f' and singed H */ 184115035Smtm debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); 185115035Smtm packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); 186115035Smtm packet_put_string(server_host_key_blob, sbloblen); 187115035Smtm packet_put_bignum2(dh->pub_key); /* f */ 188115035Smtm packet_put_string(signature, slen); 189115035Smtm packet_send(); 190112918Sjeff 191112918Sjeff xfree(signature); 192112918Sjeff xfree(server_host_key_blob); 193112918Sjeff /* have keys, free DH */ 194112918Sjeff DH_free(dh); 195112918Sjeff 196112918Sjeff kex_derive_keys(kex, hash, hashlen, shared_secret); 197112918Sjeff BN_clear_free(shared_secret); 198112918Sjeff 199112918Sjeff kex_finish(kex); 200112918Sjeff} 201112918Sjeff