ssh-keygen private keys export - new feature

Christian LESTRADE christian.lestrade at free.fr
Fri May 20 07:42:06 EST 2005


Hello,

I had some difficulties in order to convert private keys between different
implementations of SSH.

So, I wrote the following patch to allow export of SSH2 RSA and DSA private
keys into IETF SECSH format.

Note that I also slightly revised the IETF SECSH key import code.

Usage: use of the "-e" option on a private key file generates an unencrypted
private key file in IETF SECSH format.


I suggest you incorporate this patch into both the OpenBSD and portable
OpenSSH.


--- authfile.c.orig	2004-12-11 03:39:50.000000000 +0100
+++ authfile.c	2005-05-19 22:16:51.000000000 +0200
@@ -598,7 +598,7 @@
  	return prv;
  }

-static int
+int
  key_try_load_public(Key *k, const char *filename, char **commentp)
  {
  	FILE *f;
--- authfile.h.orig	2002-06-06 21:57:34.000000000 +0200
+++ authfile.h	2005-05-19 23:03:35.000000000 +0200
@@ -18,6 +18,7 @@
  int	 key_save_private(Key *, const char *, const char *, const char *);
  Key	*key_load_public(const char *, char **);
  Key	*key_load_public_type(int, const char *, char **);
+int	key_try_load_public(Key *, const char *, char **);
  Key	*key_load_private(const char *, const char *, char **);
  Key	*key_load_private_type(int, const char *, const char *, char **);
  Key	*key_load_private_pem(int, int, const char *, char **);
--- ssh-keygen.c.orig	2005-03-02 02:33:04.000000000 +0100
+++ ssh-keygen.c	2005-05-19 22:20:02.000000000 +0200
@@ -24,6 +24,7 @@
  #include "uuencode.h"
  #include "buffer.h"
  #include "bufaux.h"
+#include "getput.h"
  #include "pathnames.h"
  #include "log.h"
  #include "misc.h"
@@ -152,8 +153,104 @@
  #define SSH_COM_PUBLIC_BEGIN		"---- BEGIN SSH2 PUBLIC KEY ----"
  #define SSH_COM_PUBLIC_END		"---- END SSH2 PUBLIC KEY ----"
  #define SSH_COM_PRIVATE_BEGIN		"---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
+#define SSH_COM_PRIVATE_END		"---- END SSH2 ENCRYPTED PRIVATE KEY ----"
  #define	SSH_COM_PRIVATE_KEY_MAGIC	0x3f6ff9eb

+static int
+buffer_put_bignum_bits(Buffer *b, const BIGNUM *value)
+{
+	u_int bignum_bits = BN_num_bits(value);
+	u_int bytes = (bignum_bits + 7) / 8;
+	u_char *buf = xmalloc(bytes);
+	int oi;
+
+	/* Get the value of in binary */
+	oi = BN_bn2bin(value, buf);
+	if (oi != bytes) {
+		error("buffer_put_bignum_bits: BN_bn2bin() failed: oi %d != bytes %d",
+		    oi, bytes);
+		return (-1);
+	}
+
+	buffer_put_int(b, bignum_bits);
+	/* Store the binary data. */
+	buffer_append(b, (char *)buf, oi);
+
+	memset(buf, 0, bytes);
+	xfree(buf);
+
+	return (0);
+}
+
+static int
+do_convert_private_ssh2_to_blob(const Key *key, u_char **blobp, u_int *lenp)
+{
+	Buffer b;
+	int len, len1;
+	char *pb;
+
+	if (key == NULL) {
+		error("do_convert_private_ssh2_to_blob: key == NULL");
+		return 0;
+	}
+	buffer_init(&b);
+	buffer_put_int(&b, SSH_COM_PRIVATE_KEY_MAGIC);
+	buffer_put_int(&b, 0);
+
+	switch (key->type) {
+	case KEY_DSA:
+	       	buffer_put_cstring(&b, "dl-modp{sign{dsa-nist-sha1},dh{plain}}");
+		break;
+	case KEY_RSA:
+	       	buffer_put_cstring(&b, "if-modn{sign{rsa-pkcs1-md5}}");
+		break;
+	default:
+		error("do_convert_private_ssh2_to_blob: unsupported key type %d",
+		      key->type);
+		buffer_free(&b);
+		return 0;
+	}
+
+       	buffer_put_cstring(&b, "none");
+
+	len1 = buffer_len(&b);
+	buffer_put_int(&b, 0);
+	buffer_put_int(&b, 0);
+
+	switch (key->type) {
+	case KEY_DSA:
+		buffer_put_int(&b, 0);
+		buffer_put_bignum_bits(&b, key->dsa->p);
+		buffer_put_bignum_bits(&b, key->dsa->g);
+		buffer_put_bignum_bits(&b, key->dsa->q);
+		buffer_put_bignum_bits(&b, key->dsa->pub_key);
+		buffer_put_bignum_bits(&b, key->dsa->priv_key);
+		break;
+	case KEY_RSA:
+		buffer_put_bignum_bits(&b, key->rsa->e);
+		buffer_put_bignum_bits(&b, key->rsa->d);
+		buffer_put_bignum_bits(&b, key->rsa->n);
+		buffer_put_bignum_bits(&b, key->rsa->iqmp);
+		buffer_put_bignum_bits(&b, key->rsa->q);
+		buffer_put_bignum_bits(&b, key->rsa->p);
+		break;
+	}
+	len = buffer_len(&b);
+	if (lenp != NULL)
+		*lenp = len;
+	pb = buffer_ptr(&b);
+	PUT_32BIT(pb + 4, len);
+	PUT_32BIT(pb + len1, len - len1 - 4);
+	PUT_32BIT(pb + len1 + 4, len - len1 - 8);
+	if (blobp != NULL) {
+		*blobp = xmalloc(len);
+		memcpy(*blobp, pb, len);
+	}
+	memset(pb, 0, len);
+	buffer_free(&b);
+	return len;
+}
+
  static void
  do_convert_to_ssh2(struct passwd *pw)
  {
@@ -161,6 +258,7 @@
  	u_int len;
  	u_char *blob;
  	struct stat st;
+	int private = 0;

  	if (!have_identity)
  		ask_filename(pw, "Enter file in which the key is");
@@ -168,27 +266,39 @@
  		perror(identity_file);
  		exit(1);
  	}
-	if ((k = key_load_public(identity_file, NULL)) == NULL) {
+	k = key_new(KEY_UNSPEC);
+	if (key_try_load_public(k, identity_file, NULL) != 1) {
  		if ((k = load_identity(identity_file)) == NULL) {
  			fprintf(stderr, "load failed\n");
  			exit(1);
  		}
+		private = 1;
  	}
  	if (k->type == KEY_RSA1) {
  		fprintf(stderr, "version 1 keys are not supported\n");
  		exit(1);
  	}
-	if (key_to_blob(k, &blob, &len) <= 0) {
-		fprintf(stderr, "key_to_blob failed\n");
-		exit(1);
+	if (private) {
+		if (do_convert_private_ssh2_to_blob(k, &blob, &len) <= 0) {
+			fprintf(stderr, "do_convert_private_ssh2_to_blob failed\n");
+			exit(1);
+		}
  	}
-	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
+	else {
+		if (key_to_blob(k, &blob, &len) <= 0) {
+			fprintf(stderr, "key_to_blob failed\n");
+			exit(1);
+		}
+	}
+	fprintf(stdout, "%s\n",
+	    private?SSH_COM_PRIVATE_BEGIN:SSH_COM_PUBLIC_BEGIN);
  	fprintf(stdout,
  	    "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
  	    key_size(k), key_type(k),
  	    pw->pw_name, hostname);
  	dump_base64(stdout, blob, len);
-	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
+	fprintf(stdout, "%s\n",
+	    private?SSH_COM_PRIVATE_END:SSH_COM_PUBLIC_END);
  	key_free(k);
  	xfree(blob);
  	exit(0);
@@ -216,7 +326,6 @@
  	u_char *sig, data[] = "abcde12345";
  	int magic, rlen, ktype, i1, i2, i3, i4;
  	u_int slen;
-	u_long e;

  	buffer_init(&b);
  	buffer_append(&b, blob, blen);
@@ -232,8 +341,7 @@
  	cipher = buffer_get_string(&b, NULL);
  	i2 = buffer_get_int(&b);
  	i3 = buffer_get_int(&b);
-	i4 = buffer_get_int(&b);
-	debug("ignore (%d %d %d %d)", i1,i2,i3,i4);
+	debug("ignore (%d %d %d)", i1,i2,i3);
  	if (strcmp(cipher, "none") != 0) {
  		error("unsupported cipher %s", cipher);
  		xfree(cipher);
@@ -257,6 +365,7 @@

  	switch (key->type) {
  	case KEY_DSA:
+		i4 = buffer_get_int(&b);
  		buffer_get_bignum_bits(&b, key->dsa->p);
  		buffer_get_bignum_bits(&b, key->dsa->g);
  		buffer_get_bignum_bits(&b, key->dsa->q);
@@ -264,21 +373,7 @@
  		buffer_get_bignum_bits(&b, key->dsa->priv_key);
  		break;
  	case KEY_RSA:
-		e  = buffer_get_char(&b);
-		debug("e %lx", e);
-		if (e < 30) {
-			e <<= 8;
-			e += buffer_get_char(&b);
-			debug("e %lx", e);
-			e <<= 8;
-			e += buffer_get_char(&b);
-			debug("e %lx", e);
-		}
-		if (!BN_set_word(key->rsa->e, e)) {
-			buffer_free(&b);
-			key_free(key);
-			return NULL;
-		}
+		buffer_get_bignum_bits(&b, key->rsa->e);
  		buffer_get_bignum_bits(&b, key->rsa->d);
  		buffer_get_bignum_bits(&b, key->rsa->n);
  		buffer_get_bignum_bits(&b, key->rsa->iqmp);





More information about the openssh-unix-dev mailing list