# HG changeset patch # User Matt Johnston # Date 1369318713 -28800 # Node ID 71e7d31f76716d772cc1bf3ae2fa44ae0a406e00 # Parent 724c3e0c8734bdd4a5b1ab1afb3ec02a856b5992 hackish ECC import code from OpenSSH diff -r 724c3e0c8734 -r 71e7d31f7671 dropbearconvert.c --- a/dropbearconvert.c Thu May 23 22:18:16 2013 +0800 +++ b/dropbearconvert.c Thu May 23 22:18:33 2013 +0800 @@ -62,6 +62,9 @@ const char* infile; const char* outfile; + crypto_init(); + seedrandom(); + #ifdef DEBUG_TRACE /* It's hard for it to get in the way _too_ much */ debug_trace = 1; diff -r 724c3e0c8734 -r 71e7d31f7671 keyimport.c --- a/keyimport.c Thu May 23 22:18:16 2013 +0800 +++ b/keyimport.c Thu May 23 22:18:33 2013 +0800 @@ -36,6 +36,11 @@ #include "bignum.h" #include "buffer.h" #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}; #define PUT_32BIT(cp, value) do { \ (cp)[3] = (unsigned char)(value); \ @@ -158,7 +163,7 @@ #endif buf = buf_new(MAX_PRIVKEY_SIZE); - buf_put_priv_key(buf, key, keytype); + buf_put_priv_key(buf, key, key->type); fp = fopen(filename, "w"); if (!fp) { @@ -523,6 +528,8 @@ sign_key *retkey; buffer * blobbuf = NULL; + retkey = new_sign_key(); + key = load_openssh_key(filename); if (!key) @@ -599,6 +606,8 @@ num_integers = 9; else if (key->type == OSSH_DSA) num_integers = 6; + else if (key->type == OSSH_EC) + num_integers = 1; /* * Space to create key blob in. @@ -622,11 +631,18 @@ } if (i == 0) { - /* - * The first integer should be zero always (I think - * this is some sort of version indication). - */ - if (len != 1 || p[0] != 0) { + /* First integer is a version indicator */ + int expected; + switch (key->type) { + case OSSH_RSA: + case OSSH_DSA: + expected = 0; + break; + case OSSH_EC: + expected = 1; + break; + } + if (len != 1 || p[0] != expected) { errmsg = "Version number mismatch"; goto error; } @@ -657,21 +673,127 @@ p += len; } +#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; + int public_key_len = 0; + ecc_key *ecc; + const struct dropbear_ecc_curve *curve = NULL; + + // See SEC1 v2, Appendix C.4 + // OpenSSL (so OpenSSH) seems to include the optional parts. + + // privateKey OCTET STRING, + ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, + &id, &len, &flags); + p += ret; + // id==4 for octet string + if (ret < 0 || id != 4 || + key->keyblob+key->keyblob_len-p < len) { + errmsg = "ASN.1 decoding failure"; + goto error; + } + private_key_bytes = p; + private_key_len = len; + p += len; + + // parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, + ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, + &id, &len, &flags); + p += ret; + // id==0 + if (ret < 0 || id != 0) { + errmsg = "ASN.1 decoding failure"; + goto error; + } + + ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, + &id, &len, &flags); + p += ret; + // id==6 for object + if (ret < 0 || id != 6 || + key->keyblob+key->keyblob_len-p < len) { + errmsg = "ASN.1 decoding failure"; + goto error; + } + + if (len == sizeof(OID_SEC256R1_BLOB) + && memcmp(p, OID_SEC256R1_BLOB, len) == 0) { + retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256; + curve = &ecc_curve_nistp256; + } else if (len == sizeof(OID_SEC384R1_BLOB) + && memcmp(p, OID_SEC384R1_BLOB, len) == 0) { + retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384; + curve = &ecc_curve_nistp384; + } else if (len == sizeof(OID_SEC521R1_BLOB) + && memcmp(p, OID_SEC521R1_BLOB, len) == 0) { + retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521; + curve = &ecc_curve_nistp521; + } else { + errmsg = "Unknown ECC key type"; + goto error; + } + p += len; + + // publicKey [1] BIT STRING OPTIONAL + ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, + &id, &len, &flags); + p += ret; + // id==1 + if (ret < 0 || id != 1) { + errmsg = "ASN.1 decoding failure"; + goto error; + } + + ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, + &id, &len, &flags); + p += ret; + // id==3 for bit string + if (ret < 0 || id != 3 || + key->keyblob+key->keyblob_len-p < len) { + errmsg = "ASN.1 decoding failure"; + goto error; + } + public_key_bytes = p+1; + public_key_len = len-1; + p += len; + + buf_putbytes(blobbuf, public_key_bytes, public_key_len); + ecc = buf_get_ecc_raw_pubkey(blobbuf, curve); + if (!ecc) { + errmsg = "Error parsing ECC key"; + goto error; + } + m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL); + if (mp_read_unsigned_bin(ecc->k, private_key_bytes, private_key_len) + != MP_OKAY) { + errmsg = "Error parsing ECC key"; + goto error; + } + + retkey->ecckey = ecc; + } +#endif // DROPBEAR_ECDSA + /* * Now put together the actual key. Simplest way to do this is * to assemble our own key blobs and feed them to the createkey * functions; this is a bit faffy but it does mean we get all * the sanity checks for free. */ - retkey = new_sign_key(); - buf_setpos(blobbuf, 0); - type = DROPBEAR_SIGNKEY_ANY; - if (buf_get_priv_key(blobbuf, retkey, &type) - != DROPBEAR_SUCCESS) { - errmsg = "unable to create key structure"; - sign_key_free(retkey); - retkey = NULL; - goto error; + if (key->type == OSSH_RSA || key->type == OSSH_DSA) { + buf_setpos(blobbuf, 0); + type = DROPBEAR_SIGNKEY_ANY; + if (buf_get_priv_key(blobbuf, retkey, &type) + != DROPBEAR_SUCCESS) { + errmsg = "unable to create key structure"; + sign_key_free(retkey); + retkey = NULL; + goto error; + } } errmsg = NULL; /* no error */