1 /* 2 * Copyright (c) 2000, 2001 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 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include "includes.h" 29 RCSID("$OpenBSD: kex.c,v 1.51 2002/06/24 14:55:38 markus Exp $"); 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <locale.h> 34 35 #include <openssl/crypto.h> 36 37 #include "ssh2.h" 38 #include "xmalloc.h" 39 #include "buffer.h" 40 #include "bufaux.h" 41 #include "packet.h" 42 #include "compat.h" 43 #include "cipher.h" 44 #include "kex.h" 45 #include "key.h" 46 #include "log.h" 47 #include "mac.h" 48 #include "match.h" 49 #include "dispatch.h" 50 #include "g11n.h" 51 52 #ifdef GSSAPI 53 #include "ssh-gss.h" 54 #endif 55 56 #define KEX_COOKIE_LEN 16 57 58 char *session_lang = NULL; 59 60 61 /* prototype */ 62 static void kex_do_hook(Kex *kex); 63 static void kex_kexinit_finish(Kex *); 64 static void kex_choose_conf(Kex *); 65 66 /* put algorithm proposal into buffer */ 67 static 68 void 69 kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) 70 { 71 int i; 72 73 buffer_clear(b); 74 /* 75 * add a dummy cookie, the cookie will be overwritten by 76 * kex_send_kexinit(), each time a kexinit is set 77 */ 78 for (i = 0; i < KEX_COOKIE_LEN; i++) 79 buffer_put_char(b, 0); 80 for (i = 0; i < PROPOSAL_MAX; i++) 81 buffer_put_cstring(b, proposal[i]); 82 buffer_put_char(b, 0); /* first_kex_packet_follows */ 83 buffer_put_int(b, 0); /* uint32 reserved */ 84 } 85 86 /* parse buffer and return algorithm proposal */ 87 static 88 char ** 89 kex_buf2prop(Buffer *raw, int *first_kex_follows) 90 { 91 Buffer b; 92 int i; 93 char **proposal; 94 95 proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); 96 97 buffer_init(&b); 98 buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); 99 /* skip cookie */ 100 for (i = 0; i < KEX_COOKIE_LEN; i++) 101 buffer_get_char(&b); 102 /* extract kex init proposal strings */ 103 for (i = 0; i < PROPOSAL_MAX; i++) { 104 proposal[i] = buffer_get_string(&b,NULL); 105 debug2("kex_parse_kexinit: %s", proposal[i]); 106 } 107 /* first kex follows / reserved */ 108 i = buffer_get_char(&b); 109 if (first_kex_follows != NULL) 110 *first_kex_follows = i; 111 debug2("kex_parse_kexinit: first_kex_follows %d ", i); 112 i = buffer_get_int(&b); 113 debug2("kex_parse_kexinit: reserved %d ", i); 114 buffer_free(&b); 115 return proposal; 116 } 117 118 static 119 void 120 kex_prop_free(char **proposal) 121 { 122 int i; 123 124 for (i = 0; i < PROPOSAL_MAX; i++) 125 xfree(proposal[i]); 126 xfree(proposal); 127 } 128 129 static void 130 kex_protocol_error(int type, u_int32_t seq, void *ctxt) 131 { 132 error("Hm, kex protocol error: type %d seq %u", type, seq); 133 } 134 135 static void 136 kex_reset_dispatch(void) 137 { 138 #ifdef ALTPRIVSEP 139 /* unprivileged sshd has a kex packet handler that must not be reset */ 140 debug3("kex_reset_dispatch -- should we dispatch_set(KEXINIT) here? %d && !%d", 141 packet_is_server(), packet_is_monitor()); 142 if (packet_is_server() && !packet_is_monitor()) { 143 debug3("kex_reset_dispatch -- skipping dispatch_set(KEXINIT) in unpriv proc"); 144 return; 145 } 146 #endif /* ALTPRIVSEP */ 147 148 dispatch_range(SSH2_MSG_TRANSPORT_MIN, 149 SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); 150 dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 151 } 152 153 void 154 kex_finish(Kex *kex) 155 { 156 kex_reset_dispatch(); 157 158 packet_start(SSH2_MSG_NEWKEYS); 159 packet_send(); 160 /* packet_write_wait(); */ 161 debug("SSH2_MSG_NEWKEYS sent"); 162 163 #ifdef ALTPRIVSEP 164 if (packet_is_monitor()) 165 goto skip_newkeys; 166 #endif /* ALTPRIVSEP */ 167 debug("expecting SSH2_MSG_NEWKEYS"); 168 packet_read_expect(SSH2_MSG_NEWKEYS); 169 packet_check_eom(); 170 debug("SSH2_MSG_NEWKEYS received"); 171 #ifdef ALTPRIVSEP 172 skip_newkeys: 173 #endif /* ALTPRIVSEP */ 174 175 kex->done = 1; 176 kex->initial_kex_done = 1; /* never to be cleared once set */ 177 buffer_clear(&kex->peer); 178 /* buffer_clear(&kex->my); */ 179 kex->flags &= ~KEX_INIT_SENT; 180 xfree(kex->name); 181 kex->name = NULL; 182 } 183 184 void 185 kex_send_kexinit(Kex *kex) 186 { 187 u_int32_t rand = 0; 188 u_char *cookie; 189 int i; 190 191 if (kex == NULL) { 192 error("kex_send_kexinit: no kex, cannot rekey"); 193 return; 194 } 195 if (kex->flags & KEX_INIT_SENT) { 196 debug("KEX_INIT_SENT"); 197 return; 198 } 199 kex->done = 0; 200 201 /* update my proposal -- e.g., add/remove GSS kexalgs */ 202 kex_do_hook(kex); 203 204 /* generate a random cookie */ 205 if (buffer_len(&kex->my) < KEX_COOKIE_LEN) 206 fatal("kex_send_kexinit: kex proposal too short"); 207 cookie = buffer_ptr(&kex->my); 208 for (i = 0; i < KEX_COOKIE_LEN; i++) { 209 if (i % 4 == 0) 210 rand = arc4random(); 211 cookie[i] = rand; 212 rand >>= 8; 213 } 214 packet_start(SSH2_MSG_KEXINIT); 215 packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); 216 packet_send(); 217 debug("SSH2_MSG_KEXINIT sent"); 218 kex->flags |= KEX_INIT_SENT; 219 } 220 221 void 222 kex_input_kexinit(int type, u_int32_t seq, void *ctxt) 223 { 224 char *ptr; 225 u_int dlen; 226 int i; 227 Kex *kex = (Kex *)ctxt; 228 229 debug("SSH2_MSG_KEXINIT received"); 230 if (kex == NULL) 231 fatal("kex_input_kexinit: no kex, cannot rekey"); 232 233 ptr = packet_get_raw(&dlen); 234 buffer_append(&kex->peer, ptr, dlen); 235 236 /* discard packet */ 237 for (i = 0; i < KEX_COOKIE_LEN; i++) 238 packet_get_char(); 239 for (i = 0; i < PROPOSAL_MAX; i++) 240 xfree(packet_get_string(NULL)); 241 (void) packet_get_char(); 242 (void) packet_get_int(); 243 packet_check_eom(); 244 245 kex_kexinit_finish(kex); 246 } 247 248 /* 249 * This is for GSS keyex, where actual KEX offer can change at rekey 250 * time due to credential expiration/renewal... 251 */ 252 static 253 void 254 kex_do_hook(Kex *kex) 255 { 256 char **prop; 257 258 if (kex->kex_hook == NULL) 259 return; 260 261 /* Unmarshall my proposal, let the hook modify it, remarshall it */ 262 prop = kex_buf2prop(&kex->my, NULL); 263 buffer_clear(&kex->my); 264 (kex->kex_hook)(kex, prop); 265 kex_prop2buf(&kex->my, prop); 266 kex_prop_free(prop); 267 } 268 269 Kex * 270 kex_setup(const char *host, char *proposal[PROPOSAL_MAX], Kex_hook_func hook) 271 { 272 Kex *kex; 273 274 kex = xmalloc(sizeof(*kex)); 275 memset(kex, 0, sizeof(*kex)); 276 buffer_init(&kex->peer); 277 buffer_init(&kex->my); 278 279 kex->kex_hook = hook; /* called by kex_send_kexinit() */ 280 281 if (host != NULL && *host != '\0') 282 kex->serverhost = xstrdup(host); 283 else 284 kex->server = 1; 285 286 kex_prop2buf(&kex->my, proposal); 287 288 kex_send_kexinit(kex); 289 kex_reset_dispatch(); 290 291 return kex; 292 } 293 294 static void 295 kex_kexinit_finish(Kex *kex) 296 { 297 if (!(kex->flags & KEX_INIT_SENT)) 298 kex_send_kexinit(kex); 299 300 kex_choose_conf(kex); 301 302 if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && 303 kex->kex[kex->kex_type] != NULL) 304 (kex->kex[kex->kex_type])(kex); 305 else 306 fatal("Unsupported key exchange %d", kex->kex_type); 307 } 308 309 static void 310 choose_lang(char **lang, char *client, char *server) 311 { 312 if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS) 313 *lang = match_list(client, server, NULL); 314 else 315 *lang = g11n_srvr_locale_negotiate(client, NULL); 316 } 317 static void 318 choose_enc(Enc *enc, char *client, char *server) 319 { 320 char *name = match_list(client, server, NULL); 321 if (name == NULL) 322 fatal("no matching cipher found: client %s server %s", client, server); 323 if ((enc->cipher = cipher_by_name(name)) == NULL) 324 fatal("matching cipher is not supported: %s", name); 325 enc->name = name; 326 enc->enabled = 0; 327 enc->iv = NULL; 328 enc->key = NULL; 329 enc->key_len = cipher_keylen(enc->cipher); 330 enc->block_size = cipher_blocksize(enc->cipher); 331 } 332 static void 333 choose_mac(Mac *mac, char *client, char *server) 334 { 335 char *name = match_list(client, server, NULL); 336 if (name == NULL) 337 fatal("no matching mac found: client %s server %s", client, server); 338 if (mac_init(mac, name) < 0) 339 fatal("unsupported mac %s", name); 340 /* truncate the key */ 341 if (datafellows & SSH_BUG_HMAC) 342 mac->key_len = 16; 343 mac->name = name; 344 mac->key = NULL; 345 mac->enabled = 0; 346 } 347 static void 348 choose_comp(Comp *comp, char *client, char *server) 349 { 350 char *name = match_list(client, server, NULL); 351 if (name == NULL) 352 fatal("no matching comp found: client %s server %s", client, server); 353 if (strcmp(name, "zlib") == 0) { 354 comp->type = 1; 355 } else if (strcmp(name, "none") == 0) { 356 comp->type = 0; 357 } else { 358 fatal("unsupported comp %s", name); 359 } 360 comp->name = name; 361 } 362 static void 363 choose_kex(Kex *k, char *client, char *server) 364 { 365 k->name = match_list(client, server, NULL); 366 if (k->name == NULL) 367 fatal("no kex alg"); 368 /* XXX Finish 3.6/7 merge of kex stuff -- choose_kex() done */ 369 if (strcmp(k->name, KEX_DH1) == 0) { 370 k->kex_type = KEX_DH_GRP1_SHA1; 371 } else if (strcmp(k->name, KEX_DHGEX) == 0) { 372 k->kex_type = KEX_DH_GEX_SHA1; 373 #ifdef GSSAPI 374 } else if (strncmp(k->name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) == 0) { 375 k->kex_type = KEX_GSS_GRP1_SHA1; 376 #endif 377 } else 378 fatal("bad kex alg %s", k->name); 379 } 380 static void 381 choose_hostkeyalg(Kex *k, char *client, char *server) 382 { 383 char *hostkeyalg = match_list(client, server, NULL); 384 if (hostkeyalg == NULL) 385 fatal("no hostkey alg"); 386 k->hostkey_type = key_type_from_name(hostkeyalg); 387 if (k->hostkey_type == KEY_UNSPEC) 388 fatal("bad hostkey alg '%s'", hostkeyalg); 389 xfree(hostkeyalg); 390 } 391 392 static int 393 proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) 394 { 395 static int check[] = { 396 PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 397 }; 398 int *idx; 399 char *p; 400 401 for (idx = &check[0]; *idx != -1; idx++) { 402 if ((p = strchr(my[*idx], ',')) != NULL) 403 *p = '\0'; 404 if ((p = strchr(peer[*idx], ',')) != NULL) 405 *p = '\0'; 406 if (strcmp(my[*idx], peer[*idx]) != 0) { 407 debug2("proposal mismatch: my %s peer %s", 408 my[*idx], peer[*idx]); 409 return (0); 410 } 411 } 412 debug2("proposals match"); 413 return (1); 414 } 415 416 static void 417 kex_choose_conf(Kex *kex) 418 { 419 Newkeys *newkeys; 420 char **my, **peer; 421 char **cprop, **sprop; 422 char *p_langs_c2s, *p_langs_s2c; /* peer's langs */ 423 char *plangs = NULL; /* peer's langs*/ 424 char *mlangs = NULL; /* my langs */ 425 int nenc, nmac, ncomp; 426 int mode; 427 int ctos; /* direction: if true client-to-server */ 428 int need; 429 int first_kex_follows, type; 430 431 my = kex_buf2prop(&kex->my, NULL); 432 peer = kex_buf2prop(&kex->peer, &first_kex_follows); 433 434 if (kex->server) { 435 cprop=peer; 436 sprop=my; 437 } else { 438 cprop=my; 439 sprop=peer; 440 } 441 442 /* Algorithm Negotiation */ 443 for (mode = 0; mode < MODE_MAX; mode++) { 444 newkeys = xmalloc(sizeof(*newkeys)); 445 memset(newkeys, 0, sizeof(*newkeys)); 446 kex->newkeys[mode] = newkeys; 447 ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 448 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; 449 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 450 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 451 choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); 452 choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); 453 choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); 454 debug("kex: %s %s %s %s", 455 ctos ? "client->server" : "server->client", 456 newkeys->enc.name, 457 newkeys->mac.name, 458 newkeys->comp.name); 459 } 460 choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); 461 choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 462 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); 463 need = 0; 464 for (mode = 0; mode < MODE_MAX; mode++) { 465 newkeys = kex->newkeys[mode]; 466 if (need < newkeys->enc.key_len) 467 need = newkeys->enc.key_len; 468 if (need < newkeys->enc.block_size) 469 need = newkeys->enc.block_size; 470 if (need < newkeys->mac.key_len) 471 need = newkeys->mac.key_len; 472 } 473 /* XXX need runden? */ 474 kex->we_need = need; 475 476 /* ignore the next message if the proposals do not match */ 477 if (first_kex_follows && !proposals_match(my, peer) && 478 !(datafellows & SSH_BUG_FIRSTKEX)) { 479 type = packet_read(); 480 debug2("skipping next packet (type %u)", type); 481 } 482 483 /* Language/locale negotiation -- not worth doing on re-key */ 484 485 if (!kex->initial_kex_done) { 486 p_langs_c2s = peer[PROPOSAL_LANG_CTOS]; 487 p_langs_s2c = peer[PROPOSAL_LANG_STOC]; 488 debug("Peer sent proposed langtags, ctos: %s", p_langs_c2s); 489 debug("Peer sent proposed langtags, stoc: %s", p_langs_s2c); 490 plangs = NULL; 491 492 /* We propose the same langs for each protocol direction */ 493 mlangs = my[PROPOSAL_LANG_STOC]; 494 debug("We proposed langtags, ctos: %s", my[PROPOSAL_LANG_CTOS]); 495 debug("We proposed langtags, stoc: %s", mlangs); 496 497 /* 498 * Why oh why did they bother with negotiating langs for 499 * each protocol direction?! 500 * 501 * The semantics of this are vaguely specified, but one can 502 * imagine using one language (locale) for the whole session and 503 * a different one for message localization (e.g., 'en_US.UTF-8' 504 * overall and 'fr' for messages). Weird? Maybe. But lang 505 * tags don't include codeset info, like locales do... 506 * 507 * So, server-side we want: 508 * - setlocale(LC_ALL, c2s_locale); 509 * and 510 * - setlocale(LC_MESSAGES, s2c_locale); 511 * 512 * Client-side we don't really care. But we could do: 513 * 514 * - when very verbose, tell the use what lang the server's 515 * messages are in, if left out in the protocol 516 * - when sending messages to the server, and if applicable, we 517 * can localize them according to the language negotiated for 518 * that direction. 519 * 520 * But for now we do nothing on the client side. 521 */ 522 if ((p_langs_c2s && *p_langs_c2s) && !(p_langs_s2c && *p_langs_s2c)) 523 plangs = p_langs_c2s; 524 else if ((p_langs_s2c && *p_langs_s2c) && !(p_langs_c2s && *p_langs_c2s)) 525 plangs = p_langs_s2c; 526 else 527 plangs = p_langs_c2s; 528 529 if (kex->server) { 530 if (plangs && mlangs && *plangs && *mlangs) { 531 char *locale; 532 533 choose_lang(&locale, plangs, mlangs); 534 if (locale) { 535 g11n_setlocale(LC_ALL, locale); 536 debug("Negotiated main locale: %s", locale); 537 packet_send_debug("Negotiated main locale: %s", locale); 538 xfree(locale); 539 } 540 if (plangs != p_langs_s2c && 541 p_langs_s2c && *p_langs_s2c) { 542 choose_lang(&locale, p_langs_s2c, mlangs); 543 if (locale) { 544 g11n_setlocale(LC_MESSAGES, locale); 545 debug("Negotiated messages locale: %s", locale); 546 packet_send_debug("Negotiated " 547 "messages locale: %s", locale); 548 xfree(locale); 549 } 550 } 551 } 552 } 553 else { 554 if (plangs && mlangs && *plangs && *mlangs && 555 !(datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS)) { 556 char *lang; 557 lang = g11n_clnt_langtag_negotiate(mlangs, plangs); 558 if (lang) { 559 session_lang = lang; 560 debug("Negotiated lang: %s", lang); 561 } 562 } 563 } 564 } 565 566 kex_prop_free(my); 567 kex_prop_free(peer); 568 } 569 570 static u_char * 571 derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) 572 { 573 Buffer b; 574 const EVP_MD *evp_md = EVP_sha1(); 575 EVP_MD_CTX md; 576 char c = id; 577 int have; 578 int mdsz = EVP_MD_size(evp_md); 579 u_char *digest = xmalloc(roundup(need, mdsz)); 580 581 buffer_init(&b); 582 buffer_put_bignum2(&b, shared_secret); 583 584 /* K1 = HASH(K || H || "A" || session_id) */ 585 EVP_DigestInit(&md, evp_md); 586 if (!(datafellows & SSH_BUG_DERIVEKEY)) 587 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 588 EVP_DigestUpdate(&md, hash, mdsz); 589 EVP_DigestUpdate(&md, &c, 1); 590 EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); 591 EVP_DigestFinal(&md, digest, NULL); 592 593 /* 594 * expand key: 595 * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) 596 * Key = K1 || K2 || ... || Kn 597 */ 598 for (have = mdsz; need > have; have += mdsz) { 599 EVP_DigestInit(&md, evp_md); 600 if (!(datafellows & SSH_BUG_DERIVEKEY)) 601 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 602 EVP_DigestUpdate(&md, hash, mdsz); 603 EVP_DigestUpdate(&md, digest, have); 604 EVP_DigestFinal(&md, digest + have, NULL); 605 } 606 buffer_free(&b); 607 #ifdef DEBUG_KEX 608 fprintf(stderr, "key '%c'== ", c); 609 dump_digest("key", digest, need); 610 #endif 611 return digest; 612 } 613 614 Newkeys *current_keys[MODE_MAX]; 615 616 #define NKEYS 6 617 void 618 kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) 619 { 620 u_char *keys[NKEYS]; 621 int i, mode, ctos; 622 623 for (i = 0; i < NKEYS; i++) 624 keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); 625 626 debug2("kex_derive_keys"); 627 for (mode = 0; mode < MODE_MAX; mode++) { 628 current_keys[mode] = kex->newkeys[mode]; 629 kex->newkeys[mode] = NULL; 630 ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); 631 current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; 632 current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; 633 current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; 634 } 635 } 636 637 Newkeys * 638 kex_get_newkeys(int mode) 639 { 640 Newkeys *ret; 641 642 ret = current_keys[mode]; 643 current_keys[mode] = NULL; 644 return ret; 645 } 646 647 #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 648 void 649 dump_digest(char *msg, u_char *digest, int len) 650 { 651 int i; 652 653 fprintf(stderr, "%s\n", msg); 654 for (i = 0; i< len; i++) { 655 fprintf(stderr, "%02x", digest[i]); 656 if (i%32 == 31) 657 fprintf(stderr, "\n"); 658 else if (i%8 == 7) 659 fprintf(stderr, " "); 660 } 661 fprintf(stderr, "\n"); 662 } 663 #endif 664