Skip to content

Commit 81e3977

Browse files
committed
Add ecdsa OpenSSH format for dropbearconvert
1 parent bcbae1f commit 81e3977

File tree

4 files changed

+63
-106
lines changed

4 files changed

+63
-106
lines changed

keyimport.c

+24-102
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "rsa.h"
4040
#include "dss.h"
4141
#include "ed25519.h"
42+
#include "ecdsa.h"
4243
#include "signkey_ossh.h"
4344

4445
static const unsigned char OSSH_PKEY_BLOB[] =
@@ -629,6 +630,19 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
629630
goto ossh_error;
630631
}
631632
}
633+
#endif
634+
#if DROPBEAR_ECDSA
635+
if (signkey_is_ecdsa(type)) {
636+
if (buf_get_ecdsa_priv_ossh(blobbuf, retkey)
637+
== DROPBEAR_SUCCESS) {
638+
errmsg = NULL;
639+
retval = retkey;
640+
goto error;
641+
} else {
642+
errmsg = "Error parsing OpenSSH ed25519 key";
643+
goto ossh_error;
644+
}
645+
}
632646
#endif
633647
}
634648

@@ -911,12 +925,8 @@ static int openssh_write(const char *filename, sign_key *key,
911925
int ret = 0;
912926
FILE *fp;
913927

914-
if (
915928
#if DROPBEAR_DSS
916-
key->type == DROPBEAR_SIGNKEY_DSS ||
917-
#endif
918-
0)
919-
{
929+
if (key->type == DROPBEAR_SIGNKEY_DSS) {
920930
/*
921931
* Fetch the key blobs.
922932
*/
@@ -1001,110 +1011,17 @@ static int openssh_write(const char *filename, sign_key *key,
10011011
pos += numbers[i].bytes;
10021012
}
10031013
} /* end DSS handling */
1004-
1005-
#if DROPBEAR_ECDSA
1006-
if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
1007-
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
1008-
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
1009-
1010-
/* SEC1 V2 appendix c.4
1011-
ECPrivateKey ::= SEQUENCE {
1012-
version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
1013-
privateKey OCTET STRING,
1014-
parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
1015-
publicKey [1] BIT STRING OPTIONAL
1016-
}
1017-
*/
1018-
buffer *seq_buf = buf_new(400);
1019-
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
1020-
const long curve_size = (*eck)->dp->size;
1021-
int curve_oid_len = 0;
1022-
const void* curve_oid = NULL;
1023-
unsigned long pubkey_size = 2*curve_size+1;
1024-
int k_size;
1025-
int err = 0;
1026-
size_t written;
1027-
1028-
/* version. less than 10 bytes */
1029-
buf_incrwritepos(seq_buf,
1030-
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 2, 1, 0));
1031-
buf_putbyte(seq_buf, 1);
1032-
1033-
/* privateKey */
1034-
k_size = mp_ubin_size((*eck)->k);
1035-
dropbear_assert(k_size <= curve_size);
1036-
buf_incrwritepos(seq_buf,
1037-
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0));
1038-
if (mp_to_ubin((*eck)->k, buf_getwriteptr(seq_buf, k_size), k_size, &written) != MP_OKAY) {
1039-
dropbear_exit("ECC error");
1040-
}
1041-
buf_incrwritepos(seq_buf, written);
1042-
1043-
/* SECGCurveNames */
1044-
switch (key->type)
1045-
{
1046-
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
1047-
curve_oid_len = sizeof(OID_SEC256R1_BLOB);
1048-
curve_oid = OID_SEC256R1_BLOB;
1049-
break;
1050-
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
1051-
curve_oid_len = sizeof(OID_SEC384R1_BLOB);
1052-
curve_oid = OID_SEC384R1_BLOB;
1053-
break;
1054-
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
1055-
curve_oid_len = sizeof(OID_SEC521R1_BLOB);
1056-
curve_oid = OID_SEC521R1_BLOB;
1057-
break;
1058-
default:
1059-
dropbear_exit("Internal error");
1060-
}
1061-
1062-
buf_incrwritepos(seq_buf,
1063-
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 0, 2+curve_oid_len, 0xa0));
1064-
/* object == 6 */
1065-
buf_incrwritepos(seq_buf,
1066-
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 6, curve_oid_len, 0));
1067-
buf_putbytes(seq_buf, curve_oid, curve_oid_len);
1068-
1069-
buf_incrwritepos(seq_buf,
1070-
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 1,
1071-
(pubkey_size +1 < 128 ? 2 : 3 ) +1 +pubkey_size, 0xa0));
1072-
1073-
buf_incrwritepos(seq_buf,
1074-
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
1075-
buf_putbyte(seq_buf, 0);
1076-
err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
1077-
if (err != CRYPT_OK) {
1078-
dropbear_exit("ECC error");
1079-
}
1080-
buf_incrwritepos(seq_buf, pubkey_size);
1081-
1082-
buf_setpos(seq_buf, 0);
1083-
1084-
outblob = (unsigned char*)m_malloc(1000);
1085-
1086-
pos = 0;
1087-
pos += ber_write_id_len(outblob+pos, 16, seq_buf->len, ASN1_CONSTRUCTED);
1088-
memcpy(&outblob[pos], seq_buf->data, seq_buf->len);
1089-
pos += seq_buf->len;
1090-
len = pos;
1091-
outlen = len;
1092-
1093-
buf_burn(seq_buf);
1094-
buf_free(seq_buf);
1095-
seq_buf = NULL;
1096-
1097-
header = "-----BEGIN EC PRIVATE KEY-----\n";
1098-
footer = "-----END EC PRIVATE KEY-----\n";
1099-
}
1100-
#endif
1014+
#endif /* DROPBEAR_DSS */
11011015

11021016
if (0
11031017
#if DROPBEAR_RSA
11041018
|| key->type == DROPBEAR_SIGNKEY_RSA
11051019
#endif
11061020
#if DROPBEAR_ED25519
11071021
|| key->type == DROPBEAR_SIGNKEY_ED25519
1022+
#endif
1023+
#if DROPBEAR_ECDSA
1024+
|| signkey_is_ecdsa(key->type)
11081025
#endif
11091026
) {
11101027
buffer *buf = buf_new(3200);
@@ -1122,6 +1039,11 @@ static int openssh_write(const char *filename, sign_key *key,
11221039
buf_put_ed25519_priv_ossh(keyblob, key);
11231040
}
11241041
#endif
1042+
#if DROPBEAR_ECDSA
1043+
if (signkey_is_ecdsa(key->type)) {
1044+
buf_put_ecdsa_priv_ossh(keyblob, key);
1045+
}
1046+
#endif
11251047

11261048
/* header */
11271049
buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);

signkey_ossh.c

+36
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,39 @@ int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey) {
123123
return DROPBEAR_SUCCESS;
124124
}
125125
#endif /* DROPBEAR_ED255219 */
126+
127+
#if DROPBEAR_ECDSA
128+
/* OpenSSH raw private ecdsa format is the same as Dropbear's.
129+
# First part is the same as the SSH wire pubkey format
130+
string "ecdsa-sha2-[identifier]"
131+
string [identifier]
132+
string Q
133+
# With private part appended
134+
mpint d
135+
*/
136+
137+
void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *key) {
138+
ecc_key **eck = (ecc_key**)signkey_key_ptr((sign_key*)key, key->type);
139+
if (eck && *eck) {
140+
buf_put_ecdsa_priv_key(buf, *eck);
141+
return;
142+
}
143+
dropbear_exit("ecdsa key is not set");
144+
}
145+
146+
int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *key) {
147+
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
148+
if (eck) {
149+
if (*eck) {
150+
ecc_free(*eck);
151+
m_free(*eck);
152+
*eck = NULL;
153+
}
154+
*eck = buf_get_ecdsa_priv_key(buf);
155+
if (*eck) {
156+
return DROPBEAR_SUCCESS;
157+
}
158+
}
159+
return DROPBEAR_FAILURE;
160+
}
161+
#endif /* DROPBEAR_ECDSA */

signkey_ossh.h

+2
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ void buf_put_rsa_priv_ossh(buffer *buf, const sign_key *akey);
99
int buf_get_rsa_priv_ossh(buffer *buf, sign_key *akey);
1010
void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey);
1111
int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey);
12+
void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *akey);
13+
int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *akey);
1214

1315
#endif /* DROPBEAR_SIGNKEY_OSSH_H_ */

test/test_dropbearconvert.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ def test_from_openssh(request, tmp_path, keytype, keyformat):
2727
kt, keybits = parse_keytype(keytype)
2828

2929
if kt == 'dss' and keyformat is None:
30-
pytest.xfail("dss doesn't support openssh format")
31-
32-
if kt == 'ecdsa' and keyformat is None:
33-
pytest.skip("ecdsa doesn't support openssh format yet")
30+
pytest.skip("dss doesn't support openssh format")
3431

3532
os_kt = kt
3633
if os_kt == 'dss':

0 commit comments

Comments
 (0)