summaryrefslogtreecommitdiff
path: root/clientloop.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2015-01-26 03:04:45 +0000
committerDamien Miller <djm@mindrot.org>2015-01-27 00:00:57 +1100
commit8d4f87258f31cb6def9b3b55b6a7321d84728ff2 (patch)
treec98e66c1c0824f0b0e312d7b44d8eeac46265362 /clientloop.c
parent60b1825262b1f1e24fc72050b907189c92daf18e (diff)
upstream commit
Host key rotation support. Add a hostkeys@openssh.com protocol extension (global request) for a server to inform a client of all its available host key after authentication has completed. The client may record the keys in known_hosts, allowing it to upgrade to better host key algorithms and a server to gracefully rotate its keys. The client side of this is controlled by a UpdateHostkeys config option (default on). ok markus@
Diffstat (limited to 'clientloop.c')
-rw-r--r--clientloop.c94
1 files changed, 92 insertions, 2 deletions
diff --git a/clientloop.c b/clientloop.c
index 4522a6332..7b54b6eb0 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.266 2015/01/20 23:14:00 deraadt Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.267 2015/01/26 03:04:45 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -112,6 +112,7 @@
112#include "msg.h" 112#include "msg.h"
113#include "roaming.h" 113#include "roaming.h"
114#include "ssherr.h" 114#include "ssherr.h"
115#include "hostfile.h"
115 116
116/* import options */ 117/* import options */
117extern Options options; 118extern Options options;
@@ -1781,6 +1782,7 @@ client_input_exit_status(int type, u_int32_t seq, void *ctxt)
1781 quit_pending = 1; 1782 quit_pending = 1;
1782 return 0; 1783 return 0;
1783} 1784}
1785
1784static int 1786static int
1785client_input_agent_open(int type, u_int32_t seq, void *ctxt) 1787client_input_agent_open(int type, u_int32_t seq, void *ctxt)
1786{ 1788{
@@ -2038,6 +2040,7 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
2038 free(ctype); 2040 free(ctype);
2039 return 0; 2041 return 0;
2040} 2042}
2043
2041static int 2044static int
2042client_input_channel_req(int type, u_int32_t seq, void *ctxt) 2045client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2043{ 2046{
@@ -2085,6 +2088,91 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
2085 free(rtype); 2088 free(rtype);
2086 return 0; 2089 return 0;
2087} 2090}
2091
2092/*
2093 * Handle hostkeys@openssh.com global request to inform the client of all
2094 * the server's hostkeys. The keys are checked against the user's
2095 * HostkeyAlgorithms preference before they are accepted.
2096 */
2097static int
2098client_input_hostkeys(void)
2099{
2100 const u_char *blob = NULL;
2101 u_int i, len = 0, nkeys = 0;
2102 struct sshbuf *buf = NULL;
2103 struct sshkey *key = NULL, **tmp, **keys = NULL;
2104 int r, success = 1;
2105 char *fp, *host_str = NULL;
2106 static int hostkeys_seen = 0; /* XXX use struct ssh */
2107
2108 /*
2109 * NB. Return success for all cases other than protocol error. The
2110 * server doesn't need to know what the client does with its hosts
2111 * file.
2112 */
2113
2114 blob = packet_get_string_ptr(&len);
2115 packet_check_eom();
2116
2117 if (hostkeys_seen)
2118 fatal("%s: server already sent hostkeys", __func__);
2119 if (!options.update_hostkeys || options.num_user_hostfiles <= 0)
2120 return 1;
2121 if ((buf = sshbuf_from(blob, len)) == NULL)
2122 fatal("%s: sshbuf_from failed", __func__);
2123 while (sshbuf_len(buf) > 0) {
2124 sshkey_free(key);
2125 key = NULL;
2126 if ((r = sshkey_froms(buf, &key)) != 0)
2127 fatal("%s: parse key: %s", __func__, ssh_err(r));
2128 fp = sshkey_fingerprint(key, options.fingerprint_hash,
2129 SSH_FP_DEFAULT);
2130 debug3("%s: received %s key %s", __func__,
2131 sshkey_type(key), fp);
2132 free(fp);
2133 /* Check that the key is accepted in HostkeyAlgorithms */
2134 if (options.hostkeyalgorithms != NULL &&
2135 match_pattern_list(sshkey_ssh_name(key),
2136 options.hostkeyalgorithms,
2137 strlen(options.hostkeyalgorithms), 0) != 1) {
2138 debug3("%s: %s key not permitted by HostkeyAlgorithms",
2139 __func__, sshkey_ssh_name(key));
2140 continue;
2141 }
2142 if ((tmp = reallocarray(keys, nkeys + 1,
2143 sizeof(*keys))) == NULL)
2144 fatal("%s: reallocarray failed nkeys = %u",
2145 __func__, nkeys);
2146 keys = tmp;
2147 keys[nkeys++] = key;
2148 key = NULL;
2149 }
2150
2151 debug3("%s: received %u keys from server", __func__, nkeys);
2152 if (nkeys == 0) {
2153 error("%s: server sent no hostkeys", __func__);
2154 goto out;
2155 }
2156
2157 get_hostfile_hostname_ipaddr(host, NULL, options.port, &host_str, NULL);
2158
2159 if ((r = hostfile_replace_entries(options.user_hostfiles[0], host_str,
2160 keys, nkeys, options.hash_known_hosts, 1)) != 0) {
2161 error("%s: hostfile_replace_entries failed: %s",
2162 __func__, ssh_err(r));
2163 goto out;
2164 }
2165
2166 /* Success */
2167 out:
2168 free(host_str);
2169 sshkey_free(key);
2170 for (i = 0; i < nkeys; i++)
2171 sshkey_free(keys[i]);
2172 sshbuf_free(buf);
2173 return success;
2174}
2175
2088static int 2176static int
2089client_input_global_request(int type, u_int32_t seq, void *ctxt) 2177client_input_global_request(int type, u_int32_t seq, void *ctxt)
2090{ 2178{
@@ -2092,10 +2180,12 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
2092 int want_reply; 2180 int want_reply;
2093 int success = 0; 2181 int success = 0;
2094 2182
2095 rtype = packet_get_string(NULL); 2183 rtype = packet_get_cstring(NULL);
2096 want_reply = packet_get_char(); 2184 want_reply = packet_get_char();
2097 debug("client_input_global_request: rtype %s want_reply %d", 2185 debug("client_input_global_request: rtype %s want_reply %d",
2098 rtype, want_reply); 2186 rtype, want_reply);
2187 if (strcmp(rtype, "hostkeys@openssh.com") == 0)
2188 success = client_input_hostkeys();
2099 if (want_reply) { 2189 if (want_reply) {
2100 packet_start(success ? 2190 packet_start(success ?
2101 SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); 2191 SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);