summaryrefslogtreecommitdiff
path: root/sshd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshd.c')
-rw-r--r--sshd.c232
1 files changed, 143 insertions, 89 deletions
diff --git a/sshd.c b/sshd.c
index fd95b681b7c5b..a738c3ab6560b 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.506 2018/03/03 03:15:51 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.514 2018/08/13 02:41:05 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -91,7 +91,7 @@
#include "sshpty.h"
#include "packet.h"
#include "log.h"
-#include "buffer.h"
+#include "sshbuf.h"
#include "misc.h"
#include "match.h"
#include "servconf.h"
@@ -99,7 +99,7 @@
#include "compat.h"
#include "cipher.h"
#include "digest.h"
-#include "key.h"
+#include "sshkey.h"
#include "kex.h"
#include "myproposal.h"
#include "authfile.h"
@@ -237,10 +237,10 @@ Authctxt *the_authctxt = NULL;
struct sshauthopt *auth_opts = NULL;
/* sshd_config buffer */
-Buffer cfg;
+struct sshbuf *cfg;
/* message to be displayed after login */
-Buffer loginmsg;
+struct sshbuf *loginmsg;
/* Unprivileged user */
struct passwd *privsep_pw = NULL;
@@ -473,11 +473,11 @@ destroy_sensitive_data(void)
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
- key_free(sensitive_data.host_keys[i]);
+ sshkey_free(sensitive_data.host_keys[i]);
sensitive_data.host_keys[i] = NULL;
}
if (sensitive_data.host_certificates[i]) {
- key_free(sensitive_data.host_certificates[i]);
+ sshkey_free(sensitive_data.host_certificates[i]);
sensitive_data.host_certificates[i] = NULL;
}
}
@@ -489,11 +489,16 @@ demote_sensitive_data(void)
{
struct sshkey *tmp;
u_int i;
+ int r;
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
- tmp = key_demote(sensitive_data.host_keys[i]);
- key_free(sensitive_data.host_keys[i]);
+ if ((r = sshkey_demote(sensitive_data.host_keys[i],
+ &tmp)) != 0)
+ fatal("could not demote host %s key: %s",
+ sshkey_type(sensitive_data.host_keys[i]),
+ ssh_err(r));
+ sshkey_free(sensitive_data.host_keys[i]);
sensitive_data.host_keys[i] = tmp;
}
/* Certs do not need demotion */
@@ -649,7 +654,7 @@ privsep_postauth(Authctxt *authctxt)
fatal("fork of unprivileged child failed");
else if (pmonitor->m_pid != 0) {
verbose("User child is on pid %ld", (long)pmonitor->m_pid);
- buffer_clear(&loginmsg);
+ sshbuf_reset(loginmsg);
monitor_clear_keystate(pmonitor);
monitor_child_postauth(pmonitor);
@@ -681,45 +686,47 @@ privsep_postauth(Authctxt *authctxt)
packet_set_authenticated();
}
+static void
+append_hostkey_type(struct sshbuf *b, const char *s)
+{
+ int r;
+
+ if (match_pattern_list(s, options.hostkeyalgorithms, 0) != 1) {
+ debug3("%s: %s key not permitted by HostkeyAlgorithms",
+ __func__, s);
+ return;
+ }
+ if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) > 0 ? "," : "", s)) != 0)
+ fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r));
+}
+
static char *
list_hostkey_types(void)
{
- Buffer b;
- const char *p;
+ struct sshbuf *b;
+ struct sshkey *key;
char *ret;
u_int i;
- struct sshkey *key;
- buffer_init(&b);
+ if ((b = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
for (i = 0; i < options.num_host_key_files; i++) {
key = sensitive_data.host_keys[i];
if (key == NULL)
key = sensitive_data.host_pubkeys[i];
if (key == NULL)
continue;
- /* Check that the key is accepted in HostkeyAlgorithms */
- if (match_pattern_list(sshkey_ssh_name(key),
- options.hostkeyalgorithms, 0) != 1) {
- debug3("%s: %s key not permitted by HostkeyAlgorithms",
- __func__, sshkey_ssh_name(key));
- continue;
- }
switch (key->type) {
case KEY_RSA:
+ /* for RSA we also support SHA2 signatures */
+ append_hostkey_type(b, "rsa-sha2-512");
+ append_hostkey_type(b, "rsa-sha2-256");
+ /* FALLTHROUGH */
case KEY_DSA:
case KEY_ECDSA:
case KEY_ED25519:
case KEY_XMSS:
- if (buffer_len(&b) > 0)
- buffer_append(&b, ",", 1);
- p = key_ssh_name(key);
- buffer_append(&b, p, strlen(p));
-
- /* for RSA we also support SHA2 signatures */
- if (key->type == KEY_RSA) {
- p = ",rsa-sha2-512,rsa-sha2-256";
- buffer_append(&b, p, strlen(p));
- }
+ append_hostkey_type(b, sshkey_ssh_name(key));
break;
}
/* If the private key has a cert peer, then list that too */
@@ -728,21 +735,24 @@ list_hostkey_types(void)
continue;
switch (key->type) {
case KEY_RSA_CERT:
+ /* for RSA we also support SHA2 signatures */
+ append_hostkey_type(b,
+ "rsa-sha2-512-cert-v01@openssh.com");
+ append_hostkey_type(b,
+ "rsa-sha2-256-cert-v01@openssh.com");
+ /* FALLTHROUGH */
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_ED25519_CERT:
case KEY_XMSS_CERT:
- if (buffer_len(&b) > 0)
- buffer_append(&b, ",", 1);
- p = key_ssh_name(key);
- buffer_append(&b, p, strlen(p));
+ append_hostkey_type(b, sshkey_ssh_name(key));
break;
}
}
- if ((ret = sshbuf_dup_string(&b)) == NULL)
+ if ((ret = sshbuf_dup_string(b)) == NULL)
fatal("%s: sshbuf_dup_string failed", __func__);
- buffer_free(&b);
- debug("list_hostkey_types: %s", ret);
+ sshbuf_free(b);
+ debug("%s: %s", __func__, ret);
return ret;
}
@@ -809,7 +819,7 @@ get_hostkey_index(struct sshkey *key, int compare, struct ssh *ssh)
u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
- if (key_is_cert(key)) {
+ if (sshkey_is_cert(key)) {
if (key == sensitive_data.host_certificates[i] ||
(compare && sensitive_data.host_certificates[i] &&
sshkey_equal(key,
@@ -953,31 +963,33 @@ send_rexec_state(int fd, struct sshbuf *conf)
}
static void
-recv_rexec_state(int fd, Buffer *conf)
+recv_rexec_state(int fd, struct sshbuf *conf)
{
- Buffer m;
- char *cp;
- u_int len;
+ struct sshbuf *m;
+ u_char *cp, ver;
+ size_t len;
+ int r;
debug3("%s: entering fd = %d", __func__, fd);
- buffer_init(&m);
-
- if (ssh_msg_recv(fd, &m) == -1)
+ if ((m = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
+ if (ssh_msg_recv(fd, m) == -1)
fatal("%s: ssh_msg_recv failed", __func__);
- if (buffer_get_char(&m) != 0)
+ if ((r = sshbuf_get_u8(m, &ver)) != 0)
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
+ if (ver != 0)
fatal("%s: rexec version mismatch", __func__);
-
- cp = buffer_get_string(&m, &len);
- if (conf != NULL)
- buffer_append(conf, cp, len);
- free(cp);
-
+ if ((r = sshbuf_get_string(m, &cp, &len)) != 0)
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
+ if (conf != NULL && (r = sshbuf_put(conf, cp, len)))
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY)
- rexec_recv_rng_seed(&m);
+ rexec_recv_rng_seed(m);
#endif
- buffer_free(&m);
+ free(cp);
+ sshbuf_free(m);
debug3("%s: done", __func__);
}
@@ -1258,8 +1270,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
startup_pipe = -1;
pid = getpid();
if (rexec_flag) {
- send_rexec_state(config_s[0],
- &cfg);
+ send_rexec_state(config_s[0], cfg);
close(config_s[0]);
}
break;
@@ -1305,7 +1316,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
close(startup_p[1]);
if (rexec_flag) {
- send_rexec_state(config_s[0], &cfg);
+ send_rexec_state(config_s[0], cfg);
close(config_s[0]);
close(config_s[1]);
}
@@ -1336,7 +1347,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
* return an error if any are found). Basically we are worried about
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
- * under certain circumstances, but rhosts autentication is useless
+ * under certain circumstances, but rhosts authentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
@@ -1413,6 +1424,43 @@ set_process_rdomain(struct ssh *ssh, const char *name)
#endif
}
+static void
+accumulate_host_timing_secret(struct sshbuf *server_cfg,
+ const struct sshkey *key)
+{
+ static struct ssh_digest_ctx *ctx;
+ u_char *hash;
+ size_t len;
+ struct sshbuf *buf;
+ int r;
+
+ if (ctx == NULL && (ctx = ssh_digest_start(SSH_DIGEST_SHA512)) == NULL)
+ fatal("%s: ssh_digest_start", __func__);
+ if (key == NULL) { /* finalize */
+ /* add server config in case we are using agent for host keys */
+ if (ssh_digest_update(ctx, sshbuf_ptr(server_cfg),
+ sshbuf_len(server_cfg)) != 0)
+ fatal("%s: ssh_digest_update", __func__);
+ len = ssh_digest_bytes(SSH_DIGEST_SHA512);
+ hash = xmalloc(len);
+ if (ssh_digest_final(ctx, hash, len) != 0)
+ fatal("%s: ssh_digest_final", __func__);
+ options.timing_secret = PEEK_U64(hash);
+ freezero(hash, len);
+ ssh_digest_free(ctx);
+ ctx = NULL;
+ return;
+ }
+ if ((buf = sshbuf_new()) == NULL)
+ fatal("%s could not allocate buffer", __func__);
+ if ((r = sshkey_private_serialize(key, buf)) != 0)
+ fatal("sshkey_private_serialize: %s", ssh_err(r));
+ if (ssh_digest_update(ctx, sshbuf_ptr(buf), sshbuf_len(buf)) != 0)
+ fatal("%s: ssh_digest_update", __func__);
+ sshbuf_reset(buf);
+ sshbuf_free(buf);
+}
+
/*
* Main program for the daemon.
*/
@@ -1620,14 +1668,15 @@ main(int ac, char **av)
"test mode (-T)");
/* Fetch our configuration */
- buffer_init(&cfg);
+ if ((cfg = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
if (rexeced_flag)
- recv_rexec_state(REEXEC_CONFIG_PASS_FD, &cfg);
+ recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg);
else if (strcasecmp(config_file_name, "none") != 0)
- load_server_config(config_file_name, &cfg);
+ load_server_config(config_file_name, cfg);
parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
- &cfg, NULL);
+ cfg, NULL);
seed_rng();
@@ -1714,11 +1763,18 @@ main(int ac, char **av)
for (i = 0; i < options.num_host_key_files; i++) {
if (options.host_key_files[i] == NULL)
continue;
- key = key_load_private(options.host_key_files[i], "", NULL);
- pubkey = key_load_public(options.host_key_files[i], NULL);
-
+ if ((r = sshkey_load_private(options.host_key_files[i], "",
+ &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
+ error("Error loading host key \"%s\": %s",
+ options.host_key_files[i], ssh_err(r));
+ if ((r = sshkey_load_public(options.host_key_files[i],
+ &pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
+ error("Error loading host key \"%s\": %s",
+ options.host_key_files[i], ssh_err(r));
if (pubkey == NULL && key != NULL)
- pubkey = key_demote(key);
+ if ((r = sshkey_demote(key, &pubkey)) != 0)
+ fatal("Could not demote key: \"%s\": %s",
+ options.host_key_files[i], ssh_err(r));
sensitive_data.host_keys[i] = key;
sensitive_data.host_pubkeys[i] = pubkey;
@@ -1728,6 +1784,7 @@ main(int ac, char **av)
keytype = pubkey->type;
} else if (key != NULL) {
keytype = key->type;
+ accumulate_host_timing_secret(cfg, key);
} else {
error("Could not load host key: %s",
options.host_key_files[i]);
@@ -1753,6 +1810,7 @@ main(int ac, char **av)
key ? "private" : "agent", i, sshkey_ssh_name(pubkey), fp);
free(fp);
}
+ accumulate_host_timing_secret(cfg, NULL);
if (!sensitive_data.have_ssh2_key) {
logit("sshd: no hostkeys available -- exiting.");
exit(1);
@@ -1770,21 +1828,21 @@ main(int ac, char **av)
for (i = 0; i < options.num_host_cert_files; i++) {
if (options.host_cert_files[i] == NULL)
continue;
- key = key_load_public(options.host_cert_files[i], NULL);
- if (key == NULL) {
- error("Could not load host certificate: %s",
- options.host_cert_files[i]);
+ if ((r = sshkey_load_public(options.host_cert_files[i],
+ &key, NULL)) != 0) {
+ error("Could not load host certificate \"%s\": %s",
+ options.host_cert_files[i], ssh_err(r));
continue;
}
- if (!key_is_cert(key)) {
+ if (!sshkey_is_cert(key)) {
error("Certificate file is not a certificate: %s",
options.host_cert_files[i]);
- key_free(key);
+ sshkey_free(key);
continue;
}
/* Find matching private key */
for (j = 0; j < options.num_host_key_files; j++) {
- if (key_equal_public(key,
+ if (sshkey_equal_public(key,
sensitive_data.host_keys[j])) {
sensitive_data.host_certificates[j] = key;
break;
@@ -1793,12 +1851,12 @@ main(int ac, char **av)
if (j >= options.num_host_key_files) {
error("No matching private key for certificate: %s",
options.host_cert_files[i]);
- key_free(key);
+ sshkey_free(key);
continue;
}
sensitive_data.host_certificates[j] = key;
debug("host certificate: #%u type %d %s", j, key->type,
- key_type(key));
+ sshkey_type(key));
}
if (privsep_chroot) {
@@ -2065,7 +2123,7 @@ main(int ac, char **av)
/* allocate authentication context */
authctxt = xcalloc(1, sizeof(*authctxt));
- authctxt->loginmsg = &loginmsg;
+ authctxt->loginmsg = loginmsg;
/* XXX global for cleanup, access from other modules */
the_authctxt = authctxt;
@@ -2075,7 +2133,8 @@ main(int ac, char **av)
fatal("allocation failed");
/* prepare buffer to collect messages to display to user after login */
- buffer_init(&loginmsg);
+ if ((loginmsg = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
auth_debug_reset();
if (use_privsep) {
@@ -2178,26 +2237,21 @@ main(int ac, char **av)
int
sshd_hostkey_sign(struct sshkey *privkey, struct sshkey *pubkey,
- u_char **signature, size_t *slen, const u_char *data, size_t dlen,
+ u_char **signature, size_t *slenp, const u_char *data, size_t dlen,
const char *alg, u_int flag)
{
int r;
- u_int xxx_slen, xxx_dlen = dlen;
if (privkey) {
- if (PRIVSEP(key_sign(privkey, signature, &xxx_slen, data, xxx_dlen,
- alg) < 0))
+ if (PRIVSEP(sshkey_sign(privkey, signature, slenp, data, dlen,
+ alg, datafellows)) < 0)
fatal("%s: key_sign failed", __func__);
- if (slen)
- *slen = xxx_slen;
} else if (use_privsep) {
- if (mm_key_sign(pubkey, signature, &xxx_slen, data, xxx_dlen,
- alg) < 0)
+ if (mm_sshkey_sign(pubkey, signature, slenp, data, dlen,
+ alg, datafellows) < 0)
fatal("%s: pubkey_sign failed", __func__);
- if (slen)
- *slen = xxx_slen;
} else {
- if ((r = ssh_agent_sign(auth_sock, pubkey, signature, slen,
+ if ((r = ssh_agent_sign(auth_sock, pubkey, signature, slenp,
data, dlen, alg, datafellows)) != 0)
fatal("%s: ssh_agent_sign failed: %s",
__func__, ssh_err(r));