kex.c revision 60573
1/* 2 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Markus Friedl. 15 * 4. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "includes.h" 31RCSID("$Id: kex.c,v 1.6 2000/05/08 17:42:25 markus Exp $"); 32 33#include "ssh.h" 34#include "ssh2.h" 35#include "xmalloc.h" 36#include "buffer.h" 37#include "bufaux.h" 38#include "cipher.h" 39#include "compat.h" 40 41#include <openssl/bn.h> 42#include <openssl/dh.h> 43 44#include <openssl/crypto.h> 45#include <openssl/bio.h> 46#include <openssl/bn.h> 47#include <openssl/dh.h> 48#include <openssl/pem.h> 49 50#include "kex.h" 51 52Buffer * 53kex_init(char *myproposal[PROPOSAL_MAX]) 54{ 55 char c = 0; 56 unsigned char cookie[16]; 57 u_int32_t rand = 0; 58 int i; 59 Buffer *ki = xmalloc(sizeof(*ki)); 60 for (i = 0; i < 16; i++) { 61 if (i % 4 == 0) 62 rand = arc4random(); 63 cookie[i] = rand & 0xff; 64 rand >>= 8; 65 } 66 buffer_init(ki); 67 buffer_append(ki, (char *)cookie, sizeof cookie); 68 for (i = 0; i < PROPOSAL_MAX; i++) 69 buffer_put_cstring(ki, myproposal[i]); 70 buffer_append(ki, &c, 1); /* boolean first_kex_packet_follows */ 71 buffer_put_int(ki, 0); /* uint32 0 (reserved for future extension) */ 72 return ki; 73} 74 75/* diffie-hellman-group1-sha1 */ 76 77int 78dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) 79{ 80 int i; 81 int n = BN_num_bits(dh_pub); 82 int bits_set = 0; 83 84 /* we only accept g==2 */ 85 if (!BN_is_word(dh->g, 2)) { 86 log("invalid DH base != 2"); 87 return 0; 88 } 89 if (dh_pub->neg) { 90 log("invalid public DH value: negativ"); 91 return 0; 92 } 93 for (i = 0; i <= n; i++) 94 if (BN_is_bit_set(dh_pub, i)) 95 bits_set++; 96 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); 97 98 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ 99 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) 100 return 1; 101 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); 102 return 0; 103} 104 105DH * 106dh_new_group1() 107{ 108 static char *group1 = 109 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 110 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 111 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 112 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 113 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 114 "FFFFFFFF" "FFFFFFFF"; 115 DH *dh; 116 int ret, tries = 0; 117 dh = DH_new(); 118 if(dh == NULL) 119 fatal("DH_new"); 120 ret = BN_hex2bn(&dh->p, group1); 121 if(ret<0) 122 fatal("BN_hex2bn"); 123 dh->g = BN_new(); 124 if(dh->g == NULL) 125 fatal("DH_new g"); 126 BN_set_word(dh->g, 2); 127 do { 128 if (DH_generate_key(dh) == 0) 129 fatal("DH_generate_key"); 130 if (tries++ > 10) 131 fatal("dh_new_group1: too many bad keys: giving up"); 132 } while (!dh_pub_is_valid(dh, dh->pub_key)); 133 return dh; 134} 135 136void 137bignum_print(BIGNUM *b) 138{ 139 BN_print_fp(stderr,b); 140} 141 142void 143dump_digest(unsigned char *digest, int len) 144{ 145 int i; 146 for (i = 0; i< len; i++){ 147 fprintf(stderr, "%02x", digest[i]); 148 if(i%2!=0) 149 fprintf(stderr, " "); 150 } 151 fprintf(stderr, "\n"); 152} 153 154unsigned char * 155kex_hash( 156 char *client_version_string, 157 char *server_version_string, 158 char *ckexinit, int ckexinitlen, 159 char *skexinit, int skexinitlen, 160 char *serverhostkeyblob, int sbloblen, 161 BIGNUM *client_dh_pub, 162 BIGNUM *server_dh_pub, 163 BIGNUM *shared_secret) 164{ 165 Buffer b; 166 static unsigned char digest[EVP_MAX_MD_SIZE]; 167 EVP_MD *evp_md = EVP_sha1(); 168 EVP_MD_CTX md; 169 170 buffer_init(&b); 171 buffer_put_string(&b, client_version_string, strlen(client_version_string)); 172 buffer_put_string(&b, server_version_string, strlen(server_version_string)); 173 174 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 175 buffer_put_int(&b, ckexinitlen+1); 176 buffer_put_char(&b, SSH2_MSG_KEXINIT); 177 buffer_append(&b, ckexinit, ckexinitlen); 178 buffer_put_int(&b, skexinitlen+1); 179 buffer_put_char(&b, SSH2_MSG_KEXINIT); 180 buffer_append(&b, skexinit, skexinitlen); 181 182 buffer_put_string(&b, serverhostkeyblob, sbloblen); 183 buffer_put_bignum2(&b, client_dh_pub); 184 buffer_put_bignum2(&b, server_dh_pub); 185 buffer_put_bignum2(&b, shared_secret); 186 187#ifdef DEBUG_KEX 188 buffer_dump(&b); 189#endif 190 191 EVP_DigestInit(&md, evp_md); 192 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 193 EVP_DigestFinal(&md, digest, NULL); 194 195 buffer_free(&b); 196 197#ifdef DEBUG_KEX 198 dump_digest(digest, evp_md->md_size); 199#endif 200 return digest; 201} 202 203unsigned char * 204derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) 205{ 206 Buffer b; 207 EVP_MD *evp_md = EVP_sha1(); 208 EVP_MD_CTX md; 209 char c = id; 210 int have; 211 int mdsz = evp_md->md_size; 212 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); 213 214 buffer_init(&b); 215 buffer_put_bignum2(&b, shared_secret); 216 217 EVP_DigestInit(&md, evp_md); 218 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ 219 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ 220 EVP_DigestUpdate(&md, &c, 1); /* key id */ 221 EVP_DigestUpdate(&md, hash, mdsz); /* session id */ 222 EVP_DigestFinal(&md, digest, NULL); 223 224 /* expand */ 225 for (have = mdsz; need > have; have += mdsz) { 226 EVP_DigestInit(&md, evp_md); 227 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 228 EVP_DigestUpdate(&md, hash, mdsz); 229 EVP_DigestUpdate(&md, digest, have); 230 EVP_DigestFinal(&md, digest + have, NULL); 231 } 232 buffer_free(&b); 233#ifdef DEBUG_KEX 234 fprintf(stderr, "Digest '%c'== ", c); 235 dump_digest(digest, need); 236#endif 237 return digest; 238} 239 240#define NKEYS 6 241 242#define MAX_PROP 20 243#define SEP "," 244 245char * 246get_match(char *client, char *server) 247{ 248 char *sproposals[MAX_PROP]; 249 char *p; 250 int i, j, nproposals; 251 252 for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 253 if (i < MAX_PROP) 254 sproposals[i] = p; 255 else 256 break; 257 } 258 nproposals = i; 259 260 for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 261 for (j = 0; j < nproposals; j++) 262 if (strcmp(p, sproposals[j]) == 0) 263 return xstrdup(p); 264 } 265 return NULL; 266} 267void 268choose_enc(Enc *enc, char *client, char *server) 269{ 270 char *name = get_match(client, server); 271 if (name == NULL) 272 fatal("no matching cipher found: client %s server %s", client, server); 273 enc->type = cipher_number(name); 274 275 switch (enc->type) { 276 case SSH_CIPHER_3DES_CBC: 277 enc->key_len = 24; 278 enc->iv_len = 8; 279 enc->block_size = 8; 280 break; 281 case SSH_CIPHER_BLOWFISH_CBC: 282 case SSH_CIPHER_CAST128_CBC: 283 enc->key_len = 16; 284 enc->iv_len = 8; 285 enc->block_size = 8; 286 break; 287 case SSH_CIPHER_ARCFOUR: 288 enc->key_len = 16; 289 enc->iv_len = 0; 290 enc->block_size = 8; 291 break; 292 default: 293 fatal("unsupported cipher %s", name); 294 } 295 enc->name = name; 296 enc->enabled = 0; 297 enc->iv = NULL; 298 enc->key = NULL; 299} 300void 301choose_mac(Mac *mac, char *client, char *server) 302{ 303 char *name = get_match(client, server); 304 if (name == NULL) 305 fatal("no matching mac found: client %s server %s", client, server); 306 if (strcmp(name, "hmac-md5") == 0) { 307 mac->md = EVP_md5(); 308 } else if (strcmp(name, "hmac-sha1") == 0) { 309 mac->md = EVP_sha1(); 310 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) { 311 mac->md = EVP_ripemd160(); 312 } else { 313 fatal("unsupported mac %s", name); 314 } 315 mac->name = name; 316 mac->mac_len = mac->md->md_size; 317 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len; 318 mac->key = NULL; 319 mac->enabled = 0; 320} 321void 322choose_comp(Comp *comp, char *client, char *server) 323{ 324 char *name = get_match(client, server); 325 if (name == NULL) 326 fatal("no matching comp found: client %s server %s", client, server); 327 if (strcmp(name, "zlib") == 0) { 328 comp->type = 1; 329 } else if (strcmp(name, "none") == 0) { 330 comp->type = 0; 331 } else { 332 fatal("unsupported comp %s", name); 333 } 334 comp->name = name; 335} 336void 337choose_kex(Kex *k, char *client, char *server) 338{ 339 k->name = get_match(client, server); 340 if (k->name == NULL) 341 fatal("no kex alg"); 342 if (strcmp(k->name, KEX_DH1) != 0) 343 fatal("bad kex alg %s", k->name); 344} 345void 346choose_hostkeyalg(Kex *k, char *client, char *server) 347{ 348 k->hostkeyalg = get_match(client, server); 349 if (k->hostkeyalg == NULL) 350 fatal("no hostkey alg"); 351 if (strcmp(k->hostkeyalg, KEX_DSS) != 0) 352 fatal("bad hostkey alg %s", k->hostkeyalg); 353} 354 355Kex * 356kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) 357{ 358 int i; 359 int mode; 360 int ctos; /* direction: if true client-to-server */ 361 int need; 362 Kex *k; 363 364 k = xmalloc(sizeof(*k)); 365 memset(k, 0, sizeof(*k)); 366 k->server = server; 367 368 for (mode = 0; mode < MODE_MAX; mode++) { 369 int nenc, nmac, ncomp; 370 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 371 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 372 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 373 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 374 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]); 375 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]); 376 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]); 377 debug("kex: %s %s %s %s", 378 ctos ? "client->server" : "server->client", 379 k->enc[mode].name, 380 k->mac[mode].name, 381 k->comp[mode].name); 382 } 383 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 384 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 385 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 386 for (i = 0; i < PROPOSAL_MAX; i++) { 387 xfree(cprop[i]); 388 xfree(sprop[i]); 389 } 390 need = 0; 391 for (mode = 0; mode < MODE_MAX; mode++) { 392 if (need < k->enc[mode].key_len) 393 need = k->enc[mode].key_len; 394 if (need < k->enc[mode].iv_len) 395 need = k->enc[mode].iv_len; 396 if (need < k->mac[mode].key_len) 397 need = k->mac[mode].key_len; 398 } 399 /* need runden? */ 400#define WE_NEED 32 401 k->we_need = WE_NEED; 402 k->we_need = need; 403 return k; 404} 405 406int 407kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret) 408{ 409 int i; 410 int mode; 411 int ctos; 412 unsigned char *keys[NKEYS]; 413 414 for (i = 0; i < NKEYS; i++) 415 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret); 416 417 for (mode = 0; mode < MODE_MAX; mode++) { 418 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 419 k->enc[mode].iv = keys[ctos ? 0 : 1]; 420 k->enc[mode].key = keys[ctos ? 2 : 3]; 421 k->mac[mode].key = keys[ctos ? 4 : 5]; 422 } 423 return 0; 424} 425