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

ssh_keyalg: new method 'alternate_ssh_id'.

Previously, the fact that "ssh-rsa" sometimes comes with two subtypes
"rsa-sha2-256" and "rsa-sha2-512" was known to three different parts
of the code - two in userauth and one in transport. Now the knowledge
of what those ids are, which one goes with which signing flags, and
which key types have subtypes at all, is centralised into a method of
the key algorithm, and all those locations just query it.

This will enable the introduction of further key algorithms that have
a parallel upgrade system.
This commit is contained in:
Simon Tatham 2022-04-19 17:27:54 +01:00
parent f9775a7b67
commit cf36b9215f
7 changed files with 77 additions and 33 deletions

View File

@ -499,6 +499,7 @@ const ssh_keyalg ssh_dsa = {
.components = dsa_components,
.pubkey_bits = dsa_pubkey_bits,
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.ssh_id = "ssh-dss",
.cache_id = "dss",
};

View File

@ -1258,6 +1258,7 @@ const ssh_keyalg ssh_ecdsa_ed25519 = {
.components = eddsa_components,
.pubkey_bits = ec_shared_pubkey_bits,
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.ssh_id = "ssh-ed25519",
.cache_id = "ssh-ed25519",
.extra = &sign_extra_ed25519,
@ -1282,6 +1283,7 @@ const ssh_keyalg ssh_ecdsa_ed448 = {
.components = eddsa_components,
.pubkey_bits = ec_shared_pubkey_bits,
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.ssh_id = "ssh-ed448",
.cache_id = "ssh-ed448",
.extra = &sign_extra_ed448,
@ -1310,6 +1312,7 @@ const ssh_keyalg ssh_ecdsa_nistp256 = {
.components = ecdsa_components,
.pubkey_bits = ec_shared_pubkey_bits,
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.ssh_id = "ecdsa-sha2-nistp256",
.cache_id = "ecdsa-sha2-nistp256",
.extra = &sign_extra_nistp256,
@ -1338,6 +1341,7 @@ const ssh_keyalg ssh_ecdsa_nistp384 = {
.components = ecdsa_components,
.pubkey_bits = ec_shared_pubkey_bits,
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.ssh_id = "ecdsa-sha2-nistp384",
.cache_id = "ecdsa-sha2-nistp384",
.extra = &sign_extra_nistp384,
@ -1366,6 +1370,7 @@ const ssh_keyalg ssh_ecdsa_nistp521 = {
.components = ecdsa_components,
.pubkey_bits = ec_shared_pubkey_bits,
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.ssh_id = "ecdsa-sha2-nistp521",
.cache_id = "ecdsa-sha2-nistp521",
.extra = &sign_extra_nistp521,

View File

@ -844,6 +844,15 @@ static unsigned ssh_rsa_supported_flags(const ssh_keyalg *self)
return SSH_AGENT_RSA_SHA2_256 | SSH_AGENT_RSA_SHA2_512;
}
const char *ssh_rsa_alternate_ssh_id(const ssh_keyalg *self, unsigned flags)
{
if (flags & SSH_AGENT_RSA_SHA2_512)
return ssh_rsa_sha512.ssh_id;
if (flags & SSH_AGENT_RSA_SHA2_256)
return ssh_rsa_sha256.ssh_id;
return self->ssh_id;
}
static const struct ssh2_rsa_extra
rsa_extra = { 0 },
rsa_sha256_extra = { SSH_AGENT_RSA_SHA2_256 },
@ -869,6 +878,7 @@ const ssh_keyalg ssh_rsa = {
COMMON_KEYALG_FIELDS,
.ssh_id = "ssh-rsa",
.supported_flags = ssh_rsa_supported_flags,
.alternate_ssh_id = ssh_rsa_alternate_ssh_id,
.extra = &rsa_extra,
};
@ -876,6 +886,7 @@ const ssh_keyalg ssh_rsa_sha256 = {
COMMON_KEYALG_FIELDS,
.ssh_id = "rsa-sha2-256",
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.extra = &rsa_sha256_extra,
};
@ -883,6 +894,7 @@ const ssh_keyalg ssh_rsa_sha512 = {
COMMON_KEYALG_FIELDS,
.ssh_id = "rsa-sha2-512",
.supported_flags = nullkey_supported_flags,
.alternate_ssh_id = nullkey_alternate_ssh_id,
.extra = &rsa_sha512_extra,
};

5
ssh.h
View File

@ -835,6 +835,7 @@ struct ssh_keyalg {
/* 'Class methods' that don't deal with an ssh_key at all */
int (*pubkey_bits) (const ssh_keyalg *self, ptrlen blob);
unsigned (*supported_flags) (const ssh_keyalg *self);
const char *(*alternate_ssh_id) (const ssh_keyalg *self, unsigned flags);
/* Constant data fields giving information about the key type */
const char *ssh_id; /* string identifier in the SSH protocol */
@ -881,9 +882,13 @@ static inline const unsigned ssh_key_supported_flags(ssh_key *key)
{ return key->vt->supported_flags(key->vt); }
static inline const unsigned ssh_keyalg_supported_flags(const ssh_keyalg *self)
{ return self->supported_flags(self); }
static inline const char *ssh_keyalg_alternate_ssh_id(
const ssh_keyalg *self, unsigned flags)
{ return self->alternate_ssh_id(self, flags); }
/* Stub functions shared between multiple key types */
unsigned nullkey_supported_flags(const ssh_keyalg *self);
const char *nullkey_alternate_ssh_id(const ssh_keyalg *self, unsigned flags);
/*
* SSH2 ECDH key exchange vtable

View File

@ -640,17 +640,21 @@ static void ssh2_write_kexinit_lists(
alg->u.hk.hkflags = 0;
alg->u.hk.warn = false;
if (keyalg == &ssh_rsa) {
alg = ssh2_kexinit_addalg(&kexlists[KEXLIST_HOSTKEY],
"rsa-sha2-256");
alg->u.hk.hostkey = keyalg;
alg->u.hk.hkflags = SSH_AGENT_RSA_SHA2_256;
alg->u.hk.warn = false;
uint32_t supported_flags = ssh_keyalg_supported_flags(keyalg);
static const uint32_t try_flags[] = {
SSH_AGENT_RSA_SHA2_256,
SSH_AGENT_RSA_SHA2_512,
};
for (size_t i = 0; i < lenof(try_flags); i++) {
if (try_flags[i] & ~supported_flags)
continue; /* these flags not supported */
alg = ssh2_kexinit_addalg(
&kexlists[KEXLIST_HOSTKEY],
ssh_keyalg_alternate_ssh_id(keyalg, try_flags[i]));
alg = ssh2_kexinit_addalg(&kexlists[KEXLIST_HOSTKEY],
"rsa-sha2-512");
alg->u.hk.hostkey = keyalg;
alg->u.hk.hkflags = SSH_AGENT_RSA_SHA2_512;
alg->u.hk.hkflags = try_flags[i];
alg->u.hk.warn = false;
}
}

View File

@ -247,6 +247,31 @@ static PktIn *ssh2_userauth_pop(struct ssh2_userauth_state *s)
return pq_pop(s->ppl.in_pq);
}
static bool ssh2_userauth_signflags(struct ssh2_userauth_state *s,
unsigned *signflags, const char **algname)
{
*signflags = 0; /* default */
const ssh_keyalg *alg = find_pubkey_alg(*algname);
if (!alg)
return false; /* we don't know how to upgrade this */
unsigned supported_flags = ssh_keyalg_supported_flags(alg);
if (s->ppl.bpp->ext_info_rsa_sha512_ok &&
(supported_flags & SSH_AGENT_RSA_SHA2_512)) {
*signflags = SSH_AGENT_RSA_SHA2_512;
} else if (s->ppl.bpp->ext_info_rsa_sha256_ok &&
(supported_flags & SSH_AGENT_RSA_SHA2_256)) {
*signflags = SSH_AGENT_RSA_SHA2_256;
} else {
return false;
}
*algname = ssh_keyalg_alternate_ssh_id(alg, *signflags);
return true;
}
static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
{
struct ssh2_userauth_state *s =
@ -712,18 +737,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
* Attempt public-key authentication using a key from Pageant.
*/
s->agent_keyalg = s->agent_keys[s->agent_key_index].algorithm;
s->signflags = 0;
if (ptrlen_eq_string(s->agent_keyalg, "ssh-rsa")) {
/* Try to upgrade ssh-rsa to one of the rsa-sha2-* family,
* if the server has announced support for them. */
if (s->ppl.bpp->ext_info_rsa_sha512_ok) {
s->agent_keyalg = PTRLEN_LITERAL("rsa-sha2-512");
s->signflags = SSH_AGENT_RSA_SHA2_512;
} else if (s->ppl.bpp->ext_info_rsa_sha256_ok) {
s->agent_keyalg = PTRLEN_LITERAL("rsa-sha2-256");
s->signflags = SSH_AGENT_RSA_SHA2_256;
}
}
char *alg_tmp = mkstr(s->agent_keyalg);
const char *newalg = alg_tmp;
if (ssh2_userauth_signflags(s, &s->signflags, &newalg))
s->agent_keyalg = ptrlen_from_asciz(newalg);
sfree(alg_tmp);
s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
@ -845,18 +863,10 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
*
* First, try to upgrade its algorithm.
*/
if (!strcmp(s->publickey_algorithm, "ssh-rsa")) {
/* Try to upgrade ssh-rsa to one of the rsa-sha2-* family,
* if the server has announced support for them. */
if (s->ppl.bpp->ext_info_rsa_sha512_ok) {
sfree(s->publickey_algorithm);
s->publickey_algorithm = dupstr("rsa-sha2-512");
s->signflags = SSH_AGENT_RSA_SHA2_512;
} else if (s->ppl.bpp->ext_info_rsa_sha256_ok) {
sfree(s->publickey_algorithm);
s->publickey_algorithm = dupstr("rsa-sha2-256");
s->signflags = SSH_AGENT_RSA_SHA2_256;
}
const char *newalg = s->publickey_algorithm;
if (ssh2_userauth_signflags(s, &s->signflags, &newalg)) {
sfree(s->publickey_algorithm);
s->publickey_algorithm = dupstr(newalg);
}
/*

View File

@ -1,6 +1,13 @@
#include "misc.h"
#include "ssh.h"
unsigned nullkey_supported_flags(const ssh_keyalg *self)
{
return 0;
}
const char *nullkey_alternate_ssh_id(const ssh_keyalg *self, unsigned flags)
{
/* There are no alternate ids */
return self->ssh_id;
}