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.
This commit is contained in:
Adam Dawidowski 2016-03-14 18:21:32 +01:00 committed by Christian Hohnstaedt
parent 733f754f52
commit e94e9133b1
10 changed files with 103 additions and 3 deletions

View File

@ -307,6 +307,15 @@ QList<pki_x509*> 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<pki_x509*>(idx.internalPointer());
crt->writeIndexEntry(fname, append);
append = true;
}
break;
default:
exit(1);
}

View File

@ -46,6 +46,7 @@ class db_x509: public db_x509super
QList<pki_x509*> 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);

View File

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

View File

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

View File

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

View File

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

View File

@ -32,6 +32,7 @@ void MainWindow::cmd_help(const char* msg) {
" -h shows this help screen and exit\n"
" -e <type>:<name> 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) {

View File

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

View File

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

View File

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