1 /* $OpenBSD: kexgexc.c,v 1.11 2006/11/06 21:25:28 markus Exp $ */ 2 /* 3 * Copyright (c) 2000 Niels Provos. All rights reserved. 4 * Copyright (c) 2001 Markus Friedl. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <signal.h> 32 33 #include "xmalloc.h" 34 #include "buffer.h" 35 #include "key.h" 36 #include "cipher.h" 37 #include "kex.h" 38 #include "log.h" 39 #include "packet.h" 40 #include "dh.h" 41 #include "ssh2.h" 42 #include "compat.h" 43 44 void 45 kexgex_client(Kex *kex) 46 { 47 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 48 BIGNUM *p = NULL, *g = NULL; 49 Key *server_host_key; 50 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; 51 u_int klen, slen, sbloblen, hashlen; 52 int kout; 53 int min, max, nbits; 54 DH *dh; 55 56 nbits = dh_estimate(kex->we_need * 8); 57 58 if (datafellows & SSH_OLD_DHGEX) { 59 /* Old GEX request */ 60 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); 61 packet_put_int(nbits); 62 min = DH_GRP_MIN; 63 max = DH_GRP_MAX; 64 65 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits); 66 } else { 67 /* New GEX request */ 68 min = DH_GRP_MIN; 69 max = DH_GRP_MAX; 70 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); 71 packet_put_int(min); 72 packet_put_int(nbits); 73 packet_put_int(max); 74 75 debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent", 76 min, nbits, max); 77 } 78 #ifdef DEBUG_KEXDH 79 fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", 80 min, nbits, max); 81 #endif 82 packet_send(); 83 84 debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); 85 packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP); 86 87 if ((p = BN_new()) == NULL) 88 fatal("BN_new"); 89 packet_get_bignum2(p); 90 if ((g = BN_new()) == NULL) 91 fatal("BN_new"); 92 packet_get_bignum2(g); 93 packet_check_eom(); 94 95 if (BN_num_bits(p) < min || BN_num_bits(p) > max) 96 fatal("DH_GEX group out of range: %d !< %d !< %d", 97 min, BN_num_bits(p), max); 98 99 dh = dh_new_group(g, p); 100 dh_gen_key(dh, kex->we_need * 8); 101 102 #ifdef DEBUG_KEXDH 103 DHparams_print_fp(stderr, dh); 104 fprintf(stderr, "pub= "); 105 BN_print_fp(stderr, dh->pub_key); 106 fprintf(stderr, "\n"); 107 #endif 108 109 debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); 110 /* generate and send 'e', client DH public key */ 111 packet_start(SSH2_MSG_KEX_DH_GEX_INIT); 112 packet_put_bignum2(dh->pub_key); 113 packet_send(); 114 115 debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); 116 packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY); 117 118 /* key, cert */ 119 server_host_key_blob = packet_get_string(&sbloblen); 120 server_host_key = key_from_blob(server_host_key_blob, sbloblen); 121 if (server_host_key == NULL) 122 fatal("cannot decode server_host_key_blob"); 123 if (server_host_key->type != kex->hostkey_type) 124 fatal("type mismatch for decoded server_host_key_blob"); 125 if (kex->verify_host_key == NULL) 126 fatal("cannot verify server_host_key"); 127 if (kex->verify_host_key(server_host_key) == -1) 128 fatal("server_host_key verification failed"); 129 130 /* DH parameter f, server public DH key */ 131 if ((dh_server_pub = BN_new()) == NULL) 132 fatal("dh_server_pub == NULL"); 133 packet_get_bignum2(dh_server_pub); 134 135 #ifdef DEBUG_KEXDH 136 fprintf(stderr, "dh_server_pub= "); 137 BN_print_fp(stderr, dh_server_pub); 138 fprintf(stderr, "\n"); 139 debug("bits %d", BN_num_bits(dh_server_pub)); 140 #endif 141 142 /* signed H */ 143 signature = packet_get_string(&slen); 144 packet_check_eom(); 145 146 if (!dh_pub_is_valid(dh, dh_server_pub)) 147 packet_disconnect("bad server public DH value"); 148 149 klen = DH_size(dh); 150 kbuf = xmalloc(klen); 151 if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0) 152 fatal("DH_compute_key: failed"); 153 #ifdef DEBUG_KEXDH 154 dump_digest("shared secret", kbuf, kout); 155 #endif 156 if ((shared_secret = BN_new()) == NULL) 157 fatal("kexgex_client: BN_new failed"); 158 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 159 fatal("kexgex_client: BN_bin2bn failed"); 160 memset(kbuf, 0, klen); 161 xfree(kbuf); 162 163 if (datafellows & SSH_OLD_DHGEX) 164 min = max = -1; 165 166 /* calc and verify H */ 167 kexgex_hash( 168 kex->evp_md, 169 kex->client_version_string, 170 kex->server_version_string, 171 buffer_ptr(&kex->my), buffer_len(&kex->my), 172 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 173 server_host_key_blob, sbloblen, 174 min, nbits, max, 175 dh->p, dh->g, 176 dh->pub_key, 177 dh_server_pub, 178 shared_secret, 179 &hash, &hashlen 180 ); 181 182 /* have keys, free DH */ 183 DH_free(dh); 184 xfree(server_host_key_blob); 185 BN_clear_free(dh_server_pub); 186 187 if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) 188 fatal("key_verify failed for server_host_key"); 189 key_free(server_host_key); 190 xfree(signature); 191 192 /* save session id */ 193 if (kex->session_id == NULL) { 194 kex->session_id_len = hashlen; 195 kex->session_id = xmalloc(kex->session_id_len); 196 memcpy(kex->session_id, hash, kex->session_id_len); 197 } 198 kex_derive_keys(kex, hash, hashlen, shared_secret); 199 BN_clear_free(shared_secret); 200 201 kex_finish(kex); 202 } 203