kex.c revision 92555
160573Skris/* 292555Sdes * Copyright (c) 2000, 2001 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 * 1360573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1460573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1560573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1660573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1760573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1860573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1960573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2060573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2160573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2260573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2360573Skris */ 2460573Skris 2560573Skris#include "includes.h" 2692555SdesRCSID("$OpenBSD: kex.c,v 1.47 2002/02/28 15:46:33 markus Exp $"); 2760573Skris 2876259Sgreen#include <openssl/crypto.h> 2976259Sgreen 3060573Skris#include "ssh2.h" 3160573Skris#include "xmalloc.h" 3260573Skris#include "buffer.h" 3360573Skris#include "bufaux.h" 3461209Skris#include "packet.h" 3560573Skris#include "compat.h" 3676259Sgreen#include "cipher.h" 3760573Skris#include "kex.h" 3876259Sgreen#include "key.h" 3976259Sgreen#include "log.h" 4076259Sgreen#include "mac.h" 4176259Sgreen#include "match.h" 4276259Sgreen#include "dispatch.h" 4360573Skris 4461209Skris#define KEX_COOKIE_LEN 16 4561209Skris 4692555Sdes/* prototype */ 4792555Sdesstatic void kex_kexinit_finish(Kex *); 4892555Sdesstatic void kex_choose_conf(Kex *); 4976259Sgreen 5076259Sgreen/* put algorithm proposal into buffer */ 5192555Sdesstatic void 5276259Sgreenkex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 5360573Skris{ 5460573Skris u_int32_t rand = 0; 5560573Skris int i; 5676259Sgreen 5776259Sgreen buffer_clear(b); 5861209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) { 5960573Skris if (i % 4 == 0) 6060573Skris rand = arc4random(); 6176259Sgreen buffer_put_char(b, rand & 0xff); 6260573Skris rand >>= 8; 6360573Skris } 6460573Skris for (i = 0; i < PROPOSAL_MAX; i++) 6576259Sgreen buffer_put_cstring(b, proposal[i]); 6676259Sgreen buffer_put_char(b, 0); /* first_kex_packet_follows */ 6776259Sgreen buffer_put_int(b, 0); /* uint32 reserved */ 6860573Skris} 6960573Skris 7076259Sgreen/* parse buffer and return algorithm proposal */ 7192555Sdesstatic char ** 7276259Sgreenkex_buf2prop(Buffer *raw) 7361209Skris{ 7476259Sgreen Buffer b; 7561209Skris int i; 7676259Sgreen char **proposal; 7761209Skris 7876259Sgreen proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); 7961209Skris 8076259Sgreen buffer_init(&b); 8176259Sgreen buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 8261209Skris /* skip cookie */ 8361209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) 8476259Sgreen buffer_get_char(&b); 8561209Skris /* extract kex init proposal strings */ 8661209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 8776259Sgreen proposal[i] = buffer_get_string(&b,NULL); 8876259Sgreen debug2("kex_parse_kexinit: %s", proposal[i]); 8961209Skris } 9076259Sgreen /* first kex follows / reserved */ 9176259Sgreen i = buffer_get_char(&b); 9276259Sgreen debug2("kex_parse_kexinit: first_kex_follows %d ", i); 9376259Sgreen i = buffer_get_int(&b); 9476259Sgreen debug2("kex_parse_kexinit: reserved %d ", i); 9576259Sgreen buffer_free(&b); 9676259Sgreen return proposal; 9761209Skris} 9861209Skris 9992555Sdesstatic void 10076259Sgreenkex_prop_free(char **proposal) 10160573Skris{ 10260573Skris int i; 10360573Skris 10476259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 10576259Sgreen xfree(proposal[i]); 10676259Sgreen xfree(proposal); 10760573Skris} 10860573Skris 10992555Sdesstatic void 11092555Sdeskex_protocol_error(int type, u_int32_t seq, void *ctxt) 11160573Skris{ 11292555Sdes error("Hm, kex protocol error: type %d seq %u", type, seq); 11360573Skris} 11460573Skris 11592555Sdesstatic void 11692555Sdeskex_reset_dispatch(void) 11769587Sgreen{ 11892555Sdes dispatch_range(SSH2_MSG_TRANSPORT_MIN, 11992555Sdes SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 12092555Sdes dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 12169587Sgreen} 12269587Sgreen 12376259Sgreenvoid 12476259Sgreenkex_finish(Kex *kex) 12569587Sgreen{ 12692555Sdes kex_reset_dispatch(); 12769587Sgreen 12876259Sgreen packet_start(SSH2_MSG_NEWKEYS); 12976259Sgreen packet_send(); 13076259Sgreen /* packet_write_wait(); */ 13176259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 13269587Sgreen 13376259Sgreen debug("waiting for SSH2_MSG_NEWKEYS"); 13492555Sdes packet_read_expect(SSH2_MSG_NEWKEYS); 13592555Sdes packet_check_eom(); 13676259Sgreen debug("SSH2_MSG_NEWKEYS received"); 13769587Sgreen 13876259Sgreen kex->done = 1; 13976259Sgreen buffer_clear(&kex->peer); 14076259Sgreen /* buffer_clear(&kex->my); */ 14176259Sgreen kex->flags &= ~KEX_INIT_SENT; 14276259Sgreen xfree(kex->name); 14376259Sgreen kex->name = NULL; 14469587Sgreen} 14569587Sgreen 14660573Skrisvoid 14776259Sgreenkex_send_kexinit(Kex *kex) 14860573Skris{ 14976259Sgreen if (kex == NULL) { 15076259Sgreen error("kex_send_kexinit: no kex, cannot rekey"); 15176259Sgreen return; 15260573Skris } 15376259Sgreen if (kex->flags & KEX_INIT_SENT) { 15476259Sgreen debug("KEX_INIT_SENT"); 15576259Sgreen return; 15676259Sgreen } 15776259Sgreen kex->done = 0; 15876259Sgreen packet_start(SSH2_MSG_KEXINIT); 15976259Sgreen packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 16076259Sgreen packet_send(); 16176259Sgreen debug("SSH2_MSG_KEXINIT sent"); 16276259Sgreen kex->flags |= KEX_INIT_SENT; 16360573Skris} 16460573Skris 16576259Sgreenvoid 16692555Sdeskex_input_kexinit(int type, u_int32_t seq, void *ctxt) 16760573Skris{ 16876259Sgreen char *ptr; 16976259Sgreen int dlen; 17076259Sgreen int i; 17176259Sgreen Kex *kex = (Kex *)ctxt; 17260573Skris 17376259Sgreen debug("SSH2_MSG_KEXINIT received"); 17476259Sgreen if (kex == NULL) 17576259Sgreen fatal("kex_input_kexinit: no kex, cannot rekey"); 17660573Skris 17776259Sgreen ptr = packet_get_raw(&dlen); 17876259Sgreen buffer_append(&kex->peer, ptr, dlen); 17960573Skris 18076259Sgreen /* discard packet */ 18176259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 18276259Sgreen packet_get_char(); 18376259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 18476259Sgreen xfree(packet_get_string(NULL)); 18576259Sgreen packet_get_char(); 18676259Sgreen packet_get_int(); 18792555Sdes packet_check_eom(); 18860573Skris 18976259Sgreen kex_kexinit_finish(kex); 19060573Skris} 19160573Skris 19276259SgreenKex * 19376259Sgreenkex_setup(char *proposal[PROPOSAL_MAX]) 19469587Sgreen{ 19576259Sgreen Kex *kex; 19669587Sgreen 19776259Sgreen kex = xmalloc(sizeof(*kex)); 19876259Sgreen memset(kex, 0, sizeof(*kex)); 19976259Sgreen buffer_init(&kex->peer); 20076259Sgreen buffer_init(&kex->my); 20176259Sgreen kex_prop2buf(&kex->my, proposal); 20276259Sgreen kex->done = 0; 20369587Sgreen 20476259Sgreen kex_send_kexinit(kex); /* we start */ 20592555Sdes kex_reset_dispatch(); 20669587Sgreen 20776259Sgreen return kex; 20869587Sgreen} 20969587Sgreen 21092555Sdesstatic void 21176259Sgreenkex_kexinit_finish(Kex *kex) 21260573Skris{ 21376259Sgreen if (!(kex->flags & KEX_INIT_SENT)) 21476259Sgreen kex_send_kexinit(kex); 21560573Skris 21676259Sgreen kex_choose_conf(kex); 21760573Skris 21892555Sdes switch (kex->kex_type) { 21976259Sgreen case DH_GRP1_SHA1: 22076259Sgreen kexdh(kex); 22176259Sgreen break; 22276259Sgreen case DH_GEX_SHA1: 22376259Sgreen kexgex(kex); 22476259Sgreen break; 22576259Sgreen default: 22676259Sgreen fatal("Unsupported key exchange %d", kex->kex_type); 22760573Skris } 22860573Skris} 22960573Skris 23092555Sdesstatic void 23160573Skrischoose_enc(Enc *enc, char *client, char *server) 23260573Skris{ 23376259Sgreen char *name = match_list(client, server, NULL); 23460573Skris if (name == NULL) 23560573Skris fatal("no matching cipher found: client %s server %s", client, server); 23692555Sdes if ((enc->cipher = cipher_by_name(name)) == NULL) 23769587Sgreen fatal("matching cipher is not supported: %s", name); 23860573Skris enc->name = name; 23960573Skris enc->enabled = 0; 24060573Skris enc->iv = NULL; 24160573Skris enc->key = NULL; 24292555Sdes enc->key_len = cipher_keylen(enc->cipher); 24392555Sdes enc->block_size = cipher_blocksize(enc->cipher); 24460573Skris} 24592555Sdesstatic void 24660573Skrischoose_mac(Mac *mac, char *client, char *server) 24760573Skris{ 24876259Sgreen char *name = match_list(client, server, NULL); 24960573Skris if (name == NULL) 25060573Skris fatal("no matching mac found: client %s server %s", client, server); 25176259Sgreen if (mac_init(mac, name) < 0) 25260573Skris fatal("unsupported mac %s", name); 25376259Sgreen /* truncate the key */ 25476259Sgreen if (datafellows & SSH_BUG_HMAC) 25576259Sgreen mac->key_len = 16; 25660573Skris mac->name = name; 25760573Skris mac->key = NULL; 25860573Skris mac->enabled = 0; 25960573Skris} 26092555Sdesstatic void 26160573Skrischoose_comp(Comp *comp, char *client, char *server) 26260573Skris{ 26376259Sgreen char *name = match_list(client, server, NULL); 26460573Skris if (name == NULL) 26560573Skris fatal("no matching comp found: client %s server %s", client, server); 26660573Skris if (strcmp(name, "zlib") == 0) { 26760573Skris comp->type = 1; 26860573Skris } else if (strcmp(name, "none") == 0) { 26960573Skris comp->type = 0; 27060573Skris } else { 27160573Skris fatal("unsupported comp %s", name); 27260573Skris } 27360573Skris comp->name = name; 27460573Skris} 27592555Sdesstatic void 27660573Skrischoose_kex(Kex *k, char *client, char *server) 27760573Skris{ 27876259Sgreen k->name = match_list(client, server, NULL); 27960573Skris if (k->name == NULL) 28060573Skris fatal("no kex alg"); 28169587Sgreen if (strcmp(k->name, KEX_DH1) == 0) { 28269587Sgreen k->kex_type = DH_GRP1_SHA1; 28369587Sgreen } else if (strcmp(k->name, KEX_DHGEX) == 0) { 28469587Sgreen k->kex_type = DH_GEX_SHA1; 28569587Sgreen } else 28660573Skris fatal("bad kex alg %s", k->name); 28760573Skris} 28892555Sdesstatic void 28960573Skrischoose_hostkeyalg(Kex *k, char *client, char *server) 29060573Skris{ 29176259Sgreen char *hostkeyalg = match_list(client, server, NULL); 29276259Sgreen if (hostkeyalg == NULL) 29360573Skris fatal("no hostkey alg"); 29476259Sgreen k->hostkey_type = key_type_from_name(hostkeyalg); 29576259Sgreen if (k->hostkey_type == KEY_UNSPEC) 29676259Sgreen fatal("bad hostkey alg '%s'", hostkeyalg); 29776259Sgreen xfree(hostkeyalg); 29860573Skris} 29960573Skris 30092555Sdesstatic void 30176259Sgreenkex_choose_conf(Kex *kex) 30260573Skris{ 30376259Sgreen Newkeys *newkeys; 30476259Sgreen char **my, **peer; 30576259Sgreen char **cprop, **sprop; 30676259Sgreen int nenc, nmac, ncomp; 30760573Skris int mode; 30860573Skris int ctos; /* direction: if true client-to-server */ 30960573Skris int need; 31060573Skris 31176259Sgreen my = kex_buf2prop(&kex->my); 31276259Sgreen peer = kex_buf2prop(&kex->peer); 31360573Skris 31476259Sgreen if (kex->server) { 31576259Sgreen cprop=peer; 31676259Sgreen sprop=my; 31776259Sgreen } else { 31876259Sgreen cprop=my; 31976259Sgreen sprop=peer; 32076259Sgreen } 32176259Sgreen 32276259Sgreen /* Algorithm Negotiation */ 32360573Skris for (mode = 0; mode < MODE_MAX; mode++) { 32476259Sgreen newkeys = xmalloc(sizeof(*newkeys)); 32576259Sgreen memset(newkeys, 0, sizeof(*newkeys)); 32676259Sgreen kex->newkeys[mode] = newkeys; 32776259Sgreen ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 32860573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 32960573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 33060573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 33176259Sgreen choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 33276259Sgreen choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 33376259Sgreen choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 33460573Skris debug("kex: %s %s %s %s", 33560573Skris ctos ? "client->server" : "server->client", 33676259Sgreen newkeys->enc.name, 33776259Sgreen newkeys->mac.name, 33876259Sgreen newkeys->comp.name); 33960573Skris } 34076259Sgreen choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 34176259Sgreen choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 34260573Skris sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 34360573Skris need = 0; 34460573Skris for (mode = 0; mode < MODE_MAX; mode++) { 34576259Sgreen newkeys = kex->newkeys[mode]; 34692555Sdes if (need < newkeys->enc.key_len) 34792555Sdes need = newkeys->enc.key_len; 34892555Sdes if (need < newkeys->enc.block_size) 34992555Sdes need = newkeys->enc.block_size; 35076259Sgreen if (need < newkeys->mac.key_len) 35176259Sgreen need = newkeys->mac.key_len; 35260573Skris } 35361209Skris /* XXX need runden? */ 35476259Sgreen kex->we_need = need; 35576259Sgreen 35676259Sgreen kex_prop_free(my); 35776259Sgreen kex_prop_free(peer); 35860573Skris} 35960573Skris 36092555Sdesstatic u_char * 36176259Sgreenderive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) 36260573Skris{ 36376259Sgreen Buffer b; 36492555Sdes const EVP_MD *evp_md = EVP_sha1(); 36576259Sgreen EVP_MD_CTX md; 36676259Sgreen char c = id; 36776259Sgreen int have; 36892555Sdes int mdsz = EVP_MD_size(evp_md); 36976259Sgreen u_char *digest = xmalloc(roundup(need, mdsz)); 37060573Skris 37176259Sgreen buffer_init(&b); 37276259Sgreen buffer_put_bignum2(&b, shared_secret); 37376259Sgreen 37476259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 37576259Sgreen EVP_DigestInit(&md, evp_md); 37692555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 37792555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 37876259Sgreen EVP_DigestUpdate(&md, hash, mdsz); 37976259Sgreen EVP_DigestUpdate(&md, &c, 1); 38076259Sgreen EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 38176259Sgreen EVP_DigestFinal(&md, digest, NULL); 38276259Sgreen 38376259Sgreen /* 38476259Sgreen * expand key: 38576259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 38676259Sgreen * Key = K1 || K2 || ... || Kn 38776259Sgreen */ 38876259Sgreen for (have = mdsz; need > have; have += mdsz) { 38976259Sgreen EVP_DigestInit(&md, evp_md); 39092555Sdes if (!(datafellows & SSH_BUG_DERIVEKEY)) 39192555Sdes EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 39276259Sgreen EVP_DigestUpdate(&md, hash, mdsz); 39376259Sgreen EVP_DigestUpdate(&md, digest, have); 39476259Sgreen EVP_DigestFinal(&md, digest + have, NULL); 39576259Sgreen } 39676259Sgreen buffer_free(&b); 39776259Sgreen#ifdef DEBUG_KEX 39876259Sgreen fprintf(stderr, "key '%c'== ", c); 39976259Sgreen dump_digest("key", digest, need); 40076259Sgreen#endif 40176259Sgreen return digest; 40276259Sgreen} 40376259Sgreen 40476259SgreenNewkeys *current_keys[MODE_MAX]; 40576259Sgreen 40676259Sgreen#define NKEYS 6 40776259Sgreenvoid 40876259Sgreenkex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) 40976259Sgreen{ 41076259Sgreen u_char *keys[NKEYS]; 41176259Sgreen int i, mode, ctos; 41276259Sgreen 41360573Skris for (i = 0; i < NKEYS; i++) 41476259Sgreen keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); 41560573Skris 41676259Sgreen debug("kex_derive_keys"); 41760573Skris for (mode = 0; mode < MODE_MAX; mode++) { 41876259Sgreen current_keys[mode] = kex->newkeys[mode]; 41976259Sgreen kex->newkeys[mode] = NULL; 42076259Sgreen ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 42176259Sgreen current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 42276259Sgreen current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 42376259Sgreen current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 42460573Skris } 42560573Skris} 42676259Sgreen 42776259SgreenNewkeys * 42876259Sgreenkex_get_newkeys(int mode) 42976259Sgreen{ 43076259Sgreen Newkeys *ret; 43176259Sgreen 43276259Sgreen ret = current_keys[mode]; 43376259Sgreen current_keys[mode] = NULL; 43476259Sgreen return ret; 43576259Sgreen} 43676259Sgreen 43776259Sgreen#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 43876259Sgreenvoid 43976259Sgreendump_digest(char *msg, u_char *digest, int len) 44076259Sgreen{ 44176259Sgreen int i; 44276259Sgreen 44376259Sgreen fprintf(stderr, "%s\n", msg); 44492555Sdes for (i = 0; i< len; i++) { 44576259Sgreen fprintf(stderr, "%02x", digest[i]); 44676259Sgreen if (i%32 == 31) 44776259Sgreen fprintf(stderr, "\n"); 44876259Sgreen else if (i%8 == 7) 44976259Sgreen fprintf(stderr, " "); 45076259Sgreen } 45176259Sgreen fprintf(stderr, "\n"); 45276259Sgreen} 45376259Sgreen#endif 454