summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2013-10-20 21:06:18 +0800
committerMatt Johnston <matt@ucc.asn.au>2013-10-20 21:06:18 +0800
commit7fda6418e15a92fd538a5e72682de94f90b6e060 (patch)
tree96bb4f07062b1282cee6c368e5b9e0873110ade1
parentaafeebd0c841494e4f7315890bc97ed0daf99cbd (diff)
writing out openssh ecc keys works
--HG-- branch : ecc
-rw-r--r--dropbearconvert.c15
-rw-r--r--keyimport.c449
2 files changed, 263 insertions, 201 deletions
diff --git a/dropbearconvert.c b/dropbearconvert.c
index 01fe373..958ced6 100644
--- a/dropbearconvert.c
+++ b/dropbearconvert.c
@@ -28,6 +28,8 @@
#include "buffer.h"
#include "dbutil.h"
#include "keyimport.h"
+#include "crypto_desc.h"
+#include "random.h"
static int do_convert(int intype, const char* infile, int outtype,
@@ -114,7 +116,7 @@ static int do_convert(int intype, const char* infile, int outtype,
const char* outfile) {
sign_key * key = NULL;
- char * keytype = NULL;
+ const char * keytype = NULL;
int ret = 1;
key = import_read(infile, NULL, intype);
@@ -124,16 +126,7 @@ static int do_convert(int intype, const char* infile, int outtype,
goto out;
}
-#ifdef DROPBEAR_RSA
- if (key->rsakey != NULL) {
- keytype = "RSA";
- }
-#endif
-#ifdef DROPBEAR_DSS
- if (key->dsskey != NULL) {
- keytype = "DSS";
- }
-#endif
+ keytype = signkey_name_from_type(key->type, NULL);
fprintf(stderr, "Key is a %s key\n", keytype);
diff --git a/keyimport.c b/keyimport.c
index 05bf800..f513e8a 100644
--- a/keyimport.c
+++ b/keyimport.c
@@ -2,8 +2,6 @@
* Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com
* keyfiles.
*
- * The horribleness of the code is probably mine (matt).
- *
* Modifications copyright 2003 Matt Johnston
*
* PuTTY is copyright 1997-2003 Simon Tatham.
@@ -38,9 +36,9 @@
#include "dbutil.h"
#include "ecc.h"
-const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
-const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
-const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
+static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
+static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
+static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
#define PUT_32BIT(cp, value) do { \
(cp)[3] = (unsigned char)(value); \
@@ -130,6 +128,8 @@ static sign_key *dropbear_read(const char* filename) {
}
buf_free(buf);
+ ret->type = type;
+
return ret;
error:
@@ -145,23 +145,11 @@ error:
/* returns 0 on fail, 1 on success */
static int dropbear_write(const char*filename, sign_key * key) {
- int keytype = -1;
buffer * buf;
FILE*fp;
int len;
int ret;
-#ifdef DROPBEAR_RSA
- if (key->rsakey != NULL) {
- keytype = DROPBEAR_SIGNKEY_RSA;
- }
-#endif
-#ifdef DROPBEAR_DSS
- if (key->dsskey != NULL) {
- keytype = DROPBEAR_SIGNKEY_DSS;
- }
-#endif
-
buf = buf_new(MAX_PRIVKEY_SIZE);
buf_put_priv_key(buf, key, key->type);
@@ -616,8 +604,10 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
if (key->type == OSSH_DSA) {
buf_putstring(blobbuf, "ssh-dss", 7);
+ retkey->type = DROPBEAR_SIGNKEY_DSS;
} else if (key->type == OSSH_RSA) {
buf_putstring(blobbuf, "ssh-rsa", 7);
+ retkey->type = DROPBEAR_SIGNKEY_RSA;
}
for (i = 0; i < num_integers; i++) {
@@ -675,7 +665,6 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
#ifdef DROPBEAR_ECDSA
if (key->type == OSSH_EC) {
- const char* ecdsa_name;
unsigned char* private_key_bytes = NULL;
int private_key_len = 0;
unsigned char* public_key_bytes = NULL;
@@ -827,202 +816,282 @@ static int openssh_write(const char *filename, sign_key *key,
char zero[1];
int ret = 0;
FILE *fp;
- int keytype = -1;
#ifdef DROPBEAR_RSA
mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
-
- if (key->rsakey != NULL) {
- keytype = DROPBEAR_SIGNKEY_RSA;
- }
-#endif
-#ifdef DROPBEAR_DSS
- if (key->dsskey != NULL) {
- keytype = DROPBEAR_SIGNKEY_DSS;
- }
#endif
- dropbear_assert(keytype != -1);
+ if (key->type == DROPBEAR_SIGNKEY_RSA || key->type == DROPBEAR_SIGNKEY_DSS)
+ {
+ /*
+ * Fetch the key blobs.
+ */
+ keyblob = buf_new(3000);
+ buf_put_priv_key(keyblob, key, key->type);
- /*
- * Fetch the key blobs.
- */
- keyblob = buf_new(3000);
- buf_put_priv_key(keyblob, key, keytype);
+ buf_setpos(keyblob, 0);
+ /* skip the "ssh-rsa" or "ssh-dss" header */
+ buf_incrpos(keyblob, buf_getint(keyblob));
- buf_setpos(keyblob, 0);
- /* skip the "ssh-rsa" or "ssh-dss" header */
- buf_incrpos(keyblob, buf_getint(keyblob));
+ /*
+ * Find the sequence of integers to be encoded into the OpenSSH
+ * key blob, and also decide on the header line.
+ */
+ numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
- /*
- * Find the sequence of integers to be encoded into the OpenSSH
- * key blob, and also decide on the header line.
- */
- numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
+ #ifdef DROPBEAR_RSA
+ if (key->type == DROPBEAR_SIGNKEY_RSA) {
-#ifdef DROPBEAR_RSA
- if (keytype == DROPBEAR_SIGNKEY_RSA) {
+ if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
+ fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
+ goto error;
+ }
- if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
- fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
- goto error;
- }
+ /* e */
+ numbers[2].bytes = buf_getint(keyblob);
+ numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
+ buf_incrpos(keyblob, numbers[2].bytes);
+
+ /* n */
+ numbers[1].bytes = buf_getint(keyblob);
+ numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
+ buf_incrpos(keyblob, numbers[1].bytes);
+
+ /* d */
+ numbers[3].bytes = buf_getint(keyblob);
+ numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
+ buf_incrpos(keyblob, numbers[3].bytes);
+
+ /* p */
+ numbers[4].bytes = buf_getint(keyblob);
+ numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
+ buf_incrpos(keyblob, numbers[4].bytes);
+
+ /* q */
+ numbers[5].bytes = buf_getint(keyblob);
+ numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
+ buf_incrpos(keyblob, numbers[5].bytes);
+
+ /* now calculate some extra parameters: */
+ m_mp_init(&tmpval);
+ m_mp_init(&dmp1);
+ m_mp_init(&dmq1);
+ m_mp_init(&iqmp);
+
+ /* dmp1 = d mod (p-1) */
+ if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
+ fprintf(stderr, "Bignum error for p-1\n");
+ goto error;
+ }
+ if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
+ fprintf(stderr, "Bignum error for dmp1\n");
+ goto error;
+ }
- /* e */
- numbers[2].bytes = buf_getint(keyblob);
- numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
- buf_incrpos(keyblob, numbers[2].bytes);
-
- /* n */
- numbers[1].bytes = buf_getint(keyblob);
- numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
- buf_incrpos(keyblob, numbers[1].bytes);
-
- /* d */
- numbers[3].bytes = buf_getint(keyblob);
- numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
- buf_incrpos(keyblob, numbers[3].bytes);
-
- /* p */
- numbers[4].bytes = buf_getint(keyblob);
- numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
- buf_incrpos(keyblob, numbers[4].bytes);
-
- /* q */
- numbers[5].bytes = buf_getint(keyblob);
- numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
- buf_incrpos(keyblob, numbers[5].bytes);
-
- /* now calculate some extra parameters: */
- m_mp_init(&tmpval);
- m_mp_init(&dmp1);
- m_mp_init(&dmq1);
- m_mp_init(&iqmp);
-
- /* dmp1 = d mod (p-1) */
- if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
- fprintf(stderr, "Bignum error for p-1\n");
- goto error;
+ /* dmq1 = d mod (q-1) */
+ if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
+ fprintf(stderr, "Bignum error for q-1\n");
+ goto error;
+ }
+ if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
+ fprintf(stderr, "Bignum error for dmq1\n");
+ goto error;
+ }
+
+ /* iqmp = (q^-1) mod p */
+ if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
+ fprintf(stderr, "Bignum error for iqmp\n");
+ goto error;
+ }
+
+ extrablob = buf_new(2000);
+ buf_putmpint(extrablob, &dmp1);
+ buf_putmpint(extrablob, &dmq1);
+ buf_putmpint(extrablob, &iqmp);
+ buf_setpos(extrablob, 0);
+ mp_clear(&dmp1);
+ mp_clear(&dmq1);
+ mp_clear(&iqmp);
+ mp_clear(&tmpval);
+
+ /* dmp1 */
+ numbers[6].bytes = buf_getint(extrablob);
+ numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
+ buf_incrpos(extrablob, numbers[6].bytes);
+
+ /* dmq1 */
+ numbers[7].bytes = buf_getint(extrablob);
+ numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
+ buf_incrpos(extrablob, numbers[7].bytes);
+
+ /* iqmp */
+ numbers[8].bytes = buf_getint(extrablob);
+ numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
+ buf_incrpos(extrablob, numbers[8].bytes);
+
+ nnumbers = 9;
+ header = "-----BEGIN RSA PRIVATE KEY-----\n";
+ footer = "-----END RSA PRIVATE KEY-----\n";
}
- if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
- fprintf(stderr, "Bignum error for dmp1\n");
- goto error;
+ #endif /* DROPBEAR_RSA */
+
+ #ifdef DROPBEAR_DSS
+ if (key->type == DROPBEAR_SIGNKEY_DSS) {
+
+ /* p */
+ numbers[1].bytes = buf_getint(keyblob);
+ numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
+ buf_incrpos(keyblob, numbers[1].bytes);
+
+ /* q */
+ numbers[2].bytes = buf_getint(keyblob);
+ numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
+ buf_incrpos(keyblob, numbers[2].bytes);
+
+ /* g */
+ numbers[3].bytes = buf_getint(keyblob);
+ numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
+ buf_incrpos(keyblob, numbers[3].bytes);
+
+ /* y */
+ numbers[4].bytes = buf_getint(keyblob);
+ numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
+ buf_incrpos(keyblob, numbers[4].bytes);
+
+ /* x */
+ numbers[5].bytes = buf_getint(keyblob);
+ numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
+ buf_incrpos(keyblob, numbers[5].bytes);
+
+ nnumbers = 6;
+ header = "-----BEGIN DSA PRIVATE KEY-----\n";
+ footer = "-----END DSA PRIVATE KEY-----\n";
}
+ #endif /* DROPBEAR_DSS */
- /* dmq1 = d mod (q-1) */
- if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
- fprintf(stderr, "Bignum error for q-1\n");
- goto error;
+ /*
+ * Now count up the total size of the ASN.1 encoded integers,
+ * so as to determine the length of the containing SEQUENCE.
+ */
+ len = 0;
+ for (i = 0; i < nnumbers; i++) {
+ len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
+ len += numbers[i].bytes;
}
- if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
- fprintf(stderr, "Bignum error for dmq1\n");
- goto error;
+ seqlen = len;
+ /* Now add on the SEQUENCE header. */
+ len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
+ /* Round up to the cipher block size, ensuring we have at least one
+ * byte of padding (see below). */
+ outlen = len;
+ if (passphrase)
+ outlen = (outlen+8) &~ 7;
+
+ /*
+ * Now we know how big outblob needs to be. Allocate it.
+ */
+ outblob = (unsigned char*)m_malloc(outlen);
+
+ /*
+ * And write the data into it.
+ */
+ pos = 0;
+ pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
+ for (i = 0; i < nnumbers; i++) {
+ pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
+ memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
+ pos += numbers[i].bytes;
}
+ } // end RSA and DSS handling
- /* iqmp = (q^-1) mod p */
- if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
- fprintf(stderr, "Bignum error for iqmp\n");
- goto error;
+#ifdef DROPBEAR_ECDSA
+ if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
+ || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
+ || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
+
+ /* SEC1 V2 appendix c.4
+ ECPrivateKey ::= SEQUENCE {
+ version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ privateKey OCTET STRING,
+ parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
+ publicKey [1] BIT STRING OPTIONAL
+ }
+ */
+ buffer *seq_buf = buf_new(400);
+ ecc_key **eck = signkey_ecc_key_ptr(key, key->type);
+ const unsigned long curve_size = (*eck)->dp->size;
+ int curve_oid_len = 0;
+ const void* curve_oid = NULL;
+ unsigned long pubkey_size = 2*curve_size+1;
+
+ /* version. less than 10 bytes */
+ buf_incrwritepos(seq_buf,
+ ber_write_id_len(buf_getwriteptr(seq_buf, 10), 2, 1, 0));
+ buf_putbyte(seq_buf, 1);
+
+ /* privateKey */
+ dropbear_assert(mp_unsigned_bin_size((*eck)->k) == curve_size);
+ buf_incrwritepos(seq_buf,
+ ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, curve_size, 0));
+ mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, curve_size));
+ buf_incrwritepos(seq_buf, curve_size);
+
+ /* SECGCurveNames */
+ switch (key->type)
+ {
+ case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
+ curve_oid_len = sizeof(OID_SEC256R1_BLOB);
+ curve_oid = OID_SEC256R1_BLOB;
+ break;
+ case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
+ curve_oid_len = sizeof(OID_SEC384R1_BLOB);
+ curve_oid = OID_SEC384R1_BLOB;
+ break;
+ case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
+ curve_oid_len = sizeof(OID_SEC521R1_BLOB);
+ curve_oid = OID_SEC521R1_BLOB;
+ break;
+ default:
+ dropbear_exit("Internal error");
}
- extrablob = buf_new(2000);
- buf_putmpint(extrablob, &dmp1);
- buf_putmpint(extrablob, &dmq1);
- buf_putmpint(extrablob, &iqmp);
- buf_setpos(extrablob, 0);
- mp_clear(&dmp1);
- mp_clear(&dmq1);
- mp_clear(&iqmp);
- mp_clear(&tmpval);
-
- /* dmp1 */
- numbers[6].bytes = buf_getint(extrablob);
- numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
- buf_incrpos(extrablob, numbers[6].bytes);
-
- /* dmq1 */
- numbers[7].bytes = buf_getint(extrablob);
- numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
- buf_incrpos(extrablob, numbers[7].bytes);
-
- /* iqmp */
- numbers[8].bytes = buf_getint(extrablob);
- numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
- buf_incrpos(extrablob, numbers[8].bytes);
-
- nnumbers = 9;
- header = "-----BEGIN RSA PRIVATE KEY-----\n";
- footer = "-----END RSA PRIVATE KEY-----\n";
- }
-#endif /* DROPBEAR_RSA */
-
-#ifdef DROPBEAR_DSS
- if (keytype == DROPBEAR_SIGNKEY_DSS) {
-
- /* p */
- numbers[1].bytes = buf_getint(keyblob);
- numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
- buf_incrpos(keyblob, numbers[1].bytes);
-
- /* q */
- numbers[2].bytes = buf_getint(keyblob);
- numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
- buf_incrpos(keyblob, numbers[2].bytes);
-
- /* g */
- numbers[3].bytes = buf_getint(keyblob);
- numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
- buf_incrpos(keyblob, numbers[3].bytes);
-
- /* y */
- numbers[4].bytes = buf_getint(keyblob);
- numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
- buf_incrpos(keyblob, numbers[4].bytes);
-
- /* x */
- numbers[5].bytes = buf_getint(keyblob);
- numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
- buf_incrpos(keyblob, numbers[5].bytes);
+ buf_incrwritepos(seq_buf,
+ ber_write_id_len(buf_getwriteptr(seq_buf, 10), 0, 2+curve_oid_len, 0xa0));
+ // object == 6
+ buf_incrwritepos(seq_buf,
+ ber_write_id_len(buf_getwriteptr(seq_buf, 10), 6, curve_oid_len, 0));
+ buf_putbytes(seq_buf, curve_oid, curve_oid_len);
+
+ buf_incrwritepos(seq_buf,
+ ber_write_id_len(buf_getwriteptr(seq_buf, 10), 1, 2+1+pubkey_size, 0xa0));
+ buf_incrwritepos(seq_buf,
+ ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
+ buf_putbyte(seq_buf, 0);
+ int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
+ if (err != CRYPT_OK) {
+ dropbear_exit("ECC error");
+ }
+ buf_incrwritepos(seq_buf, pubkey_size);
- nnumbers = 6;
- header = "-----BEGIN DSA PRIVATE KEY-----\n";
- footer = "-----END DSA PRIVATE KEY-----\n";
- }
-#endif /* DROPBEAR_DSS */
+ buf_setpos(seq_buf, 0);
+
+ outblob = (unsigned char*)m_malloc(200);
- /*
- * Now count up the total size of the ASN.1 encoded integers,
- * so as to determine the length of the containing SEQUENCE.
- */
- len = 0;
- for (i = 0; i < nnumbers; i++) {
- len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
- len += numbers[i].bytes;
- }
- seqlen = len;
- /* Now add on the SEQUENCE header. */
- len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
- /* Round up to the cipher block size, ensuring we have at least one
- * byte of padding (see below). */
- outlen = len;
- if (passphrase)
- outlen = (outlen+8) &~ 7;
+ pos = 0;
+ pos += ber_write_id_len(outblob+pos, 16, seq_buf->len, ASN1_CONSTRUCTED);
+ memcpy(&outblob[pos], seq_buf->data, seq_buf->len);
+ pos += seq_buf->len;
+ len = pos;
+ outlen = len;
- /*
- * Now we know how big outblob needs to be. Allocate it.
- */
- outblob = (unsigned char*)m_malloc(outlen);
+ buf_burn(seq_buf);
+ buf_free(seq_buf);
+ seq_buf = NULL;
- /*
- * And write the data into it.
- */
- pos = 0;
- pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
- for (i = 0; i < nnumbers; i++) {
- pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
- memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
- pos += numbers[i].bytes;
+ header = "-----BEGIN EC PRIVATE KEY-----\n";
+ footer = "-----END EC PRIVATE KEY-----\n";
}
+#endif
/*
* Padding on OpenSSH keys is deterministic. The number of