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().
This commit is contained in:
Christian Hohnstaedt 2024-08-22 13:39:59 +02:00
parent c730a886c8
commit 4b6965d784
6 changed files with 57 additions and 57 deletions

View File

@ -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))

View File

@ -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))

View File

@ -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();

View File

@ -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")),

View File

@ -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;

View File

@ -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()
{