kex.c revision 76259
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 * 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" 2676259SgreenRCSID("$OpenBSD: kex.c,v 1.33 2001/04/05 10:42:50 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 4676259Sgreenvoid kex_kexinit_finish(Kex *kex); 4776259Sgreenvoid kex_choose_conf(Kex *k); 4876259Sgreen 4976259Sgreen/* put algorithm proposal into buffer */ 5076259Sgreenvoid 5176259Sgreenkex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 5260573Skris{ 5360573Skris u_int32_t rand = 0; 5460573Skris int i; 5576259Sgreen 5676259Sgreen buffer_clear(b); 5761209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) { 5860573Skris if (i % 4 == 0) 5960573Skris rand = arc4random(); 6076259Sgreen buffer_put_char(b, rand & 0xff); 6160573Skris rand >>= 8; 6260573Skris } 6360573Skris for (i = 0; i < PROPOSAL_MAX; i++) 6476259Sgreen buffer_put_cstring(b, proposal[i]); 6576259Sgreen buffer_put_char(b, 0); /* first_kex_packet_follows */ 6676259Sgreen buffer_put_int(b, 0); /* uint32 reserved */ 6760573Skris} 6860573Skris 6976259Sgreen/* parse buffer and return algorithm proposal */ 7076259Sgreenchar ** 7176259Sgreenkex_buf2prop(Buffer *raw) 7261209Skris{ 7376259Sgreen Buffer b; 7461209Skris int i; 7576259Sgreen char **proposal; 7661209Skris 7776259Sgreen proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); 7861209Skris 7976259Sgreen buffer_init(&b); 8076259Sgreen buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 8161209Skris /* skip cookie */ 8261209Skris for (i = 0; i < KEX_COOKIE_LEN; i++) 8376259Sgreen buffer_get_char(&b); 8461209Skris /* extract kex init proposal strings */ 8561209Skris for (i = 0; i < PROPOSAL_MAX; i++) { 8676259Sgreen proposal[i] = buffer_get_string(&b,NULL); 8776259Sgreen debug2("kex_parse_kexinit: %s", proposal[i]); 8861209Skris } 8976259Sgreen /* first kex follows / reserved */ 9076259Sgreen i = buffer_get_char(&b); 9176259Sgreen debug2("kex_parse_kexinit: first_kex_follows %d ", i); 9276259Sgreen i = buffer_get_int(&b); 9376259Sgreen debug2("kex_parse_kexinit: reserved %d ", i); 9476259Sgreen buffer_free(&b); 9576259Sgreen return proposal; 9661209Skris} 9761209Skris 9876259Sgreenvoid 9976259Sgreenkex_prop_free(char **proposal) 10060573Skris{ 10160573Skris int i; 10260573Skris 10376259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 10476259Sgreen xfree(proposal[i]); 10576259Sgreen xfree(proposal); 10660573Skris} 10760573Skris 10876259Sgreenvoid 10976259Sgreenkex_protocol_error(int type, int plen, void *ctxt) 11060573Skris{ 11176259Sgreen error("Hm, kex protocol error: type %d plen %d", type, plen); 11260573Skris} 11360573Skris 11476259Sgreenvoid 11576259Sgreenkex_clear_dispatch(void) 11669587Sgreen{ 11776259Sgreen int i; 11869587Sgreen 11976259Sgreen /* Numbers 30-49 are used for kex packets */ 12076259Sgreen for (i = 30; i <= 49; i++) 12176259Sgreen dispatch_set(i, &kex_protocol_error); 12269587Sgreen} 12369587Sgreen 12476259Sgreenvoid 12576259Sgreenkex_finish(Kex *kex) 12669587Sgreen{ 12776259Sgreen int plen; 12869587Sgreen 12976259Sgreen kex_clear_dispatch(); 13069587Sgreen 13176259Sgreen packet_start(SSH2_MSG_NEWKEYS); 13276259Sgreen packet_send(); 13376259Sgreen /* packet_write_wait(); */ 13476259Sgreen debug("SSH2_MSG_NEWKEYS sent"); 13569587Sgreen 13676259Sgreen debug("waiting for SSH2_MSG_NEWKEYS"); 13776259Sgreen packet_read_expect(&plen, SSH2_MSG_NEWKEYS); 13876259Sgreen debug("SSH2_MSG_NEWKEYS received"); 13969587Sgreen 14076259Sgreen kex->done = 1; 14176259Sgreen buffer_clear(&kex->peer); 14276259Sgreen /* buffer_clear(&kex->my); */ 14376259Sgreen kex->flags &= ~KEX_INIT_SENT; 14476259Sgreen xfree(kex->name); 14576259Sgreen kex->name = NULL; 14669587Sgreen} 14769587Sgreen 14860573Skrisvoid 14976259Sgreenkex_send_kexinit(Kex *kex) 15060573Skris{ 15176259Sgreen if (kex == NULL) { 15276259Sgreen error("kex_send_kexinit: no kex, cannot rekey"); 15376259Sgreen return; 15460573Skris } 15576259Sgreen if (kex->flags & KEX_INIT_SENT) { 15676259Sgreen debug("KEX_INIT_SENT"); 15776259Sgreen return; 15876259Sgreen } 15976259Sgreen kex->done = 0; 16076259Sgreen packet_start(SSH2_MSG_KEXINIT); 16176259Sgreen packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 16276259Sgreen packet_send(); 16376259Sgreen debug("SSH2_MSG_KEXINIT sent"); 16476259Sgreen kex->flags |= KEX_INIT_SENT; 16560573Skris} 16660573Skris 16776259Sgreenvoid 16876259Sgreenkex_input_kexinit(int type, int plen, void *ctxt) 16960573Skris{ 17076259Sgreen char *ptr; 17176259Sgreen int dlen; 17276259Sgreen int i; 17376259Sgreen Kex *kex = (Kex *)ctxt; 17460573Skris 17576259Sgreen debug("SSH2_MSG_KEXINIT received"); 17676259Sgreen if (kex == NULL) 17776259Sgreen fatal("kex_input_kexinit: no kex, cannot rekey"); 17860573Skris 17976259Sgreen ptr = packet_get_raw(&dlen); 18076259Sgreen buffer_append(&kex->peer, ptr, dlen); 18160573Skris 18276259Sgreen /* discard packet */ 18376259Sgreen for (i = 0; i < KEX_COOKIE_LEN; i++) 18476259Sgreen packet_get_char(); 18576259Sgreen for (i = 0; i < PROPOSAL_MAX; i++) 18676259Sgreen xfree(packet_get_string(NULL)); 18776259Sgreen packet_get_char(); 18876259Sgreen packet_get_int(); 18976259Sgreen packet_done(); 19060573Skris 19176259Sgreen kex_kexinit_finish(kex); 19260573Skris} 19360573Skris 19476259SgreenKex * 19576259Sgreenkex_setup(char *proposal[PROPOSAL_MAX]) 19669587Sgreen{ 19776259Sgreen Kex *kex; 19869587Sgreen 19976259Sgreen kex = xmalloc(sizeof(*kex)); 20076259Sgreen memset(kex, 0, sizeof(*kex)); 20176259Sgreen buffer_init(&kex->peer); 20276259Sgreen buffer_init(&kex->my); 20376259Sgreen kex_prop2buf(&kex->my, proposal); 20476259Sgreen kex->done = 0; 20569587Sgreen 20676259Sgreen kex_send_kexinit(kex); /* we start */ 20776259Sgreen kex_clear_dispatch(); 20876259Sgreen dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 20969587Sgreen 21076259Sgreen return kex; 21169587Sgreen} 21269587Sgreen 21376259Sgreenvoid 21476259Sgreenkex_kexinit_finish(Kex *kex) 21560573Skris{ 21676259Sgreen if (!(kex->flags & KEX_INIT_SENT)) 21776259Sgreen kex_send_kexinit(kex); 21860573Skris 21976259Sgreen kex_choose_conf(kex); 22060573Skris 22176259Sgreen switch(kex->kex_type) { 22276259Sgreen case DH_GRP1_SHA1: 22376259Sgreen kexdh(kex); 22476259Sgreen break; 22576259Sgreen case DH_GEX_SHA1: 22676259Sgreen kexgex(kex); 22776259Sgreen break; 22876259Sgreen default: 22976259Sgreen fatal("Unsupported key exchange %d", kex->kex_type); 23060573Skris } 23160573Skris} 23260573Skris 23360573Skrisvoid 23460573Skrischoose_enc(Enc *enc, char *client, char *server) 23560573Skris{ 23676259Sgreen char *name = match_list(client, server, NULL); 23760573Skris if (name == NULL) 23860573Skris fatal("no matching cipher found: client %s server %s", client, server); 23969587Sgreen enc->cipher = cipher_by_name(name); 24069587Sgreen if (enc->cipher == NULL) 24169587Sgreen fatal("matching cipher is not supported: %s", name); 24260573Skris enc->name = name; 24360573Skris enc->enabled = 0; 24460573Skris enc->iv = NULL; 24560573Skris enc->key = NULL; 24660573Skris} 24760573Skrisvoid 24860573Skrischoose_mac(Mac *mac, char *client, char *server) 24960573Skris{ 25076259Sgreen char *name = match_list(client, server, NULL); 25160573Skris if (name == NULL) 25260573Skris fatal("no matching mac found: client %s server %s", client, server); 25376259Sgreen if (mac_init(mac, name) < 0) 25460573Skris fatal("unsupported mac %s", name); 25576259Sgreen /* truncate the key */ 25676259Sgreen if (datafellows & SSH_BUG_HMAC) 25776259Sgreen mac->key_len = 16; 25860573Skris mac->name = name; 25960573Skris mac->key = NULL; 26060573Skris mac->enabled = 0; 26160573Skris} 26260573Skrisvoid 26360573Skrischoose_comp(Comp *comp, char *client, char *server) 26460573Skris{ 26576259Sgreen char *name = match_list(client, server, NULL); 26660573Skris if (name == NULL) 26760573Skris fatal("no matching comp found: client %s server %s", client, server); 26860573Skris if (strcmp(name, "zlib") == 0) { 26960573Skris comp->type = 1; 27060573Skris } else if (strcmp(name, "none") == 0) { 27160573Skris comp->type = 0; 27260573Skris } else { 27360573Skris fatal("unsupported comp %s", name); 27460573Skris } 27560573Skris comp->name = name; 27660573Skris} 27760573Skrisvoid 27860573Skrischoose_kex(Kex *k, char *client, char *server) 27960573Skris{ 28076259Sgreen k->name = match_list(client, server, NULL); 28160573Skris if (k->name == NULL) 28260573Skris fatal("no kex alg"); 28369587Sgreen if (strcmp(k->name, KEX_DH1) == 0) { 28469587Sgreen k->kex_type = DH_GRP1_SHA1; 28569587Sgreen } else if (strcmp(k->name, KEX_DHGEX) == 0) { 28669587Sgreen k->kex_type = DH_GEX_SHA1; 28769587Sgreen } else 28860573Skris fatal("bad kex alg %s", k->name); 28960573Skris} 29060573Skrisvoid 29160573Skrischoose_hostkeyalg(Kex *k, char *client, char *server) 29260573Skris{ 29376259Sgreen char *hostkeyalg = match_list(client, server, NULL); 29476259Sgreen if (hostkeyalg == NULL) 29560573Skris fatal("no hostkey alg"); 29676259Sgreen k->hostkey_type = key_type_from_name(hostkeyalg); 29776259Sgreen if (k->hostkey_type == KEY_UNSPEC) 29876259Sgreen fatal("bad hostkey alg '%s'", hostkeyalg); 29976259Sgreen xfree(hostkeyalg); 30060573Skris} 30160573Skris 30276259Sgreenvoid 30376259Sgreenkex_choose_conf(Kex *kex) 30460573Skris{ 30576259Sgreen Newkeys *newkeys; 30676259Sgreen char **my, **peer; 30776259Sgreen char **cprop, **sprop; 30876259Sgreen int nenc, nmac, ncomp; 30960573Skris int mode; 31060573Skris int ctos; /* direction: if true client-to-server */ 31160573Skris int need; 31260573Skris 31376259Sgreen my = kex_buf2prop(&kex->my); 31476259Sgreen peer = kex_buf2prop(&kex->peer); 31560573Skris 31676259Sgreen if (kex->server) { 31776259Sgreen cprop=peer; 31876259Sgreen sprop=my; 31976259Sgreen } else { 32076259Sgreen cprop=my; 32176259Sgreen sprop=peer; 32276259Sgreen } 32376259Sgreen 32476259Sgreen /* Algorithm Negotiation */ 32560573Skris for (mode = 0; mode < MODE_MAX; mode++) { 32676259Sgreen newkeys = xmalloc(sizeof(*newkeys)); 32776259Sgreen memset(newkeys, 0, sizeof(*newkeys)); 32876259Sgreen kex->newkeys[mode] = newkeys; 32976259Sgreen ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 33060573Skris nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 33160573Skris nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 33260573Skris ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 33376259Sgreen choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 33476259Sgreen choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 33576259Sgreen choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 33660573Skris debug("kex: %s %s %s %s", 33760573Skris ctos ? "client->server" : "server->client", 33876259Sgreen newkeys->enc.name, 33976259Sgreen newkeys->mac.name, 34076259Sgreen newkeys->comp.name); 34160573Skris } 34276259Sgreen choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 34376259Sgreen choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 34460573Skris sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 34560573Skris need = 0; 34660573Skris for (mode = 0; mode < MODE_MAX; mode++) { 34776259Sgreen newkeys = kex->newkeys[mode]; 34876259Sgreen if (need < newkeys->enc.cipher->key_len) 34976259Sgreen need = newkeys->enc.cipher->key_len; 35076259Sgreen if (need < newkeys->enc.cipher->block_size) 35176259Sgreen need = newkeys->enc.cipher->block_size; 35276259Sgreen if (need < newkeys->mac.key_len) 35376259Sgreen need = newkeys->mac.key_len; 35460573Skris } 35561209Skris /* XXX need runden? */ 35676259Sgreen kex->we_need = need; 35776259Sgreen 35876259Sgreen kex_prop_free(my); 35976259Sgreen kex_prop_free(peer); 36060573Skris} 36160573Skris 36276259Sgreenu_char * 36376259Sgreenderive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) 36460573Skris{ 36576259Sgreen Buffer b; 36676259Sgreen EVP_MD *evp_md = EVP_sha1(); 36776259Sgreen EVP_MD_CTX md; 36876259Sgreen char c = id; 36976259Sgreen int have; 37076259Sgreen int mdsz = evp_md->md_size; 37176259Sgreen u_char *digest = xmalloc(roundup(need, mdsz)); 37260573Skris 37376259Sgreen buffer_init(&b); 37476259Sgreen buffer_put_bignum2(&b, shared_secret); 37576259Sgreen 37676259Sgreen /* K1 = HASH(K || H || "A" || session_id) */ 37776259Sgreen EVP_DigestInit(&md, evp_md); 37876259Sgreen EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 37976259Sgreen EVP_DigestUpdate(&md, hash, mdsz); 38076259Sgreen EVP_DigestUpdate(&md, &c, 1); 38176259Sgreen EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 38276259Sgreen EVP_DigestFinal(&md, digest, NULL); 38376259Sgreen 38476259Sgreen /* 38576259Sgreen * expand key: 38676259Sgreen * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 38776259Sgreen * Key = K1 || K2 || ... || Kn 38876259Sgreen */ 38976259Sgreen for (have = mdsz; need > have; have += mdsz) { 39076259Sgreen EVP_DigestInit(&md, evp_md); 39176259Sgreen 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); 44476259Sgreen 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