Mailing List Archive

Feature Request: Allow certificate types in ssh-keyscan -t
Hello.

I would like for the ssh-keyscan(1) -t argument (key type) to support
the certificate types too (such as ssh-ed25519-cert-v01@openssh.com), as
from `ssh -Q key`.

This would allow to dump remote host certificates, useful for various
situations like certificate expiration monitoring.

Regards,
Aaron Jones
Re: Feature Request: Allow certificate types in ssh-keyscan -t [ In reply to ]
On Thu, Mar 18, 2021 at 10:12:30PM +0000, Aaron Jones wrote:
> Hello.
>
> I would like for the ssh-keyscan(1) -t argument (key type) to support
> the certificate types too (such as ssh-ed25519-cert-v01@openssh.com), as
> from `ssh -Q key`.

Please try this patch. It is slightly complicated by the existing
behaviour where adding "-c" will get cert type corresponding to the
specified plain types and I have attempted to maintain the existing
behaviour.

Index: ssh-keyscan.c
===================================================================
RCS file: /export/cvs/src/usr.bin/ssh/ssh-keyscan.c,v
retrieving revision 1.139
diff -u -p -r1.139 ssh-keyscan.c
--- ssh-keyscan.c 27 Jan 2021 09:26:54 -0000 1.139
+++ ssh-keyscan.c 19 Mar 2021 07:14:47 -0000
@@ -50,6 +50,10 @@ int IPv4or6 = AF_UNSPEC;

int ssh_port = SSH_DEFAULT_PORT;

+/*
+ * Key types. Note that the certificate types must appear after the non-cert
+ * types and in the same order so that -c "promotion" still works.
+ */
#define KT_DSA (1)
#define KT_RSA (1<<1)
#define KT_ECDSA (1<<2)
@@ -57,9 +61,18 @@ int ssh_port = SSH_DEFAULT_PORT;
#define KT_XMSS (1<<4)
#define KT_ECDSA_SK (1<<5)
#define KT_ED25519_SK (1<<6)
+#define KT_DSA_CERT (1<<7)
+#define KT_RSA_CERT (1<<8)
+#define KT_ECDSA_CERT (1<<9)
+#define KT_ED25519_CERT (1<<10)
+#define KT_XMSS_CERT (1<<11)
+#define KT_ECDSA_SK_CERT (1<<12)
+#define KT_ED25519_SK_CERT (1<<13)

+#define KT_NUM_KEYTYPES 14
#define KT_MIN KT_DSA
-#define KT_MAX KT_ED25519_SK
+#define KT_MIN_CERT KT_DSA_CERT
+#define KT_MAX KT_ED25519_SK_CERT

int get_cert = 0;
int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519|KT_ECDSA_SK|KT_ED25519_SK;
@@ -211,54 +224,66 @@ ssh2_capable(int remote_major, int remot
static void
keygrab_ssh2(con *c)
{
- char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
+ char *algs = NULL, *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
int r;

switch (c->c_keytype) {
case KT_DSA:
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
- "ssh-dss-cert-v01@openssh.com" : "ssh-dss";
+ algs = "ssh-dss";
+ break;
+ case KT_DSA_CERT:
+ algs = "ssh-dss-cert-v01@openssh.com";
break;
case KT_RSA:
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
- "rsa-sha2-512-cert-v01@openssh.com,"
- "rsa-sha2-256-cert-v01@openssh.com,"
- "ssh-rsa-cert-v01@openssh.com" :
- "rsa-sha2-512,"
+ algs = "rsa-sha2-512,"
"rsa-sha2-256,"
"ssh-rsa";
break;
+ case KT_RSA_CERT:
+ algs = "rsa-sha2-512-cert-v01@openssh.com,"
+ "rsa-sha2-256-cert-v01@openssh.com,"
+ "ssh-rsa-cert-v01@openssh.com";
+ break;
case KT_ED25519:
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
- "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519";
+ algs = "ssh-ed25519";
+ break;
+ case KT_ED25519_CERT:
+ algs = "ssh-ed25519-cert-v01@openssh.com";
break;
case KT_XMSS:
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
- "ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com";
+ algs = "ssh-xmss@openssh.com";
+ break;
+ case KT_XMSS_CERT:
+ algs = "ssh-xmss-cert-v01@openssh.com";
break;
case KT_ECDSA:
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
- "ecdsa-sha2-nistp256-cert-v01@openssh.com,"
- "ecdsa-sha2-nistp384-cert-v01@openssh.com,"
- "ecdsa-sha2-nistp521-cert-v01@openssh.com" :
- "ecdsa-sha2-nistp256,"
+ algs = "ecdsa-sha2-nistp256,"
"ecdsa-sha2-nistp384,"
"ecdsa-sha2-nistp521";
break;
+ case KT_ECDSA_CERT:
+ algs = "ecdsa-sha2-nistp256-cert-v01@openssh.com,"
+ "ecdsa-sha2-nistp384-cert-v01@openssh.com,"
+ "ecdsa-sha2-nistp521-cert-v01@openssh.com";
+ break;
case KT_ECDSA_SK:
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
- "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" :
- "sk-ecdsa-sha2-nistp256@openssh.com";
+ algs = "sk-ecdsa-sha2-nistp256@openssh.com";
+ break;
+ case KT_ECDSA_SK_CERT:
+ algs = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com";
break;
case KT_ED25519_SK:
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
- "sk-ssh-ed25519-cert-v01@openssh.com" :
- "sk-ssh-ed25519@openssh.com";
+ algs = "sk-ssh-ed25519@openssh.com";
+ break;
+ case KT_ED25519_SK_CERT:
+ algs = "sk-ssh-ed25519-cert-v01@openssh.com";
break;
default:
fatal("unknown key type %d", c->c_keytype);
break;
}
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = algs;
+
if ((r = kex_setup(c->c_ssh, myproposal)) != 0) {
free(c->c_ssh);
fprintf(stderr, "kex_setup: %s\n", ssh_err(r));
@@ -707,24 +732,45 @@ main(int argc, char **argv)
case KEY_DSA:
get_keytypes |= KT_DSA;
break;
+ case KEY_DSA_CERT:
+ get_keytypes |= KT_DSA_CERT;
+ break;
case KEY_ECDSA:
get_keytypes |= KT_ECDSA;
break;
+ case KEY_ECDSA_CERT:
+ get_keytypes |= KT_ECDSA_CERT;
+ break;
case KEY_RSA:
get_keytypes |= KT_RSA;
break;
+ case KEY_RSA_CERT:
+ get_keytypes |= KT_RSA_CERT;
+ break;
case KEY_ED25519:
get_keytypes |= KT_ED25519;
break;
+ case KEY_ED25519_CERT:
+ get_keytypes |= KT_ED25519_CERT;
+ break;
case KEY_XMSS:
get_keytypes |= KT_XMSS;
break;
+ case KEY_XMSS_CERT:
+ get_keytypes |= KT_XMSS_CERT;
+ break;
case KEY_ED25519_SK:
get_keytypes |= KT_ED25519_SK;
break;
+ case KEY_ED25519_SK_CERT:
+ get_keytypes |= KT_ED25519_SK_CERT;
+ break;
case KEY_ECDSA_SK:
get_keytypes |= KT_ECDSA_SK;
break;
+ case KEY_ECDSA_SK_CERT:
+ get_keytypes |= KT_ECDSA_SK_CERT;
+ break;
case KEY_UNSPEC:
default:
fatal("Unknown key type \"%s\"", tname);
@@ -747,6 +793,22 @@ main(int argc, char **argv)
usage();

log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
+
+ /*
+ * If -c is specified, promote non-cert to corresponding cert types
+ * to maintain previous behaviour. This relies on the cert key types
+ * being in the second half of the bit vector and being in the same
+ * order as the corresponding plain key types.
+ */
+ if (get_cert) {
+ if (get_keytypes >= KT_MIN_CERT)
+ fatal("Both explicit certificate types and -c "
+ "specified");
+ opt = get_keytypes << (KT_NUM_KEYTYPES / 2);
+ debug3_f("-c specified, promoted keytypes 0x%x -> 0x%x",
+ get_keytypes, opt);
+ get_keytypes = opt;
+ }

maxfd = fdlim_get(1);
if (maxfd < 0)

--
Darren Tucker (dtucker at dtucker.net)
GPG key 11EAA6FA / A86E 3E07 5B19 5880 E860 37F4 9357 ECEF 11EA A6FA (new)
Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: Feature Request: Allow certificate types in ssh-keyscan -t [ In reply to ]
On 19/03/2021 07:17, Darren Tucker wrote:
> Please try this patch. It is slightly complicated by the existing
> behaviour where adding "-c" will get cert type corresponding to the
> specified plain types and I have attempted to maintain the existing
> behaviour.

This works nicely! I will overlay it into my local build unless/until an
upstream version is released with it.

An application interfacing with this could be made to use -c, but it
would have to be coded with a list of corresponding plain key types, to
know which plain key type to pass to -c -t when it wants a cert, which
would just complicate things. Supporting the cert type directly is much
easier, and cleaner.

Thank you.

Regards,
Aaron Jones