summaryrefslogtreecommitdiff
path: root/kex.c
diff options
context:
space:
mode:
Diffstat (limited to 'kex.c')
-rw-r--r--kex.c105
1 files changed, 79 insertions, 26 deletions
diff --git a/kex.c b/kex.c
index 34808b5c3..49d701568 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.c,v 1.150 2019/01/21 12:08:13 djm Exp $ */ 1/* $OpenBSD: kex.c,v 1.155 2019/10/08 22:40:39 dtucker 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 *
@@ -111,7 +111,7 @@ static const struct kexalg kexalgs[] = {
111 { KEX_SNTRUP4591761X25519_SHA512, KEX_KEM_SNTRUP4591761X25519_SHA512, 0, 111 { KEX_SNTRUP4591761X25519_SHA512, KEX_KEM_SNTRUP4591761X25519_SHA512, 0,
112 SSH_DIGEST_SHA512 }, 112 SSH_DIGEST_SHA512 },
113#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ 113#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
114 { NULL, -1, -1, -1}, 114 { NULL, 0, -1, -1},
115}; 115};
116 116
117char * 117char *
@@ -213,8 +213,9 @@ kex_names_cat(const char *a, const char *b)
213/* 213/*
214 * Assemble a list of algorithms from a default list and a string from a 214 * Assemble a list of algorithms from a default list and a string from a
215 * configuration file. The user-provided string may begin with '+' to 215 * configuration file. The user-provided string may begin with '+' to
216 * indicate that it should be appended to the default or '-' that the 216 * indicate that it should be appended to the default, '-' that the
217 * specified names should be removed. 217 * specified names should be removed, or '^' that they should be placed
218 * at the head.
218 */ 219 */
219int 220int
220kex_assemble_names(char **listp, const char *def, const char *all) 221kex_assemble_names(char **listp, const char *def, const char *all)
@@ -223,7 +224,10 @@ kex_assemble_names(char **listp, const char *def, const char *all)
223 char *list = NULL, *ret = NULL, *matching = NULL, *opatterns = NULL; 224 char *list = NULL, *ret = NULL, *matching = NULL, *opatterns = NULL;
224 int r = SSH_ERR_INTERNAL_ERROR; 225 int r = SSH_ERR_INTERNAL_ERROR;
225 226
226 if (listp == NULL || *listp == NULL || **listp == '\0') { 227 if (listp == NULL || def == NULL || all == NULL)
228 return SSH_ERR_INVALID_ARGUMENT;
229
230 if (*listp == NULL || **listp == '\0') {
227 if ((*listp = strdup(def)) == NULL) 231 if ((*listp = strdup(def)) == NULL)
228 return SSH_ERR_ALLOC_FAIL; 232 return SSH_ERR_ALLOC_FAIL;
229 return 0; 233 return 0;
@@ -248,6 +252,14 @@ kex_assemble_names(char **listp, const char *def, const char *all)
248 free(list); 252 free(list);
249 /* filtering has already been done */ 253 /* filtering has already been done */
250 return 0; 254 return 0;
255 } else if (*list == '^') {
256 /* Place names at head of default list */
257 if ((tmp = kex_names_cat(list + 1, def)) == NULL) {
258 r = SSH_ERR_ALLOC_FAIL;
259 goto fail;
260 }
261 free(list);
262 list = tmp;
251 } else { 263 } else {
252 /* Explicit list, overrides default - just use "list" as is */ 264 /* Explicit list, overrides default - just use "list" as is */
253 } 265 }
@@ -345,18 +357,25 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
345 r = SSH_ERR_ALLOC_FAIL; 357 r = SSH_ERR_ALLOC_FAIL;
346 goto out; 358 goto out;
347 } 359 }
348 if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ 360 if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) { /* skip cookie */
361 error("%s: consume cookie: %s", __func__, ssh_err(r));
349 goto out; 362 goto out;
363 }
350 /* extract kex init proposal strings */ 364 /* extract kex init proposal strings */
351 for (i = 0; i < PROPOSAL_MAX; i++) { 365 for (i = 0; i < PROPOSAL_MAX; i++) {
352 if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 366 if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) {
367 error("%s: parse proposal %u: %s", __func__,
368 i, ssh_err(r));
353 goto out; 369 goto out;
370 }
354 debug2("%s: %s", proposal_names[i], proposal[i]); 371 debug2("%s: %s", proposal_names[i], proposal[i]);
355 } 372 }
356 /* first kex follows / reserved */ 373 /* first kex follows / reserved */
357 if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 374 if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */
358 (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ 375 (r = sshbuf_get_u32(b, &i)) != 0) { /* reserved */
376 error("%s: parse: %s", __func__, ssh_err(r));
359 goto out; 377 goto out;
378 }
360 if (first_kex_follows != NULL) 379 if (first_kex_follows != NULL)
361 *first_kex_follows = v; 380 *first_kex_follows = v;
362 debug2("first_kex_follows %d ", v); 381 debug2("first_kex_follows %d ", v);
@@ -409,6 +428,7 @@ kex_send_ext_info(struct ssh *ssh)
409 int r; 428 int r;
410 char *algs; 429 char *algs;
411 430
431 debug("Sending SSH2_MSG_EXT_INFO");
412 if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) 432 if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL)
413 return SSH_ERR_ALLOC_FAIL; 433 return SSH_ERR_ALLOC_FAIL;
414 /* XXX filter algs list by allowed pubkey/hostbased types */ 434 /* XXX filter algs list by allowed pubkey/hostbased types */
@@ -416,8 +436,10 @@ kex_send_ext_info(struct ssh *ssh)
416 (r = sshpkt_put_u32(ssh, 1)) != 0 || 436 (r = sshpkt_put_u32(ssh, 1)) != 0 ||
417 (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || 437 (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
418 (r = sshpkt_put_cstring(ssh, algs)) != 0 || 438 (r = sshpkt_put_cstring(ssh, algs)) != 0 ||
419 (r = sshpkt_send(ssh)) != 0) 439 (r = sshpkt_send(ssh)) != 0) {
440 error("%s: compose: %s", __func__, ssh_err(r));
420 goto out; 441 goto out;
442 }
421 /* success */ 443 /* success */
422 r = 0; 444 r = 0;
423 out: 445 out:
@@ -435,11 +457,11 @@ kex_send_newkeys(struct ssh *ssh)
435 (r = sshpkt_send(ssh)) != 0) 457 (r = sshpkt_send(ssh)) != 0)
436 return r; 458 return r;
437 debug("SSH2_MSG_NEWKEYS sent"); 459 debug("SSH2_MSG_NEWKEYS sent");
438 debug("expecting SSH2_MSG_NEWKEYS");
439 ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 460 ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
440 if (ssh->kex->ext_info_c) 461 if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0)
441 if ((r = kex_send_ext_info(ssh)) != 0) 462 if ((r = kex_send_ext_info(ssh)) != 0)
442 return r; 463 return r;
464 debug("expecting SSH2_MSG_NEWKEYS");
443 return 0; 465 return 0;
444} 466}
445 467
@@ -511,23 +533,32 @@ kex_send_kexinit(struct ssh *ssh)
511 struct kex *kex = ssh->kex; 533 struct kex *kex = ssh->kex;
512 int r; 534 int r;
513 535
514 if (kex == NULL) 536 if (kex == NULL) {
537 error("%s: no hex", __func__);
515 return SSH_ERR_INTERNAL_ERROR; 538 return SSH_ERR_INTERNAL_ERROR;
539 }
516 if (kex->flags & KEX_INIT_SENT) 540 if (kex->flags & KEX_INIT_SENT)
517 return 0; 541 return 0;
518 kex->done = 0; 542 kex->done = 0;
519 543
520 /* generate a random cookie */ 544 /* generate a random cookie */
521 if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) 545 if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) {
546 error("%s: bad kex length: %zu < %d", __func__,
547 sshbuf_len(kex->my), KEX_COOKIE_LEN);
522 return SSH_ERR_INVALID_FORMAT; 548 return SSH_ERR_INVALID_FORMAT;
523 if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) 549 }
550 if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) {
551 error("%s: buffer error", __func__);
524 return SSH_ERR_INTERNAL_ERROR; 552 return SSH_ERR_INTERNAL_ERROR;
553 }
525 arc4random_buf(cookie, KEX_COOKIE_LEN); 554 arc4random_buf(cookie, KEX_COOKIE_LEN);
526 555
527 if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || 556 if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
528 (r = sshpkt_putb(ssh, kex->my)) != 0 || 557 (r = sshpkt_putb(ssh, kex->my)) != 0 ||
529 (r = sshpkt_send(ssh)) != 0) 558 (r = sshpkt_send(ssh)) != 0) {
559 error("%s: compose reply: %s", __func__, ssh_err(r));
530 return r; 560 return r;
561 }
531 debug("SSH2_MSG_KEXINIT sent"); 562 debug("SSH2_MSG_KEXINIT sent");
532 kex->flags |= KEX_INIT_SENT; 563 kex->flags |= KEX_INIT_SENT;
533 return 0; 564 return 0;
@@ -544,21 +575,28 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
544 int r; 575 int r;
545 576
546 debug("SSH2_MSG_KEXINIT received"); 577 debug("SSH2_MSG_KEXINIT received");
547 if (kex == NULL) 578 if (kex == NULL) {
548 return SSH_ERR_INVALID_ARGUMENT; 579 error("%s: no hex", __func__);
549 580 return SSH_ERR_INTERNAL_ERROR;
581 }
550 ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); 582 ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
551 ptr = sshpkt_ptr(ssh, &dlen); 583 ptr = sshpkt_ptr(ssh, &dlen);
552 if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) 584 if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
553 return r; 585 return r;
554 586
555 /* discard packet */ 587 /* discard packet */
556 for (i = 0; i < KEX_COOKIE_LEN; i++) 588 for (i = 0; i < KEX_COOKIE_LEN; i++) {
557 if ((r = sshpkt_get_u8(ssh, NULL)) != 0) 589 if ((r = sshpkt_get_u8(ssh, NULL)) != 0) {
590 error("%s: discard cookie: %s", __func__, ssh_err(r));
558 return r; 591 return r;
559 for (i = 0; i < PROPOSAL_MAX; i++) 592 }
560 if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) 593 }
594 for (i = 0; i < PROPOSAL_MAX; i++) {
595 if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
596 error("%s: discard proposal: %s", __func__, ssh_err(r));
561 return r; 597 return r;
598 }
599 }
562 /* 600 /*
563 * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported 601 * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
564 * KEX method has the server move first, but a server might be using 602 * KEX method has the server move first, but a server might be using
@@ -583,6 +621,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
583 if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) 621 if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
584 return (kex->kex[kex->kex_type])(ssh); 622 return (kex->kex[kex->kex_type])(ssh);
585 623
624 error("%s: unknown kex type %u", __func__, kex->kex_type);
586 return SSH_ERR_INTERNAL_ERROR; 625 return SSH_ERR_INTERNAL_ERROR;
587} 626}
588 627
@@ -718,6 +757,7 @@ choose_enc(struct sshenc *enc, char *client, char *server)
718 if (name == NULL) 757 if (name == NULL)
719 return SSH_ERR_NO_CIPHER_ALG_MATCH; 758 return SSH_ERR_NO_CIPHER_ALG_MATCH;
720 if ((enc->cipher = cipher_by_name(name)) == NULL) { 759 if ((enc->cipher = cipher_by_name(name)) == NULL) {
760 error("%s: unsupported cipher %s", __func__, name);
721 free(name); 761 free(name);
722 return SSH_ERR_INTERNAL_ERROR; 762 return SSH_ERR_INTERNAL_ERROR;
723 } 763 }
@@ -739,6 +779,7 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
739 if (name == NULL) 779 if (name == NULL)
740 return SSH_ERR_NO_MAC_ALG_MATCH; 780 return SSH_ERR_NO_MAC_ALG_MATCH;
741 if (mac_setup(mac, name) < 0) { 781 if (mac_setup(mac, name) < 0) {
782 error("%s: unsupported MAC %s", __func__, name);
742 free(name); 783 free(name);
743 return SSH_ERR_INTERNAL_ERROR; 784 return SSH_ERR_INTERNAL_ERROR;
744 } 785 }
@@ -762,6 +803,7 @@ choose_comp(struct sshcomp *comp, char *client, char *server)
762 } else if (strcmp(name, "none") == 0) { 803 } else if (strcmp(name, "none") == 0) {
763 comp->type = COMP_NONE; 804 comp->type = COMP_NONE;
764 } else { 805 } else {
806 error("%s: unsupported compression scheme %s", __func__, name);
765 free(name); 807 free(name);
766 return SSH_ERR_INTERNAL_ERROR; 808 return SSH_ERR_INTERNAL_ERROR;
767 } 809 }
@@ -779,8 +821,10 @@ choose_kex(struct kex *k, char *client, char *server)
779 debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); 821 debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
780 if (k->name == NULL) 822 if (k->name == NULL)
781 return SSH_ERR_NO_KEX_ALG_MATCH; 823 return SSH_ERR_NO_KEX_ALG_MATCH;
782 if ((kexalg = kex_alg_by_name(k->name)) == NULL) 824 if ((kexalg = kex_alg_by_name(k->name)) == NULL) {
825 error("%s: unsupported KEX method %s", __func__, k->name);
783 return SSH_ERR_INTERNAL_ERROR; 826 return SSH_ERR_INTERNAL_ERROR;
827 }
784 k->kex_type = kexalg->type; 828 k->kex_type = kexalg->type;
785 k->hash_alg = kexalg->hash_alg; 829 k->hash_alg = kexalg->hash_alg;
786 k->ec_nid = kexalg->ec_nid; 830 k->ec_nid = kexalg->ec_nid;
@@ -797,8 +841,11 @@ choose_hostkeyalg(struct kex *k, char *client, char *server)
797 if (k->hostkey_alg == NULL) 841 if (k->hostkey_alg == NULL)
798 return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 842 return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
799 k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); 843 k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
800 if (k->hostkey_type == KEY_UNSPEC) 844 if (k->hostkey_type == KEY_UNSPEC) {
845 error("%s: unsupported hostkey algorithm %s", __func__,
846 k->hostkey_alg);
801 return SSH_ERR_INTERNAL_ERROR; 847 return SSH_ERR_INTERNAL_ERROR;
848 }
802 k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); 849 k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
803 return 0; 850 return 0;
804} 851}
@@ -967,6 +1014,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
967 kex->session_id_len) != 0 || 1014 kex->session_id_len) != 0 ||
968 ssh_digest_final(hashctx, digest, mdsz) != 0) { 1015 ssh_digest_final(hashctx, digest, mdsz) != 0) {
969 r = SSH_ERR_LIBCRYPTO_ERROR; 1016 r = SSH_ERR_LIBCRYPTO_ERROR;
1017 error("%s: KEX hash failed", __func__);
970 goto out; 1018 goto out;
971 } 1019 }
972 ssh_digest_free(hashctx); 1020 ssh_digest_free(hashctx);
@@ -983,6 +1031,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
983 ssh_digest_update(hashctx, hash, hashlen) != 0 || 1031 ssh_digest_update(hashctx, hash, hashlen) != 0 ||
984 ssh_digest_update(hashctx, digest, have) != 0 || 1032 ssh_digest_update(hashctx, digest, have) != 0 ||
985 ssh_digest_final(hashctx, digest + have, mdsz) != 0) { 1033 ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
1034 error("%s: KDF failed", __func__);
986 r = SSH_ERR_LIBCRYPTO_ERROR; 1035 r = SSH_ERR_LIBCRYPTO_ERROR;
987 goto out; 1036 goto out;
988 } 1037 }
@@ -1046,8 +1095,10 @@ kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp)
1046 *pubp = NULL; 1095 *pubp = NULL;
1047 *prvp = NULL; 1096 *prvp = NULL;
1048 if (kex->load_host_public_key == NULL || 1097 if (kex->load_host_public_key == NULL ||
1049 kex->load_host_private_key == NULL) 1098 kex->load_host_private_key == NULL) {
1099 error("%s: missing hostkey loader", __func__);
1050 return SSH_ERR_INVALID_ARGUMENT; 1100 return SSH_ERR_INVALID_ARGUMENT;
1101 }
1051 *pubp = kex->load_host_public_key(kex->hostkey_type, 1102 *pubp = kex->load_host_public_key(kex->hostkey_type,
1052 kex->hostkey_nid, ssh); 1103 kex->hostkey_nid, ssh);
1053 *prvp = kex->load_host_private_key(kex->hostkey_type, 1104 *prvp = kex->load_host_private_key(kex->hostkey_type,
@@ -1062,8 +1113,10 @@ kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key)
1062{ 1113{
1063 struct kex *kex = ssh->kex; 1114 struct kex *kex = ssh->kex;
1064 1115
1065 if (kex->verify_host_key == NULL) 1116 if (kex->verify_host_key == NULL) {
1117 error("%s: missing hostkey verifier", __func__);
1066 return SSH_ERR_INVALID_ARGUMENT; 1118 return SSH_ERR_INVALID_ARGUMENT;
1119 }
1067 if (server_host_key->type != kex->hostkey_type || 1120 if (server_host_key->type != kex->hostkey_type ||
1068 (kex->hostkey_type == KEY_ECDSA && 1121 (kex->hostkey_type == KEY_ECDSA &&
1069 server_host_key->ecdsa_nid != kex->hostkey_nid)) 1122 server_host_key->ecdsa_nid != kex->hostkey_nid))