diff options
Diffstat (limited to 'sshd.c')
| -rw-r--r-- | sshd.c | 232 |
1 files changed, 143 insertions, 89 deletions
@@ -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)); |
