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);