Consolidate export types and format in pki_export class

Move the descriptons from the ExportDialog into the
new pki_export class.

Also translate the exportType::etype to F_* flags
This commit is contained in:
Christian Hohnstädt 2021-10-24 20:05:43 +02:00
parent 36e02374ff
commit be1a44d0a8
19 changed files with 327 additions and 479 deletions

View File

@ -41,5 +41,5 @@ db_x509super.h pki_evp.h xfile.h
dhgen.cpp dhgen.h XcaProgress.cpp
XcaProgress.h XcaWarningCore.cpp XcaWarningCore.h
PwDialogCore.cpp PwDialogCore.h digest.h
digest.cpp
digest.cpp pki_export.cpp
)

View File

@ -11,7 +11,6 @@
#include <typeinfo>
#include "base.h"
#include "load_obj.h"
#include "exportType.h"
#include "pki_base.h"
#include "headerlist.h"
@ -41,10 +40,6 @@ class db_base: public QAbstractItemModel
virtual dbheaderList getHeaders();
int colResizing;
QString sqlItemSelector();
virtual exportType::etype clipboardFormat(QModelIndexList) const
{
return exportType::Separator;
}
bool isValidCol(int col) const;
void timerEvent(QTimerEvent *event);
bool treeview;

View File

@ -125,26 +125,23 @@ void db_crl::store(QModelIndex index)
if (!index.isValid() || !crl)
return;
QList<exportType> types; types <<
exportType(exportType::PEM, "pem", "PEM") <<
exportType(exportType::DER, "der", "DER") <<
exportType(exportType::vcalendar, "ics", "vCalendar");
ExportDialog *dlg = new ExportDialog(NULL,
tr("Revocation list export"),
tr("CRL ( *.pem *.der *.crl )"), crl,
QPixmap(":revImg"), types);
tr("Revocation list export"),
tr("CRL ( *.pem *.der *.crl )"), crl, QPixmap(":revImg"),
pki_export::select(revocation, 0));
if (!dlg->exec()) {
delete dlg;
return;
}
try {
const pki_export *xtype = dlg->export_type();
XFile file(dlg->filename->text());
pki_base::pem_comment = dlg->pemComment->isChecked();
file.open_key();
if (dlg->type() == exportType::vcalendar) {
if (xtype->match_all(F_CAL)) {
writeVcalendar(file, crl->icsVEVENT());
} else {
crl->writeCrl(file, dlg->type() == exportType::PEM);
crl->writeCrl(file, xtype->match_all(F_PEM));
}
}
catch (errorEx &err) {

View File

@ -194,57 +194,11 @@ void db_key::load(void)
load_default(l);
}
exportType::etype db_key::clipboardFormat(QModelIndexList indexes) const
{
QList<exportType> types;
bool allPriv = true;
bool ssh2compatible = true;
foreach(QModelIndex idx, indexes) {
pki_key *key = fromIndex<pki_key>(idx);
if (!key)
continue;
if (key->isPubKey() || key->isToken())
allPriv = false;
if (!key->SSH2_compatible())
ssh2compatible = false;
}
if (!allPriv && !ssh2compatible)
return exportType::PEM_key;
types << exportType(exportType::PEM_key, "pem", tr("PEM public"));
if (ssh2compatible)
types << exportType(exportType::SSH2_public,
"pub", tr("SSH2 public"));
if (allPriv) {
types << exportType(exportType::PEM_private, "pem",
tr("PEM private"))
<< exportType(exportType::PKCS8, "pk8",
"PKCS#8");
if (ssh2compatible)
types << exportType(exportType::SSH2_private,
"priv", tr("SSH2 private"));
}
ExportDialog *dlg = new ExportDialog(NULL,
tr("Export keys to Clipboard"), QString(), NULL,
QPixmap(":keyImg"), types, "keyexport");
dlg->filename->setText(tr("Clipboard"));
dlg->filename->setEnabled(false);
dlg->fileBut->setEnabled(false);
if (!dlg->exec()) {
delete dlg;
return exportType::Separator;
}
return dlg->type();
}
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, ed25519 = false;
int disable_flags = 0;
pki_key *key = fromIndex<pki_key>(index);
pki_evp *privkey = dynamic_cast<pki_evp *>(key);
@ -253,112 +207,63 @@ void db_key::store(QModelIndex index)
return;
int keytype = key->getKeyType();
if (keytype == EVP_PKEY_RSA || keytype == EVP_PKEY_DSA)
pvk = true;
if (keytype != EVP_PKEY_RSA && keytype != EVP_PKEY_DSA)
disable_flags |= F_PVK;
#ifdef EVP_PKEY_ED25519
if (keytype == EVP_PKEY_ED25519)
ed25519 = true;
disable_flags |= F_CRYPT;
#endif
if (!key->SSH2_compatible())
disable_flags |= F_SSH2;
types <<
exportType(exportType::PEM_key, "pem", tr("PEM public")) <<
exportType(exportType::DER_key, "der", tr("DER public"));
if (key->isPubKey() || key->isToken())
disable_flags |= F_PRIVATE;
if (key->SSH2_compatible())
types << exportType(exportType::SSH2_public,
"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::PKCS8, "pk8", "PKCS#8");
if (pvk) {
types <<
exportType(exportType::PVK_private, "pvk",
tr("PVK private")) <<
exportType(exportType::PVK_encrypt, "pvk",
tr("PVK encrypted"));
}
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, "priv",
tr("SSH2 private"));
title = tr("Export private key [%1]");
types = usual << exportType() << types;
}
ExportDialog *dlg = new ExportDialog(NULL,
title.arg(key->getTypeString()),
tr("Private Keys ( *.pem *.der *.pk8 );; "
"SSH Public Keys ( *.pub )"), key,
QPixmap(key->isToken() ? ":scardImg" : ":keyImg"),
types, "keyexport");
pki_export::select(asym_key, disable_flags), "keyexport");
if (!dlg->exec()) {
delete dlg;
return;
}
try {
exportType::etype type = dlg->type();
const pki_export *xport = dlg->export_type();
pki_base::pem_comment = dlg->pemComment->isChecked();
XFile file(dlg->filename->text());
const EVP_CIPHER *algo = NULL;
int(*pwCallback)(char *, int, int, void *) = NULL;
switch (type) {
case exportType::DER_key:
case exportType::PEM_key:
case exportType::SSH2_public:
if (xport->match_all(F_CRYPT)) {
algo = EVP_aes_256_cbc();
pwCallback = PwDialogCore::pwCallback;
}
if (xport->match_all(F_PRIVATE))
file.open_write();
break;
default:
else
file.open_key();
}
switch (type) {
case exportType::DER_key:
key->writePublic(file, false);
break;
case exportType::DER_private:
if (xport->match_all(F_DER | F_PRIVATE))
privkey->writeKey(file, NULL, NULL, false);
break;
case exportType::PEM_key:
else if (xport->match_all(F_PEM | F_PRIVATE))
privkey->writeKey(file, algo, pwCallback, true);
else if (xport->match_all(F_DER))
key->writePublic(file, false);
else if (xport->match_all(F_PEM))
key->writePublic(file, true);
break;
case exportType::PEM_private_encrypt:
algo = encrypt;
/* fallthrough */
case exportType::PEM_private:
privkey->writeKey(file, algo,
PwDialogCore::pwCallback, true);
break;
case exportType::PKCS8_encrypt:
algo = encrypt;
/* fallthrough */
case exportType::PKCS8:
privkey->writePKCS8(file, algo,
PwDialogCore::pwCallback, true);
break;
case exportType::SSH2_public:
else if (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 (xport->match_all(F_SSH2))
key->writeSSH2public(file);
break;
case exportType::SSH2_private:
key->writeSSH2private(file, PwDialogCore::pwCallback);
break;
case exportType::PVK_private:
privkey->writePVKprivate(file, NULL);
break;
case exportType::PVK_encrypt:
privkey->writePVKprivate(file,PwDialogCore::pwCallback);
break;
default:
else if (xport->match_all(F_PVK))
privkey->writePVKprivate(file, pwCallback);
else
throw errorEx(tr("Internal error"));
}
}
catch (errorEx &err) {
XCA_ERROR(err);

View File

@ -8,7 +8,7 @@
#ifndef __DB_KEY_H
#define __DB_KEY_H
#include "exportType.h"
#include "pki_export.h"
#include "db_base.h"
#include "pki_key.h"
@ -21,7 +21,6 @@ class db_key: public db_base
protected:
virtual dbheaderList getHeaders();
exportType::etype clipboardFormat(QModelIndexList indexes) const;
public:
db_key();
QList<pki_key*> getUnusedKeys();

View File

@ -558,8 +558,8 @@ void db_x509::store(QModelIndex idx)
void db_x509::store(QModelIndexList list)
{
QStringList filt;
bool chain;
QList<exportType> types, usual;
bool single = list.size() == 1;;
int disable_flags = 0;
if (list.size() == 0)
return;
@ -570,68 +570,23 @@ void db_x509::store(QModelIndexList list)
pki_key *privkey = crt->getRefKey();
pki_evp *pkey;
chain = crt->getSigner() && crt->getSigner() != crt;
usual <<
exportType(exportType::PEM, "crt", "PEM") <<
exportType(exportType::PKCS7, "p7b", "PKCS #7");
if (!single || !crt->getSigner() || crt->getSigner() == crt)
disable_flags |= F_CHAIN;
types << exportType(exportType::DER, "cer", "DER");
if (!privkey || !privkey->isPrivKey() || privkey->isToken())
disable_flags |= F_PRIVATE;
if (list.size() > 1) {
usual <<
exportType(exportType::PEM_selected, "pem",
"PEM selected") <<
exportType(exportType::PKCS7_selected, "pem",
"PKCS7 selected");
}
if (chain) {
types <<
exportType(exportType::PEM_chain, "pem",
tr("PEM chain")) <<
exportType(exportType::PKCS7_chain, "p7b",
tr("PKCS#7 chain"));
}
if (single)
disable_flags |= F_SELECT;
if (privkey && privkey->isPrivKey() && !privkey->isToken()) {
if (chain) {
usual << exportType(exportType::PKCS12_chain, "pfx",
tr("PKCS#12 chain"));
types << exportType(exportType::PKCS12, "pfx",
"PKCS #12");
} else {
usual << exportType(exportType::PKCS12, "pfx",
"PKCS #12");
}
types <<
exportType(exportType::PEM_cert_key, "pem",
tr("PEM + key")) <<
exportType(exportType::PEM_cert_pk8, "pem",
"PEM + PKCS#8");
}
types << exportType() <<
exportType(exportType::PKCS7_unrevoked, "p7b",
tr("PKCS#7 unrevoked")) <<
exportType(exportType::PKCS7_all, "p7b",
tr("PKCS#7 all")) <<
exportType(exportType::PEM_unrevoked, "pem",
tr("PEM unrevoked")) <<
exportType(exportType::PEM_all, "pem",
tr("PEM all")) <<
exportType(exportType::Index, "txt",
tr("Certificate Index file"));
if (crt->getNotAfter() > a1time())
types << exportType(exportType::vcalendar, "ics",
tr("vCalendar"));
if (!single || !crt->isCA())
disable_flags |= F_CA;
if (crt->isCA())
types << exportType(exportType::vcalendar_ca, "ics",
tr("CA vCalendar"));
types = usual << exportType() << types;
ExportDialog *dlg = new ExportDialog(NULL, tr("Certificate export"),
tr("X509 Certificates ( *.pem *.cer *.crt *.p12 *.pfx *.p7b )"), crt,
QPixmap(":certImg"), types, "certexport");
QPixmap(":certImg"), pki_export::select(x509, disable_flags),
"certexport");
if (!dlg->exec()) {
delete dlg;
return;
@ -639,108 +594,72 @@ void db_x509::store(QModelIndexList list)
QStringList vcal;
QList<pki_x509*> certs;
QList<pki_base*> items;
enum exportType::etype type = dlg->type();
try {
const pki_export *xport = dlg->export_type();
XFile file(dlg->filename->text());
file.open_write();
pki_base::pem_comment = dlg->pemComment->isChecked();
switch (type) {
case exportType::PEM:
crt->writeCert(file, true);
break;
case exportType::PEM_chain:
if (xport->match_all(F_PEM | F_CHAIN)) {
while (crt && crt != oldcrt) {
crt->writeCert(file, true);
oldcrt = crt;
crt = crt->getSigner();
}
break;
case exportType::PEM_selected:
} else if (xport->match_all(F_PEM | F_SELECT)) {
foreach(QModelIndex idx, list) {
crt = fromIndex<pki_x509>(idx);
if (crt)
crt->writeCert(file, true);
}
break;
case exportType::PEM_unrevoked:
foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
} else if (xport->match_all(F_PEM | F_UNREVOKED)) {
foreach(pki_x509 *pki, Store.getAll<pki_x509>())
if (!pki->isRevoked())
pki->writeCert(file, true);
}
break;
case exportType::PEM_all:
foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
} else if (xport->match_all(F_PEM | F_ALL)) {
foreach(pki_x509 *pki, Store.getAll<pki_x509>())
pki->writeCert(file, true);
}
break;
case exportType::DER:
crt->writeCert(file, false);
break;
case exportType::PKCS7:
case exportType::PKCS7_chain:
case exportType::PKCS7_unrevoked:
case exportType::PKCS7_selected:
case exportType::PKCS7_all:
writePKCS7(crt, file, type, list);
break;
case exportType::PKCS12:
writePKCS12(crt, file, false);
break;
case exportType::PKCS12_chain:
writePKCS12(crt, file, true);
break;
case exportType::PEM_cert_pk8:
case exportType::PEM_cert_key:
} else if (xport->match_all(F_PEM | F_PRIVATE)) {
pkey = (pki_evp *)crt->getRefKey();
if (!pkey || pkey->isPubKey()) {
XCA_WARN(tr("There was no key found for the Certificate: '%1'").
if (!pkey || pkey->isPubKey())
throw errorEx(tr("There was no key found for the Certificate: '%1'").
arg(crt->getIntName()));
break;
}
if (pkey->isToken()) {
XCA_WARN(tr("Not possible for a token key: '%1'").
if (pkey->isToken())
throw errorEx(tr("Not possible for a token key: '%1'").
arg(crt->getIntName()));
break;
}
if (type == exportType::PEM_cert_pk8) {
if (xport->match_all(F_PKCS8)) {
pkey->writePKCS8(file, EVP_des_ede3_cbc(),
PwDialogCore::pwCallback, true);
PwDialogCore::pwCallback, true);
} else {
pkey->writeKey(file, NULL, NULL, true);
}
crt->writeCert(file, true);
break;
case exportType::Index:
} else if (xport->match_all(F_PEM)) {
crt->writeCert(file, true);
} else if (xport->match_all(F_DER)) {
crt->writeCert(file, false);
} else if (xport->match_all(F_PKCS7)) {
writePKCS7(crt, file, xport->flags, list);
} else if (xport->match_all(F_PKCS12)) {
writePKCS12(crt, file, xport->match_all(F_CHAIN));
} else if (xport->match_all(F_INDEX)) {
foreach(QModelIndex idx, list) {
crt = fromIndex<pki_x509>(idx);
if (crt)
certs << crt;
}
writeIndex(file, certs);
break;
case exportType::vcalendar:
} else if (xport->match_all(F_CAL)) {
foreach(QModelIndex idx, list) {
crt = fromIndex<pki_x509>(idx);
if (crt)
vcal += crt->icsVEVENT();
if (!crt)
continue;
vcal += xport->match_all(F_CHAIN) ?
crt->icsVEVENT_ca() : crt->icsVEVENT();
}
writeVcalendar(file, vcal);
break;
case exportType::vcalendar_ca:
foreach(QModelIndex idx, list) {
crt = fromIndex<pki_x509>(idx);
if (crt)
vcal += crt->icsVEVENT_ca();
}
writeVcalendar(file, vcal);
break;
default:
exit(1);
}
}
catch (errorEx &err) {
} catch (errorEx &err) {
XCA_ERROR(err);
}
pki_base::pem_comment = false;
@ -786,43 +705,32 @@ void db_x509::writePKCS12(pki_x509 *cert, XFile &file, bool chain) const
delete p12;
}
void db_x509::writePKCS7(pki_x509 *cert, XFile &file, exportType::etype type,
void db_x509::writePKCS7(pki_x509 *cert, XFile &file, int flags,
QModelIndexList list) const
{
pki_pkcs7 *p7 = NULL;
pki_pkcs7 *p7 = new pki_pkcs7(QString());
try {
p7 = new pki_pkcs7(QString());
switch (type) {
case exportType::PKCS7_chain:
while (cert != NULL) {
if (flags & F_CHAIN) {
while (cert) {
p7->append_item(cert);
if (cert->getSigner() == cert)
cert = NULL;
else
cert = cert->getSigner();
break;
cert = cert->getSigner();
}
break;
case exportType::PKCS7:
p7->append_item(cert);
break;
case exportType::PKCS7_selected:
} else if (flags & F_SELECT) {
foreach(QModelIndex idx, list) {
cert = fromIndex<pki_x509>(idx);
if (cert)
p7->append_item(cert);
}
break;
case exportType::PKCS7_unrevoked:
case exportType::PKCS7_all:
} else if (flags & (F_UNREVOKED | F_ALL)) {
foreach(pki_x509 *cer, Store.getAll<pki_x509>()) {
if ((type == exportType::PKCS7_all) ||
(!cer->isRevoked()))
if ((flags & F_ALL) || !cer->isRevoked())
p7->append_item(cer);
}
break;
default:
exit(1);
} else {
p7->append_item(cert);
}
p7->writeP7(file, false);
}

View File

@ -9,7 +9,7 @@
#ifndef __DB_X509_H
#define __DB_X509_H
#include "exportType.h"
#include "pki_export.h"
#include "db_x509super.h"
#include "asn1int.h"
#include "x509rev.h"
@ -47,8 +47,8 @@ class db_x509: public db_x509super
pki_x509 *newCert(NewX509 *dlg);
void newCert(pki_x509 *cert);
void writePKCS12(pki_x509 *cert, XFile &file, bool chain) const;
void writePKCS7(pki_x509 *cert, XFile &file,
exportType::etype type, QModelIndexList list) const;
void writePKCS7(pki_x509 *cert, XFile &file, int flags,
QModelIndexList list) const;
void fillContextMenu(QMenu *menu, const QModelIndex &index);
void inToCont(pki_base *pki);
a1int getUniqueSerial(pki_x509 *signer);

View File

@ -108,28 +108,25 @@ void db_x509req::load(void)
void db_x509req::store(QModelIndex index)
{
QList<exportType> types;
pki_x509req *req = fromIndex<pki_x509req>(index);
if (!req)
return;
types << exportType(exportType::PEM, "pem", "PEM") <<
exportType(exportType::DER, "der", "DER");
ExportDialog *dlg = new ExportDialog(NULL,
tr("Certificate request export"),
tr("Certificate request ( *.pem *.der *.csr )"), req,
QPixmap(":csrImg"), types, "csrexport");
tr("Certificate request ( *.pem *.der *.csr )"),
req, QPixmap(":csrImg"),
pki_export::select(x509_req, 0), "csrexport");
if (!dlg->exec()) {
delete dlg;
return;
}
try {
const pki_export *xport = dlg->export_type();
XFile file(dlg->filename->text());
pki_base::pem_comment = dlg->pemComment->isChecked();
file.open_write();
req->writeReq(file, dlg->type() == exportType::PEM);
req->writeReq(file, xport->match_all(F_PEM));
}
catch (errorEx &err) {
XCA_ERROR(err);

View File

@ -1,52 +0,0 @@
/* vi: set sw=4 ts=4:
*
* Copyright (C) 2021 Christian Hohnstaedt.
*
* All rights reserved.
*/
#ifndef __EXPORTTYPE_H
#define __EXPORTTYPE_H
#include <QMetaType>
#include <QString>
class exportType {
public:
enum etype { Separator, PEM, PEM_chain, PEM_unrevoked, PEM_all,
DER, PKCS7, PKCS7_chain, PKCS7_unrevoked, PKCS7_all,
PKCS12, PKCS12_chain, PEM_cert_key, PEM_cert_pk8,
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, SSH2_private, ETYPE_max };
enum etype type;
QString extension;
QString desc;
exportType(enum etype t, const QString &e, const QString &d)
: type(t), extension(e), desc(d)
{
}
exportType() : type(Separator) { }
bool isPEM() const {
switch (type) {
case PEM:
case PEM_chain:
case PEM_unrevoked:
case PEM_all:
case PEM_cert_key:
case PEM_cert_pk8:
case PEM_key:
case PEM_private:
case PEM_private_encrypt:
case PEM_selected:
case SSH2_private:
return true;
default:
return false;
}
}
};
Q_DECLARE_METATYPE(exportType);
#endif

View File

@ -20,21 +20,11 @@
#include "headerlist.h"
#include "sql.h"
#include "xfile.h"
#include "pki_export.h"
#define pki_openssl_error() _openssl_error(*this, C_FILE, __LINE__)
#define pki_ign_openssl_error() _ign_openssl_error(*this, C_FILE, __LINE__)
enum pki_type {
none,
asym_key,
x509_req,
x509,
revocation,
tmpl,
setting,
smartCard,
};
enum pki_source {
unknown,
imported,

View File

@ -669,11 +669,9 @@ bool pki_evp::pem(BioByteArray &b)
{
EVP_PKEY *pkey;
int keytype;
int format = Settings["KeyFormat"];
const pki_export *xport = pki_export::default_key_format();
switch (format) {
case exportType::PEM_private:
case exportType::SSH2_private:
if (xport->match_all(F_PEM | F_PRIVATE)) {
pkey = decryptKey();
keytype = EVP_PKEY_id(pkey);
switch (keytype) {
@ -695,7 +693,7 @@ bool pki_evp::pem(BioByteArray &b)
break;
#ifdef EVP_PKEY_ED25519
case EVP_PKEY_ED25519:
if (format == exportType::PEM_private)
if (xport->match_all(F_PRIVATE))
return false;
write_SSH2_ed25519_private(b, pkey, NULL);
break;
@ -703,22 +701,17 @@ bool pki_evp::pem(BioByteArray &b)
#endif
}
EVP_PKEY_free(pkey);
break;
case exportType::PKCS8:
} else if (xport->match_all(F_PKCS8 | F_PRIVATE)) {
const EVP_CIPHER *algo = xport->match_all(F_CRYPT) ?
EVP_aes_256_cbc() : NULL;
pkey = decryptKey();
PEM_write_bio_PrivateKey(b, pkey, NULL, NULL, 0, NULL, NULL);
EVP_PKEY_free(pkey);
break;
case exportType::PKCS8_encrypt:
pkey = decryptKey();
PEM_write_bio_PrivateKey(b, pkey, EVP_aes_256_cbc(),
PEM_write_bio_PrivateKey(b, pkey, NULL,
passwd.constUchar(), passwd.size(),
NULL, NULL);
EVP_PKEY_free(pkey);
break;
default:
} else
return pki_key::pem(b);
}
return true;
}
void pki_evp::writePKCS8(XFile &file, const EVP_CIPHER *enc,

86
lib/pki_export.cpp Normal file
View File

@ -0,0 +1,86 @@
/* vi: set sw=4 ts=4:
*
* Copyright (C) 2021 Christian Hohnstaedt.
*
* All rights reserved.
*/
#include "pki_export.h"
#include "settings.h"
pki_export::pki_export(int i, enum pki_type p, const QString &e,
const QString &d, int f, const QString &h)
: id(i), pki_type(p), extension(e), flags(f), desc(d), help(h)
{
}
bool pki_export::match_all(int match_flags) const
{
return (flags & match_flags) == match_flags;
}
QList<const pki_export*>
pki_export::select(enum pki_type pki_type, int disable)
{
QList<const pki_export*> ret;
foreach(const pki_export *exp, elements) {
if (exp->pki_type == pki_type && (disable & exp->flags) == 0)
ret << exp;
}
return ret;
}
const pki_export *pki_export::by_id(int id)
{
foreach(const pki_export *exp, elements) {
if (exp->id == id)
return exp;
}
return NULL;
}
const pki_export *pki_export::default_key_format()
{
return by_id(Settings["KeyFormat"]);
}
QList<pki_export*> pki_export::elements {
new pki_export( 1, x509, "crt", "PEM", F_PEM | F_USUAL, tr("PEM Text format with headers")),
new pki_export( 2, x509, "pem", tr("PEM chain"), F_PEM | F_USUAL | F_CHAIN, tr("Concatenated text format of the complete certificate chain in one PEM file")),
new pki_export( 3, x509, "pem", tr("PEM selected"), F_PEM | F_USUAL | F_SELECT, tr("Concatenated list of all selected items in one PEM text file")),
new pki_export( 4, x509, "pem", tr("PEM unrevoked"), F_PEM | F_UNREVOKED, tr("Concatenated text format of all unrevoked certificates in one PEM file")),
new pki_export( 5, x509, "pem", tr("PEM all"), F_PEM | F_MULTI | F_ALL, tr("Concatenated text format of all certificates in one PEM file")),
new pki_export( 6, x509, "pem", tr("PEM + key"), F_PEM | F_PLUSKEY | F_PRIVATE, tr("Concatenation of the certificate and the unencrypted private key in one PEM file")),
new pki_export( 7, x509, "pem", "PEM + PKCS#8", F_PEM | F_PKCS8 | F_PRIVATE | F_CRYPT, tr("Concatenation of the certificate and the encrypted private key in PKCS#8 format in one file")),
new pki_export( 8, x509, "p7b", "PKCS #7", F_PKCS7 | F_USUAL, tr("PKCS#7 encoded single certificate")),
new pki_export( 9, x509, "p7b", tr("PKCS #7 all"), F_PKCS7 | F_USUAL | F_MULTI | F_ALL, tr("All selected certificates encoded in one PKCS#7 file")),
new pki_export(10, x509, "p7b", tr("PKCS #7 selected"), F_PKCS7 | F_USUAL | F_MULTI | F_SELECT, tr("All selected certificates encoded in one PKCS#7 file")),
new pki_export(11, x509, "p7b", tr("PKCS #7 unrevoked"), F_PKCS7 | F_MULTI | F_UNREVOKED, tr("All unrevoked certificates encoded in one PKCS#7 file")),
new pki_export(12, x509, "p7b", tr("PKCS #7 chain"), F_PKCS7 | F_USUAL | F_CHAIN, tr("PKCS#7 encoded complete certificate chain")),
new pki_export(13, x509, "cer", "DER", F_DER, tr("Binary DER encoded certificate")),
new pki_export(14, x509, "pfx", tr("PKCS #12 chain"),F_PKCS12 | F_USUAL | F_CHAIN | F_CRYPT | F_PRIVATE, tr("The complete certificate chain and the private key as encrypted PKCS#12 file")),
new pki_export(15, x509, "pfx", tr("PKCS #12"), F_PKCS12 | F_USUAL | F_CRYPT | F_PRIVATE, tr("The certificate and the private key as encrypted PKCS#12 file")),
new pki_export(16, x509, "txt", tr("Certificate Index file"), F_INDEX | F_CA, tr("OpenSSL specific Certificate Index file as created by the 'ca' command and required by the OCSP tool")),
new pki_export(17, x509, "ics", tr("vCalendar"), F_CAL, tr("vCalendar expiry reminder for the selected items")),
new pki_export(18, x509, "ics", tr("CA vCalendar"), F_CAL | F_CA, tr("vCalendar expiry reminder containing all issued, valid certificates, the CA itself and the latest CRL")),
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_CLIPBOARD, 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, 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, tr("Binary DER format of the public key")),
new pki_export(25, asym_key, "der", tr("DER private"), F_DER | F_PRIVATE, tr("Unencrypted private key in binary DER format")),
new pki_export(26, asym_key, "pvk", tr("PVK private"), F_PVK | F_PRIVATE, tr("Private key in Microsoft PVK format not encrypted")),
new pki_export(27, asym_key, "pvk", tr("PVK encrypted"), F_PVK | F_PRIVATE | F_CRYPT, tr("Encrypted private key in Microsoft PVK format")),
new pki_export(28, asym_key, "pk8", tr("PKCS #8 encrypted"), F_PKCS8 | F_PRIVATE | F_CRYPT | F_USUAL | F_CLIPBOARD, tr("Encrypted private key in PKCS#8 text format")),
new pki_export(29, asym_key, "pk8", tr("PKCS #8"), F_PKCS8 | F_PRIVATE | F_CLIPBOARD, tr("Unencrypted private key in PKCS#8 text format")),
new pki_export(30, x509_req, "csr", "PEM", F_PEM, tr("PEM Text format with headers")),
new pki_export(31, x509_req, "der", "DER", F_DER, tr("Binary DER format of the certificate request")),
new pki_export(32, revocation, "pem", "PEM", F_PEM, tr("PEM Text format with headers")),
new pki_export(33, revocation, "der", "DER", F_DER, tr("Binary DER format of the revocation list")),
new pki_export(34, revocation, "ics", tr("vCalendar"), F_CAL, tr("vCalendar reminder for the CRL expiry date")),
};

76
lib/pki_export.h Normal file
View File

@ -0,0 +1,76 @@
/* vi: set sw=4 ts=4:
*
* Copyright (C) 2021 Christian Hohnstaedt.
*
* All rights reserved.
*/
#ifndef __PKI_EXPORT_H
#define __PKI_EXPORT_H
#include <QObject>
#include <QMetaType>
#include <QString>
#include <QList>
#define BIT(n) (1<<n)
enum pki_type {
none,
asym_key,
x509_req,
x509,
revocation,
tmpl,
setting,
smartCard,
};
enum {
F_PEM = BIT(0), /* File is PEM encoded */
F_CRYPT = BIT(1), /* Key will be encrypted */
F_PRIVATE = BIT(2), /* File contains Private Key */
F_USUAL = BIT(3), /* Usual format */
F_SSH2 = BIT(4), /* Key is SSH2 compatible */
F_MULTI = BIT(5), /* More than one element */
F_SELECT = BIT(6), /* Selected elements */
F_ALL = BIT(7), /* All elements */
F_UNREVOKED = BIT(8), /* All unrevoked certificates */
F_PLUSKEY = BIT(9), /* Cert plus key */
F_CA = BIT(10),/* Export types for CAs */
F_CHAIN = BIT(11),/* Certificate chain */
F_PKCS7 = BIT(12),
F_PKCS8 = BIT(13),
F_PKCS12 = BIT(14),
F_CLIPBOARD = BIT(15),/* Suitable key format for the clipboard */
F_PVK = BIT(16),
F_INDEX = BIT(17),
F_CAL = BIT(18),/* Calendar entry */
F_DER = BIT(19),/* DER format */
};
class pki_export : public QObject {
Q_OBJECT
public:
int id;
enum pki_type pki_type;
QString extension;
int flags;
QString desc;
QString help;
pki_export(int i, enum pki_type p, const QString &e,
const QString &d, int f, const QString &h);
static QList<const pki_export*> select(enum pki_type, int);
static const pki_export *default_key_format();
static const pki_export *by_id(int id);
bool match_all(int match_flags) const;
private:
static QList<pki_export*> elements;
};
#endif

View File

@ -10,7 +10,7 @@
#include "pki_x509super.h"
#include "func.h"
#include "pkcs11.h"
#include "exportType.h"
#include "pki_export.h"
#include "XcaWarningCore.h"
#include <openssl/rand.h>
@ -125,16 +125,15 @@ void pki_key::write_SSH2_ed25519_private(BIO *b,
bool pki_key::pem(BioByteArray &b)
{
switch ((int)Settings["KeyFormat"]) {
case exportType::SSH2_public:
b += SSH2publicQByteArray();
break;
case exportType::PEM_key:
PEM_write_bio_PUBKEY(b, key);
break;
default:
const pki_export *xport = pki_export::default_key_format();
if (xport->match_all(F_PRIVATE))
return false;
}
if (xport->match_all(F_SSH2))
b += SSH2publicQByteArray();
else if (xport->match_all(F_PEM))
PEM_write_bio_PUBKEY(b, key);
return true;
}

View File

@ -13,7 +13,7 @@
#include <openssl/pem.h>
#include <openssl/evp.h>
#include "pki_base.h"
#include "exportType.h"
//#include "pki_export.h"
#include "builtin_curves.h"
#define PEM_STRING_OPENSSH_KEY "OPENSSH PRIVATE KEY"

View File

@ -3,7 +3,7 @@
#include "sql.h"
#include "pki_key.h"
#include "digest.h"
#include "exportType.h"
#include <QDir>
#include <QFile>
#include <openssl/asn1.h>
@ -38,7 +38,7 @@ settings::settings()
defaul["serial_len"] = "64";
defaul["fp_separator"] = ":";
defaul["fp_digits"] = "2";
defaul["KeyFormat"] = QString("%1").arg(exportType::PEM_key);
defaul["KeyFormat"] = "19"; // PEM public
hostspecific << "pkcs11path" << "workingdir" << "mw_geometry";
}

View File

@ -21,9 +21,10 @@
ExportDialog::ExportDialog(QWidget *w, const QString &title,
const QString &filt, pki_base *pki, const QPixmap &img,
QList<exportType> types, const QString &help_ctx)
QList<const pki_export*> types, const QString &help_ctx)
: QDialog(w ? w : mainwin)
{
QList<const pki_export*> usual, normal;
setupUi(this);
setWindowTitle(XCA_TITLE);
if (pki)
@ -35,66 +36,25 @@ ExportDialog::ExportDialog(QWidget *w, const QString &title,
if (pki) {
QString fn = Settings["workingdir"] +
pki->getUnderlinedName() + "." + types[0].extension;
pki->getUnderlinedName() + "." + types[0]->extension;
filename->setText(nativeSeparator(fn));
}
filter = filt + ";;" + tr("All files ( * )");
foreach(exportType t, types) {
QVariant q;
q.setValue(t);
if (t.type == exportType::Separator)
exportFormat->insertSeparator(exportFormat->count());
foreach(const pki_export *t, types) {
if (t->flags & F_USUAL)
usual << t;
else
exportFormat->addItem(QString("%1 (*.%2)").
arg(t.desc).arg(t.extension), q);
normal << t;
}
foreach(const pki_export *t, usual + normal) {
exportFormat->addItem(QString("%1 (*.%2)").
arg(t->desc).arg(t->extension), QVariant(t->id));
}
if (usual.size() > 0 && normal.size() > 0)
exportFormat->insertSeparator(usual.size());
for (int i=0; i < exportType::ETYPE_max; i++)
help.append(QString());
help[exportType::Separator] = "What the heck!?";
help[exportType::PEM] = tr("PEM Text format with headers");
help[exportType::PEM_selected] =
tr("Concatenated list of all selected items in one PEM text file");
help[exportType::PEM_chain] = tr("Concatenated text format of the complete certificate chain in one PEM file");
help[exportType::PEM_unrevoked] =
tr("Concatenated text format of all unrevoked certificates in one PEM file");
help[exportType::PEM_all] =
tr("Concatenated text format of all certificates in one PEM file");
help[exportType::DER] = tr("Binary DER encoded file");
help[exportType::PKCS7] = tr("PKCS#7 encoded single certificate");
help[exportType::PKCS7_chain] =
tr("PKCS#7 encoded complete certificate chain");
help[exportType::PKCS7_unrevoked] =
tr("All unrevoked certificates encoded in one PKCS#7 file");
help[exportType::PKCS7_selected] =
tr("All selected certificates encoded in one PKCS#7 file");
help[exportType::PKCS7_all] =
tr("All certificates encoded in one PKCS#7 file");
help[exportType::PKCS12] =
tr("The certificate and the private key as encrypted PKCS#12 file");
help[exportType::PKCS12_chain] = tr("The complete certificate chain and the private key as encrypted PKCS#12 file");
help[exportType::PEM_cert_key] = tr("Concatenation of the certificate and the unencrypted private key in one PEM file");
help[exportType::PEM_cert_pk8] = tr("Concatenation of the certificate and the encrypted private key in PKCS#8 format in one file");
help[exportType::PEM_key] = tr("Text format of the public key in one PEM file");
help[exportType::DER_key] = tr("Binary DER format of the public key");
help[exportType::PEM_private] =
tr("Unencrypted private key in text format");
help[exportType::PEM_private_encrypt] =
tr("OpenSSL specific encrypted private key in text format");
help[exportType::DER_private] =
tr("Unencrypted private key in binary DER format");
help[exportType::PKCS8] =
tr("Unencrypted private key in PKCS#8 text format");
help[exportType::PKCS8_encrypt] =
tr("Encrypted private key in PKCS#8 text format");
help[exportType::SSH2_public] = tr("The public key encoded in SSH2 format");
help[exportType::Index] = tr("OpenSSL specific Certificate Index file as created by the 'ca' command and required by the OCSP tool");
help[exportType::vcalendar] = tr("vCalendar expiry reminder for the selected items");
help[exportType::vcalendar_ca] = tr("vCalendar expiry reminder containing all issued, valid certificates, the CA itself and the latest CRL");
help[exportType::PVK_private] = tr("Private key in Microsoft PVK format not encrypted");
help[exportType::PVK_encrypt] = tr("Encrypted private key in Microsoft PVK format");
exportFormat->setCurrentIndex(0);
on_exportFormat_highlighted(0);
}
@ -111,13 +71,13 @@ void ExportDialog::on_fileBut_clicked()
void ExportDialog::on_exportFormat_activated(int selected)
{
QString fn = filename->text();
exportType form = exportFormat->itemData(selected).value<exportType>();
const pki_export *t_sel = export_type(selected);
for (int i=0; i< exportFormat->count(); i++) {
exportType t = exportFormat->itemData(i).value<exportType>();
if (fn.endsWith(QString(".") + t.extension)) {
fn = fn.left(fn.length() - t.extension.length()) +
form.extension;
const pki_export *t = export_type(i);
if (t && fn.endsWith(QString(".") + t->extension)) {
fn = fn.left(fn.length() - t->extension.length()) +
t_sel->extension;
break;
}
}
@ -157,15 +117,17 @@ void ExportDialog::accept()
}
}
enum exportType::etype ExportDialog::type()
const pki_export *ExportDialog::export_type(int idx) const
{
int selected = exportFormat->currentIndex();
exportType form = exportFormat->itemData(selected).value<exportType>();
return form.type;
if (idx == -1)
idx = exportFormat->currentIndex();
idx = exportFormat->itemData(idx).toInt();
return idx ? pki_export::by_id(idx) : NULL;
}
void ExportDialog::on_exportFormat_highlighted(int index)
{
exportType form = exportFormat->itemData(index).value<exportType>();
infoBox->setText(help[form.type]);
const pki_export *x = export_type(index);
if (x)
infoBox->setText(x->help);
}

View File

@ -9,7 +9,7 @@
#define __EXPORTDIALOG_H
#include "ui_ExportDialog.h"
#include "lib/exportType.h"
#include "lib/pki_export.h"
class QPixmap;
class pki_base;
@ -20,14 +20,14 @@ class ExportDialog: public QDialog, public Ui::ExportDialog
protected:
QString filter;
QVector<QString> help;
public:
ExportDialog(QWidget *w, const QString &title, const QString &filt,
pki_base *pki, const QPixmap &img, QList<exportType> types,
pki_base *pki, const QPixmap &img,
QList<const pki_export*> types,
const QString &help_ctx = QString());
static bool mayWriteFile(const QString &fname);
enum exportType::etype type();
const pki_export *export_type(int idx = -1) const;
public slots:
void on_fileBut_clicked();

View File

@ -24,26 +24,19 @@ void KeyTreeView::fillContextMenu(QMenu *menu, QMenu *subExport,
pki_key *key = db_base::fromIndex<pki_key>(index);
int exp_type = Settings["KeyFormat"];
const pki_export *x;
clipboard = menu->addMenu(tr("Clipboard format"));
/* The evil copy & paster striked again */
a = clipboard->addAction(tr("PEM public"));
a->setData(QVariant(exportType::PEM_key));
a->setCheckable(true);
a->setChecked(exp_type == exportType::PEM_key);
group->addAction(a);
a = clipboard->addAction(tr("PEM private"));
a->setData(QVariant(exportType::PEM_private));
a->setCheckable(true);
a->setChecked(exp_type == exportType::PEM_private);
group->addAction(a);
a = clipboard->addAction(tr("PKCS#8"));
a->setData(QVariant(exportType::PKCS8));
a->setCheckable(true);
a->setChecked(exp_type == exportType::PKCS8);
group->addAction(a);
foreach(x, pki_export::select(asym_key, 0)) {
if (!(x->flags & F_CLIPBOARD))
continue;
qWarning() << "CLIPBOARD" << x->id << x->desc;
a = clipboard->addAction(x->desc);
a->setData(x->id);
a->setCheckable(true);
a->setChecked(exp_type == x->id);
group->addAction(a);
}
connect(group, SIGNAL(triggered(QAction*)),
this, SLOT(clipboardFormat(QAction*)));