summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2022-03-29 22:27:55 +0800
committerMatt Johnston <matt@ucc.asn.au>2022-03-29 22:27:55 +0800
commitfc8b735fa6d36b1fb2b97b9e83a483fc2b675185 (patch)
tree6c4bea24de6a548c1bc4281ae8168ba1d0ab5aec
parentadcd96c4a5b7faa7c294101b00562e6d5bd97b4b (diff)
downloaddropbear-fc8b735fa6d36b1fb2b97b9e83a483fc2b675185.tar.gz
Support RSA OpenSSH new format in dropbearconvert
Added support for reading and writing. PEM writing support has been removed. OpenSSH file format routines have been moved to signkey_ossh.c
-rw-r--r--Makefile.in2
-rw-r--r--keyimport.c240
-rw-r--r--signkey_ossh.c125
-rw-r--r--signkey_ossh.h13
4 files changed, 179 insertions, 201 deletions
diff --git a/Makefile.in b/Makefile.in
index a70b03e..e824491 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -57,7 +57,7 @@ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
KEYOBJS=dropbearkey.o
-CONVERTOBJS=dropbearconvert.o keyimport.o
+CONVERTOBJS=dropbearconvert.o keyimport.o signkey_ossh.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
diff --git a/keyimport.c b/keyimport.c
index 674e77b..9de7c36 100644
--- a/keyimport.c
+++ b/keyimport.c
@@ -39,6 +39,7 @@
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
+#include "signkey_ossh.h"
static const unsigned char OSSH_PKEY_BLOB[] =
"openssh-key-v1\0" /* AUTH_MAGIC */
@@ -47,10 +48,6 @@ static const unsigned char OSSH_PKEY_BLOB[] =
"\0\0\0\0" /* kdf */
"\0\0\0\1"; /* key num */
#define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1)
-
-void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey);
-int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey);
-
#if DROPBEAR_ECDSA
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};
@@ -571,41 +568,8 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
return NULL;
if (key->encrypted) {
- errmsg = "encrypted keys not supported currently";
+ errmsg = "Encrypted keys are not supported. Please convert with ssh-keygen first";
goto error;
-#if 0
- /* matt TODO */
- /*
- * Derive encryption key from passphrase and iv/salt:
- *
- * - let block A equal MD5(passphrase || iv)
- * - let block B equal MD5(A || passphrase || iv)
- * - block C would be MD5(B || passphrase || iv) and so on
- * - encryption key is the first N bytes of A || B
- */
- struct MD5Context md5c;
- unsigned char keybuf[32];
-
- MD5Init(&md5c);
- MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
- MD5Update(&md5c, (unsigned char *)key->iv, 8);
- MD5Final(keybuf, &md5c);
-
- MD5Init(&md5c);
- MD5Update(&md5c, keybuf, 16);
- MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
- MD5Update(&md5c, (unsigned char *)key->iv, 8);
- MD5Final(keybuf+16, &md5c);
-
- /*
- * Now decrypt the key blob.
- */
- des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
- key->keyblob, key->keyblob_len);
-
- memset(&md5c, 0, sizeof(md5c));
- memset(keybuf, 0, sizeof(keybuf));
-#endif
}
/*
@@ -640,13 +604,29 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
if (type != DROPBEAR_SIGNKEY_NONE) {
retkey->type = type;
+#if DROPBEAR_RSA
+ if (type == DROPBEAR_SIGNKEY_RSA) {
+ if (buf_get_rsa_priv_ossh(blobbuf, retkey)
+ == DROPBEAR_SUCCESS) {
+ errmsg = NULL;
+ retval = retkey;
+ goto error;
+ } else {
+ errmsg = "Error parsing OpenSSH RSA key";
+ goto ossh_error;
+ }
+ }
+#endif
#if DROPBEAR_ED25519
if (type == DROPBEAR_SIGNKEY_ED25519) {
if (buf_get_ed25519_priv_ossh(blobbuf, retkey)
- == DROPBEAR_SUCCESS) {
+ == DROPBEAR_SUCCESS) {
errmsg = NULL;
retval = retkey;
goto error;
+ } else {
+ errmsg = "Error parsing OpenSSH ed25519 key";
+ goto ossh_error;
}
}
#endif
@@ -917,57 +897,6 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
return retval;
}
-#if DROPBEAR_ED25519
-/* OpenSSH raw private ed25519 format is
-string "ssh-ed25519"
-uint32 32
-byte[32] pubkey
-uint32 64
-byte[32] privkey
-byte[32] pubkey
-*/
-
-void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey) {
- const dropbear_ed25519_key *key = akey->ed25519key;
- dropbear_assert(key != NULL);
- buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
- buf_putint(buf, CURVE25519_LEN);
- buf_putbytes(buf, key->pub, CURVE25519_LEN);
- buf_putint(buf, CURVE25519_LEN*2);
- buf_putbytes(buf, key->priv, CURVE25519_LEN);
- buf_putbytes(buf, key->pub, CURVE25519_LEN);
-}
-
-int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey) {
- dropbear_ed25519_key *key = akey->ed25519key;
- uint32_t len;
-
- dropbear_assert(key != NULL);
-
- /* Parse past the first string and pubkey */
- if (buf_get_ed25519_pub_key(buf, key, DROPBEAR_SIGNKEY_ED25519)
- == DROPBEAR_FAILURE) {
- dropbear_log(LOG_ERR, "Error parsing ed25519 key, pubkey");
- return DROPBEAR_FAILURE;
- }
- len = buf_getint(buf);
- if (len != 2*CURVE25519_LEN) {
- dropbear_log(LOG_ERR, "Error parsing ed25519 key, bad length");
- return DROPBEAR_FAILURE;
- }
- memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
- buf_incrpos(buf, CURVE25519_LEN);
-
- /* Sanity check */
- if (memcmp(buf_getptr(buf, CURVE25519_LEN), key->pub,
- CURVE25519_LEN) != 0) {
- dropbear_log(LOG_ERR, "Error parsing ed25519 key, mismatch pubkey");
- return DROPBEAR_FAILURE;
- }
- return DROPBEAR_SUCCESS;
-}
-#endif
-
static int openssh_write(const char *filename, sign_key *key,
const char *passphrase)
{
@@ -982,14 +911,7 @@ static int openssh_write(const char *filename, sign_key *key,
int ret = 0;
FILE *fp;
-#if DROPBEAR_RSA
- mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
-#endif
-
if (
-#if DROPBEAR_RSA
- key->type == DROPBEAR_SIGNKEY_RSA ||
-#endif
#if DROPBEAR_DSS
key->type == DROPBEAR_SIGNKEY_DSS ||
#endif
@@ -1011,102 +933,6 @@ static int openssh_write(const char *filename, sign_key *key,
*/
numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
- #if DROPBEAR_RSA
- if (key->type == 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;
- }
-
- /* 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;
- }
-
- /* 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";
- }
- #endif /* DROPBEAR_RSA */
-
#if DROPBEAR_DSS
if (key->type == DROPBEAR_SIGNKEY_DSS) {
@@ -1174,7 +1000,7 @@ static int openssh_write(const char *filename, sign_key *key,
memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
pos += numbers[i].bytes;
}
- } /* end RSA and DSS handling */
+ } /* end DSS handling */
#if DROPBEAR_ECDSA
if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
@@ -1273,14 +1099,29 @@ static int openssh_write(const char *filename, sign_key *key,
}
#endif
+ if (0
+#if DROPBEAR_RSA
+ || key->type == DROPBEAR_SIGNKEY_RSA
+#endif
#if DROPBEAR_ED25519
- if (key->type == DROPBEAR_SIGNKEY_ED25519) {
- buffer *buf = buf_new(1200);
- keyblob = buf_new(1000);
- extrablob = buf_new(1100);
+ || key->type == DROPBEAR_SIGNKEY_ED25519
+#endif
+ ) {
+ buffer *buf = buf_new(3200);
+ keyblob = buf_new(3000);
+ extrablob = buf_new(3100);
/* private key blob w/o header */
- buf_put_ed25519_priv_ossh(keyblob, key);
+#if DROPBEAR_RSA
+ if (key->type == DROPBEAR_SIGNKEY_RSA) {
+ buf_put_rsa_priv_ossh(keyblob, key);
+ }
+#endif
+#if DROPBEAR_ED25519
+ if (key->type == DROPBEAR_SIGNKEY_ED25519) {
+ buf_put_ed25519_priv_ossh(keyblob, key);
+ }
+#endif
/* header */
buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
@@ -1314,7 +1155,6 @@ static int openssh_write(const char *filename, sign_key *key,
header = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
footer = "-----END OPENSSH PRIVATE KEY-----\n";
}
-#endif
/*
* Padding on OpenSSH keys is deterministic. The number of
diff --git a/signkey_ossh.c b/signkey_ossh.c
new file mode 100644
index 0000000..5e787a4
--- /dev/null
+++ b/signkey_ossh.c
@@ -0,0 +1,125 @@
+#include "includes.h"
+#include "dbutil.h"
+#include "ssh.h"
+#include "signkey_ossh.h"
+#include "bignum.h"
+#include "ecdsa.h"
+#include "sk-ecdsa.h"
+#include "sk-ed25519.h"
+#include "rsa.h"
+#include "dss.h"
+#include "ed25519.h"
+
+#if DROPBEAR_RSA
+/* OpenSSH raw private RSA format is
+string "ssh-rsa"
+mpint n
+mpint e
+mpint d
+mpint iqmp (q^-1) mod p
+mpint p
+mpint q
+*/
+
+void buf_put_rsa_priv_ossh(buffer *buf, const sign_key *akey) {
+ const dropbear_rsa_key *key = akey->rsakey;
+ mp_int iqmp;
+
+ dropbear_assert(key != NULL);
+ if (!(key->p && key->q)) {
+ dropbear_exit("Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
+ }
+
+ m_mp_init(&iqmp);
+ /* iqmp = (q^-1) mod p */
+ if (mp_invmod(key->q, key->p, &iqmp) != MP_OKAY) {
+ dropbear_exit("Bignum error for iqmp\n");
+ }
+ buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
+ buf_putmpint(buf, key->n);
+ buf_putmpint(buf, key->e);
+ buf_putmpint(buf, key->d);
+ buf_putmpint(buf, &iqmp);
+ buf_putmpint(buf, key->p);
+ buf_putmpint(buf, key->q);
+ mp_clear(&iqmp);
+}
+
+int buf_get_rsa_priv_ossh(buffer *buf, sign_key *akey) {
+ int ret = DROPBEAR_FAILURE;
+ dropbear_rsa_key *key = NULL;
+ mp_int iqmp;
+
+ rsa_key_free(akey->rsakey);
+ akey->rsakey = m_malloc(sizeof(*akey->rsakey));
+ key = akey->rsakey;
+ m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
+
+ buf_eatstring(buf);
+ m_mp_init(&iqmp);
+ if (buf_getmpint(buf, key->n) == DROPBEAR_SUCCESS
+ && buf_getmpint(buf, key->e) == DROPBEAR_SUCCESS
+ && buf_getmpint(buf, key->d) == DROPBEAR_SUCCESS
+ && buf_getmpint(buf, &iqmp) == DROPBEAR_SUCCESS
+ && buf_getmpint(buf, key->p) == DROPBEAR_SUCCESS
+ && buf_getmpint(buf, key->q) == DROPBEAR_SUCCESS) {
+ ret = DROPBEAR_SUCCESS;
+ }
+ mp_clear(&iqmp);
+ return ret;
+}
+
+#endif /* DROPBEAR_RSA */
+
+#if DROPBEAR_ED25519
+/* OpenSSH raw private ed25519 format is
+string "ssh-ed25519"
+uint32 32
+byte[32] pubkey
+uint32 64
+byte[32] privkey
+byte[32] pubkey
+*/
+
+void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey) {
+ const dropbear_ed25519_key *key = akey->ed25519key;
+ dropbear_assert(key != NULL);
+ buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
+ buf_putint(buf, CURVE25519_LEN);
+ buf_putbytes(buf, key->pub, CURVE25519_LEN);
+ buf_putint(buf, CURVE25519_LEN*2);
+ buf_putbytes(buf, key->priv, CURVE25519_LEN);
+ buf_putbytes(buf, key->pub, CURVE25519_LEN);
+}
+
+int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey) {
+ dropbear_ed25519_key *key = NULL;
+ uint32_t len;
+
+ ed25519_key_free(akey->ed25519key);
+ akey->ed25519key = m_malloc(sizeof(*akey->ed25519key));
+ key = akey->ed25519key;
+
+ /* Parse past the first string and pubkey */
+ if (buf_get_ed25519_pub_key(buf, key, DROPBEAR_SIGNKEY_ED25519)
+ == DROPBEAR_FAILURE) {
+ dropbear_log(LOG_ERR, "Error parsing ed25519 key, pubkey");
+ return DROPBEAR_FAILURE;
+ }
+ len = buf_getint(buf);
+ if (len != 2*CURVE25519_LEN) {
+ dropbear_log(LOG_ERR, "Error parsing ed25519 key, bad length");
+ return DROPBEAR_FAILURE;
+ }
+ memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
+ buf_incrpos(buf, CURVE25519_LEN);
+
+ /* Sanity check */
+ if (memcmp(buf_getptr(buf, CURVE25519_LEN), key->pub,
+ CURVE25519_LEN) != 0) {
+ dropbear_log(LOG_ERR, "Error parsing ed25519 key, mismatch pubkey");
+ return DROPBEAR_FAILURE;
+ }
+ return DROPBEAR_SUCCESS;
+}
+#endif /* DROPBEAR_ED255219 */
diff --git a/signkey_ossh.h b/signkey_ossh.h
new file mode 100644
index 0000000..165923a
--- /dev/null
+++ b/signkey_ossh.h
@@ -0,0 +1,13 @@
+#ifndef DROPBEAR_SIGNKEY_OSSH_H_
+#define DROPBEAR_SIGNKEY_OSSH_H_
+
+#include "signkey.h"
+
+/* Helpers for OpenSSH format keys in dropbearconvert */
+
+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);
+
+#endif /* DROPBEAR_SIGNKEY_OSSH_H_ */