summaryrefslogtreecommitdiff
path: root/monitor.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2015-02-16 22:13:32 +0000
committerDamien Miller <djm@mindrot.org>2015-02-17 09:32:32 +1100
commit523463a3a2a9bfc6cfc5afa01bae9147f76a37cc (patch)
tree772be92cee9553c19d51b4570113c3d4de0c2d8b /monitor.c
parent6c5c949782d86a6e7d58006599c7685bfcd01685 (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.c45
1 files changed, 39 insertions, 6 deletions
diff --git a/monitor.c b/monitor.c
index e97b20ef0..6e97def1c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -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)
685int 685int
686mm_answer_sign(int sock, Buffer *m) 686mm_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)