[PATCH] ssh-keygen: support public key import/export using SubjectPublicKeyInfo

Alon Bar-Lev alon.barlev at gmail.com
Sun Jul 29 04:23:17 EST 2012


ssh-keygen already supports importing and exporting ssh keys using
various formats.

The "-m PEM" which should have been the easiest to be used with
various of external application expects PKCS#1 encoded key, while
many applications use SubjectPublicKeyInfo encoded key.

This change adds SubjectPublicKeyInfo support, to ease integration
with applications.

Examples:
 ## convert SubjectPublicKeyInfo public key to SSH public key
 $ openssl req -newkey rsa:2048 -nodes -pubkey -subj "/CN=test" \
   -noout -keyout /dev/null | \
   ssh-keygen -i -m SUBJECTINFO -f /proc/self/fd/0

 ## convert X.509 certificate to SSH public key
 $ openssl req -newkey rsa:2048 -nodes -x509 -subj "/CN=test" \
   -keyout /dev/null | openssl x509 -pubkey -noout | \
   ssh-keygen -i -m SUBJECTINFO -f /proc/self/fd/0

 ## convert SSH public key to SubjectPublicKeyInfo public key
 $ ssh-keygen -e -m SUBJECTINFO -f ~/.ssh/id_rsa.pub | \
   openssl rsa -pubin -text

Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
---
 ssh-keygen.1 |    6 +++-
 ssh-keygen.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 3 deletions(-)

diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 41da207..88451ac 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -334,9 +334,11 @@ The supported key formats are:
 (RFC 4716/SSH2 public or private key),
 .Dq PKCS8
 (PEM PKCS8 public key)
-or
 .Dq PEM
-(PEM public key).
+(PEM public key)
+or
+.Dq SUBJECTINFO
+(SubjectPublicKeyInfo public key).
 The default conversion format is
 .Dq RFC4716 .
 .It Fl N Ar new_passphrase
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 5fcd3a1..072c49a 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -137,7 +137,8 @@ int convert_from = 0;
 enum {
 	FMT_RFC4716,
 	FMT_PKCS8,
-	FMT_PEM
+	FMT_PEM,
+	FMT_SUBJECTINFO
 } convert_format = FMT_RFC4716;
 int print_public = 0;
 int print_generic = 0;
@@ -330,6 +331,27 @@ do_convert_to_pem(Key *k)
 }
 
 static void
+do_convert_to_subjectinfo(Key *k)
+{
+	switch (key_type_plain(k->type)) {
+	case KEY_RSA:
+		if (!PEM_write_RSA_PUBKEY(stdout, k->rsa))
+			fatal("PEM_write_RSAPublicKey failed");
+		break;
+#if notyet /* OpenSSH 0.9.8 lacks this function */
+	case KEY_DSA:
+		if (!PEM_write_DSA_PUBKEY(stdout, k->dsa))
+			fatal("PEM_write_DSAPublicKey failed");
+		break;
+#endif
+	/* XXX ECDSA? */
+	default:
+		fatal("%s: unsupported key type %s", __func__, key_type(k));
+	}
+	exit(0);
+}
+
+static void
 do_convert_to(struct passwd *pw)
 {
 	Key *k;
@@ -360,6 +382,9 @@ do_convert_to(struct passwd *pw)
 	case FMT_PEM:
 		do_convert_to_pem(k);
 		break;
+	case FMT_SUBJECTINFO:
+		do_convert_to_subjectinfo(k);
+		break;
 	default:
 		fatal("%s: unknown key format %d", __func__, convert_format);
 	}
@@ -631,6 +656,38 @@ do_convert_from_pem(Key **k, int *private)
 }
 
 static void
+do_convert_from_subjectinfo(Key **k, int *private)
+{
+	FILE *fp;
+	RSA *rsa;
+#ifdef notyet
+	DSA *dsa;
+#endif
+
+	if ((fp = fopen(identity_file, "r")) == NULL)
+		fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+	if ((rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL)) != NULL) {
+		*k = key_new(KEY_UNSPEC);
+		(*k)->type = KEY_RSA;
+		(*k)->rsa = rsa;
+		fclose(fp);
+		return;
+	}
+#if notyet /* OpenSSH 0.9.8 lacks this function */
+	rewind(fp);
+	if ((dsa = PEM_read_DSA_PUBKEY(fp, NULL, NULL, NULL)) != NULL) {
+		*k = key_new(KEY_UNSPEC);
+		(*k)->type = KEY_DSA;
+		(*k)->dsa = dsa;
+		fclose(fp);
+		return;
+	}
+	/* XXX ECDSA */
+#endif
+	fatal("%s: unrecognised subjectinfo public key format", __func__);
+}
+
+static void
 do_convert_from(struct passwd *pw)
 {
 	Key *k = NULL;
@@ -652,6 +709,9 @@ do_convert_from(struct passwd *pw)
 	case FMT_PEM:
 		do_convert_from_pem(&k, &private);
 		break;
+	case FMT_SUBJECTINFO:
+		do_convert_from_subjectinfo(&k, &private);
+		break;
 	default:
 		fatal("%s: unknown key format %d", __func__, convert_format);
 	}
@@ -2005,6 +2065,10 @@ main(int argc, char **argv)
 				convert_format = FMT_PEM;
 				break;
 			}
+			if (strcasecmp(optarg, "SUBJECTINFO") == 0) {
+				convert_format = FMT_SUBJECTINFO;
+				break;
+			}
 			fatal("Unsupported conversion format \"%s\"", optarg);
 		case 'n':
 			cert_principals = optarg;
-- 
1.7.8.6



More information about the openssh-unix-dev mailing list