diff signkey_ossh.c @ 1908:eadd023fde4d

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
author Matt Johnston <matt@ucc.asn.au>
date Tue, 29 Mar 2022 22:27:55 +0800
parents
children ced53051e200
line wrap: on
line diff
--- /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 */