summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2022-03-29 23:27:55 +0800
committerMatt Johnston <matt@ucc.asn.au>2022-03-29 23:27:55 +0800
commitce6a452969257be775dd74fc99cd15350fa917f2 (patch)
treeacb6f76252e4776471e6e69e1758f1187abf3142
parente6827217a0ede74ad814ca44020f1e2e5964412e (diff)
downloaddropbear-ce6a452969257be775dd74fc99cd15350fa917f2.tar.gz
Add ecdsa OpenSSH format for dropbearconvert
-rw-r--r--keyimport.c126
-rw-r--r--signkey_ossh.c36
-rw-r--r--signkey_ossh.h2
-rw-r--r--test/test_dropbearconvert.py5
4 files changed, 63 insertions, 106 deletions
diff --git a/keyimport.c b/keyimport.c
index 9de7c36..5bb2e50 100644
--- a/keyimport.c
+++ b/keyimport.c
@@ -39,6 +39,7 @@
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
+#include "ecdsa.h"
#include "signkey_ossh.h"
static const unsigned char OSSH_PKEY_BLOB[] =
@@ -630,6 +631,19 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
}
}
#endif
+#if DROPBEAR_ECDSA
+ if (signkey_is_ecdsa(type)) {
+ if (buf_get_ecdsa_priv_ossh(blobbuf, retkey)
+ == DROPBEAR_SUCCESS) {
+ errmsg = NULL;
+ retval = retkey;
+ goto error;
+ } else {
+ errmsg = "Error parsing OpenSSH ed25519 key";
+ goto ossh_error;
+ }
+ }
+#endif
}
errmsg = "Unsupported OpenSSH key type";
@@ -911,12 +925,8 @@ static int openssh_write(const char *filename, sign_key *key,
int ret = 0;
FILE *fp;
- if (
#if DROPBEAR_DSS
- key->type == DROPBEAR_SIGNKEY_DSS ||
-#endif
- 0)
- {
+ if (key->type == DROPBEAR_SIGNKEY_DSS) {
/*
* Fetch the key blobs.
*/
@@ -1001,103 +1011,7 @@ static int openssh_write(const char *filename, sign_key *key,
pos += numbers[i].bytes;
}
} /* end DSS handling */
-
-#if 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 = (ecc_key**)signkey_key_ptr(key, key->type);
- const long curve_size = (*eck)->dp->size;
- int curve_oid_len = 0;
- const void* curve_oid = NULL;
- unsigned long pubkey_size = 2*curve_size+1;
- int k_size;
- int err = 0;
- size_t written;
-
- /* 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 */
- k_size = mp_ubin_size((*eck)->k);
- dropbear_assert(k_size <= curve_size);
- buf_incrwritepos(seq_buf,
- ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0));
- if (mp_to_ubin((*eck)->k, buf_getwriteptr(seq_buf, k_size), k_size, &written) != MP_OKAY) {
- dropbear_exit("ECC error");
- }
- buf_incrwritepos(seq_buf, written);
-
- /* 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");
- }
-
- 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,
- (pubkey_size +1 < 128 ? 2 : 3 ) +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);
- 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);
-
- buf_setpos(seq_buf, 0);
-
- outblob = (unsigned char*)m_malloc(1000);
-
- 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;
-
- buf_burn(seq_buf);
- buf_free(seq_buf);
- seq_buf = NULL;
-
- header = "-----BEGIN EC PRIVATE KEY-----\n";
- footer = "-----END EC PRIVATE KEY-----\n";
- }
-#endif
+#endif /* DROPBEAR_DSS */
if (0
#if DROPBEAR_RSA
@@ -1106,6 +1020,9 @@ static int openssh_write(const char *filename, sign_key *key,
#if DROPBEAR_ED25519
|| key->type == DROPBEAR_SIGNKEY_ED25519
#endif
+#if DROPBEAR_ECDSA
+ || signkey_is_ecdsa(key->type)
+#endif
) {
buffer *buf = buf_new(3200);
keyblob = buf_new(3000);
@@ -1122,6 +1039,11 @@ static int openssh_write(const char *filename, sign_key *key,
buf_put_ed25519_priv_ossh(keyblob, key);
}
#endif
+#if DROPBEAR_ECDSA
+ if (signkey_is_ecdsa(key->type)) {
+ buf_put_ecdsa_priv_ossh(keyblob, key);
+ }
+#endif
/* header */
buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
diff --git a/signkey_ossh.c b/signkey_ossh.c
index 5e787a4..59b44ad 100644
--- a/signkey_ossh.c
+++ b/signkey_ossh.c
@@ -123,3 +123,39 @@ int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey) {
return DROPBEAR_SUCCESS;
}
#endif /* DROPBEAR_ED255219 */
+
+#if DROPBEAR_ECDSA
+/* OpenSSH raw private ecdsa format is the same as Dropbear's.
+# First part is the same as the SSH wire pubkey format
+string "ecdsa-sha2-[identifier]"
+string [identifier]
+string Q
+# With private part appended
+mpint d
+*/
+
+void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *key) {
+ ecc_key **eck = (ecc_key**)signkey_key_ptr((sign_key*)key, key->type);
+ if (eck && *eck) {
+ buf_put_ecdsa_priv_key(buf, *eck);
+ return;
+ }
+ dropbear_exit("ecdsa key is not set");
+}
+
+int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *key) {
+ ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
+ if (eck) {
+ if (*eck) {
+ ecc_free(*eck);
+ m_free(*eck);
+ *eck = NULL;
+ }
+ *eck = buf_get_ecdsa_priv_key(buf);
+ if (*eck) {
+ return DROPBEAR_SUCCESS;
+ }
+ }
+ return DROPBEAR_FAILURE;
+}
+#endif /* DROPBEAR_ECDSA */
diff --git a/signkey_ossh.h b/signkey_ossh.h
index 165923a..080372c 100644
--- a/signkey_ossh.h
+++ b/signkey_ossh.h
@@ -9,5 +9,7 @@ void buf_put_rsa_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_rsa_priv_ossh(buffer *buf, sign_key *akey);
void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey);
+void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *akey);
+int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *akey);
#endif /* DROPBEAR_SIGNKEY_OSSH_H_ */
diff --git a/test/test_dropbearconvert.py b/test/test_dropbearconvert.py
index 5b5a8d6..9fd4772 100644
--- a/test/test_dropbearconvert.py
+++ b/test/test_dropbearconvert.py
@@ -27,10 +27,7 @@ def test_from_openssh(request, tmp_path, keytype, keyformat):
kt, keybits = parse_keytype(keytype)
if kt == 'dss' and keyformat is None:
- pytest.xfail("dss doesn't support openssh format")
-
- if kt == 'ecdsa' and keyformat is None:
- pytest.skip("ecdsa doesn't support openssh format yet")
+ pytest.skip("dss doesn't support openssh format")
os_kt = kt
if os_kt == 'dss':