Add support for SSH2 ED25519 private key export

Encrypting the SSH2 private keys is not supported, yet.
This commit is contained in:
Christian Hohnstädt 2021-02-20 08:40:17 +01:00
parent 241abffaad
commit 45de747461
5 changed files with 65 additions and 17 deletions

View File

@ -216,12 +216,15 @@ exportType::etype db_key::clipboardFormat(QModelIndexList indexes) const
if (ssh2compatible)
types << exportType(exportType::SSH2_public,
"pub", tr("SSH2 public"));
if (allPriv)
if (allPriv) {
types << exportType(exportType::PEM_private, "pem",
tr("PEM private"))
<< exportType(exportType::PKCS8, "pk8",
"PKCS#8");
if (ssh2compatible)
types << exportType(exportType::SSH2_private,
"", tr("SSH2 private"));
}
ExportDialog *dlg = new ExportDialog(NULL,
tr("Export keys to Clipboard"), QString(), NULL,
QPixmap(":keyImg"), types);
@ -241,7 +244,7 @@ void db_key::store(QModelIndex index)
const EVP_CIPHER *algo = NULL, *encrypt = EVP_aes_256_cbc();
QString title = tr("Export public key [%1]");
QList<exportType> types;
bool pvk = false;
bool pvk = false, ed25519 = false;
pki_key *key = fromIndex<pki_key>(index);
pki_evp *privkey = dynamic_cast<pki_evp *>(key);
@ -253,6 +256,10 @@ void db_key::store(QModelIndex index)
int keytype = key->getKeyType();
if (keytype == EVP_PKEY_RSA || keytype == EVP_PKEY_DSA)
pvk = true;
#ifdef EVP_PKEY_ED25519
if (keytype == EVP_PKEY_ED25519)
ed25519 = true;
#endif
#endif
types <<
@ -264,12 +271,13 @@ void db_key::store(QModelIndex index)
"pub", tr("SSH2 public"));
if (!key->isPubKey() && !key->isToken()) {
QList<exportType> usual;
if (!ed25519)
types << exportType(exportType::PEM_private_encrypt,
"pem", tr("PEM encryped"));
types <<
exportType(exportType::DER_private, "der",
tr("DER private")) <<
exportType(exportType::PEM_private_encrypt, "pem",
tr("PEM encryped")) <<
exportType(exportType::PKCS8, "pk8", "PKCS#8");
exportType(exportType::DER_private, "der",
tr("DER private")) <<
exportType(exportType::PKCS8, "pk8", "PKCS#8");
if (pvk) {
types <<
@ -278,11 +286,14 @@ void db_key::store(QModelIndex index)
exportType(exportType::PVK_encrypt, "pvk",
tr("PVK encrypted"));
}
usual <<
exportType(exportType::PEM_private, "pem",
tr("PEM private")) <<
exportType(exportType::PKCS8_encrypt, "pk8",
if (!ed25519)
usual << exportType(exportType::PEM_private, "pem",
tr("PEM private"));
usual << exportType(exportType::PKCS8_encrypt, "pk8",
tr("PKCS#8 encrypted"));
if (key->SSH2_compatible())
usual << exportType(exportType::SSH2_private, "",
tr("SSH2 private"));
title = tr("Export private key [%1]");
types = usual << exportType() << types;
}
@ -338,6 +349,9 @@ void db_key::store(QModelIndex index)
case exportType::SSH2_public:
key->writeSSH2public(file);
break;
case exportType::SSH2_private:
key->writeSSH2private(file, PwDialog::pwCallback);
break;
case exportType::PVK_private:
privkey->writePVKprivate(file, NULL);
break;

View File

@ -105,6 +105,7 @@ static inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
OPENSSL_free(ctx);
}
#if 0
static inline EVP_CIPHER_CTX *EVP_CIPHER_CTX_new()
{
return (EVP_CIPHER_CTX*)OPENSSL_zalloc(sizeof(EVP_CIPHER_CTX));
@ -115,6 +116,7 @@ static inline void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
EVP_CIPHER_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
#endif
#endif

View File

@ -92,9 +92,10 @@ QByteArray pki_key::i2d() const
return i2d_bytearray(I2D_VOID(i2d_PUBKEY), key);
}
void pki_key::write_SSH2_ed25519_private(BioByteArray &b,
void pki_key::write_SSH2_ed25519_private(BIO *b,
const EVP_PKEY *pkey, const EVP_CIPHER *enc) const
{
#ifndef OPENSSL_NO_EC
static const char data0001[] = { 0, 0, 0, 1};
char buf_nonce[8];
QByteArray data, priv, pubfull;
@ -118,6 +119,7 @@ void pki_key::write_SSH2_ed25519_private(BioByteArray &b,
PEM_write_bio(b, PEM_STRING_OPENSSH_KEY, (char*)"",
(unsigned char*)(data.data()), data.size());
pki_openssl_error();
#endif
}
bool pki_key::pem(BioByteArray &b, int format)
@ -131,6 +133,7 @@ bool pki_key::pem(BioByteArray &b, int format)
b += SSH2publicQByteArray();
break;
case exportType::PEM_private:
case exportType::SSH2_private:
pkey = decryptKey();
keytype = EVP_PKEY_id(pkey);
switch (keytype) {
@ -152,6 +155,8 @@ bool pki_key::pem(BioByteArray &b, int format)
break;
#ifdef EVP_PKEY_ED25519
case EVP_PKEY_ED25519:
if (format == exportType::PEM_private)
return false;
write_SSH2_ed25519_private(b, pkey, NULL);
break;
#endif
@ -173,6 +178,19 @@ bool pki_key::pem(BioByteArray &b, int format)
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;
}
write_SSH2_ed25519_private(file.bio(), pkey, NULL);
}
QString pki_key::length() const
{
bool dsa_unset = false;
@ -355,18 +373,17 @@ QString pki_key::ecPubKey() const
return pub;
}
#ifdef EVP_PKEY_ED25519
static QByteArray ed25519Key(int(*EVP_PKEY_get_raw)
(const EVP_PKEY*, unsigned char *, size_t *),
const EVP_PKEY *pkey)
{
#ifdef EVP_PKEY_ED25519
unsigned char k[ED25519_KEYLEN];
size_t len = sizeof k;
if (EVP_PKEY_id(pkey) == EVP_PKEY_ED25519 &&
EVP_PKEY_get_raw(pkey, k, &len))
return QByteArray((char*)k, len);
#endif
return QByteArray();
}
@ -379,6 +396,19 @@ QByteArray pki_key::ed25519PrivKey(const EVP_PKEY *pkey) const
{
return ed25519Key(EVP_PKEY_get_raw_private_key, pkey);
}
#else
QByteArray pki_key::ed25519PubKey() const
{
return QByteArray();
}
QByteArray pki_key::ed25519PrivKey(const EVP_PKEY *) const
{
return QByteArray();
}
#endif
#endif
QList<int> pki_key::possibleHashNids()

View File

@ -236,9 +236,10 @@ class pki_key: public pki_base
QByteArray i2d() const;
EVP_PKEY *load_ssh2_key(XFile &file);
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(BioByteArray &b,
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()

View File

@ -21,7 +21,7 @@ class exportType {
PEM_key, PEM_private, PEM_private_encrypt, DER_private,
DER_key, PKCS8, PKCS8_encrypt, SSH2_public,
PEM_selected, PKCS7_selected, Index, vcalendar, vcalendar_ca,
PVK_private, PVK_encrypt, ETYPE_max };
PVK_private, PVK_encrypt, SSH2_private, ETYPE_max };
enum etype type;
QString desc;
QString extension;
@ -41,6 +41,7 @@ class exportType {
case PEM_private:
case PEM_private_encrypt:
case PEM_selected:
case SSH2_private:
return true;
default:
return false;