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" 31 RCSID("$Id: kex.c,v 1.7 2000/05/25 20:45:20 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 "packet.h" 39 #include "cipher.h" 40 #include "compat.h" 41 42 #include <openssl/bn.h> 43 #include <openssl/dh.h> 44 45 #include <openssl/crypto.h> 46 #include <openssl/bio.h> 47 #include <openssl/bn.h> 48 #include <openssl/dh.h> 49 #include <openssl/pem.h> 50 51 #include "kex.h" 52 53 #define KEX_COOKIE_LEN 16 54 55 Buffer * 56 kex_init(char *myproposal[PROPOSAL_MAX]) 57 { 58 int first_kex_packet_follows = 0; 59 unsigned char cookie[KEX_COOKIE_LEN]; 60 u_int32_t rand = 0; 61 int i; 62 Buffer *ki = xmalloc(sizeof(*ki)); 63 for (i = 0; i < KEX_COOKIE_LEN; i++) { 64 if (i % 4 == 0) 65 rand = arc4random(); 66 cookie[i] = rand & 0xff; 67 rand >>= 8; 68 } 69 buffer_init(ki); 70 buffer_append(ki, (char *)cookie, sizeof cookie); 71 for (i = 0; i < PROPOSAL_MAX; i++) 72 buffer_put_cstring(ki, myproposal[i]); 73 buffer_put_char(ki, first_kex_packet_follows); 74 buffer_put_int(ki, 0); /* uint32 reserved */ 75 return ki; 76 } 77 78 /* send kexinit, parse and save reply */ 79 void 80 kex_exchange_kexinit( 81 Buffer *my_kexinit, Buffer *peer_kexint, 82 char *peer_proposal[PROPOSAL_MAX]) 83 { 84 int i; 85 char *ptr; 86 int plen; 87 88 debug("send KEXINIT"); 89 packet_start(SSH2_MSG_KEXINIT); 90 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit)); 91 packet_send(); 92 packet_write_wait(); 93 debug("done"); 94 95 /* 96 * read and save raw KEXINIT payload in buffer. this is used during 97 * computation of the session_id and the session keys. 98 */ 99 debug("wait KEXINIT"); 100 packet_read_expect(&plen, SSH2_MSG_KEXINIT); 101 ptr = packet_get_raw(&plen); 102 buffer_append(peer_kexint, ptr, plen); 103 104 /* parse packet and save algorithm proposal */ 105 /* skip cookie */ 106 for (i = 0; i < KEX_COOKIE_LEN; i++) 107 packet_get_char(); 108 /* extract kex init proposal strings */ 109 for (i = 0; i < PROPOSAL_MAX; i++) { 110 peer_proposal[i] = packet_get_string(NULL); 111 debug("got kexinit: %s", peer_proposal[i]); 112 } 113 /* first kex follow / reserved */ 114 i = packet_get_char(); 115 debug("first kex follow: %d ", i); 116 i = packet_get_int(); 117 debug("reserved: %d ", i); 118 packet_done(); 119 debug("done"); 120 } 121 122 /* diffie-hellman-group1-sha1 */ 123 124 int 125 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) 126 { 127 int i; 128 int n = BN_num_bits(dh_pub); 129 int bits_set = 0; 130 131 /* we only accept g==2 */ 132 if (!BN_is_word(dh->g, 2)) { 133 log("invalid DH base != 2"); 134 return 0; 135 } 136 if (dh_pub->neg) { 137 log("invalid public DH value: negativ"); 138 return 0; 139 } 140 for (i = 0; i <= n; i++) 141 if (BN_is_bit_set(dh_pub, i)) 142 bits_set++; 143 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); 144 145 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ 146 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) 147 return 1; 148 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); 149 return 0; 150 } 151 152 DH * 153 dh_new_group1() 154 { 155 static char *group1 = 156 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 157 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 158 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 159 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 160 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 161 "FFFFFFFF" "FFFFFFFF"; 162 DH *dh; 163 int ret, tries = 0; 164 dh = DH_new(); 165 if(dh == NULL) 166 fatal("DH_new"); 167 ret = BN_hex2bn(&dh->p, group1); 168 if(ret<0) 169 fatal("BN_hex2bn"); 170 dh->g = BN_new(); 171 if(dh->g == NULL) 172 fatal("DH_new g"); 173 BN_set_word(dh->g, 2); 174 do { 175 if (DH_generate_key(dh) == 0) 176 fatal("DH_generate_key"); 177 if (tries++ > 10) 178 fatal("dh_new_group1: too many bad keys: giving up"); 179 } while (!dh_pub_is_valid(dh, dh->pub_key)); 180 return dh; 181 } 182 183 void 184 dump_digest(unsigned char *digest, int len) 185 { 186 int i; 187 for (i = 0; i< len; i++){ 188 fprintf(stderr, "%02x", digest[i]); 189 if(i%2!=0) 190 fprintf(stderr, " "); 191 } 192 fprintf(stderr, "\n"); 193 } 194 195 unsigned char * 196 kex_hash( 197 char *client_version_string, 198 char *server_version_string, 199 char *ckexinit, int ckexinitlen, 200 char *skexinit, int skexinitlen, 201 char *serverhostkeyblob, int sbloblen, 202 BIGNUM *client_dh_pub, 203 BIGNUM *server_dh_pub, 204 BIGNUM *shared_secret) 205 { 206 Buffer b; 207 static unsigned char digest[EVP_MAX_MD_SIZE]; 208 EVP_MD *evp_md = EVP_sha1(); 209 EVP_MD_CTX md; 210 211 buffer_init(&b); 212 buffer_put_string(&b, client_version_string, strlen(client_version_string)); 213 buffer_put_string(&b, server_version_string, strlen(server_version_string)); 214 215 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 216 buffer_put_int(&b, ckexinitlen+1); 217 buffer_put_char(&b, SSH2_MSG_KEXINIT); 218 buffer_append(&b, ckexinit, ckexinitlen); 219 buffer_put_int(&b, skexinitlen+1); 220 buffer_put_char(&b, SSH2_MSG_KEXINIT); 221 buffer_append(&b, skexinit, skexinitlen); 222 223 buffer_put_string(&b, serverhostkeyblob, sbloblen); 224 buffer_put_bignum2(&b, client_dh_pub); 225 buffer_put_bignum2(&b, server_dh_pub); 226 buffer_put_bignum2(&b, shared_secret); 227 228 #ifdef DEBUG_KEX 229 buffer_dump(&b); 230 #endif 231 232 EVP_DigestInit(&md, evp_md); 233 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 234 EVP_DigestFinal(&md, digest, NULL); 235 236 buffer_free(&b); 237 238 #ifdef DEBUG_KEX 239 dump_digest(digest, evp_md->md_size); 240 #endif 241 return digest; 242 } 243 244 unsigned char * 245 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret) 246 { 247 Buffer b; 248 EVP_MD *evp_md = EVP_sha1(); 249 EVP_MD_CTX md; 250 char c = id; 251 int have; 252 int mdsz = evp_md->md_size; 253 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); 254 255 buffer_init(&b); 256 buffer_put_bignum2(&b, shared_secret); 257 258 EVP_DigestInit(&md, evp_md); 259 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ 260 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ 261 EVP_DigestUpdate(&md, &c, 1); /* key id */ 262 EVP_DigestUpdate(&md, hash, mdsz); /* session id */ 263 EVP_DigestFinal(&md, digest, NULL); 264 265 /* expand */ 266 for (have = mdsz; need > have; have += mdsz) { 267 EVP_DigestInit(&md, evp_md); 268 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 269 EVP_DigestUpdate(&md, hash, mdsz); 270 EVP_DigestUpdate(&md, digest, have); 271 EVP_DigestFinal(&md, digest + have, NULL); 272 } 273 buffer_free(&b); 274 #ifdef DEBUG_KEX 275 fprintf(stderr, "Digest '%c'== ", c); 276 dump_digest(digest, need); 277 #endif 278 return digest; 279 } 280 281 #define NKEYS 6 282 283 #define MAX_PROP 20 284 #define SEP "," 285 286 char * 287 get_match(char *client, char *server) 288 { 289 char *sproposals[MAX_PROP]; 290 char *c, *s, *p, *ret; 291 int i, j, nproposals; 292 293 c = xstrdup(client); 294 s = xstrdup(server); 295 296 for ((p = strtok(s, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 297 if (i < MAX_PROP) 298 sproposals[i] = p; 299 else 300 break; 301 } 302 nproposals = i; 303 304 for ((p = strtok(c, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 305 for (j = 0; j < nproposals; j++) { 306 if (strcmp(p, sproposals[j]) == 0) { 307 ret = xstrdup(p); 308 xfree(c); 309 xfree(s); 310 return ret; 311 } 312 } 313 } 314 xfree(c); 315 xfree(s); 316 return NULL; 317 } 318 void 319 choose_enc(Enc *enc, char *client, char *server) 320 { 321 char *name = get_match(client, server); 322 if (name == NULL) 323 fatal("no matching cipher found: client %s server %s", client, server); 324 enc->type = cipher_number(name); 325 326 switch (enc->type) { 327 case SSH_CIPHER_3DES_CBC: 328 enc->key_len = 24; 329 enc->iv_len = 8; 330 enc->block_size = 8; 331 break; 332 case SSH_CIPHER_BLOWFISH_CBC: 333 case SSH_CIPHER_CAST128_CBC: 334 enc->key_len = 16; 335 enc->iv_len = 8; 336 enc->block_size = 8; 337 break; 338 case SSH_CIPHER_ARCFOUR: 339 enc->key_len = 16; 340 enc->iv_len = 0; 341 enc->block_size = 8; 342 break; 343 default: 344 fatal("unsupported cipher %s", name); 345 } 346 enc->name = name; 347 enc->enabled = 0; 348 enc->iv = NULL; 349 enc->key = NULL; 350 } 351 void 352 choose_mac(Mac *mac, char *client, char *server) 353 { 354 char *name = get_match(client, server); 355 if (name == NULL) 356 fatal("no matching mac found: client %s server %s", client, server); 357 if (strcmp(name, "hmac-md5") == 0) { 358 mac->md = EVP_md5(); 359 } else if (strcmp(name, "hmac-sha1") == 0) { 360 mac->md = EVP_sha1(); 361 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) { 362 mac->md = EVP_ripemd160(); 363 } else { 364 fatal("unsupported mac %s", name); 365 } 366 mac->name = name; 367 mac->mac_len = mac->md->md_size; 368 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len; 369 mac->key = NULL; 370 mac->enabled = 0; 371 } 372 void 373 choose_comp(Comp *comp, char *client, char *server) 374 { 375 char *name = get_match(client, server); 376 if (name == NULL) 377 fatal("no matching comp found: client %s server %s", client, server); 378 if (strcmp(name, "zlib") == 0) { 379 comp->type = 1; 380 } else if (strcmp(name, "none") == 0) { 381 comp->type = 0; 382 } else { 383 fatal("unsupported comp %s", name); 384 } 385 comp->name = name; 386 } 387 void 388 choose_kex(Kex *k, char *client, char *server) 389 { 390 k->name = get_match(client, server); 391 if (k->name == NULL) 392 fatal("no kex alg"); 393 if (strcmp(k->name, KEX_DH1) != 0) 394 fatal("bad kex alg %s", k->name); 395 } 396 void 397 choose_hostkeyalg(Kex *k, char *client, char *server) 398 { 399 k->hostkeyalg = get_match(client, server); 400 if (k->hostkeyalg == NULL) 401 fatal("no hostkey alg"); 402 if (strcmp(k->hostkeyalg, KEX_DSS) != 0) 403 fatal("bad hostkey alg %s", k->hostkeyalg); 404 } 405 406 Kex * 407 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) 408 { 409 int mode; 410 int ctos; /* direction: if true client-to-server */ 411 int need; 412 Kex *k; 413 414 k = xmalloc(sizeof(*k)); 415 memset(k, 0, sizeof(*k)); 416 k->server = server; 417 418 for (mode = 0; mode < MODE_MAX; mode++) { 419 int nenc, nmac, ncomp; 420 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 421 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 422 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 423 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 424 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]); 425 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]); 426 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]); 427 debug("kex: %s %s %s %s", 428 ctos ? "client->server" : "server->client", 429 k->enc[mode].name, 430 k->mac[mode].name, 431 k->comp[mode].name); 432 } 433 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 434 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 435 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 436 need = 0; 437 for (mode = 0; mode < MODE_MAX; mode++) { 438 if (need < k->enc[mode].key_len) 439 need = k->enc[mode].key_len; 440 if (need < k->enc[mode].iv_len) 441 need = k->enc[mode].iv_len; 442 if (need < k->mac[mode].key_len) 443 need = k->mac[mode].key_len; 444 } 445 /* XXX need runden? */ 446 k->we_need = need; 447 return k; 448 } 449 450 int 451 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret) 452 { 453 int i; 454 int mode; 455 int ctos; 456 unsigned char *keys[NKEYS]; 457 458 for (i = 0; i < NKEYS; i++) 459 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret); 460 461 for (mode = 0; mode < MODE_MAX; mode++) { 462 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN); 463 k->enc[mode].iv = keys[ctos ? 0 : 1]; 464 k->enc[mode].key = keys[ctos ? 2 : 3]; 465 k->mac[mode].key = keys[ctos ? 4 : 5]; 466 } 467 return 0; 468 } 469