1a04a10f8SKris Kennaway /* 2a04a10f8SKris Kennaway * Copyright (c) 2000 Markus Friedl. All rights reserved. 3a04a10f8SKris Kennaway * 4a04a10f8SKris Kennaway * Redistribution and use in source and binary forms, with or without 5a04a10f8SKris Kennaway * modification, are permitted provided that the following conditions 6a04a10f8SKris Kennaway * are met: 7a04a10f8SKris Kennaway * 1. Redistributions of source code must retain the above copyright 8a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer. 9a04a10f8SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 10a04a10f8SKris Kennaway * notice, this list of conditions and the following disclaimer in the 11a04a10f8SKris Kennaway * documentation and/or other materials provided with the distribution. 12a04a10f8SKris Kennaway * 13a04a10f8SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14a04a10f8SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15a04a10f8SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16a04a10f8SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17a04a10f8SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18a04a10f8SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19a04a10f8SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20a04a10f8SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21a04a10f8SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22a04a10f8SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23a04a10f8SKris Kennaway */ 24a04a10f8SKris Kennaway 25a04a10f8SKris Kennaway #include "includes.h" 265b9b2fafSBrian Feldman RCSID("$OpenBSD: kex.c,v 1.12 2000/10/11 20:27:23 markus Exp $"); 27a04a10f8SKris Kennaway 28a04a10f8SKris Kennaway #include "ssh.h" 29a04a10f8SKris Kennaway #include "ssh2.h" 30a04a10f8SKris Kennaway #include "xmalloc.h" 31a04a10f8SKris Kennaway #include "buffer.h" 32a04a10f8SKris Kennaway #include "bufaux.h" 332632b0c8SKris Kennaway #include "packet.h" 34a04a10f8SKris Kennaway #include "compat.h" 35a04a10f8SKris Kennaway 36a04a10f8SKris Kennaway #include <openssl/bn.h> 37a04a10f8SKris Kennaway #include <openssl/dh.h> 38a04a10f8SKris Kennaway 39a04a10f8SKris Kennaway #include <openssl/crypto.h> 40a04a10f8SKris Kennaway #include <openssl/bio.h> 41a04a10f8SKris Kennaway #include <openssl/bn.h> 42a04a10f8SKris Kennaway #include <openssl/dh.h> 43a04a10f8SKris Kennaway #include <openssl/pem.h> 44a04a10f8SKris Kennaway 45a04a10f8SKris Kennaway #include "kex.h" 46a04a10f8SKris Kennaway 472632b0c8SKris Kennaway #define KEX_COOKIE_LEN 16 482632b0c8SKris Kennaway 49a04a10f8SKris Kennaway Buffer * 50a04a10f8SKris Kennaway kex_init(char *myproposal[PROPOSAL_MAX]) 51a04a10f8SKris Kennaway { 522632b0c8SKris Kennaway int first_kex_packet_follows = 0; 532632b0c8SKris Kennaway unsigned char cookie[KEX_COOKIE_LEN]; 54a04a10f8SKris Kennaway u_int32_t rand = 0; 55a04a10f8SKris Kennaway int i; 56a04a10f8SKris Kennaway Buffer *ki = xmalloc(sizeof(*ki)); 572632b0c8SKris Kennaway for (i = 0; i < KEX_COOKIE_LEN; i++) { 58a04a10f8SKris Kennaway if (i % 4 == 0) 59a04a10f8SKris Kennaway rand = arc4random(); 60a04a10f8SKris Kennaway cookie[i] = rand & 0xff; 61a04a10f8SKris Kennaway rand >>= 8; 62a04a10f8SKris Kennaway } 63a04a10f8SKris Kennaway buffer_init(ki); 64a04a10f8SKris Kennaway buffer_append(ki, (char *)cookie, sizeof cookie); 65a04a10f8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) 66a04a10f8SKris Kennaway buffer_put_cstring(ki, myproposal[i]); 672632b0c8SKris Kennaway buffer_put_char(ki, first_kex_packet_follows); 682632b0c8SKris Kennaway buffer_put_int(ki, 0); /* uint32 reserved */ 69a04a10f8SKris Kennaway return ki; 70a04a10f8SKris Kennaway } 71a04a10f8SKris Kennaway 722632b0c8SKris Kennaway /* send kexinit, parse and save reply */ 732632b0c8SKris Kennaway void 742632b0c8SKris Kennaway kex_exchange_kexinit( 752632b0c8SKris Kennaway Buffer *my_kexinit, Buffer *peer_kexint, 762632b0c8SKris Kennaway char *peer_proposal[PROPOSAL_MAX]) 772632b0c8SKris Kennaway { 782632b0c8SKris Kennaway int i; 792632b0c8SKris Kennaway char *ptr; 802632b0c8SKris Kennaway int plen; 812632b0c8SKris Kennaway 822632b0c8SKris Kennaway debug("send KEXINIT"); 832632b0c8SKris Kennaway packet_start(SSH2_MSG_KEXINIT); 842632b0c8SKris Kennaway packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit)); 852632b0c8SKris Kennaway packet_send(); 862632b0c8SKris Kennaway packet_write_wait(); 872632b0c8SKris Kennaway debug("done"); 882632b0c8SKris Kennaway 892632b0c8SKris Kennaway /* 902632b0c8SKris Kennaway * read and save raw KEXINIT payload in buffer. this is used during 912632b0c8SKris Kennaway * computation of the session_id and the session keys. 922632b0c8SKris Kennaway */ 932632b0c8SKris Kennaway debug("wait KEXINIT"); 942632b0c8SKris Kennaway packet_read_expect(&plen, SSH2_MSG_KEXINIT); 952632b0c8SKris Kennaway ptr = packet_get_raw(&plen); 962632b0c8SKris Kennaway buffer_append(peer_kexint, ptr, plen); 972632b0c8SKris Kennaway 982632b0c8SKris Kennaway /* parse packet and save algorithm proposal */ 992632b0c8SKris Kennaway /* skip cookie */ 1002632b0c8SKris Kennaway for (i = 0; i < KEX_COOKIE_LEN; i++) 1012632b0c8SKris Kennaway packet_get_char(); 1022632b0c8SKris Kennaway /* extract kex init proposal strings */ 1032632b0c8SKris Kennaway for (i = 0; i < PROPOSAL_MAX; i++) { 1042632b0c8SKris Kennaway peer_proposal[i] = packet_get_string(NULL); 1052632b0c8SKris Kennaway debug("got kexinit: %s", peer_proposal[i]); 1062632b0c8SKris Kennaway } 1072632b0c8SKris Kennaway /* first kex follow / reserved */ 1082632b0c8SKris Kennaway i = packet_get_char(); 1092632b0c8SKris Kennaway debug("first kex follow: %d ", i); 1102632b0c8SKris Kennaway i = packet_get_int(); 1112632b0c8SKris Kennaway debug("reserved: %d ", i); 1122632b0c8SKris Kennaway packet_done(); 1132632b0c8SKris Kennaway debug("done"); 1142632b0c8SKris Kennaway } 1152632b0c8SKris Kennaway 116a04a10f8SKris Kennaway /* diffie-hellman-group1-sha1 */ 117a04a10f8SKris Kennaway 118a04a10f8SKris Kennaway int 119a04a10f8SKris Kennaway dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) 120a04a10f8SKris Kennaway { 121a04a10f8SKris Kennaway int i; 122a04a10f8SKris Kennaway int n = BN_num_bits(dh_pub); 123a04a10f8SKris Kennaway int bits_set = 0; 124a04a10f8SKris Kennaway 125a04a10f8SKris Kennaway if (dh_pub->neg) { 126a04a10f8SKris Kennaway log("invalid public DH value: negativ"); 127a04a10f8SKris Kennaway return 0; 128a04a10f8SKris Kennaway } 129a04a10f8SKris Kennaway for (i = 0; i <= n; i++) 130a04a10f8SKris Kennaway if (BN_is_bit_set(dh_pub, i)) 131a04a10f8SKris Kennaway bits_set++; 132a04a10f8SKris Kennaway debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); 133a04a10f8SKris Kennaway 134a04a10f8SKris Kennaway /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ 135a04a10f8SKris Kennaway if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) 136a04a10f8SKris Kennaway return 1; 137a04a10f8SKris Kennaway log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); 138a04a10f8SKris Kennaway return 0; 139a04a10f8SKris Kennaway } 140a04a10f8SKris Kennaway 141a04a10f8SKris Kennaway DH * 1425b9b2fafSBrian Feldman dh_gen_key(DH *dh) 143a04a10f8SKris Kennaway { 1445b9b2fafSBrian Feldman int tries = 0; 1455b9b2fafSBrian Feldman 146a04a10f8SKris Kennaway do { 147a04a10f8SKris Kennaway if (DH_generate_key(dh) == 0) 148a04a10f8SKris Kennaway fatal("DH_generate_key"); 149a04a10f8SKris Kennaway if (tries++ > 10) 150a04a10f8SKris Kennaway fatal("dh_new_group1: too many bad keys: giving up"); 151a04a10f8SKris Kennaway } while (!dh_pub_is_valid(dh, dh->pub_key)); 152a04a10f8SKris Kennaway return dh; 153a04a10f8SKris Kennaway } 154a04a10f8SKris Kennaway 1555b9b2fafSBrian Feldman DH * 1565b9b2fafSBrian Feldman dh_new_group_asc(const char *gen, const char *modulus) 1575b9b2fafSBrian Feldman { 1585b9b2fafSBrian Feldman DH *dh; 1595b9b2fafSBrian Feldman int ret; 1605b9b2fafSBrian Feldman 1615b9b2fafSBrian Feldman dh = DH_new(); 1625b9b2fafSBrian Feldman if (dh == NULL) 1635b9b2fafSBrian Feldman fatal("DH_new"); 1645b9b2fafSBrian Feldman 1655b9b2fafSBrian Feldman if ((ret = BN_hex2bn(&dh->p, modulus)) < 0) 1665b9b2fafSBrian Feldman fatal("BN_hex2bn p"); 1675b9b2fafSBrian Feldman if ((ret = BN_hex2bn(&dh->g, gen)) < 0) 1685b9b2fafSBrian Feldman fatal("BN_hex2bn g"); 1695b9b2fafSBrian Feldman 1705b9b2fafSBrian Feldman return (dh_gen_key(dh)); 1715b9b2fafSBrian Feldman } 1725b9b2fafSBrian Feldman 1735b9b2fafSBrian Feldman DH * 1745b9b2fafSBrian Feldman dh_new_group(BIGNUM *gen, BIGNUM *modulus) 1755b9b2fafSBrian Feldman { 1765b9b2fafSBrian Feldman DH *dh; 1775b9b2fafSBrian Feldman 1785b9b2fafSBrian Feldman dh = DH_new(); 1795b9b2fafSBrian Feldman if (dh == NULL) 1805b9b2fafSBrian Feldman fatal("DH_new"); 1815b9b2fafSBrian Feldman dh->p = modulus; 1825b9b2fafSBrian Feldman dh->g = gen; 1835b9b2fafSBrian Feldman 1845b9b2fafSBrian Feldman return (dh_gen_key(dh)); 1855b9b2fafSBrian Feldman } 1865b9b2fafSBrian Feldman 1875b9b2fafSBrian Feldman DH * 1885b9b2fafSBrian Feldman dh_new_group1() 1895b9b2fafSBrian Feldman { 1905b9b2fafSBrian Feldman static char *gen = "2", *group1 = 1915b9b2fafSBrian Feldman "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 1925b9b2fafSBrian Feldman "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 1935b9b2fafSBrian Feldman "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 1945b9b2fafSBrian Feldman "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 1955b9b2fafSBrian Feldman "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 1965b9b2fafSBrian Feldman "FFFFFFFF" "FFFFFFFF"; 1975b9b2fafSBrian Feldman 1985b9b2fafSBrian Feldman return (dh_new_group_asc(gen, group1)); 1995b9b2fafSBrian Feldman } 2005b9b2fafSBrian Feldman 201a04a10f8SKris Kennaway void 202a04a10f8SKris Kennaway dump_digest(unsigned char *digest, int len) 203a04a10f8SKris Kennaway { 204a04a10f8SKris Kennaway int i; 205a04a10f8SKris Kennaway for (i = 0; i< len; i++){ 206a04a10f8SKris Kennaway fprintf(stderr, "%02x", digest[i]); 207a04a10f8SKris Kennaway if(i%2!=0) 208a04a10f8SKris Kennaway fprintf(stderr, " "); 209a04a10f8SKris Kennaway } 210a04a10f8SKris Kennaway fprintf(stderr, "\n"); 211a04a10f8SKris Kennaway } 212a04a10f8SKris Kennaway 213a04a10f8SKris Kennaway unsigned char * 214a04a10f8SKris Kennaway kex_hash( 215a04a10f8SKris Kennaway char *client_version_string, 216a04a10f8SKris Kennaway char *server_version_string, 217a04a10f8SKris Kennaway char *ckexinit, int ckexinitlen, 218a04a10f8SKris Kennaway char *skexinit, int skexinitlen, 219a04a10f8SKris Kennaway char *serverhostkeyblob, int sbloblen, 220a04a10f8SKris Kennaway BIGNUM *client_dh_pub, 221a04a10f8SKris Kennaway BIGNUM *server_dh_pub, 222a04a10f8SKris Kennaway BIGNUM *shared_secret) 223a04a10f8SKris Kennaway { 224a04a10f8SKris Kennaway Buffer b; 225a04a10f8SKris Kennaway static unsigned char digest[EVP_MAX_MD_SIZE]; 226a04a10f8SKris Kennaway EVP_MD *evp_md = EVP_sha1(); 227a04a10f8SKris Kennaway EVP_MD_CTX md; 228a04a10f8SKris Kennaway 229a04a10f8SKris Kennaway buffer_init(&b); 230a04a10f8SKris Kennaway buffer_put_string(&b, client_version_string, strlen(client_version_string)); 231a04a10f8SKris Kennaway buffer_put_string(&b, server_version_string, strlen(server_version_string)); 232a04a10f8SKris Kennaway 233a04a10f8SKris Kennaway /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 234a04a10f8SKris Kennaway buffer_put_int(&b, ckexinitlen+1); 235a04a10f8SKris Kennaway buffer_put_char(&b, SSH2_MSG_KEXINIT); 236a04a10f8SKris Kennaway buffer_append(&b, ckexinit, ckexinitlen); 237a04a10f8SKris Kennaway buffer_put_int(&b, skexinitlen+1); 238a04a10f8SKris Kennaway buffer_put_char(&b, SSH2_MSG_KEXINIT); 239a04a10f8SKris Kennaway buffer_append(&b, skexinit, skexinitlen); 240a04a10f8SKris Kennaway 241a04a10f8SKris Kennaway buffer_put_string(&b, serverhostkeyblob, sbloblen); 242a04a10f8SKris Kennaway buffer_put_bignum2(&b, client_dh_pub); 243a04a10f8SKris Kennaway buffer_put_bignum2(&b, server_dh_pub); 244a04a10f8SKris Kennaway buffer_put_bignum2(&b, shared_secret); 245a04a10f8SKris Kennaway 246a04a10f8SKris Kennaway #ifdef DEBUG_KEX 247a04a10f8SKris Kennaway buffer_dump(&b); 248a04a10f8SKris Kennaway #endif 249a04a10f8SKris Kennaway 250a04a10f8SKris Kennaway EVP_DigestInit(&md, evp_md); 251a04a10f8SKris Kennaway EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 252a04a10f8SKris Kennaway EVP_DigestFinal(&md, digest, NULL); 253a04a10f8SKris Kennaway 254a04a10f8SKris Kennaway buffer_free(&b); 255a04a10f8SKris Kennaway 256a04a10f8SKris Kennaway #ifdef DEBUG_KEX 257a04a10f8SKris Kennaway dump_digest(digest, evp_md->md_size); 258a04a10f8SKris Kennaway #endif 259a04a10f8SKris Kennaway return digest; 260a04a10f8SKris Kennaway } 261a04a10f8SKris Kennaway 262a04a10f8SKris Kennaway unsigned char * 2635b9b2fafSBrian Feldman kex_hash_gex( 2645b9b2fafSBrian Feldman char *client_version_string, 2655b9b2fafSBrian Feldman char *server_version_string, 2665b9b2fafSBrian Feldman char *ckexinit, int ckexinitlen, 2675b9b2fafSBrian Feldman char *skexinit, int skexinitlen, 2685b9b2fafSBrian Feldman char *serverhostkeyblob, int sbloblen, 2695b9b2fafSBrian Feldman int minbits, BIGNUM *prime, BIGNUM *gen, 2705b9b2fafSBrian Feldman BIGNUM *client_dh_pub, 2715b9b2fafSBrian Feldman BIGNUM *server_dh_pub, 2725b9b2fafSBrian Feldman BIGNUM *shared_secret) 2735b9b2fafSBrian Feldman { 2745b9b2fafSBrian Feldman Buffer b; 2755b9b2fafSBrian Feldman static unsigned char digest[EVP_MAX_MD_SIZE]; 2765b9b2fafSBrian Feldman EVP_MD *evp_md = EVP_sha1(); 2775b9b2fafSBrian Feldman EVP_MD_CTX md; 2785b9b2fafSBrian Feldman 2795b9b2fafSBrian Feldman buffer_init(&b); 2805b9b2fafSBrian Feldman buffer_put_string(&b, client_version_string, strlen(client_version_string)); 2815b9b2fafSBrian Feldman buffer_put_string(&b, server_version_string, strlen(server_version_string)); 2825b9b2fafSBrian Feldman 2835b9b2fafSBrian Feldman /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 2845b9b2fafSBrian Feldman buffer_put_int(&b, ckexinitlen+1); 2855b9b2fafSBrian Feldman buffer_put_char(&b, SSH2_MSG_KEXINIT); 2865b9b2fafSBrian Feldman buffer_append(&b, ckexinit, ckexinitlen); 2875b9b2fafSBrian Feldman buffer_put_int(&b, skexinitlen+1); 2885b9b2fafSBrian Feldman buffer_put_char(&b, SSH2_MSG_KEXINIT); 2895b9b2fafSBrian Feldman buffer_append(&b, skexinit, skexinitlen); 2905b9b2fafSBrian Feldman 2915b9b2fafSBrian Feldman buffer_put_string(&b, serverhostkeyblob, sbloblen); 2925b9b2fafSBrian Feldman buffer_put_int(&b, minbits); 2935b9b2fafSBrian Feldman buffer_put_bignum2(&b, prime); 2945b9b2fafSBrian Feldman buffer_put_bignum2(&b, gen); 2955b9b2fafSBrian Feldman buffer_put_bignum2(&b, client_dh_pub); 2965b9b2fafSBrian Feldman buffer_put_bignum2(&b, server_dh_pub); 2975b9b2fafSBrian Feldman buffer_put_bignum2(&b, shared_secret); 2985b9b2fafSBrian Feldman 2995b9b2fafSBrian Feldman #ifdef DEBUG_KEX 3005b9b2fafSBrian Feldman buffer_dump(&b); 3015b9b2fafSBrian Feldman #endif 3025b9b2fafSBrian Feldman 3035b9b2fafSBrian Feldman EVP_DigestInit(&md, evp_md); 3045b9b2fafSBrian Feldman EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 3055b9b2fafSBrian Feldman EVP_DigestFinal(&md, digest, NULL); 3065b9b2fafSBrian Feldman 3075b9b2fafSBrian Feldman buffer_free(&b); 3085b9b2fafSBrian Feldman 3095b9b2fafSBrian Feldman #ifdef DEBUG_KEX 3105b9b2fafSBrian Feldman dump_digest(digest, evp_md->md_size); 3115b9b2fafSBrian Feldman #endif 3125b9b2fafSBrian Feldman return digest; 3135b9b2fafSBrian Feldman } 3145b9b2fafSBrian Feldman 3155b9b2fafSBrian Feldman unsigned char * 316a04a10f8SKris Kennaway derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) 317a04a10f8SKris Kennaway { 318a04a10f8SKris Kennaway Buffer b; 319a04a10f8SKris Kennaway EVP_MD *evp_md = EVP_sha1(); 320a04a10f8SKris Kennaway EVP_MD_CTX md; 321a04a10f8SKris Kennaway char c = id; 322a04a10f8SKris Kennaway int have; 323a04a10f8SKris Kennaway int mdsz = evp_md->md_size; 324a04a10f8SKris Kennaway unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); 325a04a10f8SKris Kennaway 326a04a10f8SKris Kennaway buffer_init(&b); 327a04a10f8SKris Kennaway buffer_put_bignum2(&b, shared_secret); 328a04a10f8SKris Kennaway 329a04a10f8SKris Kennaway EVP_DigestInit(&md, evp_md); 330a04a10f8SKris Kennaway EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ 331a04a10f8SKris Kennaway EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ 332a04a10f8SKris Kennaway EVP_DigestUpdate(&md, &c, 1); /* key id */ 333a04a10f8SKris Kennaway EVP_DigestUpdate(&md, hash, mdsz); /* session id */ 334a04a10f8SKris Kennaway EVP_DigestFinal(&md, digest, NULL); 335a04a10f8SKris Kennaway 336a04a10f8SKris Kennaway /* expand */ 337a04a10f8SKris Kennaway for (have = mdsz; need > have; have += mdsz) { 338a04a10f8SKris Kennaway EVP_DigestInit(&md, evp_md); 339a04a10f8SKris Kennaway EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 340a04a10f8SKris Kennaway EVP_DigestUpdate(&md, hash, mdsz); 341a04a10f8SKris Kennaway EVP_DigestUpdate(&md, digest, have); 342a04a10f8SKris Kennaway EVP_DigestFinal(&md, digest + have, NULL); 343a04a10f8SKris Kennaway } 344a04a10f8SKris Kennaway buffer_free(&b); 345a04a10f8SKris Kennaway #ifdef DEBUG_KEX 346a04a10f8SKris Kennaway fprintf(stderr, "Digest '%c'== ", c); 347a04a10f8SKris Kennaway dump_digest(digest, need); 348a04a10f8SKris Kennaway #endif 349a04a10f8SKris Kennaway return digest; 350a04a10f8SKris Kennaway } 351a04a10f8SKris Kennaway 352a04a10f8SKris Kennaway #define NKEYS 6 353a04a10f8SKris Kennaway 354a04a10f8SKris Kennaway #define MAX_PROP 20 355a04a10f8SKris Kennaway #define SEP "," 356a04a10f8SKris Kennaway 357a04a10f8SKris Kennaway char * 358a04a10f8SKris Kennaway get_match(char *client, char *server) 359a04a10f8SKris Kennaway { 360a04a10f8SKris Kennaway char *sproposals[MAX_PROP]; 361b66f2d16SKris Kennaway char *c, *s, *p, *ret, *cp, *sp; 362a04a10f8SKris Kennaway int i, j, nproposals; 363a04a10f8SKris Kennaway 364b66f2d16SKris Kennaway c = cp = xstrdup(client); 365b66f2d16SKris Kennaway s = sp = xstrdup(server); 3662632b0c8SKris Kennaway 367b66f2d16SKris Kennaway for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; 368b66f2d16SKris Kennaway (p = strsep(&sp, SEP)), i++) { 369a04a10f8SKris Kennaway if (i < MAX_PROP) 370a04a10f8SKris Kennaway sproposals[i] = p; 371a04a10f8SKris Kennaway else 372a04a10f8SKris Kennaway break; 373a04a10f8SKris Kennaway } 374a04a10f8SKris Kennaway nproposals = i; 375a04a10f8SKris Kennaway 376b66f2d16SKris Kennaway for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; 377b66f2d16SKris Kennaway (p = strsep(&cp, SEP)), i++) { 3782632b0c8SKris Kennaway for (j = 0; j < nproposals; j++) { 3792632b0c8SKris Kennaway if (strcmp(p, sproposals[j]) == 0) { 3802632b0c8SKris Kennaway ret = xstrdup(p); 3812632b0c8SKris Kennaway xfree(c); 3822632b0c8SKris Kennaway xfree(s); 3832632b0c8SKris Kennaway return ret; 384a04a10f8SKris Kennaway } 3852632b0c8SKris Kennaway } 3862632b0c8SKris Kennaway } 3872632b0c8SKris Kennaway xfree(c); 3882632b0c8SKris Kennaway xfree(s); 389a04a10f8SKris Kennaway return NULL; 390a04a10f8SKris Kennaway } 391a04a10f8SKris Kennaway void 392a04a10f8SKris Kennaway choose_enc(Enc *enc, char *client, char *server) 393a04a10f8SKris Kennaway { 394a04a10f8SKris Kennaway char *name = get_match(client, server); 395a04a10f8SKris Kennaway if (name == NULL) 396a04a10f8SKris Kennaway fatal("no matching cipher found: client %s server %s", client, server); 3975b9b2fafSBrian Feldman enc->cipher = cipher_by_name(name); 3985b9b2fafSBrian Feldman if (enc->cipher == NULL) 3995b9b2fafSBrian Feldman fatal("matching cipher is not supported: %s", name); 400a04a10f8SKris Kennaway enc->name = name; 401a04a10f8SKris Kennaway enc->enabled = 0; 402a04a10f8SKris Kennaway enc->iv = NULL; 403a04a10f8SKris Kennaway enc->key = NULL; 404a04a10f8SKris Kennaway } 405a04a10f8SKris Kennaway void 406a04a10f8SKris Kennaway choose_mac(Mac *mac, char *client, char *server) 407a04a10f8SKris Kennaway { 408a04a10f8SKris Kennaway char *name = get_match(client, server); 409a04a10f8SKris Kennaway if (name == NULL) 410a04a10f8SKris Kennaway fatal("no matching mac found: client %s server %s", client, server); 411a04a10f8SKris Kennaway if (strcmp(name, "hmac-md5") == 0) { 412a04a10f8SKris Kennaway mac->md = EVP_md5(); 413a04a10f8SKris Kennaway } else if (strcmp(name, "hmac-sha1") == 0) { 414a04a10f8SKris Kennaway mac->md = EVP_sha1(); 415a04a10f8SKris Kennaway } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) { 416a04a10f8SKris Kennaway mac->md = EVP_ripemd160(); 417a04a10f8SKris Kennaway } else { 418a04a10f8SKris Kennaway fatal("unsupported mac %s", name); 419a04a10f8SKris Kennaway } 420a04a10f8SKris Kennaway mac->name = name; 421a04a10f8SKris Kennaway mac->mac_len = mac->md->md_size; 422a04a10f8SKris Kennaway mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len; 423a04a10f8SKris Kennaway mac->key = NULL; 424a04a10f8SKris Kennaway mac->enabled = 0; 425a04a10f8SKris Kennaway } 426a04a10f8SKris Kennaway void 427a04a10f8SKris Kennaway choose_comp(Comp *comp, char *client, char *server) 428a04a10f8SKris Kennaway { 429a04a10f8SKris Kennaway char *name = get_match(client, server); 430a04a10f8SKris Kennaway if (name == NULL) 431a04a10f8SKris Kennaway fatal("no matching comp found: client %s server %s", client, server); 432a04a10f8SKris Kennaway if (strcmp(name, "zlib") == 0) { 433a04a10f8SKris Kennaway comp->type = 1; 434a04a10f8SKris Kennaway } else if (strcmp(name, "none") == 0) { 435a04a10f8SKris Kennaway comp->type = 0; 436a04a10f8SKris Kennaway } else { 437a04a10f8SKris Kennaway fatal("unsupported comp %s", name); 438a04a10f8SKris Kennaway } 439a04a10f8SKris Kennaway comp->name = name; 440a04a10f8SKris Kennaway } 441a04a10f8SKris Kennaway void 442a04a10f8SKris Kennaway choose_kex(Kex *k, char *client, char *server) 443a04a10f8SKris Kennaway { 444a04a10f8SKris Kennaway k->name = get_match(client, server); 445a04a10f8SKris Kennaway if (k->name == NULL) 446a04a10f8SKris Kennaway fatal("no kex alg"); 4475b9b2fafSBrian Feldman if (strcmp(k->name, KEX_DH1) == 0) { 4485b9b2fafSBrian Feldman k->kex_type = DH_GRP1_SHA1; 4495b9b2fafSBrian Feldman } else if (strcmp(k->name, KEX_DHGEX) == 0) { 4505b9b2fafSBrian Feldman k->kex_type = DH_GEX_SHA1; 4515b9b2fafSBrian Feldman } else 452a04a10f8SKris Kennaway fatal("bad kex alg %s", k->name); 453a04a10f8SKris Kennaway } 454a04a10f8SKris Kennaway void 455a04a10f8SKris Kennaway choose_hostkeyalg(Kex *k, char *client, char *server) 456a04a10f8SKris Kennaway { 457a04a10f8SKris Kennaway k->hostkeyalg = get_match(client, server); 458a04a10f8SKris Kennaway if (k->hostkeyalg == NULL) 459a04a10f8SKris Kennaway fatal("no hostkey alg"); 460a04a10f8SKris Kennaway if (strcmp(k->hostkeyalg, KEX_DSS) != 0) 461a04a10f8SKris Kennaway fatal("bad hostkey alg %s", k->hostkeyalg); 462a04a10f8SKris Kennaway } 463a04a10f8SKris Kennaway 464a04a10f8SKris Kennaway Kex * 465a04a10f8SKris Kennaway kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) 466a04a10f8SKris Kennaway { 467a04a10f8SKris Kennaway int mode; 468a04a10f8SKris Kennaway int ctos; /* direction: if true client-to-server */ 469a04a10f8SKris Kennaway int need; 470a04a10f8SKris Kennaway Kex *k; 471a04a10f8SKris Kennaway 472a04a10f8SKris Kennaway k = xmalloc(sizeof(*k)); 473a04a10f8SKris Kennaway memset(k, 0, sizeof(*k)); 474a04a10f8SKris Kennaway k->server = server; 475a04a10f8SKris Kennaway 476a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 477a04a10f8SKris Kennaway int nenc, nmac, ncomp; 478a04a10f8SKris Kennaway ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 479a04a10f8SKris Kennaway nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 480a04a10f8SKris Kennaway nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 481a04a10f8SKris Kennaway ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 482a04a10f8SKris Kennaway choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]); 483a04a10f8SKris Kennaway choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]); 484a04a10f8SKris Kennaway choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]); 485a04a10f8SKris Kennaway debug("kex: %s %s %s %s", 486a04a10f8SKris Kennaway ctos ? "client->server" : "server->client", 487a04a10f8SKris Kennaway k->enc[mode].name, 488a04a10f8SKris Kennaway k->mac[mode].name, 489a04a10f8SKris Kennaway k->comp[mode].name); 490a04a10f8SKris Kennaway } 491a04a10f8SKris Kennaway choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 492a04a10f8SKris Kennaway choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 493a04a10f8SKris Kennaway sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 494a04a10f8SKris Kennaway need = 0; 495a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 4965b9b2fafSBrian Feldman if (need < k->enc[mode].cipher->key_len) 4975b9b2fafSBrian Feldman need = k->enc[mode].cipher->key_len; 4985b9b2fafSBrian Feldman if (need < k->enc[mode].cipher->block_size) 4995b9b2fafSBrian Feldman need = k->enc[mode].cipher->block_size; 500a04a10f8SKris Kennaway if (need < k->mac[mode].key_len) 501a04a10f8SKris Kennaway need = k->mac[mode].key_len; 502a04a10f8SKris Kennaway } 5032632b0c8SKris Kennaway /* XXX need runden? */ 504a04a10f8SKris Kennaway k->we_need = need; 505a04a10f8SKris Kennaway return k; 506a04a10f8SKris Kennaway } 507a04a10f8SKris Kennaway 508a04a10f8SKris Kennaway int 509a04a10f8SKris Kennaway kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret) 510a04a10f8SKris Kennaway { 511a04a10f8SKris Kennaway int i; 512a04a10f8SKris Kennaway int mode; 513a04a10f8SKris Kennaway int ctos; 514a04a10f8SKris Kennaway unsigned char *keys[NKEYS]; 515a04a10f8SKris Kennaway 516a04a10f8SKris Kennaway for (i = 0; i < NKEYS; i++) 517a04a10f8SKris Kennaway keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret); 518a04a10f8SKris Kennaway 519a04a10f8SKris Kennaway for (mode = 0; mode < MODE_MAX; mode++) { 520a04a10f8SKris Kennaway ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 521a04a10f8SKris Kennaway k->enc[mode].iv = keys[ctos ? 0 : 1]; 522a04a10f8SKris Kennaway k->enc[mode].key = keys[ctos ? 2 : 3]; 523a04a10f8SKris Kennaway k->mac[mode].key = keys[ctos ? 4 : 5]; 524a04a10f8SKris Kennaway } 525a04a10f8SKris Kennaway return 0; 526a04a10f8SKris Kennaway } 527