# HG changeset patch # User Matt Johnston # Date 1648564075 -28800 # Node ID eadd023fde4d72c210b67c7288237ce329e40fc2 # Parent 3e0aacf0a4f3aa28ebb52f88b8e62fae1828a444 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 diff -r 3e0aacf0a4f3 -r eadd023fde4d Makefile.in --- a/Makefile.in Tue Mar 29 16:46:06 2022 +0800 +++ b/Makefile.in Tue Mar 29 22:27:55 2022 +0800 @@ -57,7 +57,7 @@ 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 -r 3e0aacf0a4f3 -r eadd023fde4d keyimport.c --- a/keyimport.c Tue Mar 29 16:46:06 2022 +0800 +++ b/keyimport.c Tue Mar 29 22:27:55 2022 +0800 @@ -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 @@ "\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 @@ 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 @@ 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 @@ 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 @@ 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 @@ */ 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 @@ 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 @@ } #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 @@ header = "-----BEGIN OPENSSH PRIVATE KEY-----\n"; footer = "-----END OPENSSH PRIVATE KEY-----\n"; } -#endif /* * Padding on OpenSSH keys is deterministic. The number of diff -r 3e0aacf0a4f3 -r eadd023fde4d signkey_ossh.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/signkey_ossh.c Tue Mar 29 22:27:55 2022 +0800 @@ -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 -r 3e0aacf0a4f3 -r eadd023fde4d signkey_ossh.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/signkey_ossh.h Tue Mar 29 22:27:55 2022 +0800 @@ -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_ */