1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Merge SSH fixes from 'pre-0.79'.

This commit is contained in:
Simon Tatham 2023-05-05 00:06:00 +01:00
commit 356ccf489b
9 changed files with 103 additions and 7 deletions

View File

@ -3173,6 +3173,11 @@ void setup_config_box(struct controlbox *b, bool midsession,
s = ctrl_getset(b, "Connection/SSH/More bugs", "main",
"Detection of known bugs in SSH servers");
ctrl_droplist(s, "Rejects rsa-sha2-*-cert*@openssh.com in userauth",
'j', 20,
HELPCTX(ssh_bugs_rsa_sha2_cert_userauth),
sshbug_handler,
I(CONF_sshbug_rsa_sha2_cert_userauth));
ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
HELPCTX(ssh_bugs_rsapad2),
sshbug_handler, I(CONF_sshbug_rsapad2));

View File

@ -3664,6 +3664,23 @@ connection would deadlock. We don't know of any servers that do this,
but if there is one, then this flag will make PuTTY unable to speak to
them at all.
\S{config-ssh-bug-rsa-sha2-cert-userauth} \q{Rejects
\cw{rsa-sha2-*-cert*@openssh.com} in userauth}
If PuTTY is trying to do SSH-2 user authentication using an RSA key,
and the server is using one of the newer SHA-2 based versions of the
SSH RSA protocol, and the user's key is also a certificate, then
earlier versions of OpenSSH (up to 7.7) disagree with later versions
about the right key algorithm string to send in the
\cw{SSH2_MSG_USERAUTH_REQUEST} packet. Modern versions send a string
that indicates both the SHA-2 nature and the certificate nature of the
key, such as \cq{rsa-sha2-512-cert-v01@openssh.com}. Earlier versions
would reject that, and insist on seeing
\cq{ssh-rsa-cert-v01@openssh.com} followed by a SHA-2 based signature.
PuTTY should auto-detect the presence of this bug in earlier OpenSSH
and adjust to send the right string.
\S{config-ssh-bug-sig} \q{Requires padding on SSH-2 \i{RSA} \i{signatures}}
Versions below 3.3 of \i{OpenSSH} require SSH-2 RSA signatures to be

View File

@ -2002,6 +2002,7 @@ NORETURN void cleanup_exit(int);
X(INT, NONE, sshbug_chanreq) \
X(INT, NONE, sshbug_dropstart) \
X(INT, NONE, sshbug_filter_kexinit) \
X(INT, NONE, sshbug_rsa_sha2_cert_userauth) \
/* \
* ssh_simple means that we promise never to open any channel \
* other than the main one, which means it can safely use a very \

View File

@ -759,6 +759,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
write_setting_i(sesskey, "BugOldGex2", 2-conf_get_int(conf, CONF_sshbug_oldgex2));
write_setting_i(sesskey, "BugWinadj", 2-conf_get_int(conf, CONF_sshbug_winadj));
write_setting_i(sesskey, "BugChanReq", 2-conf_get_int(conf, CONF_sshbug_chanreq));
write_setting_i(sesskey, "BugRSASHA2CertUserauth", 2-conf_get_int(conf, CONF_sshbug_rsa_sha2_cert_userauth));
write_setting_i(sesskey, "BugDropStart", 2-conf_get_int(conf, CONF_sshbug_dropstart));
write_setting_i(sesskey, "BugFilterKexinit", 2-conf_get_int(conf, CONF_sshbug_filter_kexinit));
write_setting_b(sesskey, "StampUtmp", conf_get_bool(conf, CONF_stamp_utmp));
@ -1240,6 +1241,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
i = gppi_raw(sesskey, "BugOldGex2", 0); conf_set_int(conf, CONF_sshbug_oldgex2, 2-i);
i = gppi_raw(sesskey, "BugWinadj", 0); conf_set_int(conf, CONF_sshbug_winadj, 2-i);
i = gppi_raw(sesskey, "BugChanReq", 0); conf_set_int(conf, CONF_sshbug_chanreq, 2-i);
i = gppi_raw(sesskey, "BugRSASHA2CertUserauth", 0); conf_set_int(conf, CONF_sshbug_rsa_sha2_cert_userauth, 2-i);
i = gppi_raw(sesskey, "BugDropStart", 1); conf_set_int(conf, CONF_sshbug_dropstart, 2-i);
i = gppi_raw(sesskey, "BugFilterKexinit", 1); conf_set_int(conf, CONF_sshbug_filter_kexinit, 2-i);
conf_set_bool(conf, CONF_ssh_simple, false);

1
ssh.h
View File

@ -1882,6 +1882,7 @@ void old_keyfile_warning(void);
X(BUG_SENDS_LATE_REQUEST_REPLY) \
X(BUG_SSH2_OLDGEX) \
X(BUG_REQUIRES_FILTERED_KEXINIT) \
X(BUG_RSA_SHA2_CERT_USERAUTH) \
/* end of list */
#define TMP_DECLARE_LOG2_ENUM(thing) log2_##thing,
enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_LOG2_ENUM) };

View File

@ -474,7 +474,8 @@ void ssh_remote_error(Ssh *ssh, const char *fmt, ...)
if (ssh->base_layer || !ssh->session_started) {
GET_FORMATTED_MSG;
ssh_ppl_final_output(ssh->base_layer);
if (ssh->base_layer)
ssh_ppl_final_output(ssh->base_layer);
/* Error messages sent by the remote don't count as clean exits */
ssh->exitcode = 128;
@ -494,7 +495,8 @@ void ssh_remote_eof(Ssh *ssh, const char *fmt, ...)
if (ssh->base_layer || !ssh->session_started) {
GET_FORMATTED_MSG;
ssh_ppl_final_output(ssh->base_layer);
if (ssh->base_layer)
ssh_ppl_final_output(ssh->base_layer);
/* EOF from the remote, if we were expecting it, does count as
* a clean exit */
@ -519,7 +521,8 @@ void ssh_proto_error(Ssh *ssh, const char *fmt, ...)
if (ssh->base_layer || !ssh->session_started) {
GET_FORMATTED_MSG;
ssh_ppl_final_output(ssh->base_layer);
if (ssh->base_layer)
ssh_ppl_final_output(ssh->base_layer);
ssh->exitcode = 128;
@ -538,7 +541,8 @@ void ssh_sw_abort(Ssh *ssh, const char *fmt, ...)
if (ssh->base_layer || !ssh->session_started) {
GET_FORMATTED_MSG;
ssh_ppl_final_output(ssh->base_layer);
if (ssh->base_layer)
ssh_ppl_final_output(ssh->base_layer);
ssh->exitcode = 128;
@ -557,7 +561,8 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...)
if (ssh->base_layer || !ssh->session_started) {
GET_FORMATTED_MSG;
ssh_ppl_final_output(ssh->base_layer);
if (ssh->base_layer)
ssh_ppl_final_output(ssh->base_layer);
/* Closing the connection due to user action, even if the
* action is the user aborting during authentication prompts,

View File

@ -135,6 +135,8 @@ static void ssh2_userauth_ki_write_responses(
static void ssh2_userauth_final_output(PacketProtocolLayer *ppl);
static void ssh2_userauth_print_banner(struct ssh2_userauth_state *s);
static ptrlen workaround_rsa_sha2_cert_userauth(
struct ssh2_userauth_state *s, ptrlen id);
static const PacketProtocolLayerVtable ssh2_userauth_vtable = {
.free = ssh2_userauth_free,
@ -2377,7 +2379,28 @@ static void ssh2_userauth_add_alg_and_publickey(
ppl_logevent("Sending public key with certificate from \"%s\"",
filename_to_str(s->detached_cert_file));
}
put_stringz(pkt, ssh_keyalg_related_alg(certalg, pkalg)->ssh_id);
{
/* Strip off any existing certificate-nature from pkalg,
* for the case where we're replacing a cert embedded in
* the key with the detached one. The second argument of
* ssh_keyalg_related_alg is expected to be one of the
* bare key algorithms, or nothing useful will happen. */
const ssh_keyalg *pkalg_base =
pkalg->base_alg ? pkalg->base_alg : pkalg;
/* Construct an algorithm string that includes both the
* signature subtype (e.g. rsa-sha2-512) and the
* certificate-ness. Exception: in earlier versions of
* OpenSSH we don't want to do that, and must send just
* ssh-rsa-cert-... even when we're delivering a non-SHA-1
* signature. */
const ssh_keyalg *output_alg =
ssh_keyalg_related_alg(certalg, pkalg_base);
ptrlen output_id = ptrlen_from_asciz(output_alg->ssh_id);
output_id = workaround_rsa_sha2_cert_userauth(s, output_id);
put_stringpl(pkt, output_id);
}
put_stringpl(pkt, ptrlen_from_strbuf(s->detached_cert_blob));
done = true;
goto out;
@ -2423,11 +2446,30 @@ static void ssh2_userauth_add_alg_and_publickey(
return;
}
/* In all other cases, just put in what we were given. */
/* In all other cases, basically just put in what we were given -
* except for the same bug workaround as above. */
alg = workaround_rsa_sha2_cert_userauth(s, alg);
put_stringpl(pkt, alg);
put_stringpl(pkt, pkblob);
}
static ptrlen workaround_rsa_sha2_cert_userauth(
struct ssh2_userauth_state *s, ptrlen id)
{
if (!(s->ppl.remote_bugs & BUG_RSA_SHA2_CERT_USERAUTH))
return id;
/*
* No need to try to do this in a general way based on the
* relations between ssh_keyalgs; we know there are a limited
* number of affected versions of OpenSSH, so this doesn't have to
* be futureproof against later additions to the family.
*/
if (ptrlen_eq_string(id, "rsa-sha2-256-cert-v01@openssh.com") ||
ptrlen_eq_string(id, "rsa-sha2-512-cert-v01@openssh.com"))
return PTRLEN_LITERAL("ssh-rsa-cert-v01@openssh.com");
return id;
}
/*
* Helper function to add an SSH-2 signature blob to a packet. Expects
* to be shown the public key blob as well as the signature blob.

View File

@ -612,6 +612,28 @@ static void ssh_detect_bugs(struct ssh_verstring_state *s)
bpp_logevent("We believe remote version requires us to "
"filter our KEXINIT");
}
if (conf_get_int(s->conf, CONF_sshbug_rsa_sha2_cert_userauth) == FORCE_ON ||
(conf_get_int(s->conf, CONF_sshbug_rsa_sha2_cert_userauth) == AUTO &&
(wc_match("OpenSSH_7.[2-7]*", imp)))) {
/*
* These versions have the bug in which using RSA/SHA-2
* authentication with a certified key requires the key
* algorithm to be sent as ssh-rsa-cert-... instead of
* rsa-sha2-NNN-cert-...
*
* OpenSSH 7.8 wants rsa-sha2-NNN-cert-...:
* https://github.com/openssh/openssh-portable/commit/4ba0d54794814ec0de1ec87987d0c3b89379b436
* (also labelled "OpenBSD-Commit-ID:
* c6e9f6d45eed8962ad502d315d7eaef32c419dde")
*
* OpenSSH 7.2 was the first release supporting RSA/SHA-2
* at all, so this bug is irrelevant to anything before that.
*/
s->remote_bugs |= BUG_RSA_SHA2_CERT_USERAUTH;
bpp_logevent("We believe remote version has SSH-2 "
"RSA/SHA-2/certificate userauth bug");
}
}
const char *ssh_verstring_get_remote(BinaryPacketProtocol *bpp)

View File

@ -167,6 +167,7 @@ typedef const char *HelpCtx;
#define WINHELP_CTX_ssh_bugs_pksessid2 "config-ssh-bug-pksessid2"
#define WINHELP_CTX_ssh_bugs_rekey2 "config-ssh-bug-rekey"
#define WINHELP_CTX_ssh_bugs_maxpkt2 "config-ssh-bug-maxpkt2"
#define WINHELP_CTX_ssh_bugs_rsa_sha2_cert_userauth "config-ssh-bug-rsa-sha2-cert-userauth"
#define WINHELP_CTX_ssh_bugs_winadj "config-ssh-bug-winadj"
#define WINHELP_CTX_ssh_bugs_chanreq "config-ssh-bug-chanreq"
#define WINHELP_CTX_ssh_bugs_oldgex2 "config-ssh-bug-oldgex2"