Patch for ssh-keygen to allow conversion of public key to openssh format

Lars Nordin Lars.Nordin at SDlabs.se
Mon Sep 10 04:54:26 EST 2012


Hi,

I needed to convert a public RSA key to autorized_keys format and found 
ssh-keygen lacking this feature.

I made the option -Q publicfile to allow an conversion like
ssh-keygen -Q pubrsa.pem -y

The patch is produced using unified diff and made on latest release.

If you like it and can make a patch for the man-page also!

Regards,
/Lars
-------------- next part --------------
diff -u openssh-6.1p1/authfile.c openssh-6.1p1-lano/authfile.c
--- openssh-6.1p1/authfile.c	2012-02-10 22:19:02.000000000 +0100
+++ openssh-6.1p1-lano/authfile.c	2012-09-08 11:59:08.000000000 +0200
@@ -792,6 +792,58 @@
 	return 0;
 }
 
+Key *
+key_load_public_pem(char *filename, char **commentp)
+{
+	FILE *fp = NULL;
+	EVP_PKEY *pk = NULL;
+	X509 *x = NULL;
+	Key *pub = NULL;
+	char *name = "<no key>";
+
+	fp = fopen(filename, "r");
+	if (fp == NULL) {
+		error("fopen of %s failed: %s", filename, strerror(errno));
+		return NULL;
+	}
+	x = PEM_read_X509(fp, NULL, NULL, NULL);
+	if (x == NULL) {
+		debug3("Not X509 format, try public key format");
+		rewind(fp);
+		pk = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
+	} else {
+		pk = X509_get_pubkey(x);
+	}
+	if (pk == NULL) {
+		debug("PEM_read_PUBKEY() file %s failed", filename);
+		debug3("%s", ERR_error_string(ERR_get_error(), NULL));
+		if (x != NULL)
+			X509_free(x);
+		return NULL;
+	} else {
+		pub = key_new(KEY_UNSPEC);
+		pub->rsa = RSAPublicKey_dup(EVP_PKEY_get1_RSA(pk));
+		pub->type = KEY_RSA;
+		name = "rsa w/o comment";
+#ifdef DEBUG_PK
+		RSA_print_fp(stderr, prv->rsa, 8);
+#endif
+	}
+
+	fclose(fp);
+
+	if (pk != NULL)
+		EVP_PKEY_free(pk);
+	if (x != NULL)
+		X509_free(x);
+
+	if (pub != NULL && commentp)
+		*commentp = xstrdup(name);
+	debug("read PEM public key done: type %s",
+	    pub ? key_type(pub) : "<unknown>");
+	return pub;
+}
+
 /* load public key from ssh v1 private or any pubkey file */
 Key *
 key_load_public(const char *filename, char **commentp)
@@ -799,6 +851,11 @@
 	Key *pub;
 	char file[MAXPATHLEN];
 
+ 	/* try PEM public */
+        pub = key_load_public_pem(filename, commentp);
+        if (pub != NULL)
+                return pub;
+
 	/* try rsa1 private key */
 	pub = key_load_public_type(KEY_RSA1, filename, commentp);
 	if (pub != NULL)
diff -u openssh-6.1p1/config.status openssh-6.1p1-lano/config.status
--- openssh-6.1p1/config.status	2012-09-07 11:01:15.000000000 +0200
+++ openssh-6.1p1-lano/config.status	2012-09-08 11:59:38.000000000 +0200
@@ -445,7 +445,7 @@
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
-ac_pwd='/work/src/openssh-6.1p1'
+ac_pwd='/work/src/openssh-6.1p1-lano'
 srcdir='.'
 INSTALL='/usr/bin/install -c'
 AWK='gawk'
Common subdirectories: openssh-6.1p1/contrib and openssh-6.1p1-lano/contrib
Common subdirectories: openssh-6.1p1/openbsd-compat and openssh-6.1p1-lano/openbsd-compat
Common subdirectories: openssh-6.1p1/regress and openssh-6.1p1-lano/regress
Common subdirectories: openssh-6.1p1/scard and openssh-6.1p1-lano/scard
diff -u openssh-6.1p1/ssh-keygen.c openssh-6.1p1-lano/ssh-keygen.c
--- openssh-6.1p1/ssh-keygen.c	2012-07-31 04:20:44.000000000 +0200
+++ openssh-6.1p1-lano/ssh-keygen.c	2012-09-07 09:26:01.000000000 +0200
@@ -141,6 +141,7 @@
 } convert_format = FMT_RFC4716;
 int print_public = 0;
 int print_generic = 0;
+int read_public_only = 0;
 
 char *key_type_name = NULL;
 
@@ -240,6 +241,13 @@
 	char *pass;
 	Key *prv;
 
+	 if (read_public_only) {
+                Key *pub;
+
+                pub = key_load_public(filename, NULL);
+                return pub;
+        }
+
 	prv = key_load_private(filename, "", NULL);
 	if (prv == NULL) {
 		if (identity_passphrase)
@@ -705,7 +713,13 @@
 		perror(identity_file);
 		exit(1);
 	}
-	prv = load_identity(identity_file);
+
+ 	if (read_public_only == 1) {
+                prv = key_load_public(identity_file, NULL);
+        } else {
+                prv = load_identity(identity_file);
+        }
+
 	if (prv == NULL) {
 		fprintf(stderr, "load failed\n");
 		exit(1);
@@ -1963,7 +1977,7 @@
 	}
 
 	while ((opt = getopt(argc, argv, "AegiqpclBHLhvxXyF:b:f:t:D:I:J:j:K:P:"
-	    "m:N:n:O:C:r:g:R:T:G:M:S:s:a:V:W:z")) != -1) {
+	    "m:N:n:O:C:r:g:R:T:G:M:S:s:a:V:W:zQ:")) != -1) {
 		switch (opt) {
 		case 'A':
 			gen_all_hostkeys = 1;
@@ -2129,6 +2143,14 @@
 			if (BN_hex2bn(&start, optarg) == 0)
 				fatal("Invalid start point.");
 			break;
+        	case 'Q':
+                        if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
+                            sizeof(identity_file))
+                                fatal("Identity filename too long");
+                        have_identity = 1;
+                        print_public = 1;
+                        read_public_only = 1;
+                        break;
 		case 'V':
 			parse_cert_times(optarg);
 			break;


More information about the openssh-unix-dev mailing list