kex.c revision 61209
160573Skris/* 260573Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 360573Skris * 460573Skris * Redistribution and use in source and binary forms, with or without 560573Skris * modification, are permitted provided that the following conditions 660573Skris * are met: 760573Skris * 1. Redistributions of source code must retain the above copyright 860573Skris * notice, this list of conditions and the following disclaimer. 960573Skris * 2. Redistributions in binary form must reproduce the above copyright 1060573Skris * notice, this list of conditions and the following disclaimer in the 1160573Skris * documentation and/or other materials provided with the distribution. 1260573Skris * 3. All advertising materials mentioning features or use of this software 1360573Skris * must display the following acknowledgement: 1460573Skris * This product includes software developed by Markus Friedl. 1560573Skris * 4. The name of the author may not be used to endorse or promote products 1660573Skris * derived from this software without specific prior written permission. 1760573Skris * 1860573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1960573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2060573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2160573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2260573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2360573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2460573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2560573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2660573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2760573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2860573Skris */ 2960573Skris 3060573Skris#include "includes.h" 3161209SkrisRCSID("$Id: kex.c,v 1.7 2000/05/25 20:45:20 markus Exp $"); 3260573Skris 3360573Skris#include "ssh.h" 3460573Skris#include "ssh2.h" 3560573Skris#include "xmalloc.h" 3660573Skris#include "buffer.h" 3760573Skris#include "bufaux.h" 3861209Skris#include "packet.h" 3960573Skris#include "cipher.h" 4060573Skris#include "compat.h" 4160573Skris 4260573Skris#include <openssl/bn.h> 4360573Skris#include <openssl/dh.h> 4460573Skris 4560573Skris#include <openssl/crypto.h> 4660573Skris#include <openssl/bio.h> 4760573Skris#include <openssl/bn.h> 4860573Skris#include <openssl/dh.h> 4960573Skris#include <openssl/pem.h> 5060573Skris 5160573Skris#include "kex.h" 5260573Skris 5361209Skris#define KEX_COOKIE_LEN 16 5461209Skris 5560573SkrisBuffer * 5660573Skriskex_init(char *myproposal[PROPOSAL_MAX]) 5760573Skris{ 5861209Skris int first_kex_packet_follows = 0; 5961209Skris unsigned char cookie[KEX_COOKIE_LEN]; 6060573Skris u_int32_t rand = 0; 6160573Skris int i; 6260573Skris Buffer *ki = xmalloc(sizeof(*ki)); 6361209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) { 6460573Skris if (i % 4 == 0) 6560573Skris rand = arc4random(); 6660573Skris cookie[i] = rand & 0xff; 6760573Skris rand >>= 8; 6860573Skris } 6960573Skris buffer_init(ki); 7060573Skris buffer_append(ki, (char *)cookie, sizeof cookie); 7160573Skris for (i = 0; i < PROPOSAL_MAX; i++) 7260573Skris buffer_put_cstring(ki, myproposal[i]); 7361209Skris buffer_put_char(ki, first_kex_packet_follows); 7461209Skris buffer_put_int(ki, 0); /* uint32 reserved */ 7560573Skris return ki; 7660573Skris} 7760573Skris 7861209Skris/* send kexinit, parse and save reply */ 7961209Skrisvoid 8061209Skriskex_exchange_kexinit( 8161209Skris Buffer *my_kexinit, Buffer *peer_kexint, 8261209Skris char *peer_proposal[PROPOSAL_MAX]) 8361209Skris{ 8461209Skris int i; 8561209Skris char *ptr; 8661209Skris int plen; 8761209Skris 8861209Skris debug("send KEXINIT"); 8961209Skris packet_start(SSH2_MSG_KEXINIT); 9061209Skris packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit)); 9161209Skris packet_send(); 9261209Skris packet_write_wait(); 9361209Skris debug("done"); 9461209Skris 9561209Skris /* 9661209Skris * read and save raw KEXINIT payload in buffer. this is used during 9761209Skris * computation of the session_id and the session keys. 9861209Skris */ 9961209Skris debug("wait KEXINIT"); 10061209Skris packet_read_expect(&plen, SSH2_MSG_KEXINIT); 10161209Skris ptr = packet_get_raw(&plen); 10261209Skris buffer_append(peer_kexint, ptr, plen); 10361209Skris 10461209Skris /* parse packet and save algorithm proposal */ 10561209Skris /* skip cookie */ 10661209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) 10761209Skris packet_get_char(); 10861209Skris /* extract kex init proposal strings */ 10961209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 11061209Skris peer_proposal[i] = packet_get_string(NULL); 11161209Skris debug("got kexinit: %s", peer_proposal[i]); 11261209Skris } 11361209Skris /* first kex follow / reserved */ 11461209Skris i = packet_get_char(); 11561209Skris debug("first kex follow: %d ", i); 11661209Skris i = packet_get_int(); 11761209Skris debug("reserved: %d ", i); 11861209Skris packet_done(); 11961209Skris debug("done"); 12061209Skris} 12161209Skris 12260573Skris/* diffie-hellman-group1-sha1 */ 12360573Skris 12460573Skrisint 12560573Skrisdh_pub_is_valid(DH *dh, BIGNUM *dh_pub) 12660573Skris{ 12760573Skris int i; 12860573Skris int n = BN_num_bits(dh_pub); 12960573Skris int bits_set = 0; 13060573Skris 13160573Skris /* we only accept g==2 */ 13260573Skris if (!BN_is_word(dh->g, 2)) { 13360573Skris log("invalid DH base != 2"); 13460573Skris return 0; 13560573Skris } 13660573Skris if (dh_pub->neg) { 13760573Skris log("invalid public DH value: negativ"); 13860573Skris return 0; 13960573Skris } 14060573Skris for (i = 0; i <= n; i++) 14160573Skris if (BN_is_bit_set(dh_pub, i)) 14260573Skris bits_set++; 14360573Skris debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); 14460573Skris 14560573Skris /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ 14660573Skris if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) 14760573Skris return 1; 14860573Skris log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); 14960573Skris return 0; 15060573Skris} 15160573Skris 15260573SkrisDH * 15360573Skrisdh_new_group1() 15460573Skris{ 15560573Skris static char *group1 = 15660573Skris "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 15760573Skris "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 15860573Skris "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 15960573Skris "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 16060573Skris "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 16160573Skris "FFFFFFFF" "FFFFFFFF"; 16260573Skris DH *dh; 16360573Skris int ret, tries = 0; 16460573Skris dh = DH_new(); 16560573Skris if(dh == NULL) 16660573Skris fatal("DH_new"); 16760573Skris ret = BN_hex2bn(&dh->p, group1); 16860573Skris if(ret<0) 16960573Skris fatal("BN_hex2bn"); 17060573Skris dh->g = BN_new(); 17160573Skris if(dh->g == NULL) 17260573Skris fatal("DH_new g"); 17360573Skris BN_set_word(dh->g, 2); 17460573Skris do { 17560573Skris if (DH_generate_key(dh) == 0) 17660573Skris fatal("DH_generate_key"); 17760573Skris if (tries++ > 10) 17860573Skris fatal("dh_new_group1: too many bad keys: giving up"); 17960573Skris } while (!dh_pub_is_valid(dh, dh->pub_key)); 18060573Skris return dh; 18160573Skris} 18260573Skris 18360573Skrisvoid 18460573Skrisdump_digest(unsigned char *digest, int len) 18560573Skris{ 18660573Skris int i; 18760573Skris for (i = 0; i< len; i++){ 18860573Skris fprintf(stderr, "%02x", digest[i]); 18960573Skris if(i%2!=0) 19060573Skris fprintf(stderr, " "); 19160573Skris } 19260573Skris fprintf(stderr, "\n"); 19360573Skris} 19460573Skris 19560573Skrisunsigned char * 19660573Skriskex_hash( 19760573Skris char *client_version_string, 19860573Skris char *server_version_string, 19960573Skris char *ckexinit, int ckexinitlen, 20060573Skris char *skexinit, int skexinitlen, 20160573Skris char *serverhostkeyblob, int sbloblen, 20260573Skris BIGNUM *client_dh_pub, 20360573Skris BIGNUM *server_dh_pub, 20460573Skris BIGNUM *shared_secret) 20560573Skris{ 20660573Skris Buffer b; 20760573Skris static unsigned char digest[EVP_MAX_MD_SIZE]; 20860573Skris EVP_MD *evp_md = EVP_sha1(); 20960573Skris EVP_MD_CTX md; 21060573Skris 21160573Skris buffer_init(&b); 21260573Skris buffer_put_string(&b, client_version_string, strlen(client_version_string)); 21360573Skris buffer_put_string(&b, server_version_string, strlen(server_version_string)); 21460573Skris 21560573Skris /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 21660573Skris buffer_put_int(&b, ckexinitlen+1); 21760573Skris buffer_put_char(&b, SSH2_MSG_KEXINIT); 21860573Skris buffer_append(&b, ckexinit, ckexinitlen); 21960573Skris buffer_put_int(&b, skexinitlen+1); 22060573Skris buffer_put_char(&b, SSH2_MSG_KEXINIT); 22160573Skris buffer_append(&b, skexinit, skexinitlen); 22260573Skris 22360573Skris buffer_put_string(&b, serverhostkeyblob, sbloblen); 22460573Skris buffer_put_bignum2(&b, client_dh_pub); 22560573Skris buffer_put_bignum2(&b, server_dh_pub); 22660573Skris buffer_put_bignum2(&b, shared_secret); 22760573Skris 22860573Skris#ifdef DEBUG_KEX 22960573Skris buffer_dump(&b); 23060573Skris#endif 23160573Skris 23260573Skris EVP_DigestInit(&md, evp_md); 23360573Skris EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 23460573Skris EVP_DigestFinal(&md, digest, NULL); 23560573Skris 23660573Skris buffer_free(&b); 23760573Skris 23860573Skris#ifdef DEBUG_KEX 23960573Skris dump_digest(digest, evp_md->md_size); 24060573Skris#endif 24160573Skris return digest; 24260573Skris} 24360573Skris 24460573Skrisunsigned char * 24560573Skrisderive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) 24660573Skris{ 24760573Skris Buffer b; 24860573Skris EVP_MD *evp_md = EVP_sha1(); 24960573Skris EVP_MD_CTX md; 25060573Skris char c = id; 25160573Skris int have; 25260573Skris int mdsz = evp_md->md_size; 25360573Skris unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); 25460573Skris 25560573Skris buffer_init(&b); 25660573Skris buffer_put_bignum2(&b, shared_secret); 25760573Skris 25860573Skris EVP_DigestInit(&md, evp_md); 25960573Skris EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ 26060573Skris EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ 26160573Skris EVP_DigestUpdate(&md, &c, 1); /* key id */ 26260573Skris EVP_DigestUpdate(&md, hash, mdsz); /* session id */ 26360573Skris EVP_DigestFinal(&md, digest, NULL); 26460573Skris 26560573Skris /* expand */ 26660573Skris for (have = mdsz; need > have; have += mdsz) { 26760573Skris EVP_DigestInit(&md, evp_md); 26860573Skris EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 26960573Skris EVP_DigestUpdate(&md, hash, mdsz); 27060573Skris EVP_DigestUpdate(&md, digest, have); 27160573Skris EVP_DigestFinal(&md, digest + have, NULL); 27260573Skris } 27360573Skris buffer_free(&b); 27460573Skris#ifdef DEBUG_KEX 27560573Skris fprintf(stderr, "Digest '%c'== ", c); 27660573Skris dump_digest(digest, need); 27760573Skris#endif 27860573Skris return digest; 27960573Skris} 28060573Skris 28160573Skris#define NKEYS 6 28260573Skris 28360573Skris#define MAX_PROP 20 28460573Skris#define SEP "," 28560573Skris 28660573Skrischar * 28760573Skrisget_match(char *client, char *server) 28860573Skris{ 28960573Skris char *sproposals[MAX_PROP]; 29061209Skris char *c, *s, *p, *ret; 29160573Skris int i, j, nproposals; 29260573Skris 29361209Skris c = xstrdup(client); 29461209Skris s = xstrdup(server); 29561209Skris 29661209Skris for ((p = strtok(s, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 29760573Skris if (i < MAX_PROP) 29860573Skris sproposals[i] = p; 29960573Skris else 30060573Skris break; 30160573Skris } 30260573Skris nproposals = i; 30360573Skris 30461209Skris for ((p = strtok(c, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 30561209Skris for (j = 0; j < nproposals; j++) { 30661209Skris if (strcmp(p, sproposals[j]) == 0) { 30761209Skris ret = xstrdup(p); 30861209Skris xfree(c); 30961209Skris xfree(s); 31061209Skris return ret; 31161209Skris } 31261209Skris } 31360573Skris } 31461209Skris xfree(c); 31561209Skris xfree(s); 31660573Skris return NULL; 31760573Skris} 31860573Skrisvoid 31960573Skrischoose_enc(Enc *enc, char *client, char *server) 32060573Skris{ 32160573Skris char *name = get_match(client, server); 32260573Skris if (name == NULL) 32360573Skris fatal("no matching cipher found: client %s server %s", client, server); 32460573Skris enc->type = cipher_number(name); 32560573Skris 32660573Skris switch (enc->type) { 32760573Skris case SSH_CIPHER_3DES_CBC: 32860573Skris enc->key_len = 24; 32960573Skris enc->iv_len = 8; 33060573Skris enc->block_size = 8; 33160573Skris break; 33260573Skris case SSH_CIPHER_BLOWFISH_CBC: 33360573Skris case SSH_CIPHER_CAST128_CBC: 33460573Skris enc->key_len = 16; 33560573Skris enc->iv_len = 8; 33660573Skris enc->block_size = 8; 33760573Skris break; 33860573Skris case SSH_CIPHER_ARCFOUR: 33960573Skris enc->key_len = 16; 34060573Skris enc->iv_len = 0; 34160573Skris enc->block_size = 8; 34260573Skris break; 34360573Skris default: 34460573Skris fatal("unsupported cipher %s", name); 34560573Skris } 34660573Skris enc->name = name; 34760573Skris enc->enabled = 0; 34860573Skris enc->iv = NULL; 34960573Skris enc->key = NULL; 35060573Skris} 35160573Skrisvoid 35260573Skrischoose_mac(Mac *mac, char *client, char *server) 35360573Skris{ 35460573Skris char *name = get_match(client, server); 35560573Skris if (name == NULL) 35660573Skris fatal("no matching mac found: client %s server %s", client, server); 35760573Skris if (strcmp(name, "hmac-md5") == 0) { 35860573Skris mac->md = EVP_md5(); 35960573Skris } else if (strcmp(name, "hmac-sha1") == 0) { 36060573Skris mac->md = EVP_sha1(); 36160573Skris } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) { 36260573Skris mac->md = EVP_ripemd160(); 36360573Skris } else { 36460573Skris fatal("unsupported mac %s", name); 36560573Skris } 36660573Skris mac->name = name; 36760573Skris mac->mac_len = mac->md->md_size; 36860573Skris mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len; 36960573Skris mac->key = NULL; 37060573Skris mac->enabled = 0; 37160573Skris} 37260573Skrisvoid 37360573Skrischoose_comp(Comp *comp, char *client, char *server) 37460573Skris{ 37560573Skris char *name = get_match(client, server); 37660573Skris if (name == NULL) 37760573Skris fatal("no matching comp found: client %s server %s", client, server); 37860573Skris if (strcmp(name, "zlib") == 0) { 37960573Skris comp->type = 1; 38060573Skris } else if (strcmp(name, "none") == 0) { 38160573Skris comp->type = 0; 38260573Skris } else { 38360573Skris fatal("unsupported comp %s", name); 38460573Skris } 38560573Skris comp->name = name; 38660573Skris} 38760573Skrisvoid 38860573Skrischoose_kex(Kex *k, char *client, char *server) 38960573Skris{ 39060573Skris k->name = get_match(client, server); 39160573Skris if (k->name == NULL) 39260573Skris fatal("no kex alg"); 39360573Skris if (strcmp(k->name, KEX_DH1) != 0) 39460573Skris fatal("bad kex alg %s", k->name); 39560573Skris} 39660573Skrisvoid 39760573Skrischoose_hostkeyalg(Kex *k, char *client, char *server) 39860573Skris{ 39960573Skris k->hostkeyalg = get_match(client, server); 40060573Skris if (k->hostkeyalg == NULL) 40160573Skris fatal("no hostkey alg"); 40260573Skris if (strcmp(k->hostkeyalg, KEX_DSS) != 0) 40360573Skris fatal("bad hostkey alg %s", k->hostkeyalg); 40460573Skris} 40560573Skris 40660573SkrisKex * 40760573Skriskex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) 40860573Skris{ 40960573Skris int mode; 41060573Skris int ctos; /* direction: if true client-to-server */ 41160573Skris int need; 41260573Skris Kex *k; 41360573Skris 41460573Skris k = xmalloc(sizeof(*k)); 41560573Skris memset(k, 0, sizeof(*k)); 41660573Skris k->server = server; 41760573Skris 41860573Skris for (mode = 0; mode < MODE_MAX; mode++) { 41960573Skris int nenc, nmac, ncomp; 42060573Skris ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 42160573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 42260573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 42360573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 42460573Skris choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]); 42560573Skris choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]); 42660573Skris choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]); 42760573Skris debug("kex: %s %s %s %s", 42860573Skris ctos ? "client->server" : "server->client", 42960573Skris k->enc[mode].name, 43060573Skris k->mac[mode].name, 43160573Skris k->comp[mode].name); 43260573Skris } 43360573Skris choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 43460573Skris choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 43560573Skris sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 43660573Skris need = 0; 43760573Skris for (mode = 0; mode < MODE_MAX; mode++) { 43860573Skris if (need < k->enc[mode].key_len) 43960573Skris need = k->enc[mode].key_len; 44060573Skris if (need < k->enc[mode].iv_len) 44160573Skris need = k->enc[mode].iv_len; 44260573Skris if (need < k->mac[mode].key_len) 44360573Skris need = k->mac[mode].key_len; 44460573Skris } 44561209Skris /* XXX need runden? */ 44660573Skris k->we_need = need; 44760573Skris return k; 44860573Skris} 44960573Skris 45060573Skrisint 45160573Skriskex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret) 45260573Skris{ 45360573Skris int i; 45460573Skris int mode; 45560573Skris int ctos; 45660573Skris unsigned char *keys[NKEYS]; 45760573Skris 45860573Skris for (i = 0; i < NKEYS; i++) 45960573Skris keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret); 46060573Skris 46160573Skris for (mode = 0; mode < MODE_MAX; mode++) { 46260573Skris ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 46360573Skris k->enc[mode].iv = keys[ctos ? 0 : 1]; 46460573Skris k->enc[mode].key = keys[ctos ? 2 : 3]; 46560573Skris k->mac[mode].key = keys[ctos ? 4 : 5]; 46660573Skris } 46760573Skris return 0; 46860573Skris} 469