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