diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c96fd6ed..384a197b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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 ) diff --git a/lib/db_base.h b/lib/db_base.h index 48492e32..ad78af67 100644 --- a/lib/db_base.h +++ b/lib/db_base.h @@ -11,7 +11,6 @@ #include #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; diff --git a/lib/db_crl.cpp b/lib/db_crl.cpp index 82e385f5..8c8da367 100644 --- a/lib/db_crl.cpp +++ b/lib/db_crl.cpp @@ -125,26 +125,23 @@ void db_crl::store(QModelIndex index) if (!index.isValid() || !crl) return; - QList 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) { diff --git a/lib/db_key.cpp b/lib/db_key.cpp index 03e27913..0379f4f3 100644 --- a/lib/db_key.cpp +++ b/lib/db_key.cpp @@ -194,57 +194,11 @@ void db_key::load(void) load_default(l); } -exportType::etype db_key::clipboardFormat(QModelIndexList indexes) const -{ - QList types; - bool allPriv = true; - bool ssh2compatible = true; - - foreach(QModelIndex idx, indexes) { - pki_key *key = fromIndex(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 types; - bool pvk = false, ed25519 = false; + int disable_flags = 0; pki_key *key = fromIndex(index); pki_evp *privkey = dynamic_cast(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 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); diff --git a/lib/db_key.h b/lib/db_key.h index 179250dc..f788fbdf 100644 --- a/lib/db_key.h +++ b/lib/db_key.h @@ -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 getUnusedKeys(); diff --git a/lib/db_x509.cpp b/lib/db_x509.cpp index a2667132..726856bd 100644 --- a/lib/db_x509.cpp +++ b/lib/db_x509.cpp @@ -558,8 +558,8 @@ void db_x509::store(QModelIndex idx) void db_x509::store(QModelIndexList list) { QStringList filt; - bool chain; - QList 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 certs; QList 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(idx); if (crt) crt->writeCert(file, true); } - break; - case exportType::PEM_unrevoked: - foreach(pki_x509 *pki, Store.getAll()) { + } else if (xport->match_all(F_PEM | F_UNREVOKED)) { + foreach(pki_x509 *pki, Store.getAll()) if (!pki->isRevoked()) pki->writeCert(file, true); - } - break; - case exportType::PEM_all: - foreach(pki_x509 *pki, Store.getAll()) { + } else if (xport->match_all(F_PEM | F_ALL)) { + foreach(pki_x509 *pki, Store.getAll()) 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(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(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(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(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()) { - 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); } diff --git a/lib/db_x509.h b/lib/db_x509.h index 6dc11300..dc0a8fbc 100644 --- a/lib/db_x509.h +++ b/lib/db_x509.h @@ -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); diff --git a/lib/db_x509req.cpp b/lib/db_x509req.cpp index 40bbd6b9..aa8cc94f 100644 --- a/lib/db_x509req.cpp +++ b/lib/db_x509req.cpp @@ -108,28 +108,25 @@ void db_x509req::load(void) void db_x509req::store(QModelIndex index) { - QList types; - pki_x509req *req = fromIndex(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); diff --git a/lib/exportType.h b/lib/exportType.h deleted file mode 100644 index a7b0a6f9..00000000 --- a/lib/exportType.h +++ /dev/null @@ -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 -#include - -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 diff --git a/lib/pki_base.h b/lib/pki_base.h index 92ca4108..8c1beb2f 100644 --- a/lib/pki_base.h +++ b/lib/pki_base.h @@ -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, diff --git a/lib/pki_evp.cpp b/lib/pki_evp.cpp index 4f5aac72..d786ba4a 100644 --- a/lib/pki_evp.cpp +++ b/lib/pki_evp.cpp @@ -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, diff --git a/lib/pki_export.cpp b/lib/pki_export.cpp new file mode 100644 index 00000000..12dbc4f4 --- /dev/null +++ b/lib/pki_export.cpp @@ -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 +pki_export::select(enum pki_type pki_type, int disable) +{ + QList 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::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")), + }; diff --git a/lib/pki_export.h b/lib/pki_export.h new file mode 100644 index 00000000..85f9704a --- /dev/null +++ b/lib/pki_export.h @@ -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 +#include +#include +#include + +#define BIT(n) (1< 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 elements; +}; + +#endif diff --git a/lib/pki_key.cpp b/lib/pki_key.cpp index ce6fcfc0..dd9333e4 100644 --- a/lib/pki_key.cpp +++ b/lib/pki_key.cpp @@ -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 @@ -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; } diff --git a/lib/pki_key.h b/lib/pki_key.h index a58fd7e7..1a8fc2de 100644 --- a/lib/pki_key.h +++ b/lib/pki_key.h @@ -13,7 +13,7 @@ #include #include #include "pki_base.h" -#include "exportType.h" +//#include "pki_export.h" #include "builtin_curves.h" #define PEM_STRING_OPENSSH_KEY "OPENSSH PRIVATE KEY" diff --git a/lib/settings.cpp b/lib/settings.cpp index a16c482f..4493de3b 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -3,7 +3,7 @@ #include "sql.h" #include "pki_key.h" #include "digest.h" -#include "exportType.h" + #include #include #include @@ -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"; } diff --git a/widgets/ExportDialog.cpp b/widgets/ExportDialog.cpp index b0d9eeef..0b813153 100644 --- a/widgets/ExportDialog.cpp +++ b/widgets/ExportDialog.cpp @@ -21,9 +21,10 @@ ExportDialog::ExportDialog(QWidget *w, const QString &title, const QString &filt, pki_base *pki, const QPixmap &img, - QList types, const QString &help_ctx) + QList types, const QString &help_ctx) : QDialog(w ? w : mainwin) { + QList 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(); + const pki_export *t_sel = export_type(selected); for (int i=0; i< exportFormat->count(); i++) { - exportType t = exportFormat->itemData(i).value(); - 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(); - 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(); - infoBox->setText(help[form.type]); + const pki_export *x = export_type(index); + if (x) + infoBox->setText(x->help); } diff --git a/widgets/ExportDialog.h b/widgets/ExportDialog.h index e69d0677..58a783fb 100644 --- a/widgets/ExportDialog.h +++ b/widgets/ExportDialog.h @@ -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 help; public: ExportDialog(QWidget *w, const QString &title, const QString &filt, - pki_base *pki, const QPixmap &img, QList types, + pki_base *pki, const QPixmap &img, + QList 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(); diff --git a/widgets/KeyTreeView.cpp b/widgets/KeyTreeView.cpp index cb53c0dc..cd19d57d 100644 --- a/widgets/KeyTreeView.cpp +++ b/widgets/KeyTreeView.cpp @@ -24,26 +24,19 @@ void KeyTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, pki_key *key = db_base::fromIndex(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*)));