diff options
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 151 |
1 files changed, 91 insertions, 60 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.c,v 1.91 2013/05/17 00:13:13 djm Exp $ */ | 1 | /* $OpenBSD: kex.c,v 1.97 2014/01/25 20:35:37 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -49,6 +49,7 @@ | |||
49 | #include "dispatch.h" | 49 | #include "dispatch.h" |
50 | #include "monitor.h" | 50 | #include "monitor.h" |
51 | #include "roaming.h" | 51 | #include "roaming.h" |
52 | #include "digest.h" | ||
52 | 53 | ||
53 | #ifdef GSSAPI | 54 | #ifdef GSSAPI |
54 | #include "ssh-gss.h" | 55 | #include "ssh-gss.h" |
@@ -70,33 +71,42 @@ struct kexalg { | |||
70 | char *name; | 71 | char *name; |
71 | int type; | 72 | int type; |
72 | int ec_nid; | 73 | int ec_nid; |
73 | const EVP_MD *(*mdfunc)(void); | 74 | int hash_alg; |
74 | }; | 75 | }; |
75 | static const struct kexalg kexalgs[] = { | 76 | static const struct kexalg kexalgs[] = { |
76 | { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 }, | 77 | { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, |
77 | { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 }, | 78 | { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, |
78 | { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 }, | 79 | { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, |
79 | #ifdef HAVE_EVP_SHA256 | 80 | #ifdef HAVE_EVP_SHA256 |
80 | { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 }, | 81 | { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, |
81 | #endif | 82 | #endif |
82 | #ifdef OPENSSL_HAS_ECC | 83 | #ifdef OPENSSL_HAS_ECC |
83 | { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 }, | 84 | { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, |
84 | { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 }, | 85 | NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, |
85 | { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 }, | 86 | { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, |
87 | SSH_DIGEST_SHA384 }, | ||
88 | # ifdef OPENSSL_HAS_NISTP521 | ||
89 | { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, | ||
90 | SSH_DIGEST_SHA512 }, | ||
91 | # endif | ||
92 | #endif | ||
93 | { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, | ||
94 | #ifdef HAVE_EVP_SHA256 | ||
95 | { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, | ||
86 | #endif | 96 | #endif |
87 | { NULL, -1, -1, NULL}, | 97 | { NULL, -1, -1, -1}, |
88 | }; | 98 | }; |
89 | static const struct kexalg kexalg_prefixes[] = { | 99 | static const struct kexalg kexalg_prefixes[] = { |
90 | #ifdef GSSAPI | 100 | #ifdef GSSAPI |
91 | { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, EVP_sha1 }, | 101 | { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, |
92 | { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, EVP_sha1 }, | 102 | { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, |
93 | { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, EVP_sha1 }, | 103 | { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, |
94 | #endif | 104 | #endif |
95 | { NULL, -1, -1, NULL }, | 105 | { NULL, -1, -1, -1 }, |
96 | }; | 106 | }; |
97 | 107 | ||
98 | char * | 108 | char * |
99 | kex_alg_list(void) | 109 | kex_alg_list(char sep) |
100 | { | 110 | { |
101 | char *ret = NULL; | 111 | char *ret = NULL; |
102 | size_t nlen, rlen = 0; | 112 | size_t nlen, rlen = 0; |
@@ -104,7 +114,7 @@ kex_alg_list(void) | |||
104 | 114 | ||
105 | for (k = kexalgs; k->name != NULL; k++) { | 115 | for (k = kexalgs; k->name != NULL; k++) { |
106 | if (ret != NULL) | 116 | if (ret != NULL) |
107 | ret[rlen++] = '\n'; | 117 | ret[rlen++] = sep; |
108 | nlen = strlen(k->name); | 118 | nlen = strlen(k->name); |
109 | ret = xrealloc(ret, 1, rlen + nlen + 2); | 119 | ret = xrealloc(ret, 1, rlen + nlen + 2); |
110 | memcpy(ret + rlen, k->name, nlen + 1); | 120 | memcpy(ret + rlen, k->name, nlen + 1); |
@@ -417,7 +427,7 @@ choose_kex(Kex *k, char *client, char *server) | |||
417 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) | 427 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
418 | fatal("unsupported kex alg %s", k->name); | 428 | fatal("unsupported kex alg %s", k->name); |
419 | k->kex_type = kexalg->type; | 429 | k->kex_type = kexalg->type; |
420 | k->evp_md = kexalg->mdfunc(); | 430 | k->hash_alg = kexalg->hash_alg; |
421 | k->ec_nid = kexalg->ec_nid; | 431 | k->ec_nid = kexalg->ec_nid; |
422 | } | 432 | } |
423 | 433 | ||
@@ -464,7 +474,7 @@ kex_choose_conf(Kex *kex) | |||
464 | char **my, **peer; | 474 | char **my, **peer; |
465 | char **cprop, **sprop; | 475 | char **cprop, **sprop; |
466 | int nenc, nmac, ncomp; | 476 | int nenc, nmac, ncomp; |
467 | u_int mode, ctos, need, authlen; | 477 | u_int mode, ctos, need, dh_need, authlen; |
468 | int first_kex_follows, type; | 478 | int first_kex_follows, type; |
469 | 479 | ||
470 | my = kex_buf2prop(&kex->my, NULL); | 480 | my = kex_buf2prop(&kex->my, NULL); |
@@ -512,20 +522,21 @@ kex_choose_conf(Kex *kex) | |||
512 | choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); | 522 | choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); |
513 | choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], | 523 | choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], |
514 | sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); | 524 | sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); |
515 | need = 0; | 525 | need = dh_need = 0; |
516 | for (mode = 0; mode < MODE_MAX; mode++) { | 526 | for (mode = 0; mode < MODE_MAX; mode++) { |
517 | newkeys = kex->newkeys[mode]; | 527 | newkeys = kex->newkeys[mode]; |
518 | if (need < newkeys->enc.key_len) | 528 | need = MAX(need, newkeys->enc.key_len); |
519 | need = newkeys->enc.key_len; | 529 | need = MAX(need, newkeys->enc.block_size); |
520 | if (need < newkeys->enc.block_size) | 530 | need = MAX(need, newkeys->enc.iv_len); |
521 | need = newkeys->enc.block_size; | 531 | need = MAX(need, newkeys->mac.key_len); |
522 | if (need < newkeys->enc.iv_len) | 532 | dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); |
523 | need = newkeys->enc.iv_len; | 533 | dh_need = MAX(dh_need, newkeys->enc.block_size); |
524 | if (need < newkeys->mac.key_len) | 534 | dh_need = MAX(dh_need, newkeys->enc.iv_len); |
525 | need = newkeys->mac.key_len; | 535 | dh_need = MAX(dh_need, newkeys->mac.key_len); |
526 | } | 536 | } |
527 | /* XXX need runden? */ | 537 | /* XXX need runden? */ |
528 | kex->we_need = need; | 538 | kex->we_need = need; |
539 | kex->dh_need = dh_need; | ||
529 | 540 | ||
530 | /* ignore the next message if the proposals do not match */ | 541 | /* ignore the next message if the proposals do not match */ |
531 | if (first_kex_follows && !proposals_match(my, peer) && | 542 | if (first_kex_follows && !proposals_match(my, peer) && |
@@ -540,30 +551,34 @@ kex_choose_conf(Kex *kex) | |||
540 | 551 | ||
541 | static u_char * | 552 | static u_char * |
542 | derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, | 553 | derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, |
543 | BIGNUM *shared_secret) | 554 | const u_char *shared_secret, u_int slen) |
544 | { | 555 | { |
545 | Buffer b; | 556 | Buffer b; |
546 | EVP_MD_CTX md; | 557 | struct ssh_digest_ctx *hashctx; |
547 | char c = id; | 558 | char c = id; |
548 | u_int have; | 559 | u_int have; |
549 | int mdsz; | 560 | size_t mdsz; |
550 | u_char *digest; | 561 | u_char *digest; |
551 | 562 | ||
552 | if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) | 563 | if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) |
553 | fatal("bad kex md size %d", mdsz); | 564 | fatal("bad kex md size %zu", mdsz); |
554 | digest = xmalloc(roundup(need, mdsz)); | 565 | digest = xmalloc(roundup(need, mdsz)); |
555 | 566 | ||
556 | buffer_init(&b); | 567 | buffer_init(&b); |
557 | buffer_put_bignum2(&b, shared_secret); | 568 | buffer_append(&b, shared_secret, slen); |
558 | 569 | ||
559 | /* K1 = HASH(K || H || "A" || session_id) */ | 570 | /* K1 = HASH(K || H || "A" || session_id) */ |
560 | EVP_DigestInit(&md, kex->evp_md); | 571 | if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) |
561 | if (!(datafellows & SSH_BUG_DERIVEKEY)) | 572 | fatal("%s: ssh_digest_start failed", __func__); |
562 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); | 573 | if (ssh_digest_update_buffer(hashctx, &b) != 0 || |
563 | EVP_DigestUpdate(&md, hash, hashlen); | 574 | ssh_digest_update(hashctx, hash, hashlen) != 0 || |
564 | EVP_DigestUpdate(&md, &c, 1); | 575 | ssh_digest_update(hashctx, &c, 1) != 0 || |
565 | EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); | 576 | ssh_digest_update(hashctx, kex->session_id, |
566 | EVP_DigestFinal(&md, digest, NULL); | 577 | kex->session_id_len) != 0) |
578 | fatal("%s: ssh_digest_update failed", __func__); | ||
579 | if (ssh_digest_final(hashctx, digest, mdsz) != 0) | ||
580 | fatal("%s: ssh_digest_final failed", __func__); | ||
581 | ssh_digest_free(hashctx); | ||
567 | 582 | ||
568 | /* | 583 | /* |
569 | * expand key: | 584 | * expand key: |
@@ -571,12 +586,15 @@ derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, | |||
571 | * Key = K1 || K2 || ... || Kn | 586 | * Key = K1 || K2 || ... || Kn |
572 | */ | 587 | */ |
573 | for (have = mdsz; need > have; have += mdsz) { | 588 | for (have = mdsz; need > have; have += mdsz) { |
574 | EVP_DigestInit(&md, kex->evp_md); | 589 | if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) |
575 | if (!(datafellows & SSH_BUG_DERIVEKEY)) | 590 | fatal("%s: ssh_digest_start failed", __func__); |
576 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); | 591 | if (ssh_digest_update_buffer(hashctx, &b) != 0 || |
577 | EVP_DigestUpdate(&md, hash, hashlen); | 592 | ssh_digest_update(hashctx, hash, hashlen) != 0 || |
578 | EVP_DigestUpdate(&md, digest, have); | 593 | ssh_digest_update(hashctx, digest, have) != 0) |
579 | EVP_DigestFinal(&md, digest + have, NULL); | 594 | fatal("%s: ssh_digest_update failed", __func__); |
595 | if (ssh_digest_final(hashctx, digest + have, mdsz) != 0) | ||
596 | fatal("%s: ssh_digest_final failed", __func__); | ||
597 | ssh_digest_free(hashctx); | ||
580 | } | 598 | } |
581 | buffer_free(&b); | 599 | buffer_free(&b); |
582 | #ifdef DEBUG_KEX | 600 | #ifdef DEBUG_KEX |
@@ -590,14 +608,15 @@ Newkeys *current_keys[MODE_MAX]; | |||
590 | 608 | ||
591 | #define NKEYS 6 | 609 | #define NKEYS 6 |
592 | void | 610 | void |
593 | kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) | 611 | kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, |
612 | const u_char *shared_secret, u_int slen) | ||
594 | { | 613 | { |
595 | u_char *keys[NKEYS]; | 614 | u_char *keys[NKEYS]; |
596 | u_int i, mode, ctos; | 615 | u_int i, mode, ctos; |
597 | 616 | ||
598 | for (i = 0; i < NKEYS; i++) { | 617 | for (i = 0; i < NKEYS; i++) { |
599 | keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, | 618 | keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, |
600 | shared_secret); | 619 | shared_secret, slen); |
601 | } | 620 | } |
602 | 621 | ||
603 | debug2("kex_derive_keys"); | 622 | debug2("kex_derive_keys"); |
@@ -612,6 +631,18 @@ kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) | |||
612 | } | 631 | } |
613 | } | 632 | } |
614 | 633 | ||
634 | void | ||
635 | kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret) | ||
636 | { | ||
637 | Buffer shared_secret; | ||
638 | |||
639 | buffer_init(&shared_secret); | ||
640 | buffer_put_bignum2(&shared_secret, secret); | ||
641 | kex_derive_keys(kex, hash, hashlen, | ||
642 | buffer_ptr(&shared_secret), buffer_len(&shared_secret)); | ||
643 | buffer_free(&shared_secret); | ||
644 | } | ||
645 | |||
615 | Newkeys * | 646 | Newkeys * |
616 | kex_get_newkeys(int mode) | 647 | kex_get_newkeys(int mode) |
617 | { | 648 | { |
@@ -626,33 +657,33 @@ void | |||
626 | derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, | 657 | derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, |
627 | u_int8_t cookie[8], u_int8_t id[16]) | 658 | u_int8_t cookie[8], u_int8_t id[16]) |
628 | { | 659 | { |
629 | const EVP_MD *evp_md = EVP_md5(); | 660 | u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; |
630 | EVP_MD_CTX md; | ||
631 | u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; | ||
632 | int len; | 661 | int len; |
662 | struct ssh_digest_ctx *hashctx; | ||
633 | 663 | ||
634 | EVP_DigestInit(&md, evp_md); | 664 | if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) |
665 | fatal("%s: ssh_digest_start", __func__); | ||
635 | 666 | ||
636 | len = BN_num_bytes(host_modulus); | 667 | len = BN_num_bytes(host_modulus); |
637 | if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) | 668 | if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) |
638 | fatal("%s: bad host modulus (len %d)", __func__, len); | 669 | fatal("%s: bad host modulus (len %d)", __func__, len); |
639 | BN_bn2bin(host_modulus, nbuf); | 670 | BN_bn2bin(host_modulus, nbuf); |
640 | EVP_DigestUpdate(&md, nbuf, len); | 671 | if (ssh_digest_update(hashctx, nbuf, len) != 0) |
672 | fatal("%s: ssh_digest_update failed", __func__); | ||
641 | 673 | ||
642 | len = BN_num_bytes(server_modulus); | 674 | len = BN_num_bytes(server_modulus); |
643 | if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) | 675 | if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) |
644 | fatal("%s: bad server modulus (len %d)", __func__, len); | 676 | fatal("%s: bad server modulus (len %d)", __func__, len); |
645 | BN_bn2bin(server_modulus, nbuf); | 677 | BN_bn2bin(server_modulus, nbuf); |
646 | EVP_DigestUpdate(&md, nbuf, len); | 678 | if (ssh_digest_update(hashctx, nbuf, len) != 0 || |
647 | 679 | ssh_digest_update(hashctx, cookie, 8) != 0) | |
648 | EVP_DigestUpdate(&md, cookie, 8); | 680 | fatal("%s: ssh_digest_update failed", __func__); |
649 | 681 | if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) | |
650 | EVP_DigestFinal(&md, obuf, NULL); | 682 | fatal("%s: ssh_digest_final failed", __func__); |
651 | memcpy(id, obuf, 16); | 683 | memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); |
652 | 684 | ||
653 | memset(nbuf, 0, sizeof(nbuf)); | 685 | memset(nbuf, 0, sizeof(nbuf)); |
654 | memset(obuf, 0, sizeof(obuf)); | 686 | memset(obuf, 0, sizeof(obuf)); |
655 | memset(&md, 0, sizeof(md)); | ||
656 | } | 687 | } |
657 | 688 | ||
658 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) | 689 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) |