diff options
author | djm@openbsd.org <djm@openbsd.org> | 2015-02-16 22:13:32 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2015-02-17 09:32:32 +1100 |
commit | 523463a3a2a9bfc6cfc5afa01bae9147f76a37cc (patch) | |
tree | 772be92cee9553c19d51b4570113c3d4de0c2d8b /monitor.c | |
parent | 6c5c949782d86a6e7d58006599c7685bfcd01685 (diff) |
upstream commit
Revise hostkeys@openssh.com hostkey learning extension.
The client will not ask the server to prove ownership of the private
halves of any hitherto-unseen hostkeys it offers to the client.
Allow UpdateHostKeys option to take an 'ask' argument to let the
user manually review keys offered.
ok markus@
Diffstat (limited to 'monitor.c')
-rw-r--r-- | monitor.c | 45 |
1 files changed, 39 insertions, 6 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.c,v 1.143 2015/02/13 18:57:00 markus Exp $ */ | 1 | /* $OpenBSD: monitor.c,v 1.144 2015/02/16 22:13:32 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -685,12 +685,15 @@ mm_answer_moduli(int sock, Buffer *m) | |||
685 | int | 685 | int |
686 | mm_answer_sign(int sock, Buffer *m) | 686 | mm_answer_sign(int sock, Buffer *m) |
687 | { | 687 | { |
688 | struct ssh *ssh = active_state; /* XXX */ | ||
688 | extern int auth_sock; /* XXX move to state struct? */ | 689 | extern int auth_sock; /* XXX move to state struct? */ |
689 | struct sshkey *key; | 690 | struct sshkey *key; |
691 | struct sshbuf *sigbuf; | ||
690 | u_char *p; | 692 | u_char *p; |
691 | u_char *signature; | 693 | u_char *signature; |
692 | size_t datlen, siglen; | 694 | size_t datlen, siglen; |
693 | int r, keyid; | 695 | int r, keyid, is_proof = 0; |
696 | const char proof_req[] = "hostkeys-prove@openssh.com"; | ||
694 | 697 | ||
695 | debug3("%s", __func__); | 698 | debug3("%s", __func__); |
696 | 699 | ||
@@ -701,9 +704,38 @@ mm_answer_sign(int sock, Buffer *m) | |||
701 | /* | 704 | /* |
702 | * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), | 705 | * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), |
703 | * SHA384 (48 bytes) and SHA512 (64 bytes). | 706 | * SHA384 (48 bytes) and SHA512 (64 bytes). |
707 | * | ||
708 | * Otherwise, verify the signature request is for a hostkey | ||
709 | * proof. | ||
710 | * | ||
711 | * XXX perform similar check for KEX signature requests too? | ||
712 | * it's not trivial, since what is signed is the hash, rather | ||
713 | * than the full kex structure... | ||
704 | */ | 714 | */ |
705 | if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) | 715 | if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) { |
706 | fatal("%s: data length incorrect: %zu", __func__, datlen); | 716 | /* |
717 | * Construct expected hostkey proof and compare it to what | ||
718 | * the client sent us. | ||
719 | */ | ||
720 | if (session_id2_len == 0) /* hostkeys is never first */ | ||
721 | fatal("%s: bad data length: %zu", __func__, datlen); | ||
722 | if ((key = get_hostkey_public_by_index(keyid, ssh)) == NULL) | ||
723 | fatal("%s: no hostkey for index %d", __func__, keyid); | ||
724 | if ((sigbuf = sshbuf_new()) == NULL) | ||
725 | fatal("%s: sshbuf_new", __func__); | ||
726 | if ((r = sshbuf_put_string(sigbuf, session_id2, | ||
727 | session_id2_len) != 0) || | ||
728 | (r = sshbuf_put_cstring(sigbuf, proof_req)) != 0 || | ||
729 | (r = sshkey_puts(key, sigbuf)) != 0) | ||
730 | fatal("%s: couldn't prepare private key " | ||
731 | "proof buffer: %s", __func__, ssh_err(r)); | ||
732 | if (datlen != sshbuf_len(sigbuf) || | ||
733 | memcmp(p, sshbuf_ptr(sigbuf), sshbuf_len(sigbuf)) != 0) | ||
734 | fatal("%s: bad data length: %zu, hostkey proof len %zu", | ||
735 | __func__, datlen, sshbuf_len(sigbuf)); | ||
736 | sshbuf_free(sigbuf); | ||
737 | is_proof = 1; | ||
738 | } | ||
707 | 739 | ||
708 | /* save session id, it will be passed on the first call */ | 740 | /* save session id, it will be passed on the first call */ |
709 | if (session_id2_len == 0) { | 741 | if (session_id2_len == 0) { |
@@ -717,7 +749,7 @@ mm_answer_sign(int sock, Buffer *m) | |||
717 | datafellows)) != 0) | 749 | datafellows)) != 0) |
718 | fatal("%s: sshkey_sign failed: %s", | 750 | fatal("%s: sshkey_sign failed: %s", |
719 | __func__, ssh_err(r)); | 751 | __func__, ssh_err(r)); |
720 | } else if ((key = get_hostkey_public_by_index(keyid, active_state)) != NULL && | 752 | } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && |
721 | auth_sock > 0) { | 753 | auth_sock > 0) { |
722 | if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, | 754 | if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, |
723 | p, datlen, datafellows)) != 0) { | 755 | p, datlen, datafellows)) != 0) { |
@@ -727,7 +759,8 @@ mm_answer_sign(int sock, Buffer *m) | |||
727 | } else | 759 | } else |
728 | fatal("%s: no hostkey from index %d", __func__, keyid); | 760 | fatal("%s: no hostkey from index %d", __func__, keyid); |
729 | 761 | ||
730 | debug3("%s: signature %p(%zu)", __func__, signature, siglen); | 762 | debug3("%s: %s signature %p(%zu)", __func__, |
763 | is_proof ? "KEX" : "hostkey proof", signature, siglen); | ||
731 | 764 | ||
732 | sshbuf_reset(m); | 765 | sshbuf_reset(m); |
733 | if ((r = sshbuf_put_string(m, signature, siglen)) != 0) | 766 | if ((r = sshbuf_put_string(m, signature, siglen)) != 0) |