[BACK]Return to kex.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/kex.c between version 1.6.2.5 and 1.7

version 1.6.2.5, 2001/03/21 18:52:47 version 1.7, 2000/05/25 20:45:20
Line 9 
Line 9 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
    * 3. All advertising materials mentioning features or use of this software
    *    must display the following acknowledgement:
    *      This product includes software developed by Markus Friedl.
    * 4. The name of the author may not be used to endorse or promote products
    *    derived from this software without specific prior written permission.
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Line 23 
Line 28 
  */   */
   
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$Id$");
   
 #include <openssl/crypto.h>  #include "ssh.h"
 #include <openssl/bio.h>  
 #include <openssl/bn.h>  
 #include <openssl/dh.h>  
 #include <openssl/pem.h>  
   
 #include "ssh2.h"  #include "ssh2.h"
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "buffer.h"  #include "buffer.h"
 #include "bufaux.h"  #include "bufaux.h"
 #include "packet.h"  #include "packet.h"
 #include "compat.h"  
 #include "cipher.h"  #include "cipher.h"
   #include "compat.h"
   
   #include <openssl/bn.h>
   #include <openssl/dh.h>
   
   #include <openssl/crypto.h>
   #include <openssl/bio.h>
   #include <openssl/bn.h>
   #include <openssl/dh.h>
   #include <openssl/pem.h>
   
 #include "kex.h"  #include "kex.h"
 #include "key.h"  
 #include "log.h"  
 #include "mac.h"  
 #include "match.h"  
   
 #define KEX_COOKIE_LEN  16  #define KEX_COOKIE_LEN  16
   
Line 50 
Line 56 
 kex_init(char *myproposal[PROPOSAL_MAX])  kex_init(char *myproposal[PROPOSAL_MAX])
 {  {
         int first_kex_packet_follows = 0;          int first_kex_packet_follows = 0;
         u_char cookie[KEX_COOKIE_LEN];          unsigned char cookie[KEX_COOKIE_LEN];
         u_int32_t rand = 0;          u_int32_t rand = 0;
         int i;          int i;
         Buffer *ki = xmalloc(sizeof(*ki));          Buffer *ki = xmalloc(sizeof(*ki));
Line 81 
Line 87 
   
         debug("send KEXINIT");          debug("send KEXINIT");
         packet_start(SSH2_MSG_KEXINIT);          packet_start(SSH2_MSG_KEXINIT);
         packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));          packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
         debug("done");          debug("done");
Line 122 
Line 128 
         int n = BN_num_bits(dh_pub);          int n = BN_num_bits(dh_pub);
         int bits_set = 0;          int bits_set = 0;
   
           /* we only accept g==2 */
           if (!BN_is_word(dh->g, 2)) {
                   log("invalid DH base != 2");
                   return 0;
           }
         if (dh_pub->neg) {          if (dh_pub->neg) {
                 log("invalid public DH value: negativ");                  log("invalid public DH value: negativ");
                 return 0;                  return 0;
Line 138 
Line 149 
         return 0;          return 0;
 }  }
   
 void  
 dh_gen_key(DH *dh, int need)  
 {  
         int i, bits_set = 0, tries = 0;  
   
         if (dh->p == NULL)  
                 fatal("dh_gen_key: dh->p == NULL");  
         if (2*need >= BN_num_bits(dh->p))  
                 fatal("dh_gen_key: group too small: %d (2*need %d)",  
                     BN_num_bits(dh->p), 2*need);  
         do {  
                 if (dh->priv_key != NULL)  
                         BN_free(dh->priv_key);  
                 dh->priv_key = BN_new();  
                 if (dh->priv_key == NULL)  
                         fatal("dh_gen_key: BN_new failed");  
                 /* generate a 2*need bits random private exponent */  
                 if (!BN_rand(dh->priv_key, 2*need, 0, 0))  
                         fatal("dh_gen_key: BN_rand failed");  
                 if (DH_generate_key(dh) == 0)  
                         fatal("DH_generate_key");  
                 for (i = 0; i <= BN_num_bits(dh->priv_key); i++)  
                         if (BN_is_bit_set(dh->priv_key, i))  
                                 bits_set++;  
                 debug("dh_gen_key: priv key bits set: %d/%d",  
                     bits_set, BN_num_bits(dh->priv_key));  
                 if (tries++ > 10)  
                         fatal("dh_gen_key: too many bad keys: giving up");  
         } while (!dh_pub_is_valid(dh, dh->pub_key));  
 }  
   
 DH *  DH *
 dh_new_group_asc(const char *gen, const char *modulus)  dh_new_group1()
 {  {
         DH *dh;          static char *group1 =
         int ret;  
   
         dh = DH_new();  
         if (dh == NULL)  
                 fatal("DH_new");  
   
         if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)  
                 fatal("BN_hex2bn p");  
         if ((ret = BN_hex2bn(&dh->g, gen)) < 0)  
                 fatal("BN_hex2bn g");  
   
         return (dh);  
 }  
   
 /*  
  * This just returns the group, we still need to generate the exchange  
  * value.  
  */  
   
 DH *  
 dh_new_group(BIGNUM *gen, BIGNUM *modulus)  
 {  
         DH *dh;  
   
         dh = DH_new();  
         if (dh == NULL)  
                 fatal("DH_new");  
         dh->p = modulus;  
         dh->g = gen;  
   
         return (dh);  
 }  
   
 DH *  
 dh_new_group1(void)  
 {  
         static char *gen = "2", *group1 =  
             "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"              "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
             "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"              "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
             "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"              "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
             "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"              "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
             "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"              "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
             "FFFFFFFF" "FFFFFFFF";              "FFFFFFFF" "FFFFFFFF";
           DH *dh;
         return (dh_new_group_asc(gen, group1));          int ret, tries = 0;
           dh = DH_new();
           if(dh == NULL)
                   fatal("DH_new");
           ret = BN_hex2bn(&dh->p, group1);
           if(ret<0)
                   fatal("BN_hex2bn");
           dh->g = BN_new();
           if(dh->g == NULL)
                   fatal("DH_new g");
           BN_set_word(dh->g, 2);
           do {
                   if (DH_generate_key(dh) == 0)
                           fatal("DH_generate_key");
                   if (tries++ > 10)
                           fatal("dh_new_group1: too many bad keys: giving up");
           } while (!dh_pub_is_valid(dh, dh->pub_key));
           return dh;
 }  }
   
 #ifdef DEBUG_KEX  
 void  void
 dump_digest(u_char *digest, int len)  dump_digest(unsigned char *digest, int len)
 {  {
         int i;          int i;
         for (i = 0; i< len; i++){          for (i = 0; i< len; i++){
Line 232 
Line 191 
         }          }
         fprintf(stderr, "\n");          fprintf(stderr, "\n");
 }  }
 #endif  
   
 u_char *  unsigned char *
 kex_hash(  kex_hash(
     char *client_version_string,      char *client_version_string,
     char *server_version_string,      char *server_version_string,
Line 246 
Line 204 
     BIGNUM *shared_secret)      BIGNUM *shared_secret)
 {  {
         Buffer b;          Buffer b;
         static u_char digest[EVP_MAX_MD_SIZE];          static unsigned char digest[EVP_MAX_MD_SIZE];
         EVP_MD *evp_md = EVP_sha1();          EVP_MD *evp_md = EVP_sha1();
         EVP_MD_CTX md;          EVP_MD_CTX md;
   
Line 266 
Line 224 
         buffer_put_bignum2(&b, client_dh_pub);          buffer_put_bignum2(&b, client_dh_pub);
         buffer_put_bignum2(&b, server_dh_pub);          buffer_put_bignum2(&b, server_dh_pub);
         buffer_put_bignum2(&b, shared_secret);          buffer_put_bignum2(&b, shared_secret);
   
 #ifdef DEBUG_KEX  #ifdef DEBUG_KEX
         buffer_dump(&b);          buffer_dump(&b);
 #endif  #endif
Line 283 
Line 241 
         return digest;          return digest;
 }  }
   
 u_char *  unsigned char *
 kex_hash_gex(  derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
     char *client_version_string,  
     char *server_version_string,  
     char *ckexinit, int ckexinitlen,  
     char *skexinit, int skexinitlen,  
     char *serverhostkeyblob, int sbloblen,  
     int minbits, BIGNUM *prime, BIGNUM *gen,  
     BIGNUM *client_dh_pub,  
     BIGNUM *server_dh_pub,  
     BIGNUM *shared_secret)  
 {  {
         Buffer b;          Buffer b;
         static u_char digest[EVP_MAX_MD_SIZE];  
         EVP_MD *evp_md = EVP_sha1();          EVP_MD *evp_md = EVP_sha1();
         EVP_MD_CTX md;          EVP_MD_CTX md;
   
         buffer_init(&b);  
         buffer_put_string(&b, client_version_string, strlen(client_version_string));  
         buffer_put_string(&b, server_version_string, strlen(server_version_string));  
   
         /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */  
         buffer_put_int(&b, ckexinitlen+1);  
         buffer_put_char(&b, SSH2_MSG_KEXINIT);  
         buffer_append(&b, ckexinit, ckexinitlen);  
         buffer_put_int(&b, skexinitlen+1);  
         buffer_put_char(&b, SSH2_MSG_KEXINIT);  
         buffer_append(&b, skexinit, skexinitlen);  
   
         buffer_put_string(&b, serverhostkeyblob, sbloblen);  
         buffer_put_int(&b, minbits);  
         buffer_put_bignum2(&b, prime);  
         buffer_put_bignum2(&b, gen);  
         buffer_put_bignum2(&b, client_dh_pub);  
         buffer_put_bignum2(&b, server_dh_pub);  
         buffer_put_bignum2(&b, shared_secret);  
   
 #ifdef DEBUG_KEX  
         buffer_dump(&b);  
 #endif  
   
         EVP_DigestInit(&md, evp_md);  
         EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));  
         EVP_DigestFinal(&md, digest, NULL);  
   
         buffer_free(&b);  
   
 #ifdef DEBUG_KEX  
         dump_digest(digest, evp_md->md_size);  
 #endif  
         return digest;  
 }  
   
 u_char *  
 derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)  
 {  
         Buffer b;  
         EVP_MD *evp_md = EVP_sha1();  
         EVP_MD_CTX md;  
         char c = id;          char c = id;
         int have;          int have;
         int mdsz = evp_md->md_size;          int mdsz = evp_md->md_size;
         u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);          unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
   
         buffer_init(&b);          buffer_init(&b);
         buffer_put_bignum2(&b, shared_secret);          buffer_put_bignum2(&b, shared_secret);
Line 373 
Line 278 
         return digest;          return digest;
 }  }
   
   #define NKEYS   6
   
   #define MAX_PROP        20
   #define SEP     ","
   
   char *
   get_match(char *client, char *server)
   {
           char *sproposals[MAX_PROP];
           char *c, *s, *p, *ret;
           int i, j, nproposals;
   
           c = xstrdup(client);
           s = xstrdup(server);
   
           for ((p = strtok(s, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
                   if (i < MAX_PROP)
                           sproposals[i] = p;
                   else
                           break;
           }
           nproposals = i;
   
           for ((p = strtok(c, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
                   for (j = 0; j < nproposals; j++) {
                           if (strcmp(p, sproposals[j]) == 0) {
                                   ret = xstrdup(p);
                                   xfree(c);
                                   xfree(s);
                                   return ret;
                           }
                   }
           }
           xfree(c);
           xfree(s);
           return NULL;
   }
 void  void
 choose_enc(Enc *enc, char *client, char *server)  choose_enc(Enc *enc, char *client, char *server)
 {  {
         char *name = match_list(client, server, NULL);          char *name = get_match(client, server);
         if (name == NULL)          if (name == NULL)
                 fatal("no matching cipher found: client %s server %s", client, server);                  fatal("no matching cipher found: client %s server %s", client, server);
         enc->cipher = cipher_by_name(name);          enc->type = cipher_number(name);
         if (enc->cipher == NULL)  
                 fatal("matching cipher is not supported: %s", name);          switch (enc->type) {
           case SSH_CIPHER_3DES_CBC:
                   enc->key_len = 24;
                   enc->iv_len = 8;
                   enc->block_size = 8;
                   break;
           case SSH_CIPHER_BLOWFISH_CBC:
           case SSH_CIPHER_CAST128_CBC:
                   enc->key_len = 16;
                   enc->iv_len = 8;
                   enc->block_size = 8;
                   break;
           case SSH_CIPHER_ARCFOUR:
                   enc->key_len = 16;
                   enc->iv_len = 0;
                   enc->block_size = 8;
                   break;
           default:
                   fatal("unsupported cipher %s", name);
           }
         enc->name = name;          enc->name = name;
         enc->enabled = 0;          enc->enabled = 0;
         enc->iv = NULL;          enc->iv = NULL;
Line 390 
Line 351 
 void  void
 choose_mac(Mac *mac, char *client, char *server)  choose_mac(Mac *mac, char *client, char *server)
 {  {
         char *name = match_list(client, server, NULL);          char *name = get_match(client, server);
         if (name == NULL)          if (name == NULL)
                 fatal("no matching mac found: client %s server %s", client, server);                  fatal("no matching mac found: client %s server %s", client, server);
         if (mac_init(mac, name) < 0)          if (strcmp(name, "hmac-md5") == 0) {
                   mac->md = EVP_md5();
           } else if (strcmp(name, "hmac-sha1") == 0) {
                   mac->md = EVP_sha1();
           } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
                   mac->md = EVP_ripemd160();
           } else {
                 fatal("unsupported mac %s", name);                  fatal("unsupported mac %s", name);
         /* truncate the key */          }
         if (datafellows & SSH_BUG_HMAC)  
                 mac->key_len = 16;  
         mac->name = name;          mac->name = name;
           mac->mac_len = mac->md->md_size;
           mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
         mac->key = NULL;          mac->key = NULL;
         mac->enabled = 0;          mac->enabled = 0;
 }  }
 void  void
 choose_comp(Comp *comp, char *client, char *server)  choose_comp(Comp *comp, char *client, char *server)
 {  {
         char *name = match_list(client, server, NULL);          char *name = get_match(client, server);
         if (name == NULL)          if (name == NULL)
                 fatal("no matching comp found: client %s server %s", client, server);                  fatal("no matching comp found: client %s server %s", client, server);
         if (strcmp(name, "zlib") == 0) {          if (strcmp(name, "zlib") == 0) {
Line 420 
Line 387 
 void  void
 choose_kex(Kex *k, char *client, char *server)  choose_kex(Kex *k, char *client, char *server)
 {  {
         k->name = match_list(client, server, NULL);          k->name = get_match(client, server);
         if (k->name == NULL)          if (k->name == NULL)
                 fatal("no kex alg");                  fatal("no kex alg");
         if (strcmp(k->name, KEX_DH1) == 0) {          if (strcmp(k->name, KEX_DH1) != 0)
                 k->kex_type = DH_GRP1_SHA1;  
         } else if (strcmp(k->name, KEX_DHGEX) == 0) {  
                 k->kex_type = DH_GEX_SHA1;  
         } else  
                 fatal("bad kex alg %s", k->name);                  fatal("bad kex alg %s", k->name);
 }  }
 void  void
 choose_hostkeyalg(Kex *k, char *client, char *server)  choose_hostkeyalg(Kex *k, char *client, char *server)
 {  {
         char *hostkeyalg = match_list(client, server, NULL);          k->hostkeyalg = get_match(client, server);
         if (hostkeyalg == NULL)          if (k->hostkeyalg == NULL)
                 fatal("no hostkey alg");                  fatal("no hostkey alg");
         k->hostkey_type = key_type_from_name(hostkeyalg);          if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
         if (k->hostkey_type == KEY_UNSPEC)                  fatal("bad hostkey alg %s", k->hostkeyalg);
                 fatal("bad hostkey alg '%s'", hostkeyalg);  
         xfree(hostkeyalg);  
 }  }
   
 Kex *  Kex *
Line 474 
Line 435 
             sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);              sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
         need = 0;          need = 0;
         for (mode = 0; mode < MODE_MAX; mode++) {          for (mode = 0; mode < MODE_MAX; mode++) {
             if (need < k->enc[mode].cipher->key_len)              if (need < k->enc[mode].key_len)
                     need = k->enc[mode].cipher->key_len;                      need = k->enc[mode].key_len;
             if (need < k->enc[mode].cipher->block_size)              if (need < k->enc[mode].iv_len)
                     need = k->enc[mode].cipher->block_size;                      need = k->enc[mode].iv_len;
             if (need < k->mac[mode].key_len)              if (need < k->mac[mode].key_len)
                     need = k->mac[mode].key_len;                      need = k->mac[mode].key_len;
         }          }
Line 486 
Line 447 
         return k;          return k;
 }  }
   
 #define NKEYS   6  
 int  int
 kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)  kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
 {  {
         int i;          int i;
         int mode;          int mode;
         int ctos;          int ctos;
         u_char *keys[NKEYS];          unsigned char *keys[NKEYS];
   
         for (i = 0; i < NKEYS; i++)          for (i = 0; i < NKEYS; i++)
                 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);                  keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);

Legend:
Removed from v.1.6.2.5  
changed lines
  Added in v.1.7