diff options
author | Matt Johnston <matt@ucc.asn.au> | 2013-05-23 22:18:33 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2013-05-23 22:18:33 +0800 |
commit | 6b0d47b3645c987b457a6f2562db093827421382 (patch) | |
tree | 2b7b7130097f5e13e702bb2296eddac046c78cc4 /keyimport.c | |
parent | d9e790e7dc7737158c9affb7087035dd2c31c003 (diff) |
hackish ECC import code from OpenSSH
--HG--
branch : ecc
Diffstat (limited to 'keyimport.c')
-rw-r--r-- | keyimport.c | 152 |
1 files changed, 137 insertions, 15 deletions
diff --git a/keyimport.c b/keyimport.c index e8fded7..d0469de 100644 --- a/keyimport.c +++ b/keyimport.c @@ -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 @@ static int dropbear_write(const char*filename, sign_key * key) { #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 @@ static sign_key *openssh_read(const char *filename, char *passphrase) sign_key *retkey; buffer * blobbuf = NULL; + retkey = new_sign_key(); + key = load_openssh_key(filename); if (!key) @@ -599,6 +606,8 @@ static sign_key *openssh_read(const char *filename, char *passphrase) 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 @@ static sign_key *openssh_read(const char *filename, char *passphrase) } 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 @@ static sign_key *openssh_read(const char *filename, char *passphrase) 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 */ |