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

Darren Tucker dtucker at dtucker.net
Fri Mar 19 18:17:27 AEDT 2021


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 at 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 at openssh.com" : "ssh-dss";
+		algs = "ssh-dss";
+		break;
+	case KT_DSA_CERT:
+		algs = "ssh-dss-cert-v01 at openssh.com";
 		break;
 	case KT_RSA:
-		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
-		    "rsa-sha2-512-cert-v01 at openssh.com,"
-		    "rsa-sha2-256-cert-v01 at openssh.com,"
-		    "ssh-rsa-cert-v01 at 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 at openssh.com,"
+		    "rsa-sha2-256-cert-v01 at openssh.com,"
+		    "ssh-rsa-cert-v01 at openssh.com";
+		break;
 	case KT_ED25519:
-		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
-		    "ssh-ed25519-cert-v01 at openssh.com" : "ssh-ed25519";
+		algs = "ssh-ed25519";
+		break;
+	case KT_ED25519_CERT:
+		algs = "ssh-ed25519-cert-v01 at openssh.com";
 		break;
 	case KT_XMSS:
-		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
-		    "ssh-xmss-cert-v01 at openssh.com" : "ssh-xmss at openssh.com";
+		algs = "ssh-xmss at openssh.com";
+		break;
+	case KT_XMSS_CERT:
+		algs = "ssh-xmss-cert-v01 at openssh.com";
 		break;
 	case KT_ECDSA:
-		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
-		    "ecdsa-sha2-nistp256-cert-v01 at openssh.com,"
-		    "ecdsa-sha2-nistp384-cert-v01 at openssh.com,"
-		    "ecdsa-sha2-nistp521-cert-v01 at 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 at openssh.com,"
+		    "ecdsa-sha2-nistp384-cert-v01 at openssh.com,"
+		    "ecdsa-sha2-nistp521-cert-v01 at openssh.com";
+		break;
 	case KT_ECDSA_SK:
-		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
-		    "sk-ecdsa-sha2-nistp256-cert-v01 at openssh.com" :
-		    "sk-ecdsa-sha2-nistp256 at openssh.com";
+		algs = "sk-ecdsa-sha2-nistp256 at openssh.com";
+		break;
+	case KT_ECDSA_SK_CERT:
+		algs = "sk-ecdsa-sha2-nistp256-cert-v01 at openssh.com";
 		break;
 	case KT_ED25519_SK:
-		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
-		    "sk-ssh-ed25519-cert-v01 at openssh.com" :
-		    "sk-ssh-ed25519 at openssh.com";
+		algs = "sk-ssh-ed25519 at openssh.com";
+		break;
+	case KT_ED25519_SK_CERT:
+		algs = "sk-ssh-ed25519-cert-v01 at 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.


More information about the openssh-unix-dev mailing list