From e94e9133b17cda4518f01330d30f92bf0c7a8f88 Mon Sep 17 00:00:00 2001 From: Adam Dawidowski Date: Mon, 14 Mar 2016 18:21:32 +0100 Subject: [PATCH] Support generating an OpenSSL "index.txt" XCA currently lacks support for generating an index.txt. Such a file gets created and maintained when using CA features in openssl. As mentioned here: https://sourceforge.net/p/xca/discussion/209946/thread/6cbc727c/#2310 such a file can be used by Openssl's built-in OCSP responder. Additionally, it can be used for configuring a cron job for reminding of certificate expiration. Certificate index export is added in 3 places: - command line (-i index.txt), - the Extras menu (Extra->Export Certificate Index) and - the selected file(s) export option in the context menu on the Certificates tab (Export->File, Export Format: Certificate Index file). Please note that SubjectDN generated by this feature has different formatting than the one generated by openssl. --- lib/db_x509.cpp | 21 ++++++++++++++++++++- lib/db_x509.h | 1 + lib/pki_x509.cpp | 36 ++++++++++++++++++++++++++++++++++++ lib/pki_x509.h | 2 ++ widgets/ExportDialog.cpp | 1 + widgets/ExportDialog.h | 2 +- widgets/MW_help.cpp | 1 + widgets/MW_menu.cpp | 2 ++ widgets/MainWindow.cpp | 38 +++++++++++++++++++++++++++++++++++++- widgets/MainWindow.h | 2 ++ 10 files changed, 103 insertions(+), 3 deletions(-) diff --git a/lib/db_x509.cpp b/lib/db_x509.cpp index 18a210e0..f39899ba 100644 --- a/lib/db_x509.cpp +++ b/lib/db_x509.cpp @@ -307,6 +307,15 @@ QList db_x509::getCerts(bool onlyTrusted) return c; } +void db_x509::writeIndex(const QString fname) +{ + bool append = false; + FOR_ALL_pki(pki, pki_x509) { + pki->writeIndexEntry(fname, append); + append = true; + } +} + a1int db_x509::searchSerial(pki_x509 *signer) { // returns the highest certificate serial @@ -677,7 +686,9 @@ void db_x509::store(QModelIndexList list) exportType(exportType::PEM_trusted, "pem", tr("PEM trusted")) << exportType(exportType::PEM_all, "pem", - tr("PEM all")); + tr("PEM all")) << + exportType(exportType::Index, "txt", + tr("Certificate Index file")); types = usual << exportType() << types; ExportDialog *dlg = new ExportDialog(mainwin, tr("Certificate export"), @@ -756,6 +767,14 @@ void db_x509::store(QModelIndexList list) } crt->writeCert(fname, true, true); break; + case exportType::Index: + append = false; + foreach(QModelIndex idx, list) { + crt = static_cast(idx.internalPointer()); + crt->writeIndexEntry(fname, append); + append = true; + } + break; default: exit(1); } diff --git a/lib/db_x509.h b/lib/db_x509.h index 18aaee6e..2f1ec759 100644 --- a/lib/db_x509.h +++ b/lib/db_x509.h @@ -46,6 +46,7 @@ class db_x509: public db_x509super QList getCerts(bool onlyTrusted); a1int searchSerial(pki_x509 *signer); void writeAllCerts(const QString fname, bool onlyTrusted); + void writeIndex(const QString fname); pki_x509 *getByIssSerial(const pki_x509 *issuer, const a1int &a); pki_x509 *getBySubject(const x509name &xname, pki_x509 *last = NULL); pki_base *insert(pki_base *item); diff --git a/lib/pki_x509.cpp b/lib/pki_x509.cpp index 84830832..21a0da83 100644 --- a/lib/pki_x509.cpp +++ b/lib/pki_x509.cpp @@ -583,6 +583,42 @@ void pki_x509::writeCert(const QString fname, bool PEM, bool append) fopen_error(fname); } +void pki_x509::writeIndexEntry(FILE *fp) +{ + QString flag = NULL; + bool revoked = isRevoked(); + + if (revoked) + flag = "R"; + else if (checkDate()) + flag = "V"; + else + flag = "E"; + + QString line = QString("%1\t%2\t%3\t%4\tunknown\t%5\n").arg( + flag, getNotAfter().toPlain(), (revoked ? revocation.getDate().toPlain() : ""), + getSerial().toHex(), getSubject().oneLine(XN_FLAG_ONELINE)); + + QByteArray ba = line.toUtf8(); + fwrite(ba.constData(), ba.size(), 1, fp); +} + +void pki_x509::writeIndexEntry(const QString fname, bool append) +{ + FILE *fp; + const char *p = "w"; + if (append) + p = "a"; + fp = fopen(QString2filename(fname), p); + if (fp != NULL) { + if (cert) + writeIndexEntry(fp); + fclose(fp); + pki_openssl_error(); + } else + fopen_error(fname); +} + BIO *pki_x509::pem(BIO *b, int format) { (void)format; diff --git a/lib/pki_x509.h b/lib/pki_x509.h index 2553814f..97afad4f 100644 --- a/lib/pki_x509.h +++ b/lib/pki_x509.h @@ -74,6 +74,8 @@ class pki_x509 : public pki_x509super void oldFromData(unsigned char *p, int size); bool canSign(); void writeCert(const QString fname, bool PEM, bool append = false); + void writeIndexEntry(FILE *fp); + void writeIndexEntry(const QString fname, bool append = false); bool verify(pki_x509 *signer); bool verify_only(pki_x509 *signer); pki_key *getPubKey() const; diff --git a/widgets/ExportDialog.cpp b/widgets/ExportDialog.cpp index 1c2b2b9d..37467a0a 100644 --- a/widgets/ExportDialog.cpp +++ b/widgets/ExportDialog.cpp @@ -85,6 +85,7 @@ ExportDialog::ExportDialog(MainWindow *mw, QString title, QString filt, 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("Certificate Index file"); on_exportFormat_highlighted(0); } diff --git a/widgets/ExportDialog.h b/widgets/ExportDialog.h index 1e410bd6..a09ab7b2 100644 --- a/widgets/ExportDialog.h +++ b/widgets/ExportDialog.h @@ -21,7 +21,7 @@ class exportType { 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, + PEM_selected, PKCS7_selected, Index, ETYPE_max }; enum etype type; QString desc; diff --git a/widgets/MW_help.cpp b/widgets/MW_help.cpp index bf1c3d8b..fe4b36b7 100644 --- a/widgets/MW_help.cpp +++ b/widgets/MW_help.cpp @@ -32,6 +32,7 @@ void MainWindow::cmd_help(const char* msg) { " -h shows this help screen and exit\n" " -e : extract entry.\n" " -d expect the following argument to be the database name to use\n" + " -i expect the following argument to be the index file to generate\n" " -x Exit after processing all commandline options\n\n"); if(msg) { diff --git a/widgets/MW_menu.cpp b/widgets/MW_menu.cpp index d31e91fc..8471fcba 100644 --- a/widgets/MW_menu.cpp +++ b/widgets/MW_menu.cpp @@ -138,6 +138,8 @@ void MainWindow::init_menu() extra = menuBar()->addMenu(tr("Extra")); acList += extra->addAction(tr("&Dump DataBase"), this, SLOT(dump_database())); + acList += extra->addAction(tr("&Export Certificate Index"), this, + SLOT(exportIndex())); acList += extra->addAction(tr("C&hange DataBase password"), this, SLOT(changeDbPass())); acList += extra->addAction(tr("&Import old db_dump"), this, diff --git a/widgets/MainWindow.cpp b/widgets/MainWindow.cpp index 239dc3e4..f8d236b2 100644 --- a/widgets/MainWindow.cpp +++ b/widgets/MainWindow.cpp @@ -256,7 +256,7 @@ void MainWindow::init_images() void MainWindow::read_cmdline(int argc, char *argv[]) { - int cnt = 1, opt = 0, force_load = 0; + int cnt = 1, opt = 0, force_load = 0, export_index = 1; char *arg = NULL; exitApp = 0; QStringList failed; @@ -278,6 +278,9 @@ void MainWindow::read_cmdline(int argc, char *argv[]) case 'd': force_load=1; break; + case 'i': + export_index=1; + break; case 'v': cmd_version(); opt=0; @@ -305,6 +308,10 @@ void MainWindow::read_cmdline(int argc, char *argv[]) if (changeDB(file) == 2) exitApp = 1; force_load = 0; + } else if (export_index) { + if (exportIndex(file) == 2) + exitApp = 1; + export_index = 0; } else { int ret; pki_multi *pki = probeAnything(file, &ret); @@ -857,6 +864,35 @@ pki_multi *MainWindow::probeAnything(QString file, int *ret) return pki; } +void MainWindow::exportIndex() +{ + exportIndex(NULL); +} + +int MainWindow::exportIndex(QString fname) +{ + if (fname == NULL || fname.isEmpty()) { + + QString filter = tr("Certificate Index ( index.txt )") + ";;" + tr("All files ( * )"); + + fname = QFileDialog::getSaveFileName(this, QString(), fname, filter, NULL); + + if (fname.isEmpty()) + return 1; + + nativeSeparator(fname); + } + + if (certs == NULL) { + open_default_db(); + if (certs == NULL) + return 2; + } + + certs->writeIndex(fname); + return 0; +} + void MainWindow::generateDHparam() { DH *dh = NULL; diff --git a/widgets/MainWindow.h b/widgets/MainWindow.h index 358681b4..ae551c07 100644 --- a/widgets/MainWindow.h +++ b/widgets/MainWindow.h @@ -86,6 +86,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow QStringList urlsToOpen; int checkOldGetNewPass(Passwd &pass); QString updateDbPassword(QString newdb, Passwd pass); + int exportIndex(QString fname); protected: void init_images(); @@ -165,6 +166,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void openURLs(QStringList &files); void openURLs(); void changeEvent(QEvent *event); + void exportIndex(); protected slots: void closeEvent(QCloseEvent * event);