aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/sshconnect2.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/sshconnect2.c')
-rw-r--r--crypto/openssh/sshconnect2.c221
1 files changed, 105 insertions, 116 deletions
diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c
index b25225e645cb..745c2a0517f3 100644
--- a/crypto/openssh/sshconnect2.c
+++ b/crypto/openssh/sshconnect2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.356 2022/02/01 23:32:51 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.372 2024/01/08 00:34:34 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -56,7 +56,6 @@
#include "cipher.h"
#include "sshkey.h"
#include "kex.h"
-#include "myproposal.h"
#include "sshconnect.h"
#include "authfile.h"
#include "dh.h"
@@ -96,6 +95,11 @@ static const struct ssh_conn_info *xxx_conn_info;
static int
verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
{
+ int r;
+
+ if ((r = sshkey_check_rsa_length(hostkey,
+ options.required_rsa_size)) != 0)
+ fatal_r(r, "Bad server host key");
if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
xxx_conn_info) == -1)
fatal("Host key verification failed.");
@@ -136,7 +140,7 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port,
}
if (options.known_hosts_command != NULL) {
load_hostkeys_command(hostkeys, options.known_hosts_command,
- "ORDER", cinfo, NULL, host);
+ "ORDER", cinfo, NULL, hostname);
}
/*
* If a plain public key exists that matches the type of the best
@@ -216,14 +220,18 @@ void
ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
const struct ssh_conn_info *cinfo)
{
- char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
- char *s, *all_key;
+ char *myproposal[PROPOSAL_MAX];
+ char *all_key, *hkalgs = NULL;
int r, use_known_hosts_order = 0;
xxx_host = host;
xxx_hostaddr = hostaddr;
xxx_conn_info = cinfo;
+ if (options.rekey_limit || options.rekey_interval)
+ ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
+ options.rekey_interval);
+
/*
* If the user has not specified HostkeyAlgorithms, or has only
* appended or removed algorithms from that list then prefer algorithms
@@ -241,32 +249,15 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
fatal_fr(r, "kex_assemble_namelist");
free(all_key);
- if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
- fatal_f("kex_names_cat");
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, s);
- myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- compat_cipher_proposal(ssh, options.ciphers);
- myproposal[PROPOSAL_ENC_ALGS_STOC] =
- compat_cipher_proposal(ssh, options.ciphers);
- myproposal[PROPOSAL_COMP_ALGS_CTOS] =
- myproposal[PROPOSAL_COMP_ALGS_STOC] =
- (char *)compression_alg_list(options.compression);
- myproposal[PROPOSAL_MAC_ALGS_CTOS] =
- myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
- if (use_known_hosts_order) {
- /* Query known_hosts and prefer algorithms that appear there */
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
- compat_pkalg_proposal(ssh,
- order_hostkeyalgs(host, hostaddr, port, cinfo));
- } else {
- /* Use specified HostkeyAlgorithms exactly */
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
- compat_pkalg_proposal(ssh, options.hostkeyalgorithms);
- }
+ if (use_known_hosts_order)
+ hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo);
- if (options.rekey_limit || options.rekey_interval)
- ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
- options.rekey_interval);
+ kex_proposal_populate_entries(ssh, myproposal,
+ options.kex_algorithms, options.ciphers, options.macs,
+ compression_alg_list(options.compression),
+ hkalgs ? hkalgs : options.hostkeyalgorithms);
+
+ free(hkalgs);
/* start key exchange */
if ((r = kex_setup(ssh, myproposal)) != 0)
@@ -288,12 +279,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
ssh->kex->verify_host_key=&verify_host_key_callback;
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
-
- /* remove ext-info from the KEX proposals for rekeying */
- myproposal[PROPOSAL_KEX_ALGS] =
- compat_kex_proposal(ssh, options.kex_algorithms);
- if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
- fatal_r(r, "kex_prop2buf");
+ kex_proposal_free_entries(myproposal);
#ifdef DEBUG_KEXDH
/* send 1st encrypted/maced/compressed message */
@@ -363,7 +349,6 @@ struct cauthmethod {
};
static int input_userauth_service_accept(int, u_int32_t, struct ssh *);
-static int input_userauth_ext_info(int, u_int32_t, struct ssh *);
static int input_userauth_success(int, u_int32_t, struct ssh *);
static int input_userauth_failure(int, u_int32_t, struct ssh *);
static int input_userauth_banner(int, u_int32_t, struct ssh *);
@@ -465,10 +450,8 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
authctxt.mech_tried = 0;
#endif
authctxt.agent_fd = -1;
- pubkey_prepare(ssh, &authctxt);
- if (authctxt.method == NULL) {
+ if (authctxt.method == NULL)
fatal_f("internal error: cannot send userauth none request");
- }
if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 ||
@@ -477,10 +460,18 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
ssh->authctxt = &authctxt;
ssh_dispatch_init(ssh, &input_userauth_error);
- ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info);
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */
pubkey_cleanup(ssh);
+#ifdef GSSAPI
+ if (authctxt.gss_supported_mechs != NULL) {
+ u_int ms;
+
+ gss_release_oid_set(&ms, &authctxt.gss_supported_mechs);
+ authctxt.gss_supported_mechs = NULL;
+ }
+#endif
ssh->authctxt = NULL;
ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
@@ -497,7 +488,6 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
}
}
-/* ARGSUSED */
static int
input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
{
@@ -520,7 +510,9 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
/* initial userauth request */
userauth_none(ssh);
- ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error);
+ /* accept EXT_INFO at any time during userauth */
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, ssh->kex->ext_info_s ?
+ &kex_input_ext_info : &input_userauth_error);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
@@ -529,13 +521,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
return r;
}
-/* ARGSUSED */
-static int
-input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
-{
- return kex_input_ext_info(type, seqnr, ssh);
-}
-
void
userauth(struct ssh *ssh, char *authlist)
{
@@ -574,7 +559,6 @@ userauth(struct ssh *ssh, char *authlist)
}
}
-/* ARGSUSED */
static int
input_userauth_error(int type, u_int32_t seq, struct ssh *ssh)
{
@@ -582,7 +566,6 @@ input_userauth_error(int type, u_int32_t seq, struct ssh *ssh)
return 0;
}
-/* ARGSUSED */
static int
input_userauth_banner(int type, u_int32_t seq, struct ssh *ssh)
{
@@ -602,7 +585,6 @@ input_userauth_banner(int type, u_int32_t seq, struct ssh *ssh)
return r;
}
-/* ARGSUSED */
static int
input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
{
@@ -617,6 +599,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
free(authctxt->methoddata);
authctxt->methoddata = NULL;
authctxt->success = 1; /* break out */
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error);
return 0;
}
@@ -635,7 +618,6 @@ input_userauth_success_unexpected(int type, u_int32_t seq, struct ssh *ssh)
}
#endif
-/* ARGSUSED */
static int
input_userauth_failure(int type, u_int32_t seq, struct ssh *ssh)
{
@@ -696,7 +678,6 @@ format_identity(Identity *id)
return ret;
}
-/* ARGSUSED */
static int
input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh)
{
@@ -832,9 +813,6 @@ userauth_gssapi_cleanup(struct ssh *ssh)
ssh_gssapi_delete_ctx(&gssctxt);
authctxt->methoddata = NULL;
-
- free(authctxt->gss_supported_mechs);
- authctxt->gss_supported_mechs = NULL;
}
static OM_uint32
@@ -904,7 +882,6 @@ process_gssapi_token(struct ssh *ssh, gss_buffer_t recv_tok)
return status;
}
-/* ARGSUSED */
static int
input_gssapi_response(int type, u_int32_t plen, struct ssh *ssh)
{
@@ -949,7 +926,6 @@ input_gssapi_response(int type, u_int32_t plen, struct ssh *ssh)
return r;
}
-/* ARGSUSED */
static int
input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
{
@@ -982,7 +958,6 @@ input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
return r;
}
-/* ARGSUSED */
static int
input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
{
@@ -1017,7 +992,6 @@ input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
return 0;
}
-/* ARGSUSED */
static int
input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
{
@@ -1095,7 +1069,6 @@ userauth_passwd(struct ssh *ssh)
/*
* parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
*/
-/* ARGSUSED */
static int
input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh)
{
@@ -1231,7 +1204,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat, const char *alg)
{
struct sshkey *sign_key = NULL, *prv = NULL;
- int retried = 0, r = SSH_ERR_INTERNAL_ERROR;
+ int is_agent = 0, retried = 0, r = SSH_ERR_INTERNAL_ERROR;
struct notifier_ctx *notifier = NULL;
char *fp = NULL, *pin = NULL, *prompt = NULL;
@@ -1251,6 +1224,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
if (id->key != NULL &&
(id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) {
sign_key = id->key;
+ is_agent = 1;
} else {
/* Load the private key from the file. */
if ((prv = load_identity_file(id)) == NULL)
@@ -1262,34 +1236,31 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
goto out;
}
sign_key = prv;
- if (sshkey_is_sk(sign_key)) {
- if ((sign_key->sk_flags &
- SSH_SK_USER_VERIFICATION_REQD)) {
+ }
retry_pin:
- xasprintf(&prompt, "Enter PIN for %s key %s: ",
- sshkey_type(sign_key), id->filename);
- pin = read_passphrase(prompt, 0);
- }
- if ((sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
- /* XXX should batch mode just skip these? */
- if ((fp = sshkey_fingerprint(sign_key,
- options.fingerprint_hash,
- SSH_FP_DEFAULT)) == NULL)
- fatal_f("fingerprint failed");
- notifier = notify_start(options.batch_mode,
- "Confirm user presence for key %s %s",
- sshkey_type(sign_key), fp);
- free(fp);
- }
- }
+ /* Prompt for touch for non-agent FIDO keys that request UP */
+ if (!is_agent && sshkey_is_sk(sign_key) &&
+ (sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
+ /* XXX should batch mode just skip these? */
+ if ((fp = sshkey_fingerprint(sign_key,
+ options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
+ fatal_f("fingerprint failed");
+ notifier = notify_start(options.batch_mode,
+ "Confirm user presence for key %s %s",
+ sshkey_type(sign_key), fp);
+ free(fp);
}
if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
alg, options.sk_provider, pin, compat)) != 0) {
debug_fr(r, "sshkey_sign");
- if (pin == NULL && !retried && sshkey_is_sk(sign_key) &&
+ if (!retried && pin == NULL && !is_agent &&
+ sshkey_is_sk(sign_key) &&
r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
notify_complete(notifier, NULL);
notifier = NULL;
+ xasprintf(&prompt, "Enter PIN for %s key %s: ",
+ sshkey_type(sign_key), id->filename);
+ pin = read_passphrase(prompt, 0);
retried = 1;
goto retry_pin;
}
@@ -1604,6 +1575,13 @@ load_identity_file(Identity *id)
private = NULL;
quit = 1;
}
+ if (!quit && (r = sshkey_check_rsa_length(private,
+ options.required_rsa_size)) != 0) {
+ debug_fr(r, "Skipping key %s", id->filename);
+ sshkey_free(private);
+ private = NULL;
+ quit = 1;
+ }
if (!quit && private != NULL && id->agent_fd == -1 &&
!(id->key && id->isprivate))
maybe_add_key_to_agent(id->filename, private, comment,
@@ -1691,10 +1669,10 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
struct identity *id, *id2, *tmp;
struct idlist agent, files, *preferred;
struct sshkey *key;
- int agent_fd = -1, i, r, found;
+ int disallowed, agent_fd = -1, i, r, found;
size_t j;
struct ssh_identitylist *idlist;
- char *ident;
+ char *cp, *ident;
TAILQ_INIT(&agent); /* keys from the agent */
TAILQ_INIT(&files); /* keys from the config file */
@@ -1750,6 +1728,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
/* list of keys supported by the agent */
if ((r = get_agent_identities(ssh, &agent_fd, &idlist)) == 0) {
for (j = 0; j < idlist->nkeys; j++) {
+ if ((r = sshkey_check_rsa_length(idlist->keys[j],
+ options.required_rsa_size)) != 0) {
+ debug_fr(r, "ignoring %s agent key",
+ sshkey_ssh_name(idlist->keys[j]));
+ continue;
+ }
found = 0;
TAILQ_FOREACH(id, &files, next) {
/*
@@ -1806,16 +1790,30 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
TAILQ_CONCAT(preferred, &files, next);
/* finally, filter by PubkeyAcceptedAlgorithms */
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
- if (id->key != NULL && !key_type_allowed_by_config(id->key)) {
- debug("Skipping %s key %s - "
- "corresponding algo not in PubkeyAcceptedAlgorithms",
- sshkey_ssh_name(id->key), id->filename);
- TAILQ_REMOVE(preferred, id, next);
- sshkey_free(id->key);
- free(id->filename);
- memset(id, 0, sizeof(*id));
+ disallowed = 0;
+ cp = NULL;
+ if (id->key == NULL)
continue;
+ if (!key_type_allowed_by_config(id->key)) {
+ debug("Skipping %s key %s - corresponding algorithm "
+ "not in PubkeyAcceptedAlgorithms",
+ sshkey_ssh_name(id->key), id->filename);
+ disallowed = 1;
+ } else if (ssh->kex->server_sig_algs != NULL &&
+ (cp = key_sig_algorithm(ssh, id->key)) == NULL) {
+ debug("Skipping %s key %s - corresponding algorithm "
+ "not supported by server",
+ sshkey_ssh_name(id->key), id->filename);
+ disallowed = 1;
}
+ free(cp);
+ if (!disallowed)
+ continue;
+ /* remove key */
+ TAILQ_REMOVE(preferred, id, next);
+ sshkey_free(id->key);
+ free(id->filename);
+ memset(id, 0, sizeof(*id));
}
/* List the keys we plan on using */
TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
@@ -1855,26 +1853,18 @@ pubkey_reset(Authctxt *authctxt)
}
static int
-try_identity(struct ssh *ssh, Identity *id)
-{
- if (!id->key)
- return (0);
- if (sshkey_type_plain(id->key->type) == KEY_RSA &&
- (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
- debug("Skipped %s key %s for RSA/MD5 server",
- sshkey_type(id->key), id->filename);
- return (0);
- }
- return 1;
-}
-
-static int
userauth_pubkey(struct ssh *ssh)
{
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
Identity *id;
int sent = 0;
char *ident;
+ static int prepared;
+
+ if (!prepared) {
+ pubkey_prepare(ssh, authctxt);
+ prepared = 1;
+ }
while ((id = TAILQ_FIRST(&authctxt->keys))) {
if (id->tried++)
@@ -1888,17 +1878,15 @@ userauth_pubkey(struct ssh *ssh)
* private key instead
*/
if (id->key != NULL) {
- if (try_identity(ssh, id)) {
- ident = format_identity(id);
- debug("Offering public key: %s", ident);
- free(ident);
- sent = send_pubkey_test(ssh, id);
- }
+ ident = format_identity(id);
+ debug("Offering public key: %s", ident);
+ free(ident);
+ sent = send_pubkey_test(ssh, id);
} else {
debug("Trying private key: %s", id->filename);
id->key = load_identity_file(id);
if (id->key != NULL) {
- if (try_identity(ssh, id)) {
+ if (id->key != NULL) {
id->isprivate = 1;
sent = sign_and_send_pubkey(ssh, id);
}
@@ -2069,7 +2057,8 @@ ssh_keysign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
if (dup2(sock, STDERR_FILENO + 1) == -1)
fatal_f("dup2: %s", strerror(errno));
sock = STDERR_FILENO + 1;
- fcntl(sock, F_SETFD, 0); /* keep the socket on exec */
+ if (fcntl(sock, F_SETFD, 0) == -1) /* keep the socket on exec */
+ debug3_f("fcntl F_SETFD: %s", strerror(errno));
closefrom(sock + 1);
debug3_f("[child] pid=%ld, exec %s",