From 4b6965d7843113ad43ff024bbcab0b5e1f5d6d5e Mon Sep 17 00:00:00 2001 From: Christian Hohnstaedt Date: Thu, 22 Aug 2024 13:39:59 +0200 Subject: [PATCH] Related to #364 fix writeSSH2private() function Move writeSSH2private() and write_SSH2_ed25519_private() from pki_key.cpp (base class for public keys) to pki_evp.cpp (derived class for private keys) Extend the function to write RSA/DSA/EC in traditional format. Remove the PEM flag from the export format to not be catched by (PEM | PRIVATE) selector in db_key::exportItem(). --- lib/db_key.cpp | 4 ++-- lib/pki_evp.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++ lib/pki_evp.h | 2 ++ lib/pki_export.cpp | 2 +- lib/pki_key.cpp | 48 ---------------------------------------------- lib/pki_key.h | 11 +++++------ 6 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lib/db_key.cpp b/lib/db_key.cpp index a79d7bf3..5870a0ec 100644 --- a/lib/db_key.cpp +++ b/lib/db_key.cpp @@ -232,8 +232,8 @@ void db_key::exportItem(const QModelIndex &index, const pki_export *xport, key->writePublic(file, true); else if (privkey && xport->match_all(F_PKCS8)) privkey->writePKCS8(file, algo, pwCallback, true); - else if (xport->match_all(F_SSH2 | F_PRIVATE)) - key->writeSSH2private(file, pwCallback); + else if (privkey && xport->match_all(F_SSH2 | F_PRIVATE)) + privkey->writeSSH2private(file); else if (xport->match_all(F_SSH2)) key->writeSSH2public(file); else if (privkey && xport->match_all(F_PVK)) diff --git a/lib/pki_evp.cpp b/lib/pki_evp.cpp index 632d11e6..bca07478 100644 --- a/lib/pki_evp.cpp +++ b/lib/pki_evp.cpp @@ -891,6 +891,53 @@ void pki_evp::writeKey(XFile &file, const EVP_CIPHER *enc, file.write(b); } +void pki_evp::write_SSH2_ed25519_private(BIO *b, const EVP_PKEY *pkey) const +{ +#ifndef OPENSSL_NO_EC + static const char data0001[] = { 0, 0, 0, 1}; + char buf_nonce[8]; + QByteArray data, priv, pubfull; + + pubfull = SSH2publicQByteArray(true); + RAND_bytes((unsigned char*)buf_nonce, sizeof buf_nonce); + priv.append(buf_nonce, sizeof buf_nonce); + priv += pubfull; + ssh_key_QBA2data(ed25519PrivKey(pkey) + ed25519PubKey(), &priv); + + data = "openssh-key-v1"; + data.append('\0'); + ssh_key_QBA2data("none", &data); // enc-alg + ssh_key_QBA2data("none", &data); // KDF name + ssh_key_QBA2data("", &data); // KDF data + data.append(data0001, sizeof data0001); + ssh_key_QBA2data(pubfull, &data); + ssh_key_QBA2data(priv, &data); + + PEM_write_bio(b, PEM_STRING_OPENSSH_KEY, (char*)"", + (unsigned char*)(data.data()), data.size()); + pki_openssl_error(); +#else + (void)b; + (void)pkey; +#endif +} +void pki_evp::writeSSH2private(XFile &file) const +{ + EVP_PKEY *pkey = decryptKey(); + if (!pkey) { + pki_openssl_error(); + return; + } +#ifdef EVP_PKEY_ED25519 + if (getKeyType() == EVP_PKEY_ED25519) { + BioByteArray b; + write_SSH2_ed25519_private(b, pkey); + file.write(b); + } else +#endif + writeKey(file, nullptr, nullptr, true); +} + bool pki_evp::verify(EVP_PKEY *pkey) const { if (!EVP_PKEY_isPrivKey(pkey)) diff --git a/lib/pki_evp.h b/lib/pki_evp.h index 3788f98c..9c483a7b 100644 --- a/lib/pki_evp.h +++ b/lib/pki_evp.h @@ -71,6 +71,8 @@ class pki_evp: public pki_key void writePKCS8(XFile &file, const EVP_CIPHER *enc, pem_password_cb *cb, bool pem) const; void writePVKprivate(XFile &file) const; + void writeSSH2private(XFile &file) const; + void write_SSH2_ed25519_private(BIO *b, const EVP_PKEY *pkey) const; bool verify(EVP_PKEY *pkey) const; QVariant getIcon(const dbheader *hd) const; bool sqlUpdatePrivateKey(); diff --git a/lib/pki_export.cpp b/lib/pki_export.cpp index 802ca152..ccd6893f 100644 --- a/lib/pki_export.cpp +++ b/lib/pki_export.cpp @@ -82,7 +82,7 @@ new pki_export(39, x509, "key", tr("OpenVPN tls-auth key"), F_SINGLE | F_TAKEY, new pki_export(19, asym_key, "pem", tr("PEM public"), F_PEM | F_CLIPBOARD, tr("Text format of the public key in one PEM file")), new pki_export(20, asym_key, "pem", tr("PEM private"), F_PEM | F_PRIVATE | F_USUAL | F_CLIPBOARD, tr("Unencrypted private key in text format")), new pki_export(21, asym_key, "pem", tr("PEM encrypted"), F_PEM | F_PRIVATE | F_CRYPT | F_SINGLE, tr("OpenSSL specific encrypted private key in text format")), -new pki_export(22, asym_key, "priv",tr("SSH2 private"), F_PEM | F_PRIVATE | F_SSH2 | F_SINGLE, tr("Unencrypted private key in text format")), +new pki_export(22, asym_key, "priv",tr("SSH2 private"), F_PRIVATE | F_SSH2 | F_SINGLE, tr("Unencrypted private key in text format")), new pki_export(23, asym_key, "pub" ,tr("SSH2 public"), F_SSH2, tr("The public key encoded in SSH2 format")), new pki_export(24, asym_key, "der", tr("DER public"), F_DER | F_SINGLE, tr("Binary DER format of the public key")), new pki_export(25, asym_key, "der", tr("DER private"), F_DER | F_PRIVATE | F_SINGLE, tr("Unencrypted private key in binary DER format")), diff --git a/lib/pki_key.cpp b/lib/pki_key.cpp index b7a575e8..908ce101 100644 --- a/lib/pki_key.cpp +++ b/lib/pki_key.cpp @@ -90,39 +90,6 @@ QByteArray pki_key::i2d() const return i2d_bytearray(I2D_VOID(i2d_PUBKEY), key); } -void pki_key::write_SSH2_ed25519_private(BIO *b, - const EVP_PKEY *pkey, const EVP_CIPHER *enc) const -{ - (void)enc; -#ifndef OPENSSL_NO_EC - static const char data0001[] = { 0, 0, 0, 1}; - char buf_nonce[8]; - QByteArray data, priv, pubfull; - - pubfull = SSH2publicQByteArray(true); - RAND_bytes((unsigned char*)buf_nonce, sizeof buf_nonce); - priv.append(buf_nonce, sizeof buf_nonce); - priv += pubfull; - ssh_key_QBA2data(ed25519PrivKey(pkey) + ed25519PubKey(), &priv); - - data = "openssh-key-v1"; - data.append('\0'); - ssh_key_QBA2data("none", &data); // enc-alg - ssh_key_QBA2data("none", &data); // KDF name - ssh_key_QBA2data("", &data); // KDF data - data.append(data0001, sizeof data0001); - ssh_key_QBA2data(pubfull, &data); - ssh_key_QBA2data(priv, &data); - - PEM_write_bio(b, PEM_STRING_OPENSSH_KEY, (char*)"", - (unsigned char*)(data.data()), data.size()); - pki_openssl_error(); -#else - (void)b; - (void)pkey; -#endif -} - bool pki_key::pem(BioByteArray &b) { return pem(b, pki_export::by_id(Settings["KeyFormat"])); @@ -140,21 +107,6 @@ bool pki_key::pem(BioByteArray &b, const pki_export *xport) return true; } -void pki_key::writeSSH2private(XFile &file, pem_password_cb *cb) const -{ - (void)cb; -// pass_info p(XCA_TITLE, tr("Please enter the password protecting the SSH2 private key '%1'").arg(getIntName())); - - EVP_PKEY *pkey = decryptKey(); - if (!pkey) { - pki_openssl_error(); - return; - } - BioByteArray b; - write_SSH2_ed25519_private(b, pkey, NULL); - file.write(b); -} - QString pki_key::length() const { bool dsa_unset = false; diff --git a/lib/pki_key.h b/lib/pki_key.h index 906752b9..32e4be35 100644 --- a/lib/pki_key.h +++ b/lib/pki_key.h @@ -61,9 +61,11 @@ class keytype } QString traditionalPemName() const { - return type == EVP_PKEY_ED25519 ? - QString("PRIVATE KEY") : - QString("%1 PRIVATE KEY").arg(name); + return +#ifdef EVP_PKEY_ED25519 + type == EVP_PKEY_ED25519 ? QString("PRIVATE KEY") : +#endif + QString("%1 PRIVATE KEY").arg(name); } static const keytype byType(int type) { @@ -255,11 +257,8 @@ class pki_key: public pki_base QByteArray i2d() const; EVP_PKEY *load_ssh2_key(const QByteArray &ba); void writeSSH2public(XFile &file) const; - void writeSSH2private(XFile &file, pem_password_cb *cb) const; QString fingerprint(const QString &format) const; bool SSH2_compatible() const; - void write_SSH2_ed25519_private(BIO *b, - const EVP_PKEY *pkey, const EVP_CIPHER *enc) const; void print(BioByteArray &b, enum print_opt opt) const; void resetUcount() {