|
Lines 334-351
kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
Link Here
|
| 334 |
r = SSH_ERR_ALLOC_FAIL; |
334 |
r = SSH_ERR_ALLOC_FAIL; |
| 335 |
goto out; |
335 |
goto out; |
| 336 |
} |
336 |
} |
| 337 |
if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ |
337 |
if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) { /* skip cookie */ |
|
|
338 |
error("%s: consume cookie: %s", __func__, ssh_err(r)); |
| 338 |
goto out; |
339 |
goto out; |
|
|
340 |
} |
| 339 |
/* extract kex init proposal strings */ |
341 |
/* extract kex init proposal strings */ |
| 340 |
for (i = 0; i < PROPOSAL_MAX; i++) { |
342 |
for (i = 0; i < PROPOSAL_MAX; i++) { |
| 341 |
if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) |
343 |
if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) { |
|
|
344 |
error("%s: parse proposal %u: %s", __func__, |
| 345 |
i, ssh_err(r)); |
| 342 |
goto out; |
346 |
goto out; |
|
|
347 |
} |
| 343 |
debug2("%s: %s", proposal_names[i], proposal[i]); |
348 |
debug2("%s: %s", proposal_names[i], proposal[i]); |
| 344 |
} |
349 |
} |
| 345 |
/* first kex follows / reserved */ |
350 |
/* first kex follows / reserved */ |
| 346 |
if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ |
351 |
if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ |
| 347 |
(r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ |
352 |
(r = sshbuf_get_u32(b, &i)) != 0) { /* reserved */ |
|
|
353 |
error("%s: parse: %s", __func__, ssh_err(r)); |
| 348 |
goto out; |
354 |
goto out; |
|
|
355 |
} |
| 349 |
if (first_kex_follows != NULL) |
356 |
if (first_kex_follows != NULL) |
| 350 |
*first_kex_follows = v; |
357 |
*first_kex_follows = v; |
| 351 |
debug2("first_kex_follows %d ", v); |
358 |
debug2("first_kex_follows %d ", v); |
|
Lines 398-403
kex_send_ext_info(struct ssh *ssh)
Link Here
|
| 398 |
int r; |
405 |
int r; |
| 399 |
char *algs; |
406 |
char *algs; |
| 400 |
|
407 |
|
|
|
408 |
debug("Sending SSH2_MSG_EXT_INFO"); |
| 401 |
if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) |
409 |
if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) |
| 402 |
return SSH_ERR_ALLOC_FAIL; |
410 |
return SSH_ERR_ALLOC_FAIL; |
| 403 |
/* XXX filter algs list by allowed pubkey/hostbased types */ |
411 |
/* XXX filter algs list by allowed pubkey/hostbased types */ |
|
Lines 405-412
kex_send_ext_info(struct ssh *ssh)
Link Here
|
| 405 |
(r = sshpkt_put_u32(ssh, 1)) != 0 || |
413 |
(r = sshpkt_put_u32(ssh, 1)) != 0 || |
| 406 |
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || |
414 |
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || |
| 407 |
(r = sshpkt_put_cstring(ssh, algs)) != 0 || |
415 |
(r = sshpkt_put_cstring(ssh, algs)) != 0 || |
| 408 |
(r = sshpkt_send(ssh)) != 0) |
416 |
(r = sshpkt_send(ssh)) != 0) { |
|
|
417 |
error("%s: compose: %s", __func__, ssh_err(r)); |
| 409 |
goto out; |
418 |
goto out; |
|
|
419 |
} |
| 410 |
/* success */ |
420 |
/* success */ |
| 411 |
r = 0; |
421 |
r = 0; |
| 412 |
out: |
422 |
out: |
|
Lines 424-434
kex_send_newkeys(struct ssh *ssh)
Link Here
|
| 424 |
(r = sshpkt_send(ssh)) != 0) |
434 |
(r = sshpkt_send(ssh)) != 0) |
| 425 |
return r; |
435 |
return r; |
| 426 |
debug("SSH2_MSG_NEWKEYS sent"); |
436 |
debug("SSH2_MSG_NEWKEYS sent"); |
| 427 |
debug("expecting SSH2_MSG_NEWKEYS"); |
|
|
| 428 |
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); |
437 |
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); |
| 429 |
if (ssh->kex->ext_info_c) |
438 |
if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0) |
| 430 |
if ((r = kex_send_ext_info(ssh)) != 0) |
439 |
if ((r = kex_send_ext_info(ssh)) != 0) |
| 431 |
return r; |
440 |
return r; |
|
|
441 |
debug("expecting SSH2_MSG_NEWKEYS"); |
| 432 |
return 0; |
442 |
return 0; |
| 433 |
} |
443 |
} |
| 434 |
|
444 |
|
|
Lines 500-522
kex_send_kexinit(struct ssh *ssh)
Link Here
|
| 500 |
struct kex *kex = ssh->kex; |
510 |
struct kex *kex = ssh->kex; |
| 501 |
int r; |
511 |
int r; |
| 502 |
|
512 |
|
| 503 |
if (kex == NULL) |
513 |
if (kex == NULL) { |
|
|
514 |
error("%s: no hex", __func__); |
| 504 |
return SSH_ERR_INTERNAL_ERROR; |
515 |
return SSH_ERR_INTERNAL_ERROR; |
|
|
516 |
} |
| 505 |
if (kex->flags & KEX_INIT_SENT) |
517 |
if (kex->flags & KEX_INIT_SENT) |
| 506 |
return 0; |
518 |
return 0; |
| 507 |
kex->done = 0; |
519 |
kex->done = 0; |
| 508 |
|
520 |
|
| 509 |
/* generate a random cookie */ |
521 |
/* generate a random cookie */ |
| 510 |
if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) |
522 |
if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) { |
|
|
523 |
error("%s: bad kex length: %zu < %d", __func__, |
| 524 |
sshbuf_len(kex->my), KEX_COOKIE_LEN); |
| 511 |
return SSH_ERR_INVALID_FORMAT; |
525 |
return SSH_ERR_INVALID_FORMAT; |
| 512 |
if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) |
526 |
} |
|
|
527 |
if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) { |
| 528 |
error("%s: buffer error", __func__); |
| 513 |
return SSH_ERR_INTERNAL_ERROR; |
529 |
return SSH_ERR_INTERNAL_ERROR; |
|
|
530 |
} |
| 514 |
arc4random_buf(cookie, KEX_COOKIE_LEN); |
531 |
arc4random_buf(cookie, KEX_COOKIE_LEN); |
| 515 |
|
532 |
|
| 516 |
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || |
533 |
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || |
| 517 |
(r = sshpkt_putb(ssh, kex->my)) != 0 || |
534 |
(r = sshpkt_putb(ssh, kex->my)) != 0 || |
| 518 |
(r = sshpkt_send(ssh)) != 0) |
535 |
(r = sshpkt_send(ssh)) != 0) { |
|
|
536 |
error("%s: compose reply: %s", __func__, ssh_err(r)); |
| 519 |
return r; |
537 |
return r; |
|
|
538 |
} |
| 520 |
debug("SSH2_MSG_KEXINIT sent"); |
539 |
debug("SSH2_MSG_KEXINIT sent"); |
| 521 |
kex->flags |= KEX_INIT_SENT; |
540 |
kex->flags |= KEX_INIT_SENT; |
| 522 |
return 0; |
541 |
return 0; |
|
Lines 533-553
kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
Link Here
|
| 533 |
int r; |
552 |
int r; |
| 534 |
|
553 |
|
| 535 |
debug("SSH2_MSG_KEXINIT received"); |
554 |
debug("SSH2_MSG_KEXINIT received"); |
| 536 |
if (kex == NULL) |
555 |
if (kex == NULL) { |
| 537 |
return SSH_ERR_INVALID_ARGUMENT; |
556 |
error("%s: no hex", __func__); |
| 538 |
|
557 |
return SSH_ERR_INTERNAL_ERROR; |
|
|
558 |
} |
| 539 |
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); |
559 |
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); |
| 540 |
ptr = sshpkt_ptr(ssh, &dlen); |
560 |
ptr = sshpkt_ptr(ssh, &dlen); |
| 541 |
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) |
561 |
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) |
| 542 |
return r; |
562 |
return r; |
| 543 |
|
563 |
|
| 544 |
/* discard packet */ |
564 |
/* discard packet */ |
| 545 |
for (i = 0; i < KEX_COOKIE_LEN; i++) |
565 |
for (i = 0; i < KEX_COOKIE_LEN; i++) { |
| 546 |
if ((r = sshpkt_get_u8(ssh, NULL)) != 0) |
566 |
if ((r = sshpkt_get_u8(ssh, NULL)) != 0) { |
|
|
567 |
error("%s: discard cookie: %s", __func__, ssh_err(r)); |
| 547 |
return r; |
568 |
return r; |
| 548 |
for (i = 0; i < PROPOSAL_MAX; i++) |
569 |
} |
| 549 |
if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) |
570 |
} |
|
|
571 |
for (i = 0; i < PROPOSAL_MAX; i++) { |
| 572 |
if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) { |
| 573 |
error("%s: discard proposal: %s", __func__, ssh_err(r)); |
| 550 |
return r; |
574 |
return r; |
|
|
575 |
} |
| 576 |
} |
| 551 |
/* |
577 |
/* |
| 552 |
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported |
578 |
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported |
| 553 |
* KEX method has the server move first, but a server might be using |
579 |
* KEX method has the server move first, but a server might be using |
|
Lines 572-577
kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
Link Here
|
| 572 |
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) |
598 |
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) |
| 573 |
return (kex->kex[kex->kex_type])(ssh); |
599 |
return (kex->kex[kex->kex_type])(ssh); |
| 574 |
|
600 |
|
|
|
601 |
error("%s: unknown kex type %u", __func__, kex->kex_type); |
| 575 |
return SSH_ERR_INTERNAL_ERROR; |
602 |
return SSH_ERR_INTERNAL_ERROR; |
| 576 |
} |
603 |
} |
| 577 |
|
604 |
|
|
Lines 705-710
choose_enc(struct sshenc *enc, char *client, char *server)
Link Here
|
| 705 |
if (name == NULL) |
732 |
if (name == NULL) |
| 706 |
return SSH_ERR_NO_CIPHER_ALG_MATCH; |
733 |
return SSH_ERR_NO_CIPHER_ALG_MATCH; |
| 707 |
if ((enc->cipher = cipher_by_name(name)) == NULL) { |
734 |
if ((enc->cipher = cipher_by_name(name)) == NULL) { |
|
|
735 |
error("%s: unsupported cipher %s", __func__, name); |
| 708 |
free(name); |
736 |
free(name); |
| 709 |
return SSH_ERR_INTERNAL_ERROR; |
737 |
return SSH_ERR_INTERNAL_ERROR; |
| 710 |
} |
738 |
} |
|
Lines 726-731
choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
Link Here
|
| 726 |
if (name == NULL) |
754 |
if (name == NULL) |
| 727 |
return SSH_ERR_NO_MAC_ALG_MATCH; |
755 |
return SSH_ERR_NO_MAC_ALG_MATCH; |
| 728 |
if (mac_setup(mac, name) < 0) { |
756 |
if (mac_setup(mac, name) < 0) { |
|
|
757 |
error("%s: unsupported MAC %s", __func__, name); |
| 729 |
free(name); |
758 |
free(name); |
| 730 |
return SSH_ERR_INTERNAL_ERROR; |
759 |
return SSH_ERR_INTERNAL_ERROR; |
| 731 |
} |
760 |
} |
|
Lines 749-754
choose_comp(struct sshcomp *comp, char *client, char *server)
Link Here
|
| 749 |
} else if (strcmp(name, "none") == 0) { |
778 |
} else if (strcmp(name, "none") == 0) { |
| 750 |
comp->type = COMP_NONE; |
779 |
comp->type = COMP_NONE; |
| 751 |
} else { |
780 |
} else { |
|
|
781 |
error("%s: unsupported compression scheme %s", __func__, name); |
| 752 |
free(name); |
782 |
free(name); |
| 753 |
return SSH_ERR_INTERNAL_ERROR; |
783 |
return SSH_ERR_INTERNAL_ERROR; |
| 754 |
} |
784 |
} |
|
Lines 766-773
choose_kex(struct kex *k, char *client, char *server)
Link Here
|
| 766 |
debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); |
796 |
debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); |
| 767 |
if (k->name == NULL) |
797 |
if (k->name == NULL) |
| 768 |
return SSH_ERR_NO_KEX_ALG_MATCH; |
798 |
return SSH_ERR_NO_KEX_ALG_MATCH; |
| 769 |
if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
799 |
if ((kexalg = kex_alg_by_name(k->name)) == NULL) { |
|
|
800 |
error("%s: unsupported KEX method %s", __func__, k->name); |
| 770 |
return SSH_ERR_INTERNAL_ERROR; |
801 |
return SSH_ERR_INTERNAL_ERROR; |
|
|
802 |
} |
| 771 |
k->kex_type = kexalg->type; |
803 |
k->kex_type = kexalg->type; |
| 772 |
k->hash_alg = kexalg->hash_alg; |
804 |
k->hash_alg = kexalg->hash_alg; |
| 773 |
k->ec_nid = kexalg->ec_nid; |
805 |
k->ec_nid = kexalg->ec_nid; |
|
Lines 784-791
choose_hostkeyalg(struct kex *k, char *client, char *server)
Link Here
|
| 784 |
if (k->hostkey_alg == NULL) |
816 |
if (k->hostkey_alg == NULL) |
| 785 |
return SSH_ERR_NO_HOSTKEY_ALG_MATCH; |
817 |
return SSH_ERR_NO_HOSTKEY_ALG_MATCH; |
| 786 |
k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); |
818 |
k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); |
| 787 |
if (k->hostkey_type == KEY_UNSPEC) |
819 |
if (k->hostkey_type == KEY_UNSPEC) { |
|
|
820 |
error("%s: unsupported hostkey algorithm %s", __func__, |
| 821 |
k->hostkey_alg); |
| 788 |
return SSH_ERR_INTERNAL_ERROR; |
822 |
return SSH_ERR_INTERNAL_ERROR; |
|
|
823 |
} |
| 789 |
k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); |
824 |
k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); |
| 790 |
return 0; |
825 |
return 0; |
| 791 |
} |
826 |
} |
|
Lines 954-959
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
Link Here
|
| 954 |
kex->session_id_len) != 0 || |
989 |
kex->session_id_len) != 0 || |
| 955 |
ssh_digest_final(hashctx, digest, mdsz) != 0) { |
990 |
ssh_digest_final(hashctx, digest, mdsz) != 0) { |
| 956 |
r = SSH_ERR_LIBCRYPTO_ERROR; |
991 |
r = SSH_ERR_LIBCRYPTO_ERROR; |
|
|
992 |
error("%s: KEX hash failed", __func__); |
| 957 |
goto out; |
993 |
goto out; |
| 958 |
} |
994 |
} |
| 959 |
ssh_digest_free(hashctx); |
995 |
ssh_digest_free(hashctx); |
|
Lines 970-975
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
Link Here
|
| 970 |
ssh_digest_update(hashctx, hash, hashlen) != 0 || |
1006 |
ssh_digest_update(hashctx, hash, hashlen) != 0 || |
| 971 |
ssh_digest_update(hashctx, digest, have) != 0 || |
1007 |
ssh_digest_update(hashctx, digest, have) != 0 || |
| 972 |
ssh_digest_final(hashctx, digest + have, mdsz) != 0) { |
1008 |
ssh_digest_final(hashctx, digest + have, mdsz) != 0) { |
|
|
1009 |
error("%s: KDF failed", __func__); |
| 973 |
r = SSH_ERR_LIBCRYPTO_ERROR; |
1010 |
r = SSH_ERR_LIBCRYPTO_ERROR; |
| 974 |
goto out; |
1011 |
goto out; |
| 975 |
} |
1012 |
} |
|
Lines 1033-1040
kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp)
Link Here
|
| 1033 |
*pubp = NULL; |
1070 |
*pubp = NULL; |
| 1034 |
*prvp = NULL; |
1071 |
*prvp = NULL; |
| 1035 |
if (kex->load_host_public_key == NULL || |
1072 |
if (kex->load_host_public_key == NULL || |
| 1036 |
kex->load_host_private_key == NULL) |
1073 |
kex->load_host_private_key == NULL) { |
|
|
1074 |
error("%s: missing hostkey loader", __func__); |
| 1037 |
return SSH_ERR_INVALID_ARGUMENT; |
1075 |
return SSH_ERR_INVALID_ARGUMENT; |
|
|
1076 |
} |
| 1038 |
*pubp = kex->load_host_public_key(kex->hostkey_type, |
1077 |
*pubp = kex->load_host_public_key(kex->hostkey_type, |
| 1039 |
kex->hostkey_nid, ssh); |
1078 |
kex->hostkey_nid, ssh); |
| 1040 |
*prvp = kex->load_host_private_key(kex->hostkey_type, |
1079 |
*prvp = kex->load_host_private_key(kex->hostkey_type, |
|
Lines 1049-1056
kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key)
Link Here
|
| 1049 |
{ |
1088 |
{ |
| 1050 |
struct kex *kex = ssh->kex; |
1089 |
struct kex *kex = ssh->kex; |
| 1051 |
|
1090 |
|
| 1052 |
if (kex->verify_host_key == NULL) |
1091 |
if (kex->verify_host_key == NULL) { |
|
|
1092 |
error("%s: missing hostkey verifier", __func__); |
| 1053 |
return SSH_ERR_INVALID_ARGUMENT; |
1093 |
return SSH_ERR_INVALID_ARGUMENT; |
|
|
1094 |
} |
| 1054 |
if (server_host_key->type != kex->hostkey_type || |
1095 |
if (server_host_key->type != kex->hostkey_type || |
| 1055 |
(kex->hostkey_type == KEY_ECDSA && |
1096 |
(kex->hostkey_type == KEY_ECDSA && |
| 1056 |
server_host_key->ecdsa_nid != kex->hostkey_nid)) |
1097 |
server_host_key->ecdsa_nid != kex->hostkey_nid)) |