diff --git a/configure.ac b/configure.ac index b548661b..d3bd73fa 100644 --- a/configure.ac +++ b/configure.ac @@ -110,7 +110,7 @@ if test "${WANT_QT_VERSION}" = detect -o "${WANT_QT_VERSION}" = 5; then QT_UIC="${_QT_HOST_BINS}/uic" if test -n "$DARWIN"; then FRAMEDIR=`pkg-config --variable=libdir Qt5Core` - Qt5_CFLAGS="$Qt5_CFLAGS -std=c++11 -F${FRAMEDIR} -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtGui.framework/Headers -I${FRAMEDIR}/QtWdgets.framework/Headers -Xlinker -rpath -Xlinker ${FRAMEDIR}" + Qt5_CFLAGS="$Qt5_CFLAGS -std=c++11 -F${FRAMEDIR} -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtGui.framework/Headers -I${FRAMEDIR}/QtWdgets.framework/Headers -I${FRAMEDIR}/QtSql.framework/Headers -Xlinker -rpath -Xlinker ${FRAMEDIR}" fi WANT_QT_VERSION=5 QT_VERSION=5 @@ -128,7 +128,7 @@ if test "${WANT_QT_VERSION}" = detect -o "${WANT_QT_VERSION}" = 4; then fi if test -n "$DARWIN"; then FRAMEDIR=`pkg-config --variable=libdir QtCore` - Qt4_CFLAGS="$Qt4_CFLAGS -F${FRAMEDIR} -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtGui.framework/Headers -Xlinker -rpath -Xlinker ${FRAMEDIR}" + Qt4_CFLAGS="$Qt4_CFLAGS -F${FRAMEDIR} -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtGui.framework/Headers -I${FRAMEDIR}/QtSql.framework/Headers -Xlinker -rpath -Xlinker ${FRAMEDIR}" fi WANT_QT_VERSION=4 QT_VERSION=4 @@ -146,7 +146,7 @@ if test -z "${QT_VERSION}"; then QT_UIC="${_QT_HOST_BINS}/uic" FRAMEDIR=${_QTDIR}/lib QT_LIBS=" -framework QtGui -framework QtCore -framework QtWidgets -Xlinker -rpath -Xlinker ${FRAMEDIR}" - QT_CFLAGS="-std=c++11 -F${FRAMEDIR} -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtGui.framework/Headers -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtWidgets.framework/Headers" + QT_CFLAGS="-std=c++11 -F${FRAMEDIR} -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtGui.framework/Headers -I${FRAMEDIR}/QtCore.framework/Headers -I${FRAMEDIR}/QtWidgets.framework/Headers -I${FRAMEDIR}/QtSql.framework/Headers" fi AC_MSG_WARN([Qt pkg-config failed, using fallback defaults (${QT_LIBS})]); fi diff --git a/lib/Makefile b/lib/Makefile index c7892543..e6f4dbbe 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,7 +8,7 @@ MOCNAMES=db_crl db_key db_temp db_x509 db_x509req db_x509super db_base db_token\ pki_temp pki_x509 pki_crl pki_x509req pki_key pki_x509super pki_pkcs12 \ pki_base pki_multi pki_evp pki_scard pass_info pki_pkcs7 main NAMES=$(MOCNAMES) asn1int oid x509rev asn1time version \ - x509v3ext func load_obj x509name db import \ + x509v3ext func load_obj x509name db \ pk11_attribute pkcs11 pkcs11_lib Passwd builtin_curves entropy diff --git a/lib/asn1time.cpp b/lib/asn1time.cpp index 41449fb3..1467a3fd 100644 --- a/lib/asn1time.cpp +++ b/lib/asn1time.cpp @@ -51,9 +51,14 @@ int a1time::from_asn1(const ASN1_TIME *a) setUndefined(); return 0; } - *this = QDateTime::fromString(t, GEN_FORMAT); + return fromPlain(t); +} + +int a1time::fromPlain(QString plain) +{ + *this = QDateTime::fromString(plain, GEN_FORMAT); setTimeSpec(Qt::UTC); - return 0; + return isValid() ? 0 : -1; } int a1time::set_asn1(QString str, int type) @@ -101,6 +106,12 @@ a1time::a1time(const ASN1_TIME *a) from_asn1(a); } +a1time::a1time(QString plain) +{ + atime = NULL; + fromPlain(plain); +} + a1time::~a1time() { if (atime) diff --git a/lib/asn1time.h b/lib/asn1time.h index cb3ebc06..3b8a7d42 100644 --- a/lib/asn1time.h +++ b/lib/asn1time.h @@ -26,9 +26,11 @@ class a1time : public QDateTime a1time(const QDateTime &a); a1time(const ASN1_TIME *a); a1time(const a1time &a); + a1time(QString plain); a1time &operator = (const a1time &a); ~a1time(); a1time &set(const ASN1_TIME *a); + int fromPlain(QString plain); void setUndefined(); bool isUndefined() const; QString toPretty() const; diff --git a/lib/db_base.cpp b/lib/db_base.cpp index 5aabdcc6..28b85c87 100644 --- a/lib/db_base.cpp +++ b/lib/db_base.cpp @@ -16,12 +16,16 @@ #include #include "widgets/MainWindow.h" #include "widgets/ImportMulti.h" +#include "widgets/XcaDialog.h" -db_base::db_base(QString db, MainWindow *mw) + +QHash db_base::lookup; + +db_base::db_base(MainWindow *mw) :QAbstractItemModel(NULL) { - dbName = db; rootItem = newPKI(); + rootItem->setIntName(rootItem->getClassName()); mainwin = mw; colResizing = 0; currentIdx = QModelIndex(); @@ -34,8 +38,9 @@ db_base::~db_base() delete rootItem; } -pki_base *db_base::newPKI(db_header_t *) +pki_base *db_base::newPKI(enum pki_type type) { + (void)type; return new pki_base("rootItem"); } @@ -64,139 +69,75 @@ void db_base::remFromCont(QModelIndex &idx) emit columnsContentChanged(); } -int db_base::handleBadEntry(unsigned char *p, db_header_t *head) +QString db_base::sqlItemSelector() { - QString name = QString::fromUtf8(head->name); - QString txt = tr("Bad database item\nName: %1\nType: %2\nSize: %3\n%4") - .arg(name).arg(class_name) - .arg(head->len - sizeof(db_header_t)) - .arg(tr("Do you want to delete the item from the database? The bad item may be extracted into a separate file.")); + QStringList sl; + QString selector; - xcaWarning msg(mainwin, txt); - msg.addButton(QMessageBox::Ok)->setText(tr("Delete")); - msg.addButton(QMessageBox::Apply)->setText(tr("Delete and extract")); - msg.addButton(QMessageBox::Cancel)->setText(tr("Continue")); + foreach(enum pki_type pt, pkitype) + sl << QString("type=%1").arg(pt); - switch (msg.exec()) { - case QMessageBox::Ok: - return 1; - case QMessageBox::Cancel: - default: - return 0; - case QMessageBox::Apply: - break; + return sl.join(" OR "); +} + +QList db_base::sqlSELECTpki(QString query, QList values) +{ + QList x; + XSqlQuery q; + int i, num_values = values.size(); + + SQL_PREPARE(q, query); + for (i=0; i < num_values; i++) { + q.bindValue(i, values[i]); } - - QString s = QFileDialog::getSaveFileName(mainwin, QString(), name, - QString(), NULL, QFileDialog::DontConfirmOverwrite); - - size_t l; - db_header_t h; - FILE *fp = fopen_write(s); - if (!fp) { - throw errorEx(tr("Error opening file: '%1': %2"). - arg(s).arg(strerror(errno)), class_name); - } - - h.magic = xntohl(head->magic); - h.len = xntohl(head->len); - h.headver = xntohs(head->headver); - h.type = xntohs(head->type); - h.version = xntohs(head->version); - h.flags = xntohs(head->flags); - memcpy(h.name, head->name, NAMELEN); - - l = fwrite(&h, sizeof h, 1, fp); - l += fwrite(p, head->len - sizeof h, 1, fp); - fclose(fp); - - return (l == 2); + q.exec(); + mainwin->dbSqlError(q.lastError()); + while (q.next()) + x << lookupPki(q.value(0).toULongLong()); + return x; } void db_base::loadContainer() { - db mydb(dbName); - unsigned char *p = NULL; - db_header_t head; - pki_base *pki; + XSqlQuery q; + QSqlError e; + QString stmt; - for (int i=0; i < pkitype.count(); i++) { - mydb.first(); - while (mydb.find(pkitype[i], QString()) == 0) { - QString s; - p = mydb.load(&head); - if (!p) { - qWarning("Load was empty !"); - goto next; - } - pki = newPKI(&head); - if (pki->getVersion() < head.version) { - qWarning("Item[%s]: Version %d " - "> known version: %d -> ignored", - head.name, head.version, - pki->getVersion() - ); - free(p); - delete pki; - goto next; - } - pki->setIntName(QString::fromUtf8(head.name)); + stmt = QString("SELECT id, type FROM items WHERE ") + sqlItemSelector(); + q.exec(stmt); + e = q.lastError(); + mainwin->dbSqlError(e); - try { - pki->fromData(p, &head); - } - catch (errorEx &err) { - err.appendString(pki->getIntName()); - mainwin->Error(err); - delete pki; - pki = NULL; - try { - if (handleBadEntry(p, &head)) { - mydb.erase(); - } - } catch (errorEx &err) { - mainwin->Error(err); - } - } - free(p); - if (pki) { - inToCont(pki); - } -next: - if (mydb.next()) - break; + while (q.next()) { + enum pki_type t = (enum pki_type)q.value(1).toInt(); + pki_base *pki = newPKI(t); + e = pki->restoreSql(q.value(0)); + if (!e.isValid()) { + insertChild(rootItem, pki); + lookup[q.value(0).toULongLong()] = pki; + } else { + mainwin->dbSqlError(e); } } - mydb.first(); - if (!mydb.find(setting, class_name + "_hdView")) { - QByteArray ba; - char *p; - if ((p = (char *)mydb.load(&head))) { - ba = QByteArray(p, head.len - sizeof(db_header_t)); - free(p); - } - if (head.version != 5) - return; - try { - allHeaders.fromData(ba); - } catch (errorEx()) { - for (int i=0; i< allHeaders.count(); i++) { - allHeaders[i]->reset(); - } + QString view = mainwin->getSetting(class_name + "_hdView"); + if (view.isEmpty()) { + for (int i=0; i< allHeaders.count(); i++) { + allHeaders[i]->reset(); } + } else { + allHeaders.fromData(view); } emit columnsContentChanged(); - return; } void db_base::updateHeaders() { - QByteArray ba = allHeaders.toData(); + QString s = allHeaders.toData(); foreach(dbheader *h, allHeaders) delete h; allHeaders = getHeaders(); - allHeaders.fromData(ba); + allHeaders.fromData(s); } dbheaderList db_base::getHeaders() @@ -204,19 +145,20 @@ dbheaderList db_base::getHeaders() dbheaderList h; /* "No." handled in XcaProxyModel */ h << new dbheader(HD_internal_name, true, tr("Internal name")) - << new dbheader(HD_counter, false, tr("No.")); + << new dbheader(HD_counter, false, tr("No.")) + << new dbheader(HD_creation, false, tr("Date"), + tr("Date of creation or insertion")) + << new dbheader(HD_comment, false, tr("Comment"), + tr("First line of the comment field")); return h; } - void db_base::saveHeaderState() { - if (dbName.isEmpty()) - return; - QByteArray ba = allHeaders.toData(); - db mydb(dbName); - mydb.set((const unsigned char *)ba.constData(), ba.size(), 5, - setting, class_name + "_hdView"); + QSqlDatabase *db = mainwin->getDb(); + if (db->isOpen()) + mainwin->storeSetting(class_name + "_hdView", + allHeaders.toData()); } void db_base::setVisualIndex(int i, int visualIndex) @@ -267,19 +209,26 @@ void db_base::sortIndicatorChanged(int logicalIndex, Qt::SortOrder order) allHeaders[logicalIndex]->sortIndicator = order; } +QSqlError db_base::insertPKI_noTransaction(pki_base *pki) +{ + QSqlError e = pki->insertSql(); + lookup[pki->getSqlItemId().toULongLong()] = pki; + inToCont(pki); + mainwin->dbSqlError(e); + emit columnsContentChanged(); + return e; +} + void db_base::insertPKI(pki_base *pki) { - QString name; - db mydb(dbName); - QByteArray ba = pki->toData(); - - if (ba.count() > 0) { - name = mydb.uniq_name(pki->getIntName(), pkitype); - pki->setIntName(name); - mydb.add((const unsigned char*)ba.constData(), ba.count(), - pki->getVersion(), pki->getType(), name); + QSqlDatabase *db = mainwin->getDb(); + if (db->transaction()) { + QSqlError e = insertPKI_noTransaction(pki); + if (e.isValid()) + db->rollback(); + else + db->commit(); } - inToCont(pki); emit columnsContentChanged(); } @@ -319,6 +268,7 @@ void db_base::pem2clipboard(QModelIndexList indexes) const void db_base::deletePKI(QModelIndex idx) { pki_base *pki = static_cast(idx.internalPointer()); + QSqlDatabase *db = mainwin->getDb(); try { try { pki->deleteFromToken(); @@ -326,12 +276,16 @@ void db_base::deletePKI(QModelIndex idx) MainWindow::Error(err); } - remFromCont(idx); - - db mydb(dbName); - mydb.find(pki->getType(), pki->getIntName()); - mydb.erase(); - delete pki; + if (db->transaction()) { + QSqlError e = pki->deleteSql(); + remFromCont(idx); + mainwin->dbSqlError(e); + if (e.isValid()) + db->rollback(); + else + db->commit(); + mainwin->dbSqlError(e); + } } catch (errorEx &err) { MainWindow::Error(err); } @@ -339,14 +293,9 @@ void db_base::deletePKI(QModelIndex idx) void db_base::updatePKI(pki_base *pki) { - db mydb(dbName); - - QByteArray ba = pki->toData(); - - if (ba.count() > 0) { - mydb.set((const unsigned char*)ba.constData(), ba.count(), - pki->getVersion(), pki->getType(), pki->getIntName()); - } + (void)pki; +#warning UPDATING updatePKI + fprintf(stderr, "UUUUUUUUUUUUPDATE MIT SQL FEHLER\n"); } void db_base::showItem(const QModelIndex &index) @@ -356,7 +305,7 @@ void db_base::showItem(const QModelIndex &index) void db_base::showItem(const QString name) { - pki_base *pki = getByName(name); + pki_base *pki = lookupPki(name.toULongLong()); if (pki) showPki(pki); } @@ -376,6 +325,10 @@ void db_base::insertChild(pki_base *parent, pki_base *child) endInsertRows(); } +/* Does all the linking from existing keys, crls, certs + * to the new imported or generated item + * called before the new item will be inserted into the database + */ void db_base::inToCont(pki_base *pki) { insertChild(rootItem, pki); @@ -394,7 +347,10 @@ pki_base *db_base::getByReference(pki_base *refpki) { if (refpki == NULL) return NULL; - FOR_ALL_pki(pki, pki_base) { + QList list = sqlSELECTpki( + QString("SELECT item FROM %1 WHERE hash=?").arg(sqlHashTable), + QList() << QVariant(refpki->hash())); + foreach(pki_base *pki, list) { if (refpki->compare(pki)) return pki; } @@ -444,6 +400,8 @@ QModelIndex db_base::index(int row, int column, const QModelIndex &parent) { pki_base *parentItem; +if(column <0) + abort(); if (!parent.isValid()) parentItem = rootItem; else @@ -569,19 +527,52 @@ bool db_base::setData(const QModelIndex &index, const QVariant &value, int role) on = item->getIntName(); if (nn == on) return true; - db mydb(dbName); - try { - mydb.rename(item->getType(), on, nn); - item->setIntName(nn); - emit dataChanged(index, index); - return true; - } catch (errorEx &err) { - mainwin->Error(err); - } + updateItem(item, nn, item->getComment()); + return true; } return false; } +void db_base::updateItem(pki_base *pki, QString name, QString comment) +{ + XSqlQuery q; + QSqlError e; + + SQL_PREPARE(q, "UPDATE items SET name=?, comment=? WHERE id=?"); + q.bindValue(0, name); + q.bindValue(1, comment); + q.bindValue(2, pki->getSqlItemId()); + q.exec(); + e = q.lastError(); + mainwin->dbSqlError(e); + if (e.isValid()) + return; + pki->setIntName(name); + pki->setComment(comment); + + QModelIndex i, j; + i = index(pki); + j = index(i.row(), allHeaders.size(), i.parent()); + emit dataChanged(i, j); +} + +void db_base::editComment(const QModelIndex &index) +{ + pki_base *item = static_cast(index.internalPointer()); + if (!index.isValid() || !item) + return; + + QTextEdit *t = new QTextEdit(mainwin); + t->setAutoFormatting(QTextEdit::AutoNone); + t->setAcceptRichText(false); + t->setPlainText(item->getComment()); + XcaDialog *d = new XcaDialog(mainwin, item->getType(), t, + tr("Edit comment"), item->getIntName()); + if (d->exec()) + updateItem(item, item->getIntName(), t->toPlainText()); + delete d; +} + void db_base::load_default(load_base &load) { QString s; diff --git a/lib/db_base.h b/lib/db_base.h index 2e251647..06ef71ab 100644 --- a/lib/db_base.h +++ b/lib/db_base.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "widgets/ExportDialog.h" #include "pki_base.h" #include "headerlist.h" @@ -35,7 +36,7 @@ class db_base: public QAbstractItemModel Q_OBJECT protected: - QString dbName; + static QHash lookup; QModelIndex currentIdx; void _writePKI(pki_base *pki, bool overwrite); void _removePKI(pki_base *pki ); @@ -43,10 +44,13 @@ class db_base: public QAbstractItemModel QList pkitype; MainWindow *mainwin; QString class_name; + /* Sql table containing the 'hash' of this items */ + QString sqlHashTable; dbheaderList allHeaders; virtual dbheaderList getHeaders(); int colResizing; - int handleBadEntry(unsigned char *p, db_header_t *head); + QString sqlItemSelector(); + void updateItem(pki_base *pki, QString name, QString comment); virtual exportType::etype clipboardFormat(QModelIndexList) const { return exportType::Separator; @@ -54,12 +58,23 @@ class db_base: public QAbstractItemModel bool isValidCol(int col) const; public: + static pki_base *lookupPki(quint64 i) + { + return lookup[i]; + } + static void flushLookup() + { + lookup.clear(); + } + QList sqlSELECTpki(QString query, + QList values = QList()); + virtual pki_base *newPKI(enum pki_type type = none); pki_base *rootItem; - db_base(QString db, MainWindow *mw); + db_base(MainWindow *mw); virtual void updateHeaders(); virtual ~db_base(); - virtual pki_base *newPKI(db_header_t *head = NULL); virtual void insertPKI(pki_base *pki); + virtual QSqlError insertPKI_noTransaction(pki_base *pki); virtual void updatePKI(pki_base *pki); pki_base *getByName(QString desc); pki_base *getByReference(pki_base *refpki); @@ -89,7 +104,7 @@ class db_base: public QAbstractItemModel void createSuccess(pki_base *pki); bool columnHidden(int col) const; bool isNumericCol(int col) const; - void saveHeaderState(); + virtual void saveHeaderState(); void initHeaderView(QHeaderView *hv); void setVisualIndex(int i, int visualIndex); bool fixedHeaderSize(int sect); @@ -111,7 +126,7 @@ class db_base: public QAbstractItemModel void deletePKI(QModelIndex idx); QMimeData *mimeData(const QModelIndexList &indexes) const; - + void editComment(const QModelIndex &index); public slots: virtual void newItem() { } diff --git a/lib/db_crl.cpp b/lib/db_crl.cpp index 72e2a2f3..736224f9 100644 --- a/lib/db_crl.cpp +++ b/lib/db_crl.cpp @@ -13,13 +13,15 @@ #include "widgets/NewCrl.h" #include #include -#include +#include "widgets/XcaDialog.h" +#include "widgets/ItemCombo.h" #include "ui_NewCrl.h" -db_crl::db_crl(QString db, MainWindow *mw) - :db_x509name(db,mw) +db_crl::db_crl(MainWindow *mw) + :db_x509name(mw) { class_name = "crls"; + sqlHashTable = "crls"; pkitype << revocation; updateHeaders(); loadContainer(); @@ -38,8 +40,9 @@ dbheaderList db_crl::getHeaders() return h; } -pki_base *db_crl::newPKI(db_header_t *) +pki_base *db_crl::newPKI(enum pki_type type) { + (void)type; return new pki_crl(); } @@ -69,40 +72,28 @@ void db_crl::revokeCerts(pki_crl *crl) void db_crl::removeSigner(pki_base *signer) { +#warning FIXME ...... FOR_ALL_pki(crl, pki_crl) { - if (crl->getIssuer() == signer) + if (crl->getIssuer() == signer) { crl->setIssuer(NULL); + } } } void db_crl::inToCont(pki_base *pki) { pki_crl *crl = (pki_crl *)pki; - if (crl->getIssuer() == NULL) { - pki_x509 *iss = NULL, *last = NULL, *newest = NULL; - x509name issname = crl->getSubject(); - while (1) { - iss = mainwin->certs->getBySubject(issname, last); - if (!iss) - break; - last = iss; - pki_key *key = iss->getPubKey(); - if (!key) - continue; + unsigned hash = crl->getSubject().hashNum(); + QList items; - if (!crl->verify(key)) { - delete key; - continue; - } - delete key; - if (!newest) { - newest = iss; - } else { - if (newest->getNotAfter() < iss->getNotAfter()) - newest = iss; - } - } - crl->setIssuer(newest); + items = sqlSELECTpki( "SELECT x509super.item FROM x509super " + "JOIN certs ON certs.item = x509super.item " + "WHERE x509super.subj_hash=? AND certs.ca=1", + QList() << QVariant(hash)); + foreach(pki_base *b, items) { + fprintf(stderr, "Possible Crl issuer: '%s'\n", + CCHAR(b->getIntName())); + crl->verify(static_cast(b)); } db_base::inToCont(pki); } @@ -130,13 +121,22 @@ void db_crl::showPki(pki_base *pki) CrlDetail *dlg; dlg = new CrlDetail(mainwin); - if (dlg) { - dlg->setCrl(crl); - connect( dlg->issuerIntName, SIGNAL( doubleClicked(QString) ), - mainwin->certs, SLOT( showItem(QString) )); - dlg->exec(); - delete dlg; + if (!dlg) + return; + + dlg->setCrl(crl); + connect( dlg->issuerIntName, SIGNAL( doubleClicked(QString) ), + mainwin->certs, SLOT( showItem(QString) )); + if (dlg->exec()) { + QString newname = dlg->descr->text(); + QString newcomment = dlg->comment->toPlainText(); + if (newname != pki->getIntName() || + newcomment != pki->getComment()) + { + updateItem(pki, newname, newcomment); + } } + delete dlg; } void db_crl::store(QModelIndex index) @@ -170,6 +170,7 @@ void db_crl::store(QModelIndex index) delete dlg; } +#if 0 void db_crl::updateRevocations(pki_x509 *cert) { x509name issname = cert->getSubject(); @@ -203,82 +204,116 @@ void db_crl::updateRevocations(pki_x509 *cert) cert->setCrlNumber(latest->getCrlNumber()); } } +#endif void db_crl::newItem() { - bool ok = false; - QStringList sl = mainwin->certs->getSignerDesc(); - QString ca; + QList cas = mainwin->certs->getAllIssuers(); + pki_base *ca = NULL; - switch (sl.size()) { + switch (cas.size()) { case 0: XCA_INFO(tr("There are no CA certificates for CRL generation")); - break; - case 1: - ca = sl[0]; - ok = true; - break; - default: - ca = QInputDialog::getItem(mainwin, XCA_TITLE, - tr("Select CA certificate"), sl, 0, false, &ok, 0); - } - if (!ok) return; - - pki_x509 *cert = static_cast - (mainwin->certs->getByName(ca)); - newItem(cert); + case 1: + ca = cas[0]; + break; + default: { + itemCombo *c = new itemCombo(NULL); + XcaDialog *d = new XcaDialog(mainwin, revocation, c, + tr("Select CA certificate"), QString()); + c->insertPkiItems(cas); + if (!d->exec()) { + delete d; + return; + } + ca = c->currentPkiItem(); + delete d; + } + } + newItem(static_cast(ca)); } void db_crl::newItem(pki_x509 *cert) { + bool transact = false; if (!cert) return; pki_crl *crl = NULL; - NewCrl *dlg = new NewCrl(mainwin, cert); - + NewCrl *widget = new NewCrl(NULL, cert); + XcaDialog *dlg = new XcaDialog(mainwin, revocation, widget, + tr("Create CRL"), QString()); if (!dlg->exec()) { delete dlg; return; } + QSqlDatabase *db = mainwin->getDb(); try { x509v3ext e; X509V3_CTX ext_ctx; X509V3_set_ctx(&ext_ctx, cert->getCert(), NULL, NULL, NULL, 0); X509V3_set_ctx_nodb(&ext_ctx); + XSqlQuery q; crl = new pki_crl(); crl->createCrl(cert->getIntName(), cert); - bool withReason = dlg->revocationReasons->isChecked(); + bool withReason = widget->revocationReasons->isChecked(); foreach(x509rev rev, cert->revList) crl->addRev(rev, withReason); - if (dlg->authKeyId->isChecked()) { + if (widget->authKeyId->isChecked()) { crl->addV3ext(e.create(NID_authority_key_identifier, "keyid,issuer", &ext_ctx)); } - if (dlg->subAltName->isChecked()) { + if (widget->subAltName->isChecked()) { if (cert->hasExtension(NID_subject_alt_name)) { crl->addV3ext(e.create(NID_issuer_alt_name, "issuer:copy", &ext_ctx)); } } - if (dlg->setCrlNumber->isChecked()) { + QSqlError err; + if (widget->setCrlNumber->isChecked()) { a1int num; - num.setDec(dlg->crlNumber->text()); + num.setDec(widget->crlNumber->text()); crl->setCrlNumber(num); cert->setCrlNumber(num); } - crl->setLastUpdate(dlg->lastUpdate->getDate()); - crl->setNextUpdate(dlg->nextUpdate->getDate()); - crl->sign(cert->getRefKey(), dlg->hashAlgo->currentHash()); - cert->setCrlExpiry(dlg->nextUpdate->getDate()); - mainwin->certs->updatePKI(cert); - createSuccess(insert(crl)); + crl->setIssuer(cert); + crl->setLastUpdate(widget->lastUpdate->getDate()); + crl->setNextUpdate(widget->nextUpdate->getDate()); + crl->sign(cert->getRefKey(), widget->hashAlgo->currentHash()); + if (!db->transaction()) + throw errorEx(tr("Failed to initiate DB transaction")); + transact = true; + cert->setCrlExpire(widget->nextUpdate->getDate()); + SQL_PREPARE(q, "UPDATE certs set crlNo=?, crlExpire=? WHERE item=?"); + q.bindValue(0, (uint)cert->getCrlNumber().getLong()); + q.bindValue(1, widget->nextUpdate->getDate().toPlain()); + q.bindValue(2, cert->getSqlItemId()); + q.exec(); + err = q.lastError(); + if (err.isValid()) + throw errorEx(tr("Database error: ").arg(err.text())); + SQL_PREPARE(q, "UPDATE revocations set crlNo=? " + "WHERE crlNo IS NULL AND caId=?"); + q.bindValue(0, (uint)crl->getCrlNumber().getLong()); + q.bindValue(1, cert->getSqlItemId()); + q.exec(); + err = q.lastError(); + if (err.isValid()) + throw errorEx(tr("Database error: ").arg(err.text())); + insertPKI_noTransaction(crl); + err = db->lastError(); + if (err.isValid()) + throw errorEx(tr("Database error: ").arg(err.text())); + db->commit(); + createSuccess((crl)); } catch (errorEx &err) { + if (transact) + db->rollback(); MainWindow::Error(err); if (crl) delete crl; diff --git a/lib/db_crl.h b/lib/db_crl.h index d5e4f9ea..8c0f3cab 100644 --- a/lib/db_crl.h +++ b/lib/db_crl.h @@ -22,8 +22,8 @@ class db_crl: public db_x509name QPixmap *crlicon; dbheaderList getHeaders(); public: - db_crl(QString db, MainWindow *mw); - pki_base *newPKI(db_header_t *head = NULL); + db_crl(MainWindow *mw); + pki_base *newPKI(enum pki_type type); void revokeCerts(pki_crl *crl); void inToCont(pki_base *pki); pki_base *insert(pki_base *item); @@ -32,7 +32,6 @@ class db_crl: public db_x509name void load(); void showPki(pki_base *pki); void updateCertView(); - void updateRevocations(pki_x509 *cert); public slots: void newItem(); diff --git a/lib/db_key.cpp b/lib/db_key.cpp index 70498535..72ef0abb 100644 --- a/lib/db_key.cpp +++ b/lib/db_key.cpp @@ -28,11 +28,11 @@ #include "widgets/KeyDetail.h" #include "widgets/NewKey.h" -db_key::db_key(QString db, MainWindow *mw) - :db_base(db, mw) +db_key::db_key(MainWindow *mw) + :db_base(mw) { - rootItem->setIntName("[key root]"); class_name = "keys"; + sqlHashTable = "public_keys"; pkitype << asym_key << smartCard; updateHeaders(); loadContainer(); @@ -51,45 +51,66 @@ dbheaderList db_key::getHeaders() return h; } -pki_base *db_key::newPKI(db_header_t *head) +pki_base *db_key::newPKI(enum pki_type type) { - if (!head || head->type == asym_key) + if (type == asym_key) return new pki_evp(""); return new pki_scard(""); } - -QStringList db_key::getPrivateDesc() +QList db_key::getAllKeys() { - QStringList x; - x.clear(); - FOR_ALL_pki(pki, pki_key) - if (pki->isPrivKey()) - x.append(pki->getIntName()); - return x; + return sqlSELECTpki("SELECT item from public_keys"); } -QStringList db_key::get0KeyDesc(bool all) +QList db_key::getUnusedKeys() { - QStringList x; - FOR_ALL_pki(pki, pki_key) { - if ((pki->getUcount() == 0) || all) - x.append(pki->getIntNameWithType()); - } - return x; + return sqlSELECTpki("SELECT public_keys.item FROM public_keys " + "LEFT OUTER JOIN x509super ON x509super.key = public_keys.item " + "WHERE x509super.item IS NULL"); } void db_key::remFromCont(QModelIndex &idx) { db_base::remFromCont(idx); - pki_base *pki = static_cast(idx.internalPointer()); - emit delKey((pki_key *)pki); + XSqlQuery q; + pki_key *pki = static_cast(idx.internalPointer()); + + QList items = sqlSELECTpki( + "SELECT item FROM x509super WHERE key=?", + QList() << QVariant(pki->getSqlItemId())); + foreach(pki_base *b, items) { + pki_x509super *x509s = static_cast(b); + x509s->setRefKey(NULL); + } + + SQL_PREPARE(q, "UPDATE x509super SET key=NULL WHERE item=?"); + q.bindValue(0, pki->getSqlItemId()); + q.exec(); + mainwin->dbSqlError(q.lastError()); } void db_key::inToCont(pki_base *pki) { db_base::inToCont(pki); - emit newKey((pki_key *)pki); + pki_key *key = static_cast(pki); + unsigned hash = key->hash(); + QList items = sqlSELECTpki( + "SELECT item FROM x509super WHERE key IS NULL AND key_hash=?", + QList() << QVariant(hash)); + XSqlQuery q; + SQL_PREPARE(q, "UPDATE x509super SET key=? WHERE item=?"); + q.bindValue(0, key->getSqlItemId()); + foreach(pki, items) { + pki_x509super *x509s = static_cast(pki); + if (!x509s->compareRefKey(key)) + continue; + /* Found item matching this key */ + x509s->setRefKey(key); + q.bindValue(1, x509s->getSqlItemId()); + q.exec(); + mainwin->dbSqlError(q.lastError()); + } } pki_base* db_key::insert(pki_base *item) @@ -162,7 +183,7 @@ void db_key::newItem(QString name) dlg->getKeyCurve_nid()); } key = (pki_key*)insert(key); - emit keyDone(key->getIntNameWithType()); + emit keyDone(key); createSuccess(key); } catch (errorEx &err) { @@ -172,7 +193,7 @@ void db_key::newItem(QString name) if (dlg->rememberDefault->isChecked()) { QString def = dlg->getAsString(); if (dlg->setDefault(def) == 0) - mainwin->setDefaultKey(def); + mainwin->storeSetting("defaultkey", def); } status->removeWidget(bar); delete bar; @@ -203,7 +224,7 @@ exportType::etype db_key::clipboardFormat(QModelIndexList indexes) const foreach(QModelIndex idx, indexes) { pki_key *key = static_cast - (idx.internalPointer()); + (idx.internalPointer()); if (key->isPubKey() || key->isToken()) allPriv = false; if (key->getKeyType() != EVP_PKEY_RSA && @@ -334,5 +355,4 @@ void db_key::setOwnPass(QModelIndex idx, enum pki_key::passType x) throw errorEx(tr("Tried to change password of a token")); } targetKey->setOwnPass(x); - updatePKI(targetKey); } diff --git a/lib/db_key.h b/lib/db_key.h index 872f9c78..cb5aebc5 100644 --- a/lib/db_key.h +++ b/lib/db_key.h @@ -25,10 +25,10 @@ class db_key: public db_base virtual dbheaderList getHeaders(); exportType::etype clipboardFormat(QModelIndexList indexes) const; public: - db_key(QString db, MainWindow *mw); - QStringList getPrivateDesc(); - QStringList get0KeyDesc(bool all = false); - pki_base *newPKI(db_header_t *head = NULL); + db_key(MainWindow *mw); + QList getUnusedKeys(); + QList getAllKeys(); + pki_base *newPKI(enum pki_type type = none); void inToCont(pki_base *pki); void remFromCont(QModelIndex &idx); pki_base* insert(pki_base *item); @@ -45,7 +45,7 @@ class db_key: public db_base signals: void delKey(pki_key *delkey); void newKey(pki_key *newkey); - void keyDone(QString name); + void keyDone(pki_key *nkey); }; #endif diff --git a/lib/db_temp.cpp b/lib/db_temp.cpp index 1edfda1c..9190fbf6 100644 --- a/lib/db_temp.cpp +++ b/lib/db_temp.cpp @@ -9,6 +9,7 @@ #include "db_temp.h" #include "func.h" #include +#include #include #include #include @@ -17,23 +18,26 @@ #include #include -db_temp::db_temp(QString DBfile, MainWindow *mw) - :db_x509name(DBfile, mw) +db_temp::db_temp(MainWindow *mw) + :db_x509name(mw) { class_name = "templates"; + sqlHashTable = "templates"; pkitype << tmpl; updateHeaders(); loadContainer(); - predefs = newPKI(); QDir dir; if (!dir.cd(getPrefix())) return; dir.setFilter(QDir::Files | QDir::NoSymLinks); QFileInfoList list = dir.entryInfoList(); load_temp l; - pki_base *tmpl; + pki_temp *tmpl = new pki_temp(tr("Empty template")); + tmpl->setAsPreDefined(); + predefs << tmpl; + for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); QString name = getPrefix() + QDir::separator() + @@ -41,55 +45,33 @@ db_temp::db_temp(QString DBfile, MainWindow *mw) if (!name.endsWith(".xca", Qt::CaseInsensitive)) continue; try { - tmpl = l.loadItem(name); - if (tmpl) - predefs->append(tmpl); + tmpl = (pki_temp*)l.loadItem(name); + if (tmpl) { + tmpl->setAsPreDefined(); + predefs << tmpl; + } } catch(errorEx &err) { XCA_WARN(tr("Bad template: %1").arg(name)); } } } -dbheaderList db_temp::getHeaders() -{ - dbheaderList h = db_x509name::getHeaders(); - h << new dbheader(HD_temp_type, true, tr("Type")); - return h; -} - db_temp::~db_temp() { - delete predefs; + return; + while (!predefs.isEmpty()) + delete predefs.takeFirst(); } -pki_base *db_temp::newPKI(db_header_t *) +pki_base *db_temp::newPKI(enum pki_type type) { + (void)type; return new pki_temp(""); } -QStringList db_temp::getDescPredefs() +QList db_temp::getDescPredefs() { - QStringList x; - x.clear(); - for(pki_temp *pki=(pki_temp*)predefs->iterate(); pki; - pki=(pki_temp*)pki->iterate()) { - x.append(QString("[default] ") + pki->getIntName()); - } - x += getDesc(); - return x; -} - -pki_base *db_temp::getByName(QString desc) -{ - if (!desc.startsWith("[default] ")) - return db_base::getByName(desc); - desc.remove(0, 10); // "[default] " - for(pki_temp *pki=(pki_temp*)predefs->iterate(); pki; - pki=(pki_temp*)pki->iterate()) { - if (pki->getIntName() == desc) - return pki; - } - return NULL; + return predefs << sqlSELECTpki("SELECT item FROM templates");; } bool db_temp::runTempDlg(pki_temp *temp) @@ -98,7 +80,6 @@ bool db_temp::runTempDlg(pki_temp *temp) emit connNewX509(dlg); dlg->setTemp(temp); - dlg->fromTemplate(temp); if (!dlg->exec()) { delete dlg; return false; @@ -111,39 +92,24 @@ bool db_temp::runTempDlg(pki_temp *temp) void db_temp::newItem() { pki_temp *temp = NULL; - QStringList sl; QString type; - bool ok; - int i, len; - len = predefs->childCount(); - sl << tr("Nothing"); - for (i=0; ichild(i)->getIntName(); - } - type = QInputDialog::getItem(mainwin, XCA_TITLE, - tr("Preset Template values"), sl, 0, false, &ok, 0); - if (ok) { - if (type == sl[0]) { - temp = new pki_temp(""); - } else { - for (i=0; ichild(i); - if (type == t->getIntName()) { - temp = new pki_temp(t); - break; - } + + itemCombo *ic = new itemCombo(NULL); + ic->insertPkiItems(predefs); + XcaDialog *dlg = new XcaDialog(mainwin, tmpl, ic, + tr("Preset Template values"), QString()); + if (dlg->exec()) { + temp = new pki_temp((pki_temp*)ic->currentPkiItem()); + if (temp) { + if (runTempDlg(temp)) { + insertPKI(temp); + createSuccess(temp); + } else { + delete temp; } } - if (!temp) - return; - temp->setIntName("--"); - if (runTempDlg(temp)) { - insertPKI(temp); - createSuccess(temp); - return; - } } - delete temp; + delete dlg; } void db_temp::showPki(pki_base *pki) { @@ -182,8 +148,27 @@ void db_temp::store(QModelIndex index) bool db_temp::alterTemp(pki_temp *temp) { + XSqlQuery q; + QSqlError e; + QSqlDatabase *db = mainwin->getDb(); + if (!runTempDlg(temp)) return false; - updatePKI(temp); + + if (!db->transaction()) + return false; + SQL_PREPARE(q, "UPDATE templates SET version=?, template=? WHERE item=?"); + q.bindValue(0, TMPL_VERSION); + q.bindValue(1, temp->toData().toBase64()); + q.bindValue(2, temp->getSqlItemId()); + q.exec(); + e = q.lastError(); + mainwin->dbSqlError(e); + if (e.isValid()) { + db->rollback(); + return false; + } + updateItem(temp, temp->getIntName(), temp->getComment()); + db->commit(); return true; } diff --git a/lib/db_temp.h b/lib/db_temp.h index b268972f..a176e7b8 100644 --- a/lib/db_temp.h +++ b/lib/db_temp.h @@ -20,18 +20,16 @@ class db_temp: public db_x509name Q_OBJECT protected: QPixmap *keyicon; - pki_base *predefs; - dbheaderList getHeaders(); + QList predefs; public: - db_temp(QString DBfile, MainWindow *mw); + db_temp(MainWindow *mw); ~db_temp(); - pki_base *newPKI(db_header_t *head = NULL); + pki_base *newPKI(enum pki_type type = none); bool runTempDlg(pki_temp *temp); bool alterTemp(pki_temp *temp); void fillContextMenu(QMenu *menu, const QModelIndex &index); - pki_base *getByName(QString desc); - QStringList getDescPredefs(); + QList getDescPredefs(); void newItem(); void showPki(pki_base *pki); void load(); diff --git a/lib/db_token.cpp b/lib/db_token.cpp index d4c4a886..f54a3fb8 100644 --- a/lib/db_token.cpp +++ b/lib/db_token.cpp @@ -3,13 +3,17 @@ #include "exception.h" #include "widgets/MainWindow.h" -db_token::db_token(QString db, MainWindow *mw) - :db_base(db, mw) +db_token::db_token(MainWindow *mw) + :db_base(mw) { class_name = "manageTokens"; updateHeaders(); } +void db_token::saveHeaderState() +{ +} + bool db_token::setData(const QModelIndex &index, const QVariant &value, int role) { QString on, nn; diff --git a/lib/db_token.h b/lib/db_token.h index 50b2f431..754bd2f5 100644 --- a/lib/db_token.h +++ b/lib/db_token.h @@ -21,13 +21,14 @@ class db_token: public db_base private: slotid slot; public: - db_token(QString db, MainWindow *mw); + db_token(MainWindow *mw); bool setData(const QModelIndex &index, const QVariant &value, int role); void setSlot(slotid s) { slot = s; } + void saveHeaderState(); }; #endif diff --git a/lib/db_x509.cpp b/lib/db_x509.cpp index f65f7b79..411ef271 100644 --- a/lib/db_x509.cpp +++ b/lib/db_x509.cpp @@ -11,29 +11,52 @@ #include "pki_evp.h" #include "pki_scard.h" #include "pass_info.h" -#include "widgets/CertDetail.h" #include "widgets/CertExtend.h" #include "widgets/ExportDialog.h" #include "widgets/MainWindow.h" #include "widgets/PwDialog.h" #include "widgets/RevocationList.h" -#include "ui_TrustState.h" #include "ui_CaProperties.h" -#include "ui_About.h" #include #include #include bool db_x509::treeview = true; -db_x509::db_x509(QString DBfile, MainWindow *mw) - :db_x509super(DBfile, mw) +db_x509::db_x509(MainWindow *mw) + :db_x509super(mw) { - rootItem->setIntName("[x509 root]"); class_name = "certificates"; + sqlHashTable = "certs"; pkitype << x509; updateHeaders(); loadContainer(); + dereferenceIssuer(); +} + +void db_x509::dereferenceIssuer() +{ + XSqlQuery q("SELECT item, issuer FROM certs"); + while (q.next()) { + pki_base *root = rootItem; + pki_x509 *cert = static_cast( + lookupPki(q.value(0).toULongLong())); + pki_x509 *issuer = static_cast( + lookupPki(q.value(1).toULongLong())); + if (cert && issuer) { + cert->setSigner(issuer); + if (cert != issuer) + root = issuer; + } + if (cert->getParent() != root) { + fprintf(stderr, "MOVE '%s' from '%s' to '%s'\n", + CCHAR(cert->getIntName()), + CCHAR(cert->getParent()->getIntName()), + CCHAR(root->getIntName())); + cert->getParent()->takeChild(cert); + insertChild(root, cert); + } + } } void db_x509::updateAfterCrlLoad(pki_x509 *pki) @@ -64,85 +87,41 @@ dbheaderList db_x509::getHeaders() tr("Not before")) << new dbheader(HD_cert_notAfter, true, tr("Expiry date"), tr("Not after")) << - new dbheader(HD_cert_trust, false,tr("Trust state")) << new dbheader(HD_cert_revocation,false, tr("Revocation")) << new dbheader(HD_cert_crl_expire,true, tr("CRL Expiration")); return h; } -pki_base *db_x509::newPKI(db_header_t *) +pki_base *db_x509::newPKI(enum pki_type type) { + (void)type; return new pki_x509(); } -pki_x509 *db_x509::findSigner(pki_x509 *client) +QList db_x509::getAllIssuers() { - pki_x509 *signer; - if ((signer = client->getSigner()) != NULL) - return signer; - // first check for self-signed - if (client->verify(client)) { - return client; - } - FOR_ALL_pki(pki, pki_x509) { - if (client->verify(pki)) { - return pki; - } - } - return NULL; + /* Select X509 CA certificates with available private key */ + return sqlSELECTpki("SELECT x509super.item FROM x509super " + "JOIN private_keys ON x509super.key = private_keys.item " + "JOIN certs ON certs.item = x509super.item " + "WHERE certs.ca=1"); } -QStringList db_x509::getPrivateDesc() -{ - QStringList x; - FOR_ALL_pki(pki, pki_x509) - if (pki->getRefKey()) - x.append(pki->getIntName()); - return x; -} - -QStringList db_x509::getSignerDesc() -{ - QStringList x; - FOR_ALL_pki(pki, pki_x509) - if (pki->canSign()) - x.append(pki->getIntName()); - return x; -} - - void db_x509::remFromCont(QModelIndex &idx) { - int row; + db_x509super::remFromCont(idx); pki_base *pki = static_cast(idx.internalPointer()); - pki_base *parent_pki = pki->getParent(); - row = pki->row(); pki_x509 *child; pki_base *new_parent; QModelIndex new_idx; - beginRemoveRows(parent(idx), row, row); - parent_pki->takeChild(pki); - endRemoveRows(); - while (pki->childCount()) { child = (pki_x509*)pki->childItems.takeFirst(); child->delSigner((pki_x509*)pki); - new_parent = findSigner(child); + new_parent = child->findIssuer(); insertChild(new_parent, child); } mainwin->crls->removeSigner(pki); - pki_key *pub = ((pki_x509*)pki)->getPubKey(); - if (pub) { - if (mainwin->certs->findByPubKey(pub).count() == 0) { - QList reqs; - reqs = mainwin->reqs->findByPubKey(pub); - foreach(pki_x509super *r, reqs) - ((pki_x509req*)r)->setDone(false); - } - delete pub; - } - return; } void db_x509::changeView() @@ -157,9 +136,9 @@ void db_x509::changeView() beginRemoveRows(QModelIndex(), 0, rows -1); pki_base *pki = rootItem; pki_base *parent; - while(pki->childCount()) { + while (pki->childCount()) { pki = pki->takeFirst(); - while(pki != rootItem && !pki->childCount()) { + while (pki != rootItem && !pki->childCount()) { parent = pki->getParent(); temproot->append(pki); pki = parent; @@ -174,18 +153,15 @@ void db_x509::changeView() mainwin->BNviewState->setText(tr("Tree View")); while ((temproot->childCount())) { + pki_base *parent = rootItem; pki = temproot->takeFirst(); - inToCont(pki); + if (treeview) + parent = static_cast(pki)->getSigner(); + insertChild(parent, pki); } delete temproot; } -void db_x509::calcEffTrust() -{ - FOR_ALL_pki(pki, pki_x509) - pki->calcEffTrust(); -} - static bool recursiveSigning(pki_x509 *cert, pki_x509 *client) { /* recursive signing check */ @@ -207,8 +183,6 @@ void db_x509::inToCont(pki_base *pki) { pki_x509 *cert = (pki_x509*)pki; cert->setParent(NULL); - cert->delSigner(cert->getSigner()); - findSigner(cert); pki_base *root = cert->getSigner(); if (!treeview || root == cert || root == NULL) root = rootItem; @@ -216,30 +190,45 @@ void db_x509::inToCont(pki_base *pki) insertChild(root, cert); QList childs; + QList items; + unsigned pubhash = cert->pubHash(); + unsigned namehash = cert->getSubject().hashNum(); + /* Search for another certificate (name and key) * and use its childs if we are newer */ - FOR_ALL_pki(client, pki_x509) { - if (client == cert) + items = sqlSELECTpki( + "SELECT x509super.item FROM x509super " + "JOIN public_keys ON x509super.key = public_keys.item " + "JOIN certs ON certs.item = x509super.item " + "WHERE certs.ca=1 AND x509super.subj_hash=? " + "AND x509super.key_hash=?", + QList() << namehash << pubhash); + foreach(pki_base *b, items) { + pki_x509 *other = static_cast(b); + if (other == cert) continue; - if (!client->compareNameAndKey(cert)) + if (!other->compareNameAndKey(cert)) continue; - if (cert->getNotAfter() < client->getNotAfter()) + if (cert->getNotAfter() < other->getNotAfter()) continue; - foreach(pki_base *_child, client->childItems) { - pki_x509 *child = static_cast(_child); - child->delSigner(client); + foreach(pki_base *b, other->childItems) { + pki_x509 *child = static_cast(b); + child->delSigner(other); childs << child; } } /* Search rootItem childs, whether they are ours */ - foreach(pki_base *_child, rootItem->childItems) { - pki_x509 *child = static_cast(_child); + foreach(pki_base *b, rootItem->childItems) { + pki_x509 *child = static_cast(b); if (child == cert || child->getSigner() == child) continue; if (child->verify_only(cert)) childs << child; } /* move collected childs to us */ + XSqlQuery q; + SQL_PREPARE(q, "UPDATE certs SET issuer=? WHERE item=?"); + q.bindValue(0, cert->getSqlItemId()); foreach(pki_x509 *child, childs) { int row; if (recursiveSigning(cert, child)) @@ -247,61 +236,51 @@ void db_x509::inToCont(pki_base *pki) if (!child->verify(cert)) continue; row = child->row(); - beginRemoveRows(index(child), row, row); - child->getParent()->takeChild(child); - endRemoveRows(); - if (treeview) + if (treeview) { + beginRemoveRows(index(child->getParent()), row, row); + child->getParent()->takeChild(child); + endRemoveRows(); insertChild(cert, child); - else - insertChild(rootItem, child); - } - findKey(cert); - pki_key *pub = cert->getPubKey(); - if (pub) { - QList reqs = mainwin->reqs->findByPubKey(pub); - delete pub; - - foreach(pki_x509super *r, reqs) { - ((pki_x509req*)r)->setDone(); } + q.bindValue(1, child->getSqlItemId()); + q.exec(); + mainwin->dbSqlError(q.lastError()); + } + /* Update CRLs */ + items = sqlSELECTpki( "SELECT item FROM crls WHERE iss_hash=?", + QList() << namehash); + SQL_PREPARE(q, "UPDATE crls SET issuer=? WHERE item=?"); + foreach(pki_base *b, items) { + pki_crl *crl = static_cast(b); + crl->verify(cert); + cert = crl->getIssuer(); + if (!cert) + continue; + q.bindValue(0, cert->getSqlItemId()); + q.bindValue(1, crl->getSqlItemId()); + q.exec(); + mainwin->dbSqlError(q.lastError()); } - calcEffTrust(); } -pki_x509 *db_x509::getBySubject(const x509name &xname, pki_x509 *last) -{ - bool lastfound = false; - if (last == NULL) lastfound = true; - - FOR_ALL_pki(pki, pki_x509) { - if ( pki->getSubject() == xname) { - if (lastfound) { - return pki; - } - } - if (pki == last) { - lastfound = true; - } - } - return NULL; -} - -void db_x509::writeAllCerts(const QString fname, bool onlyTrusted) +void db_x509::writeAllCerts(const QString fname, bool unrevoked) { bool append = false; FOR_ALL_pki(pki, pki_x509) { - if (onlyTrusted && pki->getTrust() != 2) continue; + if (unrevoked && pki->isRevoked()) + continue; pki->writeCert(fname.toLatin1(), true, append); append = true; } } -QList db_x509::getCerts(bool onlyTrusted) +QList db_x509::getCerts(bool unrevoked) { QList c; c.clear(); FOR_ALL_pki(pki, pki_x509) { - if (onlyTrusted && pki->getTrust() != 2) continue; + if (unrevoked && pki->isRevoked()) + continue; c.append(pki); } return c; @@ -396,9 +375,6 @@ pki_base *db_x509::insert(pki_base *item) if ( ++serial > cert->getCaSerial()) { cert->setCaSerial(serial); } - if (mainwin->crls) { - mainwin->crls->updateRevocations(cert); - } updatePKI(cert); return cert; } @@ -521,7 +497,6 @@ void db_x509::newCert(NewX509 *dlg) return; serial = getUniqueSerial(signcert); signkey = signcert->getRefKey(); - cert->setTrust(1); #ifdef WG_QA_SERIAL } else if (dlg->selfQASignRB->isChecked()){ Passwd pass; @@ -531,13 +506,11 @@ void db_x509::newCert(NewX509 *dlg) signcert = cert; signkey = clientkey; serial.setHex(pass); - cert->setTrust(2); #endif } else { signcert = cert; signkey = clientkey; serial.setHex(dlg->serialNr->text()); - cert->setTrust(2); } dlg->initCtx(cert, signcert, NULL); @@ -588,6 +561,9 @@ void db_x509::newCert(NewX509 *dlg) // and finally sign the request cert->sign(signkey, hashAlgo); + // set the comment field + cert->setComment(dlg->comment->toPlainText()); + cert = (pki_x509*)insert(cert); createSuccess(cert); updatePKI(signcert); @@ -615,22 +591,6 @@ void db_x509::newCert(NewX509 *dlg) } } -void db_x509::showPki(pki_base *pki) -{ - pki_x509 *crt = (pki_x509 *)pki; - CertDetail *dlg; - dlg = new CertDetail(mainwin); - if (dlg) { - dlg->setCert(crt); - connect(dlg->privKey, SIGNAL(doubleClicked(QString)), - mainwin->keys, SLOT(showItem(QString))); - connect(dlg->signature, SIGNAL(doubleClicked(QString)), - this, SLOT( showItem(QString) )); - dlg->exec(); - delete dlg; - } -} - void db_x509::store(QModelIndex idx) { QModelIndexList l; @@ -694,12 +654,12 @@ void db_x509::store(QModelIndexList list) "PEM + PKCS#8"); } types << exportType() << - exportType(exportType::PKCS7_trusted, "p7b", - tr("PKCS#7 trusted")) << + exportType(exportType::PKCS7_unrevoked, "p7b", + tr("PKCS#7 unrevoked")) << exportType(exportType::PKCS7_all, "p7b", tr("PKCS#7 all")) << - exportType(exportType::PEM_trusted, "pem", - tr("PEM trusted")) << + exportType(exportType::PEM_unrevoked, "pem", + tr("PEM unrevoked")) << exportType(exportType::PEM_all, "pem", tr("PEM all")) << exportType(exportType::Index, "txt", @@ -738,7 +698,7 @@ void db_x509::store(QModelIndexList list) append = true; } break; - case exportType::PEM_trusted: + case exportType::PEM_unrevoked: writeAllCerts(fname,true); break; case exportType::PEM_all: @@ -749,7 +709,7 @@ void db_x509::store(QModelIndexList list) break; case exportType::PKCS7: case exportType::PKCS7_chain: - case exportType::PKCS7_trusted: + case exportType::PKCS7_unrevoked: case exportType::PKCS7_selected: case exportType::PKCS7_all: writePKCS7(crt, fname, type, list); @@ -858,11 +818,11 @@ void db_x509::writePKCS7(pki_x509 *cert, QString s, exportType::etype type, p7->addCert(cert); } break; - case exportType::PKCS7_trusted: + case exportType::PKCS7_unrevoked: case exportType::PKCS7_all: FOR_ALL_pki(cer, pki_x509) { if ((type == exportType::PKCS7_all) || - (cer->getTrust() == 2)) + (!cer->isRevoked())) p7->addCert(cer); } break; @@ -879,6 +839,19 @@ void db_x509::writePKCS7(pki_x509 *cert, QString s, exportType::etype type, } +void db_x509::storeRevocations(pki_x509 *cert) +{ + QSqlDatabase *db = mainwin->getDb(); + if (db->transaction()) { + QSqlError e; + e = cert->revList.sqlUpdate(cert->getSqlItemId()); + if (e.isValid()) + db->rollback(); + else + db->commit(); + } +} + void db_x509::manageRevocations(QModelIndex idx) { pki_x509 *cert = static_cast(idx.internalPointer()); @@ -890,56 +863,11 @@ void db_x509::manageRevocations(QModelIndex idx) mainwin->crls, SLOT(newItem(pki_x509*))); if (dlg->exec()) { cert->setRevocations(dlg->getRevList()); - updatePKI(cert); + storeRevocations(cert); emit columnsContentChanged(); } } -void db_x509::setTrust(QModelIndexList indexes) -{ - int newstate = -1; - Ui::TrustState ui; - pki_x509 *cert = NULL; - - if (indexes.size() == 0) - return; - if (indexes.size() == 1) - cert = static_cast(indexes[0].internalPointer()); - - QDialog *dlg = new QDialog(mainwin); - ui.setupUi(dlg); - ui.image->setPixmap(*MainWindow::certImg); - if (cert) { - int state = cert->getTrust(); - if (cert->getSigner() == cert) { - if (state == 1) - state = 0; - ui.trust1->setDisabled(true); - } - if (state == 0 ) ui.trust0->setChecked(true); - if (state == 1 ) ui.trust1->setChecked(true); - if (state == 2 ) ui.trust2->setChecked(true); - } - if (!dlg->exec()) { - delete dlg; - return; - } - if (ui.trust0->isChecked()) newstate = 0; - if (ui.trust1->isChecked()) newstate = 1; - if (ui.trust2->isChecked()) newstate = 2; - delete dlg; - if (newstate == -1) { - return; - } - foreach(QModelIndex idx, indexes) { - cert = static_cast(idx.internalPointer()); - if (newstate != cert->getTrust()) { - cert->setTrust(newstate); - updatePKI(cert); - } - } -} - void db_x509::certRenewal(QModelIndexList indexes) { pki_x509 *oldcert = NULL, *signer = NULL, *newcert =NULL; @@ -1048,7 +976,7 @@ void db_x509::do_revoke(QModelIndexList indexes, const x509rev &r) revlist << rev; } parent->mergeRevList(revlist); - updatePKI(parent); + storeRevocations(parent); } void db_x509::unRevoke(QModelIndexList indexes) @@ -1081,7 +1009,7 @@ void db_x509::unRevoke(QModelIndexList indexes) if (i != -1) parent->revList.takeAt(i); } - updatePKI(parent); + storeRevocations(parent); emit columnsContentChanged(); } @@ -1130,6 +1058,7 @@ void db_x509::caProperties(QModelIndex idx) { Ui::CaProperties ui; int i; +#warning FIXME for Policies pki_x509 *cert = static_cast(idx.internalPointer()); if (!cert) @@ -1144,7 +1073,7 @@ void db_x509::caProperties(QModelIndex idx) ui.days->setMaximum(1000000); ui.days->setValue(cert->getCrlDays()); ui.image->setPixmap(*MainWindow::certImg); - QString templ = cert->getTemplate(); + QString templ; //cert->getTemplate()->getIntName(); QStringList tempList = mainwin->temps->getDesc(); for (i=0; iaddItems(tempList); ui.temp->setCurrentIndex(i); ui.certName->setTitle(cert->getIntName()); + + QStringList sl; + sl << tr("Type") << tr("Action"); + ui.subjectManager->initCols(sl); + + sl.clear(); + foreach(int nid, *MainWindow::dn_nid) + sl << QString(OBJ_nid2ln(nid)); + ui.subjectManager->setKeys(sl, 0); + + sl.clear(); + sl << "From request" << "From template" << "Erase" << "Match" + << "Template as regex"; + ui.subjectManager->setKeys(sl, 1); + if (dlg->exec()) { a1int nserial; cert->setCrlDays(ui.days->value()); nserial.setHex(ui.serial->text()); cert->setCaSerial(nserial); - cert->setTemplate(ui.temp->currentText()); +#warning Fixme, too +// cert->setTemplate(ui.temp->currentText()); cert->setUseRandomSerial(ui.randomSerial->isChecked()); updatePKI(cert); } diff --git a/lib/db_x509.h b/lib/db_x509.h index f7554e6a..2ae41e74 100644 --- a/lib/db_x509.h +++ b/lib/db_x509.h @@ -27,12 +27,13 @@ class db_x509: public db_x509super QPixmap *certicon[4]; pki_x509 *get1SelectedCert(); dbheaderList getHeaders(); + void dereferenceIssuer(); public: static bool treeview; - db_x509(QString DBfile, MainWindow *mw); - pki_base *newPKI(db_header_t *head = NULL); - pki_x509 *findSigner(pki_x509 *client); + db_x509(MainWindow *mw); + pki_base *newPKI(enum pki_type type = none); + pki_x509 *findIssuer(pki_x509 *client); void updateAfterDbLoad(); void updateAfterCrlLoad(pki_x509 *pki); @@ -40,15 +41,11 @@ class db_x509: public db_x509super void updateViewAll(); void updateViewPKI(pki_base *pki); void remFromCont(QModelIndex &idx); - QStringList getPrivateDesc(); - QStringList getSignerDesc(); - void calcEffTrust(); - QList getCerts(bool onlyTrusted); + QList getAllIssuers(); + QList getCerts(bool unrevoked); a1int searchSerial(pki_x509 *signer); - void writeAllCerts(const QString fname, bool onlyTrusted); void writeIndex(const QString fname, bool hierarchy); - pki_x509 *getByIssSerial(const pki_x509 *issuer, const a1int &a); - pki_x509 *getBySubject(const x509name &xname, pki_x509 *last = NULL); + void writeAllCerts(const QString fname, bool unrevoked); pki_base *insert(pki_base *item); void newCert(NewX509 *dlg); void newCert(pki_x509 *cert); @@ -63,7 +60,6 @@ class db_x509: public db_x509super void toRequest(QModelIndex idx); void store(QModelIndex idx); void store(QModelIndexList list); - void showPki(pki_base *pki); void load(); void caProperties(QModelIndex idx); void toCertificate(QModelIndex index); @@ -72,7 +68,7 @@ class db_x509: public db_x509super void revoke(QModelIndexList indexes); void do_revoke(QModelIndexList indexes, const x509rev &r); void unRevoke(QModelIndexList indexes); - void setTrust(QModelIndexList indexes); + void storeRevocations(pki_x509 *cert); public slots: void newItem(); diff --git a/lib/db_x509req.cpp b/lib/db_x509req.cpp index 245da76c..81bdc848 100644 --- a/lib/db_x509req.cpp +++ b/lib/db_x509req.cpp @@ -8,17 +8,17 @@ #include "db_x509req.h" #include "pki_x509req.h" -#include "widgets/CertDetail.h" #include "widgets/MainWindow.h" #include #include #include -db_x509req::db_x509req(QString DBfile, MainWindow *mw) - :db_x509super(DBfile, mw) +db_x509req::db_x509req(MainWindow *mw) + :db_x509super(mw) { class_name = "requests"; + sqlHashTable = "requests"; pkitype << x509_req; updateHeaders(); loadContainer(); @@ -36,8 +36,9 @@ dbheaderList db_x509req::getHeaders() return h; } -pki_base *db_x509req::newPKI(db_header_t *) +pki_base *db_x509req::newPKI(enum pki_type type) { + (void)type; return new pki_x509req(); } @@ -86,6 +87,9 @@ void db_x509req::newItem(pki_temp *temp, pki_x509req *orig) dlg->initCtx(NULL, NULL, req); dlg->getReqAttributes(req); req->createReq(key, xn, dlg->hashAlgo->currentHash(), dlg->getAllExt()); + // set the comment field + req->setComment(dlg->comment->toPlainText()); + createSuccess(insert(req)); } catch (errorEx &err) { @@ -103,43 +107,12 @@ void db_x509req::toRequest(QModelIndex index) newItem(NULL, req); } -void db_x509req::inToCont(pki_base *pki) -{ - pki_x509req *req = (pki_x509req *)pki; - db_base::inToCont(pki); - findKey(req); - if (!mainwin->certs) - return; - pki_key *pub = req->getPubKey(); - if (pub) { - int certs = mainwin->certs->findByPubKey(pub).count(); - delete pub; - if (certs > 0) { - req->setDone(); - } - } -} - void db_x509req::load(void) { load_req l; load_default(l); } -void db_x509req::showPki(pki_base *pki) -{ - pki_x509req *req = (pki_x509req *)pki; - CertDetail *dlg; - dlg = new CertDetail(mainwin); - if (dlg) { - dlg->setReq(req); - connect(dlg->privKey, SIGNAL( doubleClicked(QString) ), - mainwin->keys, SLOT( showItem(QString) )); - dlg->exec(); - delete dlg; - } -} - void db_x509req::store(QModelIndex index) { QList types; @@ -174,3 +147,8 @@ void db_x509req::signReq(QModelIndex index) pki_x509req *req = static_cast(index.internalPointer()); emit newCert(req); } + +QList db_x509req::getAllRequests() +{ + return sqlSELECTpki("SELECT item FROM requests"); +} diff --git a/lib/db_x509req.h b/lib/db_x509req.h index aedae4b3..5761a975 100644 --- a/lib/db_x509req.h +++ b/lib/db_x509req.h @@ -21,16 +21,16 @@ class db_x509req: public db_x509super protected: dbheaderList getHeaders(); public: - db_x509req(QString DBfile, MainWindow *mw); + db_x509req(MainWindow *mw); pki_base* insert(pki_base *item); - pki_base *newPKI(db_header_t *head = NULL); + pki_base *newPKI(enum pki_type type = none); void fillContextMenu(QMenu *menu, const QModelIndex &index); - void inToCont(pki_base *pki); +// void inToCont(pki_base *pki); void store(QModelIndex index); void signReq(QModelIndex index); void toRequest(QModelIndex index); void load(); - void showPki(pki_base *pki); + QList getAllRequests(); public slots: void newItem(pki_temp *temp, pki_x509req *orig = NULL); diff --git a/lib/db_x509super.cpp b/lib/db_x509super.cpp index a9daa052..f2e93962 100644 --- a/lib/db_x509super.cpp +++ b/lib/db_x509super.cpp @@ -8,12 +8,13 @@ #include "pki_base.h" #include "db_x509super.h" #include "widgets/MainWindow.h" -#include "ui_About.h" +#include "widgets/CertDetail.h" +#include "widgets/XcaDialog.h" #include "oid.h" #include -db_x509name::db_x509name(QString db, MainWindow *mw) - :db_base(db, mw) +db_x509name::db_x509name(MainWindow *mw) + :db_base(mw) { } @@ -30,11 +31,26 @@ dbheaderList db_x509name::getHeaders() return h; } -db_x509super::db_x509super(QString db, MainWindow *mw) - :db_x509name(db, mw) +db_x509super::db_x509super(MainWindow *mw) + :db_x509name(mw) { } +void db_x509super::loadContainer() +{ + db_x509name::loadContainer(); + /* Resolve Key references */ + FOR_ALL_pki(pki, pki_x509super) { + QVariant keySqlId = pki->getKeySqlId(); + if (!keySqlId.isValid()) + continue; + quint64 id = keySqlId.toULongLong(); + if (!lookup.contains(id)) + continue; + pki->setRefKey(static_cast(lookup[id])); + } +} + dbheaderList db_x509super::getHeaders() { dbheaderList h = db_x509name::getHeaders(); @@ -71,16 +87,6 @@ dbheaderList db_x509super::getHeaders() return h; } -void db_x509super::delKey(pki_key *delkey) -{ - FOR_ALL_pki(pki, pki_x509super) { pki->delRefKey(delkey); } -} - -void db_x509super::newKey(pki_key *newkey) -{ - FOR_ALL_pki(pki,pki_x509super) { pki->setRefKey(newkey); } -} - pki_key *db_x509super::findKey(pki_x509super *ref) { pki_key *key, *refkey; @@ -158,18 +164,15 @@ void db_x509super::toTemplate(QModelIndex index) temp->setIntName(pki->getIntName()); extList el = temp->fromCert(pki); if (el.size()) { - Ui::About ui; QString etext; - QDialog *d = new QDialog(mainwin, 0); - ui.setupUi(d); etext = QString("

") + tr("The following extensions were not ported into the template") + QString("


") + el.getHtml("
"); - ui.textbox->setHtml(etext); - d->setWindowTitle(XCA_TITLE); - ui.image->setPixmap(*MainWindow::tempImg); - ui.image1->setPixmap(*MainWindow::certImg); + QTextEdit *textbox = new QTextEdit(etext); + XcaDialog *d = new XcaDialog(mainwin, x509, textbox, + QString(), QString()); + d->aboutDialog(MainWindow::tempImg); d->exec(); delete d; } @@ -180,3 +183,33 @@ void db_x509super::toTemplate(QModelIndex index) } } +void db_x509super::showPki(pki_base *pki) +{ + pki_x509super *x = (pki_x509req *)pki; + CertDetail *dlg; + dlg = new CertDetail(mainwin); + if (!dlg) + return; + + switch (x->getType()) { + case x509_req: dlg->setReq((pki_x509req*)x); break; + case x509: dlg->setCert((pki_x509*)x); break; + default: + delete dlg; + return; + } + connect(dlg->privKey, SIGNAL(doubleClicked(QString)), + mainwin->keys, SLOT(showItem(QString))); + connect(dlg->signature, SIGNAL(doubleClicked(QString)), + this, SLOT(showItem(QString))); + if (dlg->exec()) { + QString newname = dlg->descr->text(); + QString newcomment = dlg->comment->toPlainText(); + if (newname != pki->getIntName() || + newcomment != pki->getComment()) + { + updateItem(pki, newname, newcomment); + } + } + delete dlg; +} diff --git a/lib/db_x509super.h b/lib/db_x509super.h index 4b7317ef..bbab687b 100644 --- a/lib/db_x509super.h +++ b/lib/db_x509super.h @@ -21,7 +21,7 @@ class db_x509name: public db_base protected: dbheaderList getHeaders(); public: - db_x509name(QString db, MainWindow *mw); + db_x509name(MainWindow *mw); }; class db_x509super: public db_x509name @@ -30,17 +30,15 @@ class db_x509super: public db_x509name protected: dbheaderList getHeaders(); + void loadContainer(); public: - db_x509super(QString db, MainWindow *mw); + db_x509super(MainWindow *mw); pki_key *findKey(pki_x509super *ref); QList findByPubKey(pki_key *refkey); void extractPubkey(QModelIndex index); void toTemplate(QModelIndex index); void toOpenssl(QModelIndex index) const; - - public slots: - void delKey(pki_key *delkey); - void newKey(pki_key *newKey); + void showPki(pki_base *pki); }; #endif diff --git a/lib/headerlist.h b/lib/headerlist.h index 9fcb76b6..29177267 100644 --- a/lib/headerlist.h +++ b/lib/headerlist.h @@ -23,11 +23,13 @@ #define HD_x509key_name -5 #define HD_counter -6 #define HD_x509_sigalg -7 +#define HD_creation -8 +#define HD_comment -9 #define HD_cert_serial -10 #define HD_cert_notBefore -11 #define HD_cert_notAfter -12 -#define HD_cert_trust -13 +//#define HD_cert_trust -13 #define HD_cert_revocation -14 #define HD_cert_ca -15 #define HD_cert_md5fp -16 @@ -38,7 +40,7 @@ #define HD_req_signed -20 #define HD_req_unstr_name -21 #define HD_req_chall_pass -22 -#define HD_temp_type -30 +//#define HD_temp_type -30 #define HD_crl_signer -40 #define HD_crl_revoked -42 @@ -92,7 +94,7 @@ class dbheader name = aname; } #endif - dbheader(int aid, bool ashow, + dbheader(int aid, bool ashow = false, QString aname = QString(), QString atip = QString()) { init(); @@ -135,21 +137,22 @@ class dbheader } return false; } - QByteArray toData() + QString toData() { - QByteArray ba; - ba += db::intToData(visualIndex); - ba += db::intToData(sortIndicator); - ba += db::intToData(size); - ba += db::boolToData(show); - return ba; + QStringList sl; sl + << QString::number(visualIndex) + << QString::number(sortIndicator) + << QString::number(size) + << QString::number(show); + return sl.join(" "); } - void fromData(QByteArray &ba) + void fromData(QString s) { - visualIndex = db::intFromData(ba); - sortIndicator = db::intFromData(ba); - size = db::intFromData(ba); - show = db::boolFromData(ba); + QStringList sl = s.split(" "); + visualIndex = sl[0].toInt(); + sortIndicator = sl[1].toInt(); + size = sl[2].toInt(); + show = sl[3].toInt(); } void setupHeaderView(int sect, QHeaderView *hv) { @@ -207,43 +210,40 @@ class dbheaderList: public QList } dbheaderList() :QList() { } - QByteArray toData() + QString toData() { - QByteArray ba; + QStringList sl; for (int i=0; imustSave()) continue; - ba += db::intToData(h->id); + seq << QString("%1").arg(h->id); if (h->id > 0) { - ASN1_OBJECT *o = OBJ_nid2obj(h->id); - ba += i2d_bytearray(I2D_VOID(i2d_ASN1_OBJECT), o); + seq << OBJ_obj2QString( + OBJ_nid2obj(h->id), 1); } - ba += h->toData(); + seq << h->toData(); + sl << seq.join(":"); } - return ba; + return sl.join(","); } - void fromData(QByteArray &ba) + void fromData(QString s) { - while (ba.size()) { - int id = db::intFromData(ba); + QStringList sl = s.split(","); + foreach(QString hd, sl) { + QStringList sl1 = hd.split(":"); + int id = sl1.takeFirst().toInt(); if (id > 0) { - ASN1_OBJECT *o = (ASN1_OBJECT*)d2i_bytearray(D2I_VOID(d2i_ASN1_OBJECT), ba); - id = OBJ_obj2nid(o); - ASN1_OBJECT_free(o); + id = OBJ_txt2nid(CCHAR(sl1.takeFirst())); } for (int i=0; iid == id) { - h->fromData(ba); - id = 0; + h->fromData(sl1.takeFirst()); break; } } - if (id != 0) { - dbheader h("dummy"); - h.fromData(ba); - } } } }; diff --git a/lib/import.cpp b/lib/import.cpp deleted file mode 100644 index 8075bb40..00000000 --- a/lib/import.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* vi: set sw=4 ts=4: - * - * Copyright (C) 2001 - 2007 Christian Hohnstaedt. - * - * All rights reserved. - */ - - -#include "exception.h" -#include "db_base.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#define RESIZE 1024 -#define RDBUF 256 - -static int database = -1; - -static int h2n(const char c) -{ - if (c>='0' && c<='9') - return c-'0'; - if (c>='a' && c<='f') - return c-'a'+10; - if (c>='A' && c<='F') - return c-'A'+10; - return 0; -} - -static char *read_data(const char *asc, int *retlen) -{ - char *p; - int len=0, binlen=0, alloclen=RESIZE; - p = (char*)malloc(alloclen); - if (!p) - return NULL; - *retlen = 0; - while(asc[len] != '\0') { - p[binlen] = (h2n(asc[len])<<4) + h2n(asc[len+1]); - len +=2; - binlen++; - if (binlen == alloclen) { - alloclen +=RESIZE; - p = (char *)realloc(p, alloclen); - } - } - *retlen = binlen; - return p; -} - -QString readLine(QFile *file) -{ - QString data; - qint64 begin; - char buffer[RDBUF], *p; - int ret, len; - - while ((ret = file->read(buffer, RDBUF-1)) >0) { - p = strchr(buffer, '\n'); - if (p) { - begin = file->pos() - ret; - len = p - buffer; - file->seek(begin + len + 1); - //printf("Begin: %ld len=%d\n", begin,len); - if (p > buffer && p[-1] == '\r') - p--; - *p = '\0'; - data += buffer; - return data; - } - buffer[ret] = '\0'; - data += buffer; - continue; - } - return data; -} - -static int set_db(const char *name) -{ - QStringList sl; - sl << "keydb" << "reqdb" << "certdb" << "tempdb" << "crldb" << "settings"; - for (int i=0; i= 0 && database < 5) - db = dbs[database]; - else - db = NULL; - kv ^= 1; - p = read_data(CCHAR(line.trimmed()), &retlen); - if (db && !md5) { - if (kv) { - pki = db->newPKI(); - if (!pki) { - break; - } - pki->setIntName(p); - } else { - try { - pki->oldFromData((unsigned char*)p, retlen); - db->insert(pki); - } catch (errorEx &err) { - printf("Error caught for '%s'\n", CCHAR(pki->getIntName())); - } - } - } else if (md5) { - if (database == 5) { - p = read_data(CCHAR(line.trimmed()), &retlen); - if (kv) - md5sum = (!strcmp(p, "pwhash")) ? true : false; - if (!kv && md5sum) { - strncpy(md5, p, md5_len); - ret = 0; - break; - } - } - } - free(p); - } else { - if (kv) { - printf("Binary value expected\n"); - break; - } - handle_option(line); - } - } - file.close(); - if (ret <0) { - throw errorEx(filename, strerror(errno)); - return -1; - } - return 0; -} diff --git a/lib/main.cpp b/lib/main.cpp index fa401396..b148c539 100644 --- a/lib/main.cpp +++ b/lib/main.cpp @@ -256,13 +256,6 @@ int main_extract(int argc, char *argv[]) case revocation: pki = new pki_crl(name); break; default: return usage_extract(argv); } - if (pki->getVersion() < head.version) { - fprintf(stderr, "Item[%s]: Version %d > known version: %d", - head.name, head.version, pki->getVersion()); - free(p); - delete pki; - return usage_extract(argv); - } pki->setIntName(QString::fromUtf8(head.name)); try { pki->fromData(p, &head); @@ -301,7 +294,7 @@ static void segv_handler_gui(int) int main( int argc, char *argv[] ) { - int ret = 0, pkictr; + int ret = 0; MainWindow *mw; QDir d; @@ -332,9 +325,5 @@ int main( int argc, char *argv[] ) } delete mw; - pkictr = pki_base::get_pki_counter(); - if (pkictr) - fprintf(stderr, "PKI Counter (%d)\n", pkictr); - return ret; } diff --git a/lib/pki_base.cpp b/lib/pki_base.cpp index b6e8dc83..61960f58 100644 --- a/lib/pki_base.cpp +++ b/lib/pki_base.cpp @@ -10,50 +10,41 @@ #include "pki_base.h" #include "exception.h" #include +#include +#include -int pki_base::pki_counter = 0; int pki_base::suppress_messages = 0; QRegExp pki_base::limitPattern; pki_base::pki_base(const QString name, pki_base *p) { desc = name; - class_name = "pki_base"; parent = p; - pki_counter++; childItems.clear(); - dataVersion=0; pkiType=none; } -int pki_base::getVersion() -{ - return dataVersion; -} - -enum pki_type pki_base::getType() -{ - return pkiType; -} - pki_base::~pki_base(void) { while (childItems.size() > 0) delete takeFirst(); - pki_counter--; } - -QString pki_base::getIntName() const +QString pki_base::comboText() const { return desc; } - -QString pki_base::getUnderlinedName() const +void pki_base::deleteFromToken() { }; +void pki_base::deleteFromToken(slotid) { }; +void pki_base::writeDefault(const QString) { } +void pki_base::fromPEM_BIO(BIO *, QString) { } +void pki_base::fload(const QString) { } +int pki_base::renameOnToken(slotid, QString) { - return getIntName().replace(QRegExp("[ &;`/\\\\]+"), "_"); + return 0; } + bool pki_base::visible() { if (limitPattern.isEmpty()) @@ -61,20 +52,26 @@ bool pki_base::visible() return getIntName().contains(limitPattern); } -int pki_base::get_pki_counter() +QString pki_base::getMsg(msg_type msg) { - return pki_counter; + return tr("Internal error: Unexpected message: %1 %2") + .arg(getClassName()).arg(msg); } -QString pki_base::getClassName() +QByteArray pki_base::i2d() { - QString x = class_name; - return x; + return QByteArray(); } -void pki_base::setIntName(const QString &d) +BIO *pki_base::pem(BIO *, int format) { - desc = d; + (void)format; + return NULL; +} + +const char *pki_base::getClassName() const +{ + return "pki_base"; } void pki_base::fopen_error(const QString fname) @@ -97,7 +94,7 @@ void pki_base::my_error(const QString error) const { if (!error.isEmpty()) { fprintf(stderr, "%s\n", CCHAR(tr("Error: ") + error)); - throw errorEx(error, class_name); + throw errorEx(error, getClassName()); } } @@ -117,6 +114,78 @@ QString pki_base::rmslashdot(const QString &s) return s.mid(l+1,r-l-1); } +QSqlError pki_base::insertSql() +{ + XSqlQuery q; + QString insert; + QSqlError e; + insertion_date.now(); + + SQL_PREPARE(q, "INSERT INTO items " + "(name, type, date, comment) " + "VALUES (?, ?, ?, ?)"); + q.bindValue(0, getIntName()); + q.bindValue(1, getType()); + q.bindValue(2, insertion_date.toPlain()); + q.bindValue(3, getComment()); + q.exec(); + e = q.lastError(); + if (!e.isValid()) { + sqlItemId = q.lastInsertId(); + e = insertSqlData(); + } + return e; +} + +QSqlError pki_base::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + SQL_PREPARE(q, "SELECT name, date, comment FROM items WHERE id=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + + if (e.isValid()) + return e; + if (!q.first()) + return sqlItemNotFound(sqlId); + desc = q.value(0).toString(); + insertion_date.fromPlain(q.value(1).toString()); + comment = q.value(2).toString(); + sqlItemId = sqlId; + return e; +} + +QSqlError pki_base::deleteSql() +{ + XSqlQuery q; + QString insert; + QSqlError e; + + if (!sqlItemId.isValid()) { + qDebug("INVALID sqlItemId (DELETE %s)", CCHAR(getIntName())); + return sqlItemNotFound(QVariant()); + } + SQL_PREPARE(q, "DELETE FROM items WHERE id=?"); + q.bindValue(0, sqlItemId); + q.exec(); + e = q.lastError(); + if (!e.isValid()) + e = deleteSqlData(); + return e; +} + +QSqlError pki_base::sqlItemNotFound(QVariant sqlId) const +{ + return QSqlError(QString("XCA SQL database inconsistent"), + QString("Item %2 not found %1") + .arg(getClassName()) + .arg(sqlId.toString()), + QSqlError::UnknownError); +} + pki_base *pki_base::getParent() { return parent; @@ -187,6 +256,10 @@ QVariant pki_base::column_data(dbheader *hd) switch (hd->id) { case HD_internal_name: return QVariant(getIntName()); + case HD_creation: + return QVariant(insertion_date.toSortable()); + case HD_comment: + return QVariant(comment.section('\n', 0, 0)); } return QVariant(); } @@ -197,23 +270,26 @@ QVariant pki_base::getIcon(dbheader *hd) return QVariant(); } -uint32_t pki_base::intFromData(QByteArray &ba) -{ - /* For import "oldFromData" use the endian dependent version */ - uint32_t ret; - if ((unsigned)(ba.count()) < sizeof(uint32_t)) { - ba.clear(); - return 0; - } - memcpy(&ret, ba.constData(), sizeof(uint32_t)); - ba = ba.mid(sizeof(uint32_t)); - return ret; -} - -bool pki_base::compare(pki_base *refcrl) +bool pki_base::compare(pki_base *ref) { bool ret; - ret = (i2d() == refcrl->i2d()); + ret = (i2d() == ref->i2d()); pki_openssl_error(); return ret; } + +/* Signed 32 bit interger */ +unsigned pki_base::hash(QByteArray ba) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + + SHA1((const unsigned char *)ba.constData(), ba.length(), md); + + return (((unsigned)md[0] ) | ((unsigned)md[1]<<8L) | + ((unsigned)md[2]<<16L) | ((unsigned)md[3]<<24L) + ) & 0x7fffffffL; +} +unsigned pki_base::hash() +{ + return hash(i2d()); +} diff --git a/lib/pki_base.h b/lib/pki_base.h index 9e5025c7..4a604fa8 100644 --- a/lib/pki_base.h +++ b/lib/pki_base.h @@ -11,24 +11,92 @@ #include #include #include +#include +#include "asn1time.h" #include "pkcs11_lib.h" #include "db.h" #include "base.h" #include "headerlist.h" -#define __ME QString("(%1:%2)").arg(class_name).arg(getIntName()) +#define __ME QString("(%1:%2)").arg(getClassName()).arg(getIntName()) #define pki_openssl_error() _openssl_error(__ME, C_FILE, __LINE__) #define pki_ign_openssl_error() _ign_openssl_error(__ME, C_FILE, __LINE__) +#define SQL_PREPARE(q,cmd) do { \ + (q).prepare(cmd); \ + (q).location(__FILE__,__LINE__); \ +} while (0); + +class XSqlQuery: public QSqlQuery +{ + QString lastq; + const char *file; + int line; + public: + QString query_details() + { + QString lq = lastq; + QList list = boundValues().values(); + QStringList sl; + for (int i = 0; i < list.size(); ++i) + sl << list.at(i).toString(); + if (sl.size()) + lq += QString("[%1]").arg(sl.join(", ")); + return QString("%1:%2 (%3)") + .arg(file).arg(line).arg(lq); + } + QSqlError lastError() + { + QSqlError e = QSqlQuery::lastError(); + if (!e.isValid()) + return e; + QString dt = e.driverText(); + e.setDriverText(QString("%1 - %2") + .arg(dt).arg(query_details())); + return e; + } + XSqlQuery() : QSqlQuery() { } + XSqlQuery(QString q) : QSqlQuery(q) + { + file = ""; line = 0; + lastq = q; + } + bool exec(QString q) + { + lastq = q; + file = ""; line = 0; + return QSqlQuery::exec(q); + } + bool exec() + { + fprintf(stderr, "QUERY: %s\n", CCHAR(query_details())); + return QSqlQuery::exec(); + } + bool prepare(QString q) + { + lastq = q; + return QSqlQuery::prepare(q); + } + void location(const char *f, int l) + { + file = f; line = l; + } +}; + class pki_base : public QObject { Q_OBJECT - private: - static int pki_counter; + + public: /* static */ + static int suppress_messages; + static QRegExp limitPattern; + static QString rmslashdot(const QString &fname); + static unsigned hash(QByteArray ba); + protected: - const char *class_name; - QString desc; - int dataVersion; + QVariant sqlItemId; + QString desc, comment; + a1time insertion_date; enum pki_type pkiType; /* model data */ pki_base *parent; @@ -42,74 +110,99 @@ class pki_base : public QObject msg_delete_multi, msg_create, }; - static int suppress_messages; - static QRegExp limitPattern; QList childItems; + pki_base(const QString d = "", pki_base *p = NULL); - virtual void fload(const QString) {}; - virtual void writeDefault(const QString) {}; - static int get_pki_counter(void); - virtual void fromData(const unsigned char *, db_header_t *) {}; - virtual void oldFromData(unsigned char *, int ) {}; - virtual QByteArray toData() - { - return QByteArray(); - } - virtual bool compare(pki_base *); - virtual bool visible(); virtual ~pki_base(); - QString getIntName() const; - QString getUnderlinedName() const; - void setIntName(const QString &d); - QString getClassName(); - static QString rmslashdot(const QString &fname); - virtual QString getMsg(msg_type msg) + + QString getIntName() const { - return tr("Internal error: Unexpected message: %1 %2"). - arg(class_name).arg(msg); - }; - int getVersion(); - enum pki_type getType(); + return desc; + } + virtual QString comboText() const; + QString getUnderlinedName() const + { + return getIntName().replace( + QRegExp("[ &;`/\\\\]+"), "_"); + } + void setIntName(const QString &d) + { + desc = d; + } + QString getComment() const + { + return comment; + } + void setComment(QString c) + { + comment = c; + } + QVariant getSqlItemId() + { + return sqlItemId; + } + enum pki_type getType() const + { + return pkiType; + } + virtual QByteArray i2d(); + virtual bool compare(pki_base *); + virtual QString getMsg(msg_type msg); + virtual const char *getClassName() const; + + /* Tree View management */ void setParent(pki_base *p); virtual pki_base *getParent(); pki_base *child(int row); void append(pki_base *item); void insert(int row, pki_base *item); int childCount(); - int row() const; pki_base *iterate(pki_base *pki = NULL); void takeChild(pki_base *pki); pki_base *takeFirst(); - virtual QVariant column_data(dbheader *hd); - virtual QVariant getIcon(dbheader *hd); - const char *className() - { - return class_name; - }; - uint32_t intFromData(QByteArray &ba); - virtual void fromPEM_BIO(BIO *, QString) {}; + + /* Token handling */ + virtual void deleteFromToken(); + virtual void deleteFromToken(slotid); + virtual int renameOnToken(slotid, QString); + + /* Import / Export management */ + virtual BIO *pem(BIO *, int format=0); + virtual void fromPEM_BIO(BIO *, QString); virtual void fromPEMbyteArray(QByteArray &, QString); - virtual void deleteFromToken() { }; - virtual void deleteFromToken(slotid) { }; - virtual int renameOnToken(slotid, QString) - { - return 0; - }; - virtual QByteArray i2d() - { - return QByteArray(); - } - virtual BIO *pem(BIO *, int format=0) - { - (void)format; - return NULL; - } void fwrite_ba(FILE *fp, QByteArray ba, QString fname); + virtual void fload(const QString); + virtual void writeDefault(const QString); + + /* Old database management methods */ + virtual void fromData(const unsigned char *, db_header_t *) {}; + /* Qt Model-View methods */ virtual QVariant bg_color(dbheader *hd) { (void)hd; return QVariant(); } + int row() const; + virtual QVariant column_data(dbheader *hd); + virtual QVariant getIcon(dbheader *hd); + virtual bool visible(); + + + /* SQL management methods */ + QSqlError insertSql(); + virtual QSqlError insertSqlData() + { + return QSqlError(); + } + QSqlError deleteSql(); + virtual QSqlError deleteSqlData() + { + return QSqlError(); + } + virtual QSqlError restoreSql(QVariant sqlId); + QSqlError sqlItemNotFound(QVariant sqlId) const; + unsigned hash(); }; +Q_DECLARE_METATYPE(pki_base *); #endif diff --git a/lib/pki_crl.cpp b/lib/pki_crl.cpp index 7088819e..ec0eea17 100644 --- a/lib/pki_crl.cpp +++ b/lib/pki_crl.cpp @@ -9,6 +9,7 @@ #include "pki_crl.h" #include "func.h" #include "exception.h" +#include "db_base.h" #include #include "openssl_compat.h" @@ -20,12 +21,15 @@ pki_crl::pki_crl(const QString name ) { issuer = NULL; crl = X509_CRL_new(); - class_name="pki_crl"; pki_openssl_error(); - dataVersion=1; pkiType=revocation; } +const char *pki_crl::getClassName() const +{ + return "pki_crl"; +} + void pki_crl::fromPEM_BIO(BIO *bio, QString name) { X509_CRL *_crl; @@ -54,6 +58,74 @@ QString pki_crl::getMsg(msg_type msg) return pki_base::getMsg(msg); } +QSqlError pki_crl::insertSqlData() +{ + XSqlQuery q; + unsigned name_hash = getSubject().hashNum(); + + SQL_PREPARE(q, "SELECT x509super.item FROM x509super " + "JOIN certs ON certs.item = x509super.item " + "WHERE x509super.subj_hash=? AND certs.ca=1"); + q.bindValue(0, name_hash); + q.exec(); + if (q.lastError().isValid()) + return q.lastError(); + while (q.next()) { + pki_x509 *x = static_cast( + db_base::lookupPki(q.value(0).toULongLong())); + if (!x) { + qDebug("CA certificate with id %d not found", + q.value(0).toInt()); + continue; + } + verify(x); + } + SQL_PREPARE(q, "INSERT INTO crls (item, hash, num, iss_hash, issuer, crl) " + "VALUES (?, ?, ?, ?, ?, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, hash()); + q.bindValue(2, numRev()); + q.bindValue(3, name_hash); + q.bindValue(4, issuer ? issuer->getSqlItemId() : QVariant()); + q.bindValue(5, i2d().toBase64()); + q.exec(); + return q.lastError(); +} + +QSqlError pki_crl::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + e = pki_base::restoreSql(sqlId); + if (e.isValid()) + return e; + SQL_PREPARE(q, "SELECT crl, issuer FROM crls WHERE item=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (!q.first()) + return sqlItemNotFound(sqlId); + QByteArray ba = QByteArray::fromBase64(q.value(0).toByteArray()); + d2i(ba); + setIssuer(static_cast( + db_base::lookupPki(q.value(1).toULongLong()))); + return e; +} + +QSqlError pki_crl::deleteSqlData() +{ + XSqlQuery q; + QSqlError e; + + SQL_PREPARE(q, "DELETE FROM crls WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); +} + void pki_crl::fload(const QString fname) { FILE *fp = fopen_read(fname); @@ -151,13 +223,6 @@ void pki_crl::fromData(const unsigned char *p, db_header_t *head) } } -QByteArray pki_crl::toData() -{ - QByteArray ba = i2d(); - pki_openssl_error(); - return ba; -} - void pki_crl::addRev(const x509rev &xrev, bool withReason) { X509_CRL_add0_revoked(crl, xrev.get(withReason)); @@ -265,14 +330,25 @@ x509name pki_crl::getSubject() const return x509name(X509_CRL_get_issuer(crl)); } -bool pki_crl::verify(pki_key *key) +bool pki_crl::verify(pki_x509 *issuer) { - bool ret=false; - if (key) { - ret = (X509_CRL_verify(crl, key->getPubKey()) == 1); - pki_ign_openssl_error(); + if (getSubject() != issuer->getSubject()) + return false; + pki_key *key = issuer->getPubKey(); + if (!key) + return false; + int ret = X509_CRL_verify(crl, key->getPubKey()); + pki_ign_openssl_error(); + if (ret != 1) { + delete key; + return false; } - return ret; + delete key; + pki_x509 *curr = getIssuer(); + if (curr && curr->getNotAfter() > issuer->getNotAfter()) + return true; + setIssuer(issuer); + return true; } void pki_crl::setCrlNumber(a1int num) @@ -350,13 +426,3 @@ QVariant pki_crl::getIcon(dbheader *hd) { return hd->id == HD_internal_name ? QVariant(*icon) : QVariant(); } - -void pki_crl::oldFromData(unsigned char *p, int size) -{ - QByteArray ba((const char *)p, size); - d2i(ba); - - if (ba.count() > 0) { - my_error(tr("Wrong Size %1").arg(ba.count())); - } -} diff --git a/lib/pki_crl.h b/lib/pki_crl.h index 52c570f1..8d533b75 100644 --- a/lib/pki_crl.h +++ b/lib/pki_crl.h @@ -26,8 +26,8 @@ class pki_crl: public pki_x509name extList extensions() const; public: pki_crl(const QString name = ""); - /* destructor */ ~pki_crl(); + const char *getClassName() const; void fromPEM_BIO(BIO *bio, QString name); void fload(const QString fname); QString getSigAlg(); @@ -54,9 +54,7 @@ class pki_crl: public pki_x509name a1time getNextUpdate(); a1time getLastUpdate(); void fromData(const unsigned char *p, db_header_t *head); - void oldFromData(unsigned char *p, int size); - QByteArray toData(); - bool verify(pki_key *pkey); + bool verify(pki_x509 *issuer); int numRev(); x509revList getRevList(); QString printV3ext(); @@ -72,6 +70,9 @@ class pki_crl: public pki_x509name a1int getCrlNumber(); BIO *pem(BIO *, int); bool visible(); + QSqlError insertSqlData(); + QSqlError deleteSqlData(); + QSqlError restoreSql(QVariant sqlId); }; #endif diff --git a/lib/pki_evp.cpp b/lib/pki_evp.cpp index c6a37824..1c7c60c5 100644 --- a/lib/pki_evp.cpp +++ b/lib/pki_evp.cpp @@ -33,18 +33,13 @@ QPixmap *pki_evp::icon[2]= { NULL, NULL }; void pki_evp::init() { - class_name = "pki_evp"; ownPass = ptCommon; - dataVersion=2; - pkiType=asym_key; + pkiType = asym_key; } -QString pki_evp::removeTypeFromIntName(QString n) +const char *pki_evp::getClassName() const { - if (n.right(1) != ")" ) - return n; - n.truncate(n.length() - 6); - return n; + return "pki_evp"; } void pki_evp::setOwnPass(enum passType x) @@ -71,7 +66,26 @@ void pki_evp::setOwnPass(enum passType x) ownPass = oldOwnPass; throw(err); } - EVP_PKEY_free(pk_back); + if (!sqlUpdatePrivateKey()) { + EVP_PKEY_free(pk); + key = pk_back; + ownPass = oldOwnPass; + } +} + +bool pki_evp::sqlUpdatePrivateKey() +{ + XSqlQuery q; + SQL_PREPARE(q, "UPDATE private_keys SET private=?, ownPass=? " + "WHERE item=?"); + q.bindValue(0, encKey.toBase64()); + q.bindValue(1, ownPass); + q.bindValue(2, sqlItemId); + q.exec(); + + encKey.fill(0); + encKey.clear(); + return !q.lastError().isValid() && q.numRowsAffected() == 1; } void pki_evp::generate(int bits, int type, QProgressBar *progress, int curve_nid) @@ -141,7 +155,7 @@ void pki_evp::generate(int bits, int type, QProgressBar *progress, int curve_nid #if OPENSSL_VERSION_NUMBER >= 0x10100000L BN_GENCB_free(bar); #endif - + isPub = false; pki_openssl_error(); encryptKey(); } @@ -152,7 +166,7 @@ pki_evp::pki_evp(const pki_evp *pk) init(); pki_openssl_error(); ownPass = pk->ownPass; - encKey = pk->encKey; + isPub = pk->isPub; } pki_evp::pki_evp(const QString name, int type) @@ -163,16 +177,6 @@ pki_evp::pki_evp(const QString name, int type) pki_openssl_error(); } -pki_evp::pki_evp(EVP_PKEY *pkey) - :pki_key() -{ - init(); - if (key) { - EVP_PKEY_free(key); - } - key = pkey; -} - #if OPENSSL_VERSION_NUMBER >= 0x10100000L static bool EVP_PKEY_isPrivKey(EVP_PKEY *key) { @@ -217,6 +221,23 @@ static bool EVP_PKEY_isPrivKey(EVP_PKEY *key) } #endif +pki_evp::pki_evp(EVP_PKEY *pkey) + :pki_key() +{ + init(); + if (key) { + EVP_PKEY_free(key); + } + key = pkey; + isPub = true; + if (EVP_PKEY_isPrivKey(key)) { + isPub = false; + ownPass = ptPrivate; + encryptKey(); + pki_openssl_error(); + } +} + void pki_evp::openssl_pw_error(QString fname) { switch (ERR_peek_error() & 0xff000fff) { @@ -225,7 +246,7 @@ void pki_evp::openssl_pw_error(QString fname) case ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BAD_DECRYPT): pki_ign_openssl_error(); throw errorEx(tr("Failed to decrypt the key (bad password) ")+ - fname, class_name, E_PASSWD); + fname, getClassName(), E_PASSWD); } } @@ -397,15 +418,34 @@ void pki_evp::fromData(const unsigned char *p, db_header_t *head) throw errorEx(tr("Ignoring unsupported private key")); encKey = ba; + isPub = encKey.size() == 0; + if (isPub) + return; + + /* Convert old encryption scheme to the new one */ + EVP_PKEY *pk = decryptKey(1); + EVP_PKEY_free(key); + key = pk; + encryptKey(); + pki_openssl_error(); } -EVP_PKEY *pki_evp::decryptKey() const +static void passToKey(Passwd &pass, unsigned char *iv, + const EVP_CIPHER *cipher, unsigned char *ckey, int old) +{ + /* generate the key */ + EVP_BytesToKey(cipher, old ? EVP_sha1() : EVP_sha256(), iv, + pass.constUchar(), pass.size(), old ? 1 : 8000, ckey, NULL); +} + +EVP_PKEY *pki_evp::decryptKey(int oldkey) const { unsigned char *p; const unsigned char *p1; int outl, decsize; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char ckey[EVP_MAX_KEY_LENGTH]; + QByteArray myencKey; EVP_PKEY *tmpkey; #if OPENSSL_VERSION_NUMBER < 0x10100000L @@ -432,35 +472,36 @@ EVP_PKEY *pki_evp::decryptKey() const pass_info pi(XCA_TITLE, tr("Please enter the password to decrypt the private key: '%1'").arg(getIntName())); ret = PwDialog::execute(&pi, &ownPassBuf, false); if (ret != 1) - throw errorEx(tr("Password input aborted"), class_name); + throw errorEx(tr("Password input aborted"), + getClassName()); } else if (ownPass == ptBogus) { // BOGUS pass ownPassBuf = "Bogus"; } else { ownPassBuf = passwd; - while (md5passwd(ownPassBuf) != passHash && + while (sha512passwT(ownPassBuf, passHash) != passHash && sha512passwd(ownPassBuf, passHash) != passHash) { pass_info p(XCA_TITLE, tr("Please enter the database password for decrypting the key '%1'").arg(getIntName())); ret = PwDialog::execute(&p, &ownPassBuf, false); if (ret != 1) - throw errorEx(tr("Password input aborted"), class_name); + throw errorEx(tr("Password input aborted"), + getClassName()); } } - p = (unsigned char *)OPENSSL_malloc(encKey.count()); + if (encKey.count() == 0) + myencKey = getEncKey(); + else + myencKey = encKey; + if (myencKey.count() == 0) + return NULL; + p = (unsigned char *)OPENSSL_malloc(myencKey.count()); check_oom(p); pki_openssl_error(); p1 = p; memset(iv, 0, EVP_MAX_IV_LENGTH); - memcpy(iv, encKey.constData(), 8); /* recover the iv */ - /* generate the key */ - EVP_BytesToKey(cipher, EVP_sha1(), iv, - ownPassBuf.constUchar(), - ownPassBuf.size(), 1, ckey, NULL); - /* we use sha1 as message digest, - * because an md5 version of the password is - * stored in the database... - */ + memcpy(iv, myencKey.constData(), 8); /* recover the iv */ + passToKey(ownPassBuf, iv, cipher, ckey, oldkey); #if OPENSSL_VERSION_NUMBER >= 0x10100000L ctx = EVP_CIPHER_CTX_new(); #else @@ -469,15 +510,16 @@ EVP_PKEY *pki_evp::decryptKey() const EVP_CIPHER_CTX_init(ctx); EVP_DecryptInit(ctx, cipher, ckey, iv); EVP_DecryptUpdate(ctx, p , &outl, - (const unsigned char*)encKey.constData() +8, encKey.count() -8); - + (const unsigned char*)myencKey.constData() +8, + myencKey.count() -8); decsize = outl; EVP_DecryptFinal(ctx, p + decsize , &outl); decsize += outl; - //printf("Decrypt decsize=%d, encKey_len=%d\n", decsize, encKey.count() -8); + //printf("Decrypt decsize=%d, encKey_len=%d\n", decsize, myencKey.count() -8); pki_openssl_error(); tmpkey = d2i_PrivateKey(getKeyType(), NULL, &p1, decsize); pki_openssl_error(); + OPENSSL_cleanse(p, myencKey.count()); OPENSSL_free(p); EVP_CIPHER_CTX_cleanup(ctx); #if OPENSSL_VERSION_NUMBER >= 0x10100000L @@ -488,20 +530,10 @@ EVP_PKEY *pki_evp::decryptKey() const RSA *rsa = EVP_PKEY_get0_RSA(tmpkey); RSA_blinding_on(rsa, NULL); } + myencKey.fill(0); return tmpkey; } -QByteArray pki_evp::toData() -{ - QByteArray ba; - - ba += db::intToData(getKeyType()); - ba += db::intToData(ownPass); - ba += i2d(); - ba += encKey; - return ba; -} - EVP_PKEY *pki_evp::priv2pub(EVP_PKEY* key) { int keylen; @@ -542,7 +574,7 @@ void pki_evp::encryptKey(const char *password) arg(getIntName())); ret = PwDialog::execute(&p, &ownPassBuf, true); if (ret != 1) - throw errorEx("Password input aborted", class_name); + throw errorEx("Password input aborted", getClassName()); } else if (ownPass == ptBogus) { // BOGUS password ownPassBuf = "Bogus"; } else { @@ -554,12 +586,13 @@ void pki_evp::encryptKey(const char *password) int ret = 0; ownPassBuf = passwd; pass_info p(XCA_TITLE, tr("Please enter the database password for encrypting the key")); - while (md5passwd(ownPassBuf) != passHash && - sha512passwd(ownPassBuf, passHash) != passHash ) + while (sha512passwT(ownPassBuf, passHash) != passHash && + sha512passwd(ownPassBuf, passHash) != passHash) { ret = PwDialog::execute(&p, &ownPassBuf, false); if (ret != 1) - throw errorEx("Password input aborted", class_name); + throw errorEx("Password input aborted", + getClassName()); } } } @@ -567,9 +600,7 @@ void pki_evp::encryptKey(const char *password) /* Prepare Encryption */ memset(iv, 0, EVP_MAX_IV_LENGTH); Entropy::get(iv, 8); /* Generate a salt */ - EVP_BytesToKey(cipher, EVP_sha1(), iv, - ownPassBuf.constUchar(), - ownPassBuf.size(), 1, ckey, NULL); + passToKey(ownPassBuf, iv, cipher, ckey, 0); #if OPENSSL_VERSION_NUMBER >= 0x10100000L ctx = EVP_CIPHER_CTX_new(); #else @@ -578,9 +609,10 @@ void pki_evp::encryptKey(const char *password) EVP_CIPHER_CTX_init (ctx); pki_openssl_error(); - /* reserve space for unencrypted and encrypted key */ + /* reserve space for encrypted key */ keylen = i2d_PrivateKey(key, NULL); encKey.resize(keylen + EVP_MAX_KEY_LENGTH + 8); + /* allocate space for unencrypted key */ punenc1 = punenc = (unsigned char *)OPENSSL_malloc(keylen); check_oom(punenc); keylen = i2d_PrivateKey(key, &punenc1); @@ -606,7 +638,7 @@ void pki_evp::encryptKey(const char *password) EVP_CIPHER_CTX_free(ctx); #endif /* wipe out the memory */ - memset(punenc, 0, keylen); + OPENSSL_cleanse(punenc, keylen); OPENSSL_free(punenc); pki_openssl_error(); @@ -616,9 +648,6 @@ void pki_evp::encryptKey(const char *password) key = pkey1; pki_openssl_error(); - //CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF); - - //printf("Encrypt: encKey_len=%d\n", encKey_len); return; } @@ -632,13 +661,83 @@ void pki_evp::set_evp_key(EVP_PKEY *pkey) void pki_evp::bogusEncryptKey() { ownPass = ptBogus; + isPub = false; encryptKey(); } pki_evp::~pki_evp() { + encKey.fill(0); } +QSqlError pki_evp::insertSqlData() +{ + XSqlQuery q; + QSqlError e = pki_key::insertSqlData(); + if (e.isValid()) + return e; + if (isPubKey()) + return QSqlError(); + + SQL_PREPARE(q, "INSERT INTO private_keys (item, ownPass, private) " + "VALUES (?, ?, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, ownPass); + q.bindValue(2, encKey.toBase64()); + q.exec(); + encKey.fill(0); + encKey.clear(); + return q.lastError(); +} + +QSqlError pki_evp::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + e = pki_key::restoreSql(sqlId); + if (e.isValid()) + return e; + SQL_PREPARE(q, "SELECT ownPass FROM private_keys WHERE item=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (!q.first()) + return QSqlError(); + /* This is a private key */ + ownPass = q.value(0).toInt(); + isPub = false; + return e; +} + +QByteArray pki_evp::getEncKey() const +{ + XSqlQuery q; + QSqlError e; + QByteArray ba; + + SQL_PREPARE(q, "SELECT private FROM private_keys WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + e = q.lastError(); + if (e.isValid() || !q.first()) + return QByteArray(); + return QByteArray::fromBase64(q.value(0).toByteArray()); +} + +QSqlError pki_evp::deleteSqlData() +{ + XSqlQuery q; + QSqlError e = pki_key::deleteSqlData(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "DELETE FROM private_keys WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); +} void pki_evp::writePKCS8(const QString fname, const EVP_CIPHER *enc, pem_password_cb *cb, bool pem) @@ -729,14 +828,6 @@ void pki_evp::writeKey(const QString fname, const EVP_CIPHER *enc, pki_openssl_error(); } -bool pki_evp::isPubKey() const -{ - if (encKey.count() == 0) { - return true; - } - return false; -} - int pki_evp::verify() { bool veri = false; @@ -812,7 +903,8 @@ QString pki_evp::md5passwd(QByteArray pass) return str; } -QString pki_evp::sha512passwd(QByteArray pass, QString salt) +QString pki_evp::_sha512passwd(QByteArray pass, QString salt, + int size, int repeat) { #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_MD_CTX mdctxbuf; @@ -823,10 +915,10 @@ QString pki_evp::sha512passwd(QByteArray pass, QString salt) int j; unsigned char m[EVP_MAX_MD_SIZE]; - if (salt.length() <5) + if (salt.length() < size) { abort(); - - str = salt.left(5); + } + str = salt.left(size); pass = str.toLatin1() + pass; #if OPENSSL_VERSION_NUMBER >= 0x10100000L @@ -834,15 +926,16 @@ QString pki_evp::sha512passwd(QByteArray pass, QString salt) #else mdctx = &mdctxbuf; #endif + while (repeat--) { + EVP_DigestInit(mdctx, EVP_sha512()); + EVP_DigestUpdate(mdctx, pass.constData(), pass.size()); + EVP_DigestFinal(mdctx, m, (unsigned*)&n); + pass = QByteArray((char*)m, n); - EVP_DigestInit(mdctx, EVP_sha512()); - EVP_DigestUpdate(mdctx, pass.constData(), pass.size()); - EVP_DigestFinal(mdctx, m, (unsigned*)&n); - + } #if OPENSSL_VERSION_NUMBER >= 0x10100000L EVP_MD_CTX_free(mdctx); #endif - for (j=0; j= 0x10100000L - ctx = EVP_CIPHER_CTX_new(); -#else - ctx = &ctxbuf; -#endif - - EVP_CIPHER_CTX_init(ctx); - EVP_DecryptInit(ctx, cipher, ckey, iv); - EVP_DecryptUpdate(ctx, pdec , &outl, p + 8, size - 8); - decsize = outl; - EVP_DecryptFinal(ctx, pdec + decsize, &outl); - decsize += outl; - pki_openssl_error(); - memcpy(sik, pdec, decsize); - if (getKeyType() == EVP_PKEY_RSA) { - rsakey=d2i_RSAPrivateKey(NULL,(const unsigned char **)&pdec, decsize); - if (pki_ign_openssl_error()) { - rsakey = d2i_RSA_PUBKEY(NULL, (const unsigned char **)&sik, decsize); - } - pki_openssl_error(); - if (rsakey) EVP_PKEY_assign_RSA(key, rsakey); - } - OPENSSL_free(sik1); - OPENSSL_free(pdec1); - EVP_CIPHER_CTX_cleanup(ctx); -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - EVP_CIPHER_CTX_free(ctx); -#endif - pki_openssl_error(); - encryptKey(); + return _sha512passwd(pass, salt, 5, 1); } -void pki_evp::oldFromData(unsigned char *p, int size ) +QString pki_evp::sha512passwT(QByteArray pass, QString salt) { - int version, type; - - QByteArray ba; - - version = intFromData(ba); - if (version != 1) { // backward compatibility - veryOldFromData(p, size); - return; - } - if (key) - EVP_PKEY_free(key); - - key = NULL; - type = intFromData(ba); - ownPass = intFromData(ba); - - d2i_old(ba, type); - pki_openssl_error(); - - encKey = ba; + return _sha512passwd(pass, salt, 17, 8000); } - diff --git a/lib/pki_evp.h b/lib/pki_evp.h index 8c373d3e..f73e9a7d 100644 --- a/lib/pki_evp.h +++ b/lib/pki_evp.h @@ -20,10 +20,12 @@ class pki_evp: public pki_key { Q_OBJECT - protected: QByteArray encKey; void init(); - void veryOldFromData(unsigned char *p, int size); + QByteArray getEncKey() const; + static QString _sha512passwd(QByteArray pass, QString salt, + int size, int repeat); + protected: void openssl_pw_error(QString fname); public: static QPixmap *icon[2]; @@ -32,16 +34,18 @@ class pki_evp: public pki_key static Passwd oldpasswd; static QString md5passwd(QByteArray pass); static QString sha512passwd(QByteArray pass, QString salt); + static QString sha512passwT(QByteArray pass, QString salt); void generate(int bits, int type, QProgressBar *progress); void generate(int bits, int type, QProgressBar *progress, int curve_nid); void setOwnPass(enum passType); + const char *getClassName() const; pki_evp(const QString name = "", int type = EVP_PKEY_RSA); pki_evp(EVP_PKEY *pkey); void set_evp_key(EVP_PKEY *pkey); void encryptKey(const char *password = NULL); void bogusEncryptKey(); - EVP_PKEY *decryptKey() const; + EVP_PKEY *decryptKey(int oldkey=0) const; pki_evp(const pki_evp *pk); /* destructor */ virtual ~pki_evp(); @@ -52,16 +56,17 @@ class pki_evp: public pki_key void fload(const QString fname); void writeDefault(const QString fname); void fromData(const unsigned char *p, db_header_t *head); - void oldFromData(unsigned char *p, int size); - QByteArray toData(); void writeKey(const QString fname, const EVP_CIPHER *enc, pem_password_cb *cb, bool pem); void writePKCS8(const QString fname, const EVP_CIPHER *enc, pem_password_cb *cb, bool pem); - bool isPubKey() const; int verify(); const EVP_MD *getDefaultMD(); QVariant getIcon(dbheader *hd); + bool sqlUpdatePrivateKey(); + QSqlError insertSqlData(); + QSqlError deleteSqlData(); + QSqlError restoreSql(QVariant sqlId); }; #endif diff --git a/lib/pki_key.cpp b/lib/pki_key.cpp index b3229cdd..9715aca3 100644 --- a/lib/pki_key.cpp +++ b/lib/pki_key.cpp @@ -24,19 +24,25 @@ pki_key::pki_key(const QString name) :pki_base(name) { key = EVP_PKEY_new(); - ucount = 0; - class_name = "pki_key"; + key_size = 0; + isPub = true; +} + +const char *pki_key::getClassName() const +{ + return "pki_key"; } pki_key::pki_key(const pki_key *pk) :pki_base(pk->desc) { - ucount = pk->ucount; - key = EVP_PKEY_new(); if (pk->key) { QByteArray ba = i2d_bytearray(I2D_VOID(i2d_PUBKEY), pk->key); d2i(ba); + } else { + key = EVP_PKEY_new(); } + key_size = pk->key_size; } pki_key::~pki_key() @@ -45,6 +51,19 @@ pki_key::~pki_key() EVP_PKEY_free(key); } +EVP_PKEY *pki_key::decryptKey(int oldkey) const +{ + (void)oldkey; + qDebug("VIRTUAL pki_key::decryptKey() should NEVER be called"); + return NULL; +} + +const EVP_MD *pki_key::getDefaultMD() +{ + qDebug("VIRTUAL pki_key::getDefaultMD() should NEVER be called"); + return NULL; +} + void pki_key::d2i(QByteArray &ba) { EVP_PKEY *k = (EVP_PKEY*)d2i_bytearray(D2I_VOID(d2i_PUBKEY), ba); @@ -127,7 +146,7 @@ BIO *pki_key::pem(BIO *b, int format) return b; } -QString pki_key::length() +QString pki_key::length() const { bool dsa_unset = false; @@ -197,24 +216,13 @@ QString pki_key::getMsg(msg_type msg) return pki_base::getMsg(msg); } -QString pki_key::getIntNameWithType() +QString pki_key::comboText() const { return QString("%1 (%2:%3%4)").arg(getIntName()).arg(getTypeString()). arg(length()).arg(isPubKey() ? QString(" ") + tr("Public key") : QString("")); } -QString pki_key::removeTypeFromIntName(QString n) -{ - int i; - if (n.right(1) != ")" ) - return n; - i = n.lastIndexOf(" ("); - if (i > 0) - n.truncate(i); - return n; -} - bool pki_key::isToken() { return false; @@ -225,20 +233,19 @@ bool pki_key::isPrivKey() const return !isPubKey(); } -int pki_key::incUcount() -{ - ucount++; - return ucount; -} -int pki_key::decUcount() -{ - ucount--; - return ucount; -} - int pki_key::getUcount() { - return ucount; + XSqlQuery q; + int size = -1; + SQL_PREPARE(q, "SELECT COUNT(*) FROM x509super WHERE key=?"); + q.bindValue(0, sqlItemId); + q.exec(); + if (q.first()) + size = q.value(0).toInt(); + else + qDebug("Failed to get key count for %s", CCHAR(getIntName())); + MainWindow::dbSqlError(q.lastError()); + return size; } int pki_key::getKeyType() const @@ -395,8 +402,7 @@ QString pki_key::BN2QString(const BIGNUM *bn) const return "--"; QString x=""; char zs[10]; - int j; - int size = BN_num_bytes(bn); + int j, size = BN_num_bytes(bn); unsigned char *buf = (unsigned char *)OPENSSL_malloc(size); check_oom(buf); BN_bn2bin(bn, buf); @@ -438,6 +444,92 @@ QVariant pki_key::column_data(dbheader *hd) return pki_base::column_data(hd); } +QSqlError pki_key::insertSqlData() +{ + unsigned myhash = hash(); + XSqlQuery q; + QList list; + + SQL_PREPARE(q, "SELECT item FROM x509super WHERE key_hash=? AND key IS NULL"); + q.bindValue(0, myhash); + q.exec(); + if (q.lastError().isValid()) + return q.lastError(); + while (q.next()) { + pki_x509super *x = static_cast( + db_base::lookupPki(q.value(0).toULongLong())); + if (!x) { + qDebug("X509 Super class with id %d not found", + q.value(0).toInt()); + continue; + } + if (x->compareRefKey(this)) { + x->setRefKey(this); + list << x; + } + } + q.finish(); + + SQL_PREPARE(q, "UPDATE x509super SET key=? WHERE item=?"); + q.bindValue(0, sqlItemId); + foreach(pki_x509super* x, list) { + q.bindValue(1, x->getSqlItemId()); + q.exec(); + if (q.lastError().isValid()) + return q.lastError(); + } + q.finish(); + + SQL_PREPARE(q, "INSERT INTO public_keys (item, type, hash, len, public) " + "VALUES (?, ?, ?, ?, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, getTypeString()); + q.bindValue(2, myhash); + q.bindValue(3, EVP_PKEY_bits(key)); + q.bindValue(4, i2d().toBase64()); + q.exec(); + return q.lastError(); +} + +QSqlError pki_key::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + e = pki_base::restoreSql(sqlId); + if (e.isValid()) + return e; + SQL_PREPARE(q, "SELECT public, len FROM public_keys WHERE item=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (!q.first()) + return sqlItemNotFound(sqlId); + QByteArray ba = QByteArray::fromBase64(q.value(0).toByteArray()); + d2i(ba); + key_size = q.value(1).toInt(); + return e; +} + +QSqlError pki_key::deleteSqlData() +{ + XSqlQuery q; + QSqlError e; + + SQL_PREPARE(q, "DELETE FROM public_keys WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "UPDATE x509super SET key=NULL WHERE key=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); +} + BIGNUM *pki_key::ssh_key_data2bn(QByteArray *ba, bool skip) { const unsigned char *d = (const unsigned char *)ba->constData(); diff --git a/lib/pki_key.h b/lib/pki_key.h index 11954ec6..6c614d88 100644 --- a/lib/pki_key.h +++ b/lib/pki_key.h @@ -22,7 +22,8 @@ class pki_key: public pki_base { Q_OBJECT protected: - int ownPass; + int ownPass, key_size; + bool isPub; EVP_PKEY *key; QString BN2QString(const BIGNUM *bn) const; QString BNoneLine(BIGNUM *bn) const; @@ -37,39 +38,22 @@ class pki_key: public pki_base pki_key(const QString name = ""); pki_key(const pki_key *pk); virtual ~pki_key(); + const char *getClassName() const; static builtin_curves builtinCurves; enum passType { ptCommon, ptPrivate, ptBogus, ptPin }; - - virtual EVP_PKEY *decryptKey() const - { - return NULL; - } - virtual QString length() const - { - return QString(); - } - virtual bool isPubKey() const - { - return true; - } - virtual const EVP_MD *getDefaultMD() - { - return NULL; - } + QString length() const; + QString comboText() const; + virtual EVP_PKEY *decryptKey(int oldkey=0) const; + virtual const EVP_MD *getDefaultMD(); virtual bool isToken(); virtual QString getTypeString(void) const; - virtual QString getIntNameWithType(void); virtual QList possibleHashNids(); virtual QString getMsg(msg_type msg); - virtual QString length(); void writePublic(const QString fname, bool pem); bool compare(pki_base *ref); int getKeyType() const; - static QString removeTypeFromIntName(QString n); bool isPrivKey() const; - int incUcount(); - int decUcount(); int getUcount(); int getOwnPass(void) { @@ -79,6 +63,10 @@ class pki_key: public pki_base { return key; } + bool isPubKey() const + { + return isPub; + } BIO *pem(BIO *, int); QVariant column_data(dbheader *hd); QString modulus(); @@ -92,6 +80,9 @@ class pki_key: public pki_base QByteArray i2d(); EVP_PKEY *load_ssh2_key(FILE *fp); void writeSSH2public(QString fname); + QSqlError insertSqlData(); + QSqlError deleteSqlData(); + QSqlError restoreSql(QVariant sqlId); }; #endif diff --git a/lib/pki_multi.cpp b/lib/pki_multi.cpp index b92a9420..b51bc36e 100644 --- a/lib/pki_multi.cpp +++ b/lib/pki_multi.cpp @@ -24,7 +24,6 @@ pki_multi::pki_multi(const QString name) :pki_base(name) { multi.clear(); - class_name="pki_multi"; } pki_multi::~pki_multi() @@ -34,6 +33,11 @@ pki_multi::~pki_multi() delete pki; } +const char *pki_multi::getClassName() const +{ + return "pki_multi"; +} + pki_base *pki_multi::pull() { if (multi.isEmpty()) diff --git a/lib/pki_multi.h b/lib/pki_multi.h index c0aa4170..41cfb9a7 100644 --- a/lib/pki_multi.h +++ b/lib/pki_multi.h @@ -31,6 +31,7 @@ class pki_multi: public pki_base { return multi.count(); } + const char *getClassName() const; }; diff --git a/lib/pki_pkcs12.cpp b/lib/pki_pkcs12.cpp index cf9594a0..5278215e 100644 --- a/lib/pki_pkcs12.cpp +++ b/lib/pki_pkcs12.cpp @@ -19,13 +19,17 @@ pki_pkcs12::pki_pkcs12(const QString d, pki_x509 *acert, pki_evp *akey) :pki_base(d) { - class_name="pki_pkcs12"; key = new pki_evp(akey); cert = new pki_x509(acert); certstack = sk_X509_new_null(); openssl_error(); } +const char *pki_pkcs12::getClassName() const +{ + return "pki_pkcs12"; +} + pki_pkcs12::pki_pkcs12(const QString fname) :pki_base(fname) { @@ -34,7 +38,6 @@ pki_pkcs12::pki_pkcs12(const QString fname) EVP_PKEY *mykey = NULL; X509 *mycert = NULL; key=NULL; cert=NULL; - class_name="pki_pkcs12"; certstack = sk_X509_new_null(); pass_info p(XCA_TITLE, tr("Please enter the password to decrypt the PKCS#12 file:\n%1").arg(compressFilename(fname))); fp = fopen_read(fname); diff --git a/lib/pki_pkcs12.h b/lib/pki_pkcs12.h index 1aa6a829..627478bc 100644 --- a/lib/pki_pkcs12.h +++ b/lib/pki_pkcs12.h @@ -34,6 +34,7 @@ class pki_pkcs12: public pki_base pki_pkcs12(const QString fname); ~pki_pkcs12(); + const char *getClassName() const; void addCaCert(pki_x509 *acert); pki_key *getKey(); pki_x509 *getCert(); diff --git a/lib/pki_pkcs7.cpp b/lib/pki_pkcs7.cpp index 5470a999..4b4dec12 100644 --- a/lib/pki_pkcs7.cpp +++ b/lib/pki_pkcs7.cpp @@ -17,9 +17,12 @@ pki_pkcs7::pki_pkcs7(const QString name) p7 = PKCS7_new(); PKCS7_set_type(p7, NID_pkcs7_signed); PKCS7_content_new(p7, NID_pkcs7_data); - class_name = "pki_pkcs7"; } +const char *pki_pkcs7::getClassName() const +{ + return "pki_pkcs7"; +} pki_pkcs7::~pki_pkcs7() { @@ -56,7 +59,8 @@ void pki_pkcs7::signBio(pki_x509 *crt, BIO *bio) STACK_OF(X509) *certstack; if (!crt) return; privkey = crt->getRefKey(); - if (!privkey) throw errorEx("No private key for signing found", class_name); + if (!privkey) throw errorEx("No private key for signing found", + getClassName()); certstack = sk_X509_new_null(); pki_x509 *signer = crt->getSigner(); diff --git a/lib/pki_pkcs7.h b/lib/pki_pkcs7.h index aa09a05e..6c78a13a 100644 --- a/lib/pki_pkcs7.h +++ b/lib/pki_pkcs7.h @@ -21,8 +21,8 @@ class pki_pkcs7: public pki_base void encryptBio(pki_x509 *crt, BIO * bio); public: pki_pkcs7(const QString name = ""); - /* destructor */ virtual ~pki_pkcs7(); + const char *getClassName() const; void signFile(pki_x509 *crt, QString filename); void signCert(pki_x509 *crt, pki_x509 *contCert); diff --git a/lib/pki_scard.cpp b/lib/pki_scard.cpp index 85c8e001..cc1614c7 100644 --- a/lib/pki_scard.cpp +++ b/lib/pki_scard.cpp @@ -34,15 +34,18 @@ bool pki_scard::only_token_hashes = false; void pki_scard::init(void) { - class_name = "pki_scard"; ownPass = ptPin; - dataVersion = 2; pkiType = smartCard; card_serial = card_manufacturer = card_label = ""; card_model = slot_label = ""; } +const char *pki_scard::getClassName() const +{ + return "pki_scard"; +} + pki_scard::pki_scard(const QString name) :pki_key(name) { @@ -67,6 +70,56 @@ QString pki_scard::getMsg(msg_type msg) return pki_base::getMsg(msg); } +QSqlError pki_scard::insertSqlData() +{ + XSqlQuery q; + QSqlError e = pki_key::insertSqlData(); + if (e.isValid()) + return e; + + SQL_PREPARE(q, "INSERT INTO tokens (item, card_manufacturer, card_serial, " + "card_model, card_label, slot_label, " + "object_id) " + "VALUES (?, ?, ?, ?, ?, ?, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, card_manufacturer); + q.bindValue(2, card_serial); + q.bindValue(3, card_model); + q.bindValue(4, card_label); + q.bindValue(5, slot_label); + q.bindValue(6, object_id); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "INSERT INTO token_mechanism (item, mechanism) " + "VALUES (?, ?)"); + q.bindValue(0, sqlItemId); + foreach(CK_MECHANISM_TYPE m, mech_list) { + q.bindValue(1, QVariant((uint)m)); + q.exec(); + } + return q.lastError(); +} + +QSqlError pki_scard::deleteSqlData() +{ + XSqlQuery q; + QSqlError e = pki_key::deleteSqlData(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "DELETE FROM tokens WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "DELETE FROM token_mechanism WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); +} + EVP_PKEY *pki_scard::load_pubkey(pkcs11 &p11, CK_OBJECT_HANDLE object) const { unsigned long keytype; @@ -690,24 +743,6 @@ pki_scard::~pki_scard() { } -QByteArray pki_scard::toData() -{ - QByteArray ba; - - ba += db::stringToData(card_serial); - ba += db::stringToData(card_manufacturer); - ba += db::stringToData(card_label); - ba += db::stringToData(slot_label); - ba += db::stringToData(card_model); - ba += db::stringToData(object_id); - ba += db::intToData(mech_list.count()); - for (int i=0; i +#include +#include -QPixmap *pki_temp::icon= NULL; +#define TEMPLATE_DS_VERSION (QDataStream::Qt_4_2) + +QList pki_temp::tmpl_keys = QList() + << "subAltName" + << "issAltName" + << "crlDist" + << "authInfAcc" + << "nsCertType" + << "nsComment" + << "nsBaseUrl" + << "nsRevocationUrl" + << "nsCARevocationUrl" + << "nsRenewalUrl" + << "nsCaPolicyUrl" + << "nsSslServerName" + << "ca" + << "bcCritical" + << "ekuCritical" + << "kuCritical" + << "subKey" + << "authKey" + << "basicPath" + << "validN" + << "validM" + << "validMidn" + << "keyUse" + << "eKeyUse" + << "adv_ext" + << "noWellDefinedExpDate"; + +QPixmap *pki_temp::icon = NULL; pki_temp::pki_temp(const pki_temp *pk) :pki_x509name(pk->desc) { - class_name = pk->class_name; - dataVersion=pk->dataVersion; - pkiType=pk->pkiType; + pkiType = pk->pkiType; - xname=pk->xname; - subAltName=pk->subAltName; - issAltName=pk->issAltName; - crlDist=pk->crlDist; - authInfAcc=pk->authInfAcc; - certPol=pk->certPol; - nsCertType=pk->nsCertType; - nsComment=pk->nsComment; - nsBaseUrl=pk->nsBaseUrl; - nsRevocationUrl=pk->nsRevocationUrl; - nsCARevocationUrl=pk->nsCARevocationUrl; - nsRenewalUrl=pk->nsRenewalUrl; - nsCaPolicyUrl=pk->nsCaPolicyUrl; - nsSslServerName=pk->nsSslServerName; - ca=pk->ca; - bcCrit=pk->bcCrit; - keyUseCrit=pk->keyUseCrit; - eKeyUseCrit=pk->eKeyUseCrit; - subKey=pk->subKey; - authKey=pk->authKey; - pathLen=pk->pathLen; - validN=pk->validN; - validM=pk->validM; - validMidn=pk->validMidn; - keyUse=pk->keyUse; - eKeyUse=pk->eKeyUse; - adv_ext=pk->adv_ext; - noWellDefined=pk->noWellDefined; + xname = pk->xname; + settings = pk->settings; } pki_temp::pki_temp(const QString d) :pki_x509name(d) { - class_name = "pki_temp"; - dataVersion=6; pkiType=tmpl; - subAltName=""; - issAltName=""; - crlDist=""; - authInfAcc=""; - certPol=""; - nsCertType=0; - nsComment="xca certificate"; - nsBaseUrl=""; - nsRevocationUrl=""; - nsCARevocationUrl=""; - nsRenewalUrl=""; - nsCaPolicyUrl=""; - nsSslServerName=""; - ca=0; - bcCrit=false; - keyUseCrit=false; - eKeyUseCrit=false; - subKey=false; - authKey=false; - validMidn=false; - pathLen=""; - validN=365; - validM=0; - keyUse=0; - eKeyUse=""; - adv_ext=""; - noWellDefined=false; + foreach(QString key, tmpl_keys) { + settings[key] = QString(); + } + settings["nsComment"] = "xca certificate"; + settings["validN"] = "365"; +} + +const char *pki_temp::getClassName() const +{ + return "pki_temp"; +} + +QString pki_temp::comboText() const +{ + return pre_defined ? QString("[default] ") + pki_base::comboText() : + pki_base::comboText(); +} + +QSqlError pki_temp::insertSqlData() +{ + XSqlQuery q; + QSqlError e = pki_x509name::insertSqlData(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "INSERT INTO templates (item, version, template) " + "VALUES (?, ?, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, TMPL_VERSION); + q.bindValue(2, toData().toBase64()); + q.exec(); + return q.lastError(); +} + +QSqlError pki_temp::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + e = pki_x509name::restoreSql(sqlId); + if (e.isValid()) + return e; + SQL_PREPARE(q, "SELECT version, template FROM templates WHERE item=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (!q.first()) + return sqlItemNotFound(sqlId); + int version = q.value(0).toInt(); + QByteArray ba = QByteArray::fromBase64(q.value(1).toByteArray()); + fromData(ba, version); + return e; +} + +QSqlError pki_temp::deleteSqlData() +{ + XSqlQuery q; + QSqlError e = pki_x509name::deleteSqlData(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "DELETE FROM templates WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); } QString pki_temp::getMsg(msg_type msg) @@ -129,12 +169,20 @@ static int bitsToInt(extList &el, int nid, bool *crit) return ret; } +void pki_temp::fromExtList(extList *el, int nid, const char *item) +{ + QString target; + el->genConf(nid, &target, &adv_ext); + settings[item] = target; +} + extList pki_temp::fromCert(pki_x509super *cert_or_req) { x509name n; extList el = cert_or_req->getV3ext(); + adv_ext.clear(); - nsComment = ""; + settings["nsComment"] = ""; n = cert_or_req->getSubject(); foreach(QString sn, MainWindow::explicit_dn) { @@ -149,50 +197,51 @@ extList pki_temp::fromCert(pki_x509super *cert_or_req) xname.addEntryByNid(nid, n.getEntry(i)); } - el.genConf(NID_subject_alt_name, &subAltName, &adv_ext); - el.genConf(NID_issuer_alt_name, &issAltName, &adv_ext); - el.genConf(NID_crl_distribution_points, &crlDist, &adv_ext); - el.genConf(NID_info_access, &authInfAcc, &adv_ext); - - el.genConf(NID_netscape_comment, &nsComment); - el.genConf(NID_netscape_base_url, &nsBaseUrl); - el.genConf(NID_netscape_revocation_url, &nsRevocationUrl); - el.genConf(NID_netscape_ca_revocation_url, &nsCARevocationUrl); - el.genConf(NID_netscape_renewal_url, &nsRenewalUrl); - el.genConf(NID_netscape_ca_policy_url, &nsCaPolicyUrl); - el.genConf(NID_netscape_ssl_server_name, &nsSslServerName); + fromExtList(&el, NID_subject_alt_name, "subAltName"); + fromExtList(&el, NID_issuer_alt_name, "issAltName"); + fromExtList(&el, NID_crl_distribution_points, "crlDist"); + fromExtList(&el, NID_info_access, "authInfAcc"); + fromExtList(&el, NID_netscape_comment, "nsComment"); + fromExtList(&el, NID_netscape_base_url, "nsBaseUrl"); + fromExtList(&el, NID_netscape_revocation_url, "nsRevocationUrl"); + fromExtList(&el, NID_netscape_ca_revocation_url, "nsCARevocationUrl"); + fromExtList(&el, NID_netscape_renewal_url, "nsRenewalUrl"); + fromExtList(&el, NID_netscape_ca_policy_url, "nsCaPolicyUrl"); + fromExtList(&el, NID_netscape_ssl_server_name, "nsSslServerName"); QString r; if (el.genConf(NID_basic_constraints, &r)) { QStringList sl = r.split(","); if (sl.contains("critical")) - bcCrit = true; - ca = sl.contains("CA:TRUE") ? 1 : 2; - pathLen = sl.filter("pathlen:").join("").mid(8, -1); + settings["bcCritical"] = "1"; + settings["ca"] = sl.contains("CA:TRUE") ? 1 : 2; + settings["basicPath"]=sl.filter("pathlen:").join("") .mid(8,-1); } else { - bcCrit = false; - ca = 0; + settings["bcCritical"] = ""; + settings["ca"] = ""; + settings["basicPath"] = ""; } - authKey = el.delByNid(NID_authority_key_identifier); - subKey = el.delByNid(NID_subject_key_identifier); + settings["authKey"] = el.delByNid(NID_authority_key_identifier); + settings["subKey"] = el.delByNid(NID_subject_key_identifier); - nsCertType = bitsToInt(el, NID_netscape_cert_type, NULL); + int nsCT = bitsToInt(el, NID_netscape_cert_type, NULL); /* bit 4 is unused. Move higher bits down. */ - nsCertType = (nsCertType & 0xf) | ((nsCertType & 0xf0) >> 1); + settings["nsCertType"] = (nsCT & 0xf) | ((nsCT & 0xf0) >> 1); - keyUse = bitsToInt(el, NID_key_usage, &keyUseCrit); + bool keyUseCritical; + settings["keyUse"] = QString::number( + bitsToInt(el, NID_key_usage, &keyUseCritical)); + + settings["keyUseCritical"] = keyUseCritical ? "1" : "0"; + fromExtList(&el, NID_ext_key_usage, "eKeyUse"); - el.genConf(NID_ext_key_usage, &eKeyUse); - if (eKeyUse.startsWith("critical,")) { - eKeyUseCrit = true; - eKeyUse = eKeyUse.mid(9, -1); - } el.genGenericConf(&adv_ext); + settings["adv_ext"] = adv_ext; if (cert_or_req->getType() == x509) { pki_x509 *cert = (pki_x509*)cert_or_req; if (cert->getNotAfter().isUndefined()) { - noWellDefined = true; + settings["noWellDefinedExpDate"] = "1"; } else { a1time notBefore = cert->getNotBefore(); a1time notAfter = cert->getNotAfter(); @@ -200,20 +249,20 @@ extList pki_temp::fromCert(pki_x509super *cert_or_req) if (notBefore.toPlain().endsWith("000000Z") && notAfter.toPlain().endsWith("235959Z")) { - validMidn = true; + settings["validMidn"] = "1"; } int diff = notBefore.daysTo(notAfter); - validM = 0; + settings["validM"] = "0"; if (diff > 60) { - validM = 1; + settings["validM"] = "1"; diff /= 30; if (diff > 24) { - validM = 2; + settings["validM"] = "2"; diff /= 12; } } - validN = diff; + settings["validN"] = QString::number(diff); } } return el; @@ -241,52 +290,53 @@ static QString old_eKeyUse2QString(int old) return sl.join(", "); } -void pki_temp::fromData(const unsigned char *p, int size, int version) +void pki_temp::old_fromData(const unsigned char *p, int size, int version) { QByteArray ba((const char*)p, size); - destination = db::stringFromData(ba); - bcCrit = db::boolFromData(ba); - keyUseCrit = db::boolFromData(ba); - eKeyUseCrit = db::boolFromData(ba); - subKey = db::boolFromData(ba); - authKey = db::boolFromData(ba); - ca = db::intFromData(ba); + /* destination = */ db::stringFromData(ba); + settings["bcCritical"] = QString::number(db::boolFromData(ba)); + settings["keyUseCritical"] = QString::number(db::boolFromData(ba)); + settings["eKyUseCritical"] = QString::number(db::boolFromData(ba)); + settings["subKey"] = QString::number(db::boolFromData(ba)); + settings["authKey"] = QString::number(db::boolFromData(ba)); + settings["ca"] = QString::number(db::intFromData(ba)); if (version > 5) { - pathLen = db::stringFromData(ba); + settings["basicPath"] = db::stringFromData(ba); } else { - pathLen = QString::number(db::intFromData(ba)); - if (pathLen == "0") - pathLen = ""; + settings["basicPath"] = QString::number(db::intFromData(ba)); + if (settings["basicPath"] == "0") + settings["basicPath"] = ""; } - validN = db::intFromData(ba); - validM = db::intFromData(ba); - keyUse = db::intFromData(ba); + settings["validN"] = QString::number(db::intFromData(ba)); + settings["validM"] = QString::number(db::intFromData(ba)); + settings["keyUse"] = QString::number(db::intFromData(ba)); if (version > 4) { - eKeyUse = db::stringFromData(ba); + settings["eKeyUse"] = db::stringFromData(ba); } else { int old = db::intFromData(ba); - eKeyUse = old_eKeyUse2QString(old); + settings["eKeyUse"] = old_eKeyUse2QString(old); } - nsCertType = db::intFromData(ba); - subAltName = db::stringFromData(ba); - issAltName = db::stringFromData(ba); - crlDist = db::stringFromData(ba); - nsComment = db::stringFromData(ba); - nsBaseUrl = db::stringFromData(ba); - nsRevocationUrl = db::stringFromData(ba); - nsCARevocationUrl = db::stringFromData(ba); - nsRenewalUrl = db::stringFromData(ba); - nsCaPolicyUrl = db::stringFromData(ba); - nsSslServerName = db::stringFromData(ba); + settings["nsCertType"] = QString::number(db::intFromData(ba)); + settings["subAltName"] = db::stringFromData(ba); + settings["issAltName"] = db::stringFromData(ba); + settings["crlDist"] = db::stringFromData(ba); + settings["nsComment"] = db::stringFromData(ba); + settings["nsBaseUrl"] = db::stringFromData(ba); + settings["nsRevocationUrl"] = db::stringFromData(ba); + settings["nsCARevocationUrl"] = db::stringFromData(ba); + settings["nsRenewalUrl"] = db::stringFromData(ba); + settings["nsCaPolicyUrl"] = db::stringFromData(ba); + settings["nsSslServerName"] = db::stringFromData(ba); xname.d2i(ba); - authInfAcc = db::stringFromData(ba); - certPol = db::stringFromData(ba); - validMidn = db::boolFromData(ba); + settings["authInfAcc"] = db::stringFromData(ba); + /* certPol = */ db::stringFromData(ba); + settings["validMidn"] = QString::number(db::boolFromData(ba)); if (version>2) - adv_ext = db::stringFromData(ba); + settings["adv_ext"] = db::stringFromData(ba); if (version>3) - noWellDefined = db::boolFromData(ba); + settings["noWellDefinedExpDate"] = + QString::number(db::boolFromData(ba)); if (ba.count() > 0) { my_error(tr("Wrong Size %1").arg(ba.count())); @@ -297,45 +347,49 @@ QByteArray pki_temp::toData() { QByteArray ba; - ba += db::stringToData(destination); - ba += db::boolToData(bcCrit); - ba += db::boolToData(keyUseCrit); - ba += db::boolToData(eKeyUseCrit); - ba += db::boolToData(subKey); - ba += db::boolToData(authKey); - ba += db::intToData(ca); - ba += db::stringToData(pathLen); - ba += db::intToData(validN); - ba += db::intToData(validM); - ba += db::intToData(keyUse); - ba += db::stringToData(eKeyUse); - ba += db::intToData(nsCertType); - ba += db::stringToData(subAltName); - ba += db::stringToData(issAltName); - ba += db::stringToData(crlDist); - ba += db::stringToData(nsComment); - ba += db::stringToData(nsBaseUrl); - ba += db::stringToData(nsRevocationUrl); - ba += db::stringToData(nsCARevocationUrl); - ba += db::stringToData(nsRenewalUrl); - ba += db::stringToData(nsCaPolicyUrl); - ba += db::stringToData(nsSslServerName); ba += xname.i2d(); - ba += db::stringToData(authInfAcc); - ba += db::stringToData(certPol); - ba += db::boolToData(validMidn); - ba += db::stringToData(adv_ext); - ba += db::boolToData(noWellDefined); + QBuffer buf(&ba); + buf.open(QIODevice::WriteOnly | QIODevice::Append); + QDataStream out(&buf); + out.setVersion(TEMPLATE_DS_VERSION); + out << settings; + buf.close(); return ba; } +void pki_temp::fromData(QByteArray &ba, int version) +{ + int size = ba.size(); + xname.d2i(ba); + QBuffer buf(&ba); + buf.open(QIODevice::ReadOnly); + QDataStream in(&buf); + in.setVersion(TEMPLATE_DS_VERSION); + in >> settings; + buf.close(); + fprintf(stderr, "Settings: %d, ba-size:%d size:%d\n", + settings.size(), ba.size(), size); + (void)version; + //if (version < 11) .... +} + +void pki_temp::fromData(const unsigned char *p, int size, int version) +{ + if (version < 10) { + old_fromData(p, size, version); + } else { + QByteArray ba((const char*)p, size); + fromData(ba, version); + } +} + QByteArray pki_temp::toExportData() { QByteArray data, header; data = toData(); header = db::intToData(data.count()); - header += db::intToData(dataVersion); + header += db::intToData(TMPL_VERSION); header += data; return header; } @@ -377,34 +431,14 @@ BIO *pki_temp::pem(BIO *b, int format) void pki_temp::fromExportData(QByteArray data) { int size, version; - const int hsize = sizeof(uint32_t); - bool oldimport = false; - if (data.size() < hsize) { + if (data.size() < (int)sizeof(uint32_t)) my_error(tr("Template file content error (too small)")); - } - QByteArray header = data.mid(0, hsize); - size = db::intFromData(header); - - if (size > 65535 || size <0) { - /* oldimport templates are prepended by its size in - * host endianess. Recover the size */ - size = intFromData(data); - if (size > 65535 || size <0) { - my_error(tr("Template file content error (bad size)")); - } - oldimport = true; - } - if (oldimport) { - oldFromData((const unsigned char*)data.constData(), - data.size()); - } else { - size = db::intFromData(data); - version = db::intFromData(data); - fromData((const unsigned char*)data.constData(), - data.size(), version); - } + size = db::intFromData(data); + version = db::intFromData(data); + fromData((const unsigned char*)data.constData(), + data.size(), version); } void pki_temp::try_fload(QString fname, const char *mode) @@ -471,7 +505,8 @@ void pki_temp::fromPEM_BIO(BIO *bio, QString name) PEM_read_bio(bio, &nm, &header, &data, &len); if (ign_openssl_error()) - throw errorEx(tr("Not a PEM encoded XCA Template"), class_name); + throw errorEx(tr("Not a PEM encoded XCA Template"), + getClassName()); if (!strcmp(nm, PEM_STRING_XCA_TEMPLATE)) { ba = QByteArray::fromRawData((char*)data, len); @@ -489,7 +524,6 @@ void pki_temp::fromPEM_BIO(BIO *bio, QString name) pki_temp::~pki_temp() { - } bool pki_temp::compare(pki_base *) @@ -499,86 +533,7 @@ bool pki_temp::compare(pki_base *) return false; } -QVariant pki_temp::column_data(dbheader *hd) -{ - switch (hd->id) { - case HD_temp_type: - return QVariant(destination); - } - return pki_x509name::column_data(hd); -} - QVariant pki_temp::getIcon(dbheader *hd) { return hd->id == HD_internal_name ? QVariant(*icon) : QVariant(); } - -void pki_temp::oldFromData(const unsigned char *p, int size) -{ - int version; - - QByteArray ba((const char*)p, size); - - version=intFromData(ba); - intFromData(ba); /* type */ - if (version == 1) { - ca = 2; - bool mca = intFromData(ba); - if (mca) ca = 1; - } - bcCrit=db::boolFromData(ba); - keyUseCrit=db::boolFromData(ba); - eKeyUseCrit=db::boolFromData(ba); - subKey=db::boolFromData(ba); - authKey=db::boolFromData(ba); - db::boolFromData(ba); - db::boolFromData(ba); - if (version >= 2) { - ca = intFromData(ba); - } - pathLen = QString::number(db::intFromData(ba)); - if (pathLen == "0") - pathLen = ""; - validN = intFromData(ba); - validM = intFromData(ba); - keyUse=intFromData(ba); - int old=db::intFromData(ba); - eKeyUse = old_eKeyUse2QString(old); - nsCertType=intFromData(ba); - if (version == 1) { - xname.addEntryByNid(OBJ_sn2nid("C"), db::stringFromData(ba)); - xname.addEntryByNid(OBJ_sn2nid("ST"), db::stringFromData(ba)); - xname.addEntryByNid(OBJ_sn2nid("L"), db::stringFromData(ba)); - xname.addEntryByNid(OBJ_sn2nid("O"), db::stringFromData(ba)); - xname.addEntryByNid(OBJ_sn2nid("OU"), db::stringFromData(ba)); - xname.addEntryByNid(OBJ_sn2nid("CN"), db::stringFromData(ba)); - xname.addEntryByNid(OBJ_sn2nid("Email"),db::stringFromData(ba)); - } - pki_openssl_error(); - subAltName=db::stringFromData(ba); - issAltName=db::stringFromData(ba); - crlDist=db::stringFromData(ba); - nsComment=db::stringFromData(ba); - nsBaseUrl=db::stringFromData(ba); - nsRevocationUrl=db::stringFromData(ba); - nsCARevocationUrl=db::stringFromData(ba); - nsRenewalUrl=db::stringFromData(ba); - nsCaPolicyUrl=db::stringFromData(ba); - nsSslServerName=db::stringFromData(ba); - // next version: - if (version >= 2) { - xname.d2i(ba); - pki_openssl_error(); - } - if (version >= 3) { - authInfAcc=db::stringFromData(ba); - certPol=db::stringFromData(ba); - validMidn=db::boolFromData(ba); - } - - if (ba.count() > 0) { - my_error(tr("Wrong Size %1").arg(ba.count())); - } - pki_openssl_error(); -} - diff --git a/lib/pki_temp.h b/lib/pki_temp.h index 850009c4..f25272d2 100644 --- a/lib/pki_temp.h +++ b/lib/pki_temp.h @@ -11,52 +11,84 @@ #include "pki_base.h" #include "x509name.h" #include "asn1time.h" -#include "pki_x509.h" +#include "pki_x509super.h" #define D5 "-----" #define PEM_STRING_XCA_TEMPLATE "XCA TEMPLATE" +#define TMPL_VERSION 10 + +#define CHECK_TMPL_KEY if (!tmpl_keys.contains(key)) { qDebug("Unknown template key: %s(%s)", __func__, CCHAR(key)); } class pki_temp: public pki_x509name { Q_OBJECT protected: + static QList tmpl_keys; int dataSize(); void try_fload(QString fname, const char *mode); + bool pre_defined; + x509name xname; + QMap settings; + QString adv_ext; + void fromExtList(extList *el, int nid, const char *item); + public: static QPixmap *icon; - x509name xname; - QString subAltName, issAltName, crlDist, authInfAcc, certPol; - QString nsComment, nsBaseUrl, nsRevocationUrl, - nsCARevocationUrl, nsRenewalUrl, nsCaPolicyUrl, - nsSslServerName, destination, adv_ext, eKeyUse, pathLen; - bool bcCrit, keyUseCrit, eKeyUseCrit, subKey, authKey, - validMidn, noWellDefined; - int nsCertType, keyUse, ca; - int validN, validM; // methods - extList fromCert(pki_x509super *cert_or_req); - + const char *getClassName() const; + QString getSetting(QString key) + { + CHECK_TMPL_KEY + return settings[key]; + } + int getSettingInt(QString key) + { + CHECK_TMPL_KEY + return settings[key].toInt(); + } + void setSetting(QString key, QString value) + { + CHECK_TMPL_KEY + settings[key] = value; + } + void setSetting(QString key, int value) + { + CHECK_TMPL_KEY + settings[key] = QString::number(value); + } pki_temp(const pki_temp *pk); pki_temp(const QString d = QString()); void fload(const QString fname); void writeDefault(const QString fname); ~pki_temp(); void fromData(const unsigned char *p, int size, int version); + void old_fromData(const unsigned char *p, int size, int version); void fromData(const unsigned char *p, db_header_t *head ); - void oldFromData(const unsigned char *p, int size); - + void fromData(QByteArray &ba, int version); + void setAsPreDefined() + { + pre_defined = true; + } + QString comboText() const; QByteArray toData(); bool compare(pki_base *ref); void writeTemp(QString fname); - QVariant column_data(dbheader *hd); QVariant getIcon(dbheader *hd); - virtual QString getMsg(msg_type msg); + QString getMsg(msg_type msg); x509name getSubject() const; + void setSubject(x509name n) + { + xname = n; + } BIO *pem(BIO *b, int format); QByteArray toExportData(); void fromPEM_BIO(BIO *, QString); void fromExportData(QByteArray data); + extList fromCert(pki_x509super *cert_or_req); + QSqlError insertSqlData(); + QSqlError deleteSqlData(); + QSqlError restoreSql(QVariant sqlId); }; #endif diff --git a/lib/pki_x509.cpp b/lib/pki_x509.cpp index 1cfdcb92..f3bfb5aa 100644 --- a/lib/pki_x509.cpp +++ b/lib/pki_x509.cpp @@ -9,6 +9,7 @@ #include "pki_x509.h" #include "pki_evp.h" #include "pki_scard.h" +#include "db_base.h" #include "func.h" #include "base.h" #include "exception.h" @@ -33,6 +34,11 @@ pki_x509::pki_x509(X509 *c) pki_openssl_error(); } +const char *pki_x509::getClassName() const +{ + return "pki_x509"; +} + pki_x509::pki_x509(const pki_x509 *crt) :pki_x509super(crt->desc) { @@ -41,13 +47,11 @@ pki_x509::pki_x509(const pki_x509 *crt) pki_openssl_error(); psigner = crt->psigner; setRefKey(crt->getRefKey()); - trust = crt->trust; - efftrust = crt->efftrust; caSerial = crt->caSerial; caTemplate = crt->caTemplate; revocation = crt->revocation; crlDays = crt->crlDays; - crlExpiry = crt->crlExpiry; + crlExpire = crt->crlExpire; pki_openssl_error(); } @@ -73,12 +77,137 @@ QString pki_x509::getMsg(msg_type msg) case msg_import: return tr("Successfully imported the certificate '%1'"); case msg_delete: return tr("Delete the certificate '%1'?"); case msg_create: return tr("Successfully created the certificate '%1'"); - /* %1: Number of certs; %2: list of cert ames */ + /* %1: Number of certs; %2: list of cert names */ case msg_delete_multi: return tr("Delete the %1 certificates: %2?"); } return pki_base::getMsg(msg); } +QSqlError pki_x509::insertSqlData() +{ + XSqlQuery q; + a1time now; + pki_x509 *signer = findIssuer(); + QSqlError e = pki_x509super::insertSqlData(); + if (e.isValid()) + return e; + + SQL_PREPARE(q, "INSERT INTO certs (item, hash, iss_hash, serial, issuer, " + "ca, crlExpire, crlNo, cert) " + "VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, hash()); + q.bindValue(2, (uint)getIssuerName().hashNum()); + q.bindValue(3, getSerial().toHex()); + q.bindValue(4, signer ? signer->getSqlItemId() : QVariant()); + q.bindValue(5, (int)isCA()); + q.bindValue(6, now.toPlain()); + q.bindValue(7, i2d().toBase64()); + q.exec(); + return q.lastError(); +} + +QSqlError pki_x509::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + e = pki_x509super::restoreSql(sqlId); + if (e.isValid()) + return e; + SQL_PREPARE(q, "SELECT cert, issuer, crlNo, crlExpire, serial FROM certs " + "WHERE item=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (!q.first()) + return sqlItemNotFound(sqlId); + QByteArray ba = QByteArray::fromBase64(q.value(0).toByteArray()); + d2i(ba); + signerSqlId = q.value(1); + crlNumber.set(q.value(2).toUInt()); + crlExpire.fromPlain(q.value(3).toString()); + revList = x509revList::fromSql(sqlId); + QVariant serial = q.value(4); + + SQL_PREPARE(q, "SELECT serial, date, invaldate, crlNo, reasonBit " + "FROM revocations WHERE caId=? AND serial=?"); + q.bindValue(0, signerSqlId); + q.bindValue(1, serial); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (q.first()) + revocation = x509rev(q.record()); + return q.lastError(); +} + +QSqlError pki_x509::deleteSqlData() +{ + XSqlQuery q; + QSqlError e = pki_x509super::deleteSqlData(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "DELETE FROM certs WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "UPDATE crls SET issuer=NULL WHERE issuer=?"); + q.bindValue(0, sqlItemId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "UPDATE certs SET issuer=NULL WHERE issuer=?"); + q.bindValue(0, sqlItemId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "DELETE FROM revocations WHERE caId=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); +} + +pki_x509 *pki_x509::findIssuer() +{ + XSqlQuery q; + pki_x509 *issuer; + unsigned hash; + + if ((issuer = getSigner()) != NULL) + return issuer; + // first check for self-signed + if (verify(this)) + return this; + + hash = getIssuerName().hashNum(); + /* Select X509 CA certificates with subject-hash == hash */ + SQL_PREPARE(q, "SELECT x509super.item from x509super " + "JOIN certs ON certs.item = x509super.item " + "WHERE certs.ca=1 AND x509super.subj_hash=?"); + q.bindValue(0, hash); + q.exec(); + while (q.next()) { + issuer = static_cast( + db_base::lookupPki(q.value(0).toULongLong())); + if (!issuer) { + qDebug("Certificate with id %d not found", + q.value(0).toInt()); + } + if (verify(issuer)) { + return issuer; + } + } + return NULL; +} + void pki_x509::fromPEM_BIO(BIO *bio, QString name) { X509 *_cert; @@ -89,8 +218,6 @@ void pki_x509::fromPEM_BIO(BIO *bio, QString name) autoIntName(); if (getIntName().isEmpty()) setIntName(rmslashdot(name)); - trust = 1; - efftrust = 1; } void pki_x509::fload(const QString fname) @@ -118,8 +245,6 @@ void pki_x509::fload(const QString fname) autoIntName(); if (getIntName().isEmpty()) setIntName(rmslashdot(fname)); - trust = 1; - efftrust = 1; } pki_x509::~pki_x509() @@ -133,15 +258,11 @@ pki_x509::~pki_x509() void pki_x509::init() { psigner = NULL; - trust = 0; - efftrust = 0; caSerial = 1; - caTemplate = ""; + caTemplate = NULL; crlDays = 30; - crlExpiry.setUndefined(); - class_name = "pki_x509"; + crlExpire.setUndefined(); cert = NULL; - dataVersion = 4; pkiType = x509; randomSerial = false; } @@ -287,7 +408,7 @@ void pki_x509::store_token(bool alwaysSelect) pk11_attr_bool(CKA_TOKEN, true) << pk11_attr_bool(CKA_PRIVATE, false) << pk11_attr_data(CKA_SUBJECT, getSubject().i2d()) << - pk11_attr_data(CKA_ISSUER, getIssuer().i2d()) << + pk11_attr_data(CKA_ISSUER, getIssuerName().i2d()) << pk11_attr_data(CKA_SERIAL_NUMBER, getSerial().i2d()) << pk11_attr_data(CKA_LABEL, desc.toUtf8()) << (card ? card->getIdAttr() : p11.findUniqueID(CKO_CERTIFICATE)); @@ -404,7 +525,7 @@ x509name pki_x509::getSubject() const return x; } -x509name pki_x509::getIssuer() const +x509name pki_x509::getIssuerName() const { x509name x(X509_get_issuer_name(cert)); pki_openssl_error(); @@ -442,19 +563,26 @@ void pki_x509::delSigner(pki_base *s) psigner = NULL; } -bool pki_x509::canSign() +bool pki_x509::isCA() const { - BASIC_CONSTRAINTS *bc; + bool ca; int crit; + BASIC_CONSTRAINTS *bc = (BASIC_CONSTRAINTS *) + X509_get_ext_d2i(cert, NID_basic_constraints, &crit, NULL); + pki_openssl_error(); + ca = bc && bc->ca; + if (bc) + BASIC_CONSTRAINTS_free(bc); + return ca; +} + +bool pki_x509::canSign() const +{ if (!privkey || privkey->isPubKey()) return false; if (privkey->isToken() && !pkcs11::loaded()) return false; - bc = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(cert, NID_basic_constraints, &crit, NULL); - pki_openssl_error(); - if (!bc || !bc->ca) - return false; - return true; + return isCA(); } bool pki_x509::hasExtension(int nid) @@ -488,7 +616,7 @@ void pki_x509::fromData(const unsigned char *p, db_header_t *head) d2i(ba); pki_openssl_error(); - trust = db::intFromData(ba); + /* trust = */ db::intFromData(ba); if (version < 4) { a1time revoked; isRevoked = db::boolFromData(ba); @@ -501,9 +629,9 @@ void pki_x509::fromData(const unsigned char *p, db_header_t *head) } caSerial.setHex(db::stringFromData(ba)); pki_openssl_error(); - caTemplate = db::stringFromData(ba); + QString __caTemplate = db::stringFromData(ba); crlDays = db::intFromData(ba); - crlExpiry.d2i(ba); + crlExpire.d2i(ba); pki_openssl_error(); if (version > 1) randomSerial = db::boolFromData(ba); @@ -536,29 +664,6 @@ void pki_x509::fromData(const unsigned char *p, db_header_t *head) pki_openssl_error(); } -QByteArray pki_x509::toData() -{ - QByteArray ba; - - ba += i2d(); // cert - ba += db::intToData(trust); - // version 4: don't store isrevoked, revoked - - // the serial if this is a CA - ba += db::stringToData(caSerial.toHex()); - // the name of the template to use for signing - ba += db::stringToData(caTemplate); - // version 3 - ba += db::intToData(crlDays); // the CRL period - ba += crlExpiry.i2d(); // last CRL date - ba += db::boolToData(randomSerial); - ba += db::stringToData(crlNumber.toHex()); - // version 4: don't store own revocation but client revocations - ba += revList.toBA(); - pki_openssl_error(); - return ba; -} - void pki_x509::writeDefault(const QString fname) { writeCert(fname + QDir::separator() + getIntName() + ".crt", @@ -662,6 +767,9 @@ bool pki_x509::verify(pki_x509 *signer) return true; if ((psigner != NULL) || (signer == NULL)) return false; + if (signer == this && signerSqlId == sqlItemId) + return true; + if (verify_only(signer)) { int idx; x509rev r; @@ -807,32 +915,6 @@ pki_x509 *pki_x509::getSigner() return (pki_x509 *)psigner; } -int pki_x509::getTrust() -{ - if (trust > 2) trust = 2; - if (trust < 0) trust = 0; - return trust; -} - -void pki_x509::setTrust(int t) -{ - if (t>=0 && t<=2) - trust = t; -} - -int pki_x509::getEffTrust() -{ - if (efftrust > 2) efftrust = 2; - if (efftrust < 0) efftrust = 0; - return efftrust; -} - -void pki_x509::setEffTrust(int t) -{ - if (t>= 0 && t<= 2) - efftrust = t; -} - bool pki_x509::isRevoked() { return revocation.isValid(); @@ -841,44 +923,6 @@ bool pki_x509::isRevoked() void pki_x509::setRevoked(const x509rev &revok) { revocation = revok; - if (revok.isValid()) { - setEffTrust(0); - setTrust(0); - } -} - -int pki_x509::calcEffTrust() -{ - int mytrust = trust; - if (mytrust != 1) { - efftrust = mytrust; - return mytrust; - } - if (isRevoked()) { - efftrust = 0; - return 0; - } - if (getSigner() == this && trust == 1) { // inherit trust, but self signed - trust=0; - efftrust=0; - return 0; - } - //we must look at the parent certs - pki_x509 *signer = getSigner(); - while (mytrust == 1 && signer && signer != this) { - mytrust = signer->getTrust(); - signer = signer->getSigner(); - } - - if (mytrust == 1) mytrust = 0; - efftrust = mytrust; - return mytrust; -} - -void pki_x509::setCrlExpiry(const a1time &time) -{ - crlExpiry = time; - pki_openssl_error(); } bool pki_x509::caAndPathLen(bool *ca, a1int *pathlen, bool *hasLen) @@ -900,9 +944,6 @@ bool pki_x509::caAndPathLen(bool *ca, a1int *pathlen, bool *hasLen) QVariant pki_x509::column_data(dbheader *hd) { - QString truststatus[] = - { tr("Not trusted"), tr("Trust inherited"), tr("Always Trusted") }; - switch (hd->id) { case HD_cert_serial: return QVariant(getSerial().toHex()); @@ -910,14 +951,12 @@ QVariant pki_x509::column_data(dbheader *hd) return QVariant(getNotBefore().toSortable()); case HD_cert_notAfter: return QVariant(getNotAfter().toSortable()); - case HD_cert_trust: - return QVariant(truststatus[getTrust()]); case HD_cert_revocation: return QVariant(isRevoked() ? revocation.getDate().toSortable() : ""); case HD_cert_crl_expire: - if (canSign() && !crlExpiry.isUndefined()) - return QVariant(crlExpiry.toSortable()); + if (canSign() && !crlExpire.isUndefined()) + return QVariant(crlExpire.toSortable()); else return QVariant(); case HD_cert_md5fp: @@ -962,7 +1001,7 @@ QVariant pki_x509::getIcon(dbheader *hd) if (k && k->isPrivKey()) { pixnum += 1; } - if (calcEffTrust() == 0){ + if (isRevoked()){ pixnum += 2; } break; @@ -976,7 +1015,7 @@ bool pki_x509::visible() { if (pki_x509super::visible()) return true; - if (getIssuer().search(limitPattern)) + if (getIssuerName().search(limitPattern)) return true; if (fingerprint(EVP_md5()).contains(limitPattern)) return true; @@ -1026,8 +1065,8 @@ QVariant pki_x509::bg_color(dbheader *hd) case HD_cert_crl_expire: if (canSign()) { QDateTime crlwarn, crlex; - crlex = crlExpiry; - if (!crlExpiry.isUndefined()) { + crlex = crlExpire; + if (!crlExpire.isUndefined()) { crlwarn = crlex.addSecs(-2 *60*60*24); if (crlex < now) return QVariant(BG_RED); @@ -1038,72 +1077,3 @@ QVariant pki_x509::bg_color(dbheader *hd) } return QVariant(); } - -void pki_x509::oldFromData(unsigned char *p, int size) -{ - int version, sRev, sLastCrl; - QByteArray ba((char*)p, size); - X509 *cert_sik = cert; - cert = NULL; - version = intFromData(ba); - if (version >=1 && version <= 5) { - intFromData(ba); /* sCert */ - d2i(ba); - trust = intFromData(ba); - sRev = intFromData(ba); - if (sRev) { - a1time r; - r.d2i(ba); - if (version != 3) { - revocation.setSerial(getSerial()); - revocation.setDate(r); - } - } else { - revocation = x509rev(); - } - - if (version == 1) { - caTemplate=""; - caSerial=1; - crlExpiry.setUndefined(); - crlDays=30; - } - - if (version >= 2 ) { - if (version >= 5) - caSerial.setHex(db::stringFromData(ba)); - else { - int i = intFromData(ba); - if (i>=0) - caSerial = i; - else { - caSerial = getSerial(); - ++caSerial; - } - } - caTemplate = db::stringFromData(ba); - } - if (version >= 3 ) { - crlDays = intFromData(ba); - sLastCrl = intFromData(ba); - if (sLastCrl) { - crlExpiry.d2i(ba); - } - } - // version 4 saves a NULL as revoked - // version 3 did save a recent date :-(( - } - else { // old version - d2i(ba); - trust = 1; - efftrust = 1; - } - if (cert) - X509_free(cert_sik); - else - cert = cert_sik; - - if (ba.count() > 0) { - my_error(tr("Wrong Size %1").arg(ba.count())); - } -} diff --git a/lib/pki_x509.h b/lib/pki_x509.h index 5ad0b050..551432e7 100644 --- a/lib/pki_x509.h +++ b/lib/pki_x509.h @@ -12,6 +12,7 @@ #include #include #include +#include "pki_temp.h" #include "pki_key.h" #include "pki_x509req.h" #include "pki_x509super.h" @@ -26,14 +27,13 @@ class pki_x509 : public pki_x509super Q_OBJECT private: pki_x509 *psigner; - a1time crlExpiry; + QVariant signerSqlId; + a1time crlExpire; bool randomSerial; - int trust; - int efftrust; a1int caSerial; a1int crlNumber; int crlDays; - QString caTemplate; + pki_temp *caTemplate; X509 *cert; void init(); x509rev revocation; @@ -51,6 +51,11 @@ class pki_x509 : public pki_x509super pki_x509(const QString name = ""); ~pki_x509(); + const char *getClassName() const; + void setSigner(pki_x509 *signer) + { + psigner = signer; + } void fload(const QString fname); void load_token(pkcs11 &p11, CK_OBJECT_HANDLE object); void store_token(bool alwaysSelect); @@ -64,15 +69,14 @@ class pki_x509 : public pki_x509super a1time getNotBefore() const; a1time getNotAfter() const; x509name getSubject() const; - x509name getIssuer() const; + x509name getIssuerName() const; void setSubject(const x509name &n); void setIssuer(const x509name &n); bool caAndPathLen(bool *ca, a1int *pathlen, bool *hasLen); - QByteArray toData(); void fromData(const unsigned char *p, db_header_t *head); - void oldFromData(unsigned char *p, int size); - bool canSign(); + bool isCA() const; + bool canSign() const; void writeCert(const QString fname, bool PEM, bool append = false); void writeIndexEntry(FILE *fp); void writeIndexEntry(const QString fname, bool append = false); @@ -87,20 +91,16 @@ class pki_x509 : public pki_x509super bool checkDate(); bool addV3ext(const x509v3ext &e, bool skip_existing = false); void sign(pki_key *signkey, const EVP_MD *digest); + pki_x509 *findIssuer(); X509 *getCert() { return cert; } - int getTrust(); - void setTrust(int t); - int getEffTrust(); - void setEffTrust(int t); void setRevoked(bool rev, a1time inval = a1time(), QString reason = QString()); void setRevoked(const x509rev &revok); bool isRevoked(); pki_x509 *getBySerial(const a1int &a) const; - int calcEffTrust(); a1int getIncCaSerial(); a1int getCaSerial() { @@ -119,12 +119,12 @@ class pki_x509 : public pki_x509super if (n > crlNumber) crlNumber = n; } - void setTemplate(QString s) + void setTemplate(pki_temp *t) { - if (s.length() > 0) - caTemplate = s; + if (t) + caTemplate = t; } - QString getTemplate() + pki_temp *getTemplate() { return caTemplate; } @@ -150,7 +150,6 @@ class pki_x509 : public pki_x509super return revocation; } pk11_attlist objectAttributes(); - void setCrlExpiry(const a1time &time); bool hasExtension(int nid); bool cmpIssuerAndSerial(pki_x509 *refcert); bool visible(); @@ -171,6 +170,13 @@ class pki_x509 : public pki_x509super } void setRevocations(const x509revList &rl); bool compareNameAndKey(pki_x509 *other); + void setCrlExpire(a1time a) + { + crlExpire = a; + } + QSqlError insertSqlData(); + QSqlError deleteSqlData(); + QSqlError restoreSql(QVariant sqlId); }; #endif diff --git a/lib/pki_x509req.cpp b/lib/pki_x509req.cpp index 27e27d12..3c988b7d 100644 --- a/lib/pki_x509req.cpp +++ b/lib/pki_x509req.cpp @@ -24,20 +24,72 @@ pki_x509req::pki_x509req(const QString name) : pki_x509super(name) { privkey = NULL; - class_name = "pki_x509req"; request = X509_REQ_new(); pki_openssl_error(); - dataVersion=1; pkiType=x509_req; done = false; } +const char *pki_x509req::getClassName() const +{ + return "pki_x509req"; +} + pki_x509req::~pki_x509req() { if (request) X509_REQ_free(request); } +QSqlError pki_x509req::insertSqlData() +{ + XSqlQuery q; + QSqlError e = pki_x509super::insertSqlData(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "INSERT INTO requests (item, hash, signed, request) " + "VALUES (?, ?, 0, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, hash()); + q.bindValue(2, i2d().toBase64()); + q.exec(); + return q.lastError(); +} + +QSqlError pki_x509req::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + e = pki_x509super::restoreSql(sqlId); + if (e.isValid()) + return e; + SQL_PREPARE(q, "SELECT request, signed FROM requests WHERE item=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (!q.first()) + return sqlItemNotFound(sqlId); + QByteArray ba = QByteArray::fromBase64(q.value(0).toByteArray()); + d2i(ba); + done = q.value(1).toBool(); + return e; +} + +QSqlError pki_x509req::deleteSqlData() +{ + XSqlQuery q; + QSqlError e = pki_x509super::deleteSqlData(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "DELETE FROM requests WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); +} + void pki_x509req::createReq(pki_key *key, const x509name &dn, const EVP_MD *md, extList el) { int bad_nids[] = { NID_subject_key_identifier, NID_authority_key_identifier, @@ -163,7 +215,15 @@ void pki_x509req::fromData(const unsigned char *p, db_header_t *head ) size = head->len - sizeof(db_header_t); - oldFromData((unsigned char *)p, size); + QByteArray ba((const char *)p, size); + privkey = NULL; + + d2i(ba); + pki_openssl_error(); + + if (ba.count() > 0) { + my_error(tr("Wrong Size %1").arg(ba.count())); + } } void pki_x509req::addAttribute(int nid, QString content) @@ -194,13 +254,6 @@ void pki_x509req::setSubject(const x509name &n) X509_REQ_set_subject_name(request, n.get()); } -QByteArray pki_x509req::toData() -{ - QByteArray ba = i2d(); - pki_openssl_error(); - return ba; -} - void pki_x509req::writeDefault(const QString fname) { writeReq(fname + QDir::separator() + getIntName() + ".csr", true); @@ -325,11 +378,3 @@ bool pki_x509req::visible() return true; return false; } - -void pki_x509req::oldFromData(unsigned char *p, int size) -{ - QByteArray ba((const char *)p, size); - privkey = NULL; - - d2i(ba); -} diff --git a/lib/pki_x509req.h b/lib/pki_x509req.h index 51870c56..b0f9aba5 100644 --- a/lib/pki_x509req.h +++ b/lib/pki_x509req.h @@ -30,14 +30,13 @@ class pki_x509req : public pki_x509super public: extList getV3ext(); static QPixmap *icon[3]; + const char *getClassName() const; pki_x509req(QString name = ""); void fromPEM_BIO(BIO *bio, QString name); void fload(const QString fname); void writeDefault(const QString fname); ~pki_x509req(); void fromData(const unsigned char *p, db_header_t *head); - void oldFromData(unsigned char *p, int size); - QByteArray toData(); x509name getSubject() const; void writeReq(const QString fname, bool pem); X509_REQ *getReq() @@ -49,8 +48,8 @@ class pki_x509req : public pki_x509super int verify(); pki_key *getPubKey() const; - void createReq(pki_key *key, const x509name &dn, const EVP_MD *md, - extList el); + void createReq(pki_key *key, const x509name &dn, + const EVP_MD *md, extList el); void setSubject(const x509name &n); /* SPKAC special functions */ QVariant column_data(dbheader *hd); @@ -68,6 +67,9 @@ class pki_x509req : public pki_x509super QByteArray i2d(); BIO *pem(BIO *, int); bool visible(); + QSqlError insertSqlData(); + QSqlError deleteSqlData(); + QSqlError restoreSql(QVariant sqlId); }; #endif diff --git a/lib/pki_x509super.cpp b/lib/pki_x509super.cpp index 764bcc4b..ba5077c8 100644 --- a/lib/pki_x509super.cpp +++ b/lib/pki_x509super.cpp @@ -8,6 +8,7 @@ #include "func.h" #include "oid.h" #include "pki_x509super.h" +#include "db_base.h" pki_x509super::pki_x509super(const QString name) : pki_x509name(name) @@ -17,9 +18,70 @@ pki_x509super::pki_x509super(const QString name) pki_x509super::~pki_x509super() { - if (privkey) - privkey->decUcount(); +} + +QSqlError pki_x509super::insertSqlData() +{ + XSqlQuery q; + unsigned hash = pubHash(); + + SQL_PREPARE(q, "SELECT item FROM public_keys WHERE hash=?"); + q.bindValue(0, hash); + q.exec(); + if (q.lastError().isValid()) + return q.lastError(); + while (q.next()) { + pki_key *x = static_cast( + db_base::lookupPki(q.value(0).toULongLong())); + if (!x) { + qDebug("Public key with id %d not found", + q.value(0).toInt()); + continue; + } + if (compareRefKey(x)) { + setRefKey(x); + break; + } + } + + SQL_PREPARE(q, "INSERT INTO x509super (item, subj_hash, key, key_hash) " + "VALUES (?, ?, ?, ?)"); + q.bindValue(0, sqlItemId); + q.bindValue(1, (uint)getSubject().hashNum()); + q.bindValue(2, privkey ? privkey->getSqlItemId() : QVariant()); + q.bindValue(3, hash); + q.exec(); + return q.lastError(); +} + +QSqlError pki_x509super::restoreSql(QVariant sqlId) +{ + XSqlQuery q; + QSqlError e; + + e = pki_base::restoreSql(sqlId); + if (e.isValid()) + return e; + SQL_PREPARE(q, "SELECT key FROM x509super WHERE item=?"); + q.bindValue(0, sqlId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + if (!q.first()) + return sqlItemNotFound(sqlId); + keySqlId = q.value(0); privkey = NULL; + return e; +} + +QSqlError pki_x509super::deleteSqlData() +{ + XSqlQuery q; + SQL_PREPARE(q, "DELETE FROM x509super WHERE item=?"); + q.bindValue(0, sqlItemId); + q.exec(); + return q.lastError(); } pki_key *pki_x509super::getRefKey() const @@ -27,27 +89,36 @@ pki_key *pki_x509super::getRefKey() const return privkey; } -void pki_x509super::setRefKey(pki_key *ref) +unsigned pki_x509super::pubHash() { - if (ref == NULL || privkey != NULL ) - return; - pki_key *mk = getPubKey(); - if (mk == NULL) - return; - if (ref->compare(mk)) { - // this is our key - privkey = ref; - ref->incUcount(); + unsigned hash; + if (privkey) { + hash = privkey->hash(); + } else { + pki_key *x = getPubKey(); + hash = x->hash(); + delete x; } - delete mk; + return hash; } -void pki_x509super::delRefKey(pki_key *ref) +bool pki_x509super::compareRefKey(pki_key *ref) const { - if (ref != privkey || ref == NULL) - return; - ref->decUcount(); - privkey = NULL; + bool x; + + if (ref == NULL) + return false; + pki_key *mk = getPubKey(); + if (mk == NULL) + return false; + x = ref->compare(mk); + delete mk; + return x; +} + +void pki_x509super::setRefKey(pki_key *ref) +{ + privkey = ref; } QString pki_x509super::getSigAlg() diff --git a/lib/pki_x509super.h b/lib/pki_x509super.h index 179a4046..ef43d138 100644 --- a/lib/pki_x509super.h +++ b/lib/pki_x509super.h @@ -31,6 +31,7 @@ class pki_x509super : public pki_x509name { Q_OBJECT protected: + QVariant keySqlId; pki_key *privkey; virtual int sigAlg() { return NID_undef; @@ -42,6 +43,7 @@ class pki_x509super : public pki_x509name { return -1; }; + unsigned pubHash(); virtual pki_key *getPubKey() const { return NULL; @@ -52,12 +54,20 @@ class pki_x509super : public pki_x509name }; virtual QString getSigAlg(); virtual const EVP_MD *getDigest(); + QVariant getKeySqlId() + { + return keySqlId; + } pki_key *getRefKey() const; + bool compareRefKey(pki_key* ref) const; void setRefKey(pki_key *ref); void delRefKey(pki_key *ref); QVariant column_data(dbheader *hd); void opensslConf(QString fname); bool visible(); + QSqlError insertSqlData(); + QSqlError deleteSqlData(); + QSqlError restoreSql(QVariant sqlId); }; #endif diff --git a/lib/x509name.cpp b/lib/x509name.cpp index 72b45b6b..4f97d1fd 100644 --- a/lib/x509name.cpp +++ b/lib/x509name.cpp @@ -142,6 +142,12 @@ QString x509name::hash() const return QString("%1").arg(X509_NAME_hash(xn), 8, 16, QChar('0')); } +/* 32 bit signed integer */ +unsigned long x509name::hashNum() const +{ + return X509_NAME_hash(xn) & 0x7fffffffL; +} + QStringList x509name::entryList(int i) const { QStringList sl; @@ -195,6 +201,11 @@ bool x509name::operator == (const x509name &x) const return (X509_NAME_cmp(xn, x.xn) == 0); } +bool x509name::operator != (const x509name &x) const +{ + return (X509_NAME_cmp(xn, x.xn) != 0); +} + x509name &x509name::operator = (const x509name &x) { set(x.xn); diff --git a/lib/x509name.h b/lib/x509name.h index 9c95f948..6f9e6f43 100644 --- a/lib/x509name.h +++ b/lib/x509name.h @@ -36,6 +36,7 @@ class x509name int entryCount() const; x509name &operator = (const x509name &x); bool operator == (const x509name &x) const; + bool operator != (const x509name &x) const; static int getNidByName(const QString &nid_name); void addEntryByNid(int nid, const QString entry); QString checkLength() const; @@ -45,6 +46,7 @@ class x509name QString getMostPopular() const; QString taggedValues() const; QString hash() const; + unsigned long hashNum() const; bool search(const QRegExp &pattern); }; diff --git a/lib/x509rev.cpp b/lib/x509rev.cpp index 79077be0..71b74112 100644 --- a/lib/x509rev.cpp +++ b/lib/x509rev.cpp @@ -7,11 +7,13 @@ #include "x509rev.h" #include "db.h" -#include "base.h" +#include "pki_base.h" #include "func.h" #include "exception.h" #include #include +#include +#include #include "openssl_compat.h" @@ -56,6 +58,16 @@ QString x509rev::getReason() const return crl_reasons[reason_idx].lname; } +static int reasonBit2Idx(int bit) +{ + for (int i=0; crl_reasons[i].lname; i++) { + if (bit == crl_reasons[i].bitnum) { + return i; + } + } + return 0; +} + void x509rev::fromREVOKED(const X509_REVOKED *rev) { ASN1_ENUMERATED *reason; @@ -74,11 +86,7 @@ void x509rev::fromREVOKED(const X509_REVOKED *rev) if (reason) { r = ASN1_ENUMERATED_get(reason); openssl_error(); - for (int i=0; crl_reasons[i].lname; i++) { - if (r == crl_reasons[i].bitnum) { - reason_idx = i; - } - } + reason_idx = reasonBit2Idx(r); ASN1_ENUMERATED_free(reason); } ivalDate.setUndefined(); @@ -157,6 +165,25 @@ void x509rev::dump() const crl_reasons[reason_idx].lname); } +x509rev::x509rev(QSqlRecord rec) +{ + serial.setHex(rec.value(0).toString()); + date.fromPlain(rec.value(1).toString()); + ivalDate.fromPlain(rec.value(2).toString()); + crlNo = rec.value(3).toInt(); + reason_idx = reasonBit2Idx(rec.value(4).toInt()); +} + +void x509rev::executeQuery(XSqlQuery &q) +{ + // 0 is the caId + q.bindValue(1, serial.toHex()); + q.bindValue(2, date.toPlain()); + q.bindValue(3, ivalDate.toPlain()); + q.bindValue(4, crl_reasons[reason_idx].bitnum); + q.exec(); +} + void x509revList::fromBA(QByteArray &ba) { int i, num = db::intFromData(ba); @@ -204,3 +231,42 @@ bool x509revList::identical(const x509revList &other) const } return true; } + +x509revList x509revList::fromSql(QVariant caId) +{ + XSqlQuery q; + x509revList list; + + SQL_PREPARE(q, "SELECT serial, date, invaldate, crlNo, reasonBit " + "FROM revocations WHERE caId=?"); + q.bindValue(0, caId); + q.exec(); + if (q.lastError().isValid()) + return list; + while (q.next()) { + x509rev r(q.record()); + list.append(r); + } + return list; +} + +QSqlError x509revList::sqlUpdate(QVariant caId) +{ + // Transaction from outside !! + XSqlQuery q; + QSqlError e; + SQL_PREPARE(q, "DELETE FROM revocations WHERE caId=?"); + q.bindValue(0, caId); + q.exec(); + e = q.lastError(); + if (e.isValid()) + return e; + SQL_PREPARE(q, "INSERT INTO revocations " + "(caId, serial, date, invaldate, reasonBit) " + "VALUES (?,?,?,?,?)"); + q.bindValue(0, caId); + for (int i=0; i +#include +#include +#include #include #include "asn1time.h" #include "asn1int.h" +#include "pki_base.h" class x509rev { private: a1int serial; a1time date, ivalDate; - int reason_idx; + int reason_idx, crlNo; void set(const x509rev &x); X509_REVOKED *toREVOKED(bool withReason=true) const; @@ -45,7 +49,8 @@ class x509rev { set(n); } - + x509rev(QSqlRecord rec); + void executeQuery(XSqlQuery &q); bool isValid() const { return serial != a1int(0L) && !date.isUndefined(); @@ -92,6 +97,10 @@ class x509rev { return ivalDate; } + int getCrlNo() const + { + return crlNo; + } X509_REVOKED *get(bool withReason=true) const { return toREVOKED(withReason); @@ -101,6 +110,7 @@ class x509rev class x509revList : public QList { public: + static x509revList fromSql(QVariant caId); bool merged; QByteArray toBA(); void fromBA(QByteArray &ba); @@ -121,5 +131,6 @@ class x509revList : public QList append(r); } } + QSqlError sqlUpdate(QVariant caId); }; #endif diff --git a/ui/About.ui b/ui/About.ui deleted file mode 100644 index 66ea9128..00000000 --- a/ui/About.ui +++ /dev/null @@ -1,157 +0,0 @@ - - About - - - - 0 - 0 - 561 - 392 - - - - - - - - 6 - - - 8 - - - 8 - - - 8 - - - 8 - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 95 - 40 - - - - - 95 - 40 - - - - - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Done - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - 95 - 40 - - - - - 95 - 40 - - - - - - - true - - - - - - - - - - - - - - button - clicked() - About - accept() - - - 270 - 28 - - - 213 - 18 - - - - - diff --git a/ui/CaProperties.ui b/ui/CaProperties.ui index 8a479dee..7847c89f 100644 --- a/ui/CaProperties.ui +++ b/ui/CaProperties.ui @@ -7,7 +7,7 @@ 0 0 487 - 320 + 501 @@ -81,6 +81,49 @@ + + + + Subject manager + + + + + + + + + + + Add + + + + + + + Delete + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + @@ -89,13 +132,6 @@ - - - - Use random Serial numbers - - - @@ -123,6 +159,20 @@ + + + + + + + + + + + Use random Serial numbers + + + @@ -150,6 +200,17 @@ + + + kvView + QTableView +
widgets/kvView.h
+ + addKvRow() + deleteCurrentRow() + +
+
@@ -159,12 +220,12 @@ setDisabled(bool) - 39 - 141 + 240 + 345 271 - 111 + 306 @@ -176,7 +237,7 @@ 341 - 291 + 472 292 @@ -192,7 +253,7 @@ 445 - 292 + 473 445 @@ -200,5 +261,37 @@ + + extDNadd + clicked() + subjectManager + addKvRow() + + + 407 + 113 + + + 363 + 106 + + + + + extDNdel + clicked() + subjectManager + deleteCurrentRow() + + + 399 + 138 + + + 362 + 139 + + + diff --git a/ui/CertDetail.ui b/ui/CertDetail.ui index c0896b99..8c6d1ce8 100644 --- a/ui/CertDetail.ui +++ b/ui/CertDetail.ui @@ -6,19 +6,13 @@ 0 0 - 450 - 450 + 535 + 498 - - 6 - - - 0 - @@ -81,7 +75,7 @@ - S&tatus + Status @@ -105,62 +99,7 @@ QFrame::Sunken - - - 9 - - - 6 - - - - - - - - 6 - - - 0 - - - - - - - - - 0 - 0 - - - - Serial - - - - - - - - 0 - 0 - - - - The serial number of the certificate - - - - - - - - - The internal name of the certificate in the database - - - + @@ -168,26 +107,10 @@ - - - - 6 - - - 0 - - - - - - - - - - - - - Signature algorithm + + + + The internal name of the certificate in the database @@ -198,6 +121,24 @@ + + + + + + + + + + + + + + + + + + @@ -205,6 +146,42 @@ + + + + + + + + + + + + 0 + 0 + + + + Serial + + + + + + + + 0 + 0 + + + + The serial number of the certificate + + + + + + @@ -265,9 +242,6 @@ Validity - - 6 - 8 @@ -315,12 +289,9 @@ - &Subject + Subject - - 6 - 11 @@ -331,12 +302,9 @@ - &Issuer + Issuer - - 6 - 11 @@ -357,7 +325,7 @@ - &Extensions + Extensions @@ -376,12 +344,33 @@ + + + Comment + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html> + + + false + + + + + - QDialogButtonBox::Ok + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -414,8 +403,8 @@ accept() - 369 - 422 + 378 + 488 235 @@ -423,5 +412,21 @@ + + buttonBox + rejected() + CertDetail + reject() + + + 485 + 475 + + + 530 + 428 + + + diff --git a/ui/CrlDetail.ui b/ui/CrlDetail.ui index ed18c90f..ad8e40ed 100644 --- a/ui/CrlDetail.ui +++ b/ui/CrlDetail.ui @@ -281,12 +281,33 @@ + + + Comment + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html> + + + false + + + + + - QDialogButtonBox::Ok + QDialogButtonBox::Cancel|QDialogButtonBox::Ok diff --git a/ui/Makefile b/ui/Makefile index 835d59d6..28fd16eb 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -4,11 +4,11 @@ TOPDIR=.. BUILD=.. endif -UI_H = ui_About.h ui_CaProperties.h ui_CertDetail.h ui_CertExtend.h \ +UI_H = ui_CaProperties.h ui_CertDetail.h ui_CertExtend.h \ ui_CrlDetail.h ui_ExportDialog.h ui_Help.h \ ui_ImportMulti.h ui_KeyDetail.h ui_MainWindow.h ui_NewCrl.h \ ui_NewKey.h ui_NewX509.h ui_Options.h ui_PwDialog.h ui_Revoke.h \ - ui_SelectToken.h ui_TrustState.h ui_v3ext.h ui_SearchPkcs11.h \ + ui_SelectToken.h ui_XcaDialog.h ui_v3ext.h ui_SearchPkcs11.h \ ui_RevocationList.h ui_OidResolver.h include $(TOPDIR)/Rules.mak diff --git a/ui/NewCrl.ui b/ui/NewCrl.ui index 80acc3f4..935ba839 100644 --- a/ui/NewCrl.ui +++ b/ui/NewCrl.ui @@ -1,257 +1,218 @@ NewCrl - + 0 0 - 451 - 478 + 354 + 369 + + Form + - - - - - - - Arial - 14 - 50 - false - false - false - false - - - - Create CRL - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 95 - 40 - - - - - 95 - 40 - - - - true - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - + + QLayout::SetMinAndMaxSize + - - - - - Last update - - - - - - - true - - - - - - - Next update - - - - - - - true - - - - - - - - - Qt::Horizontal - + + + + + + Last update + + + + + + + true + + + + + + + Next update + + + + + + + true + + + + - - - - - - - + + + + + + + + + + Days + + + + + Months + + + + + Years + + + + + + - Days + Midnight - - + + + + - Months + Local time - - + + + + - Years + Apply - - - - - - - Midnight - - - - - - - Local time - - - - - - - Apply - - - - + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + Options - - - - - + + - CRL number - - - true - - - - - - - Subject alternative name - - - - - - - Revocation reasons - - - true - - - - - - - Authority key identifier + Hash algorithm - - + + - Hash algorithm + Subject alternative name - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + Authority key identifier + + + + + + + + + + + + + + CRL number + + + + + + + QLayout::SetDefaultConstraint + + + + + + + + true + + + + + + + + + + + + Revocation reasons + + + + + + + + + + true - - - - Qt::Vertical - - - - 21 - 20 - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - @@ -271,123 +232,8 @@
widgets/hashBox.h
- - subAltName - - - midnightCB - stateChanged(int) - nextUpdate - hideTimeCheck(int) - - - 104 - 243 - - - 233 - 149 - - - - - midnightCB - stateChanged(int) - lastUpdate - hideTimeCheck(int) - - - 124 - 243 - - - 233 - 118 - - - - - buttonBox - accepted() - NewCrl - accept() - - - 316 - 538 - - - 70 - 459 - - - - - buttonBox - rejected() - NewCrl - reject() - - - 410 - 538 - - - 179 - 454 - - - - - checkBox - stateChanged(int) - nextUpdate - localTime(int) - - - 291 - 243 - - - 418 - 160 - - - - - checkBox - stateChanged(int) - lastUpdate - localTime(int) - - - 291 - 243 - - - 422 - 124 - - - - - midnightCB - clicked(bool) - checkBox - setDisabled(bool) - - - 81 - 243 - - - 291 - 243 - - - setCrlNumber clicked(bool) @@ -395,12 +241,12 @@ setEnabled(bool) - 158 - 424 + 198 + 326 - 220 - 428 + 225 + 326 diff --git a/ui/NewX509.ui b/ui/NewX509.ui index d3d82068..8b057e37 100644 --- a/ui/NewX509.ui +++ b/ui/NewX509.ui @@ -6,8 +6,8 @@ 0 0 - 712 - 634 + 747 + 637 @@ -68,7 +68,7 @@ - 2 + 0 @@ -97,23 +97,14 @@ Signing request - - 6 - - - 9 - 0 - - 6 - - + @@ -152,9 +143,6 @@ - - 6 - 0 @@ -186,20 +174,8 @@ Signing - - 6 - - - 9 - - - 6 - - - 0 - @@ -224,12 +200,6 @@ - - 6 - - - 0 - @@ -238,7 +208,7 @@ - + All certificates in your database that can create valid signatures @@ -264,12 +234,6 @@ - - 6 - - - 0 - @@ -305,7 +269,7 @@ - + 0 @@ -476,14 +440,8 @@ Private key - - 6 - - - 9 - - + 0 @@ -589,9 +547,6 @@ Key identifier - - 6 - 8 @@ -639,9 +594,6 @@ true - - 6 - 0 @@ -689,7 +641,7 @@ - + @@ -724,7 +676,7 @@ - + Set the time to 00:00:00 and 23:59:59 respectively @@ -925,26 +877,14 @@ Key usage - - 6 - 8 - - 6 - - - 0 - - - 6 - 8 @@ -1016,9 +956,6 @@ - - 6 - 8 @@ -1119,12 +1056,6 @@ - - 6 - - - 0 - @@ -1160,12 +1091,6 @@ - - 0 - - - 6 - @@ -1263,6 +1188,16 @@ + + + Comment + + + + + + + @@ -1302,7 +1237,12 @@ DoubleClickLabel QLabel -
widgets/clicklabel.h
+
widgets/clicklabel.h
+
+ + itemCombo + QComboBox +
widgets/ItemCombo.h
@@ -1333,8 +1273,8 @@ authKey notBefore notAfter - validNumber - midnightCB + validN + validMidn checkBox noWellDefinedExpDate validRange @@ -1406,8 +1346,8 @@ deleteCurrentRow() - 622 - 284 + 713 + 199 57 @@ -1422,8 +1362,8 @@ addKvRow() - 622 - 252 + 713 + 167 57 @@ -1464,7 +1404,7 @@ - midnightCB + validMidn stateChanged(int) notBefore hideTimeCheck(int) @@ -1480,7 +1420,7 @@ - midnightCB + validMidn stateChanged(int) notAfter hideTimeCheck(int) @@ -1502,8 +1442,8 @@ accept() - 557 - 584 + 566 + 627 285 @@ -1518,8 +1458,8 @@ reject() - 643 - 587 + 652 + 627 405 @@ -1560,14 +1500,14 @@ - midnightCB + validMidn clicked(bool) checkBox setDisabled(bool) - 350 - 333 + 431 + 348 447 diff --git a/ui/TimeInput.ui b/ui/TimeInput.ui new file mode 100644 index 00000000..258ce7de --- /dev/null +++ b/ui/TimeInput.ui @@ -0,0 +1,235 @@ + + + Form + + + + 0 + 0 + 491 + 224 + + + + TimeInput + + + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + + + last update + + + + + + + true + + + + + + + next update + + + + + + + true + + + + + + + + + + + + + + + + + Days + + + + + Months + + + + + Years + + + + + + + + Apply + + + + + + + Midnight + + + + + + + Local time + + + + + + + No well-defined expiration + + + + + + + + + + + + + + Validity + QDateTimeEdit +
widgets/validity.h
+ 1 + + hideTimeCheck(int) + localTime(int) + +
+
+ + + + midnightCB + clicked(bool) + checkBox + setDisabled(bool) + + + 128 + 189 + + + 256 + 189 + + + + + checkBox + stateChanged(int) + nextUpdate + localTime(int) + + + 187 + 187 + + + 360 + 100 + + + + + checkBox + stateChanged(int) + lastUpdate + localTime(int) + + + 256 + 189 + + + 360 + 64 + + + + + midnightCB + stateChanged(int) + lastUpdate + hideTimeCheck(int) + + + 131 + 189 + + + 360 + 64 + + + + + midnightCB + stateChanged(int) + nextUpdate + hideTimeCheck(int) + + + 146 + 189 + + + 360 + 100 + + + + + applyTime + clicked() + Form + applyTimeRange() + + + 310 + 195 + + + 297 + 228 + + + + + + applyTimeRange() + +
diff --git a/ui/XcaDialog.ui b/ui/XcaDialog.ui new file mode 100644 index 00000000..fabad236 --- /dev/null +++ b/ui/XcaDialog.ui @@ -0,0 +1,197 @@ + + + XcaDialog + + + + 0 + 0 + 435 + 177 + + + + + + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + + 95 + 40 + + + + + 16777215 + 40 + + + + + Arial + 14 + 50 + false + false + false + false + + + + + + + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 95 + 40 + + + + + 95 + 40 + + + + + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + 0 + 0 + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + XcaDialog + accept() + + + 286 + 264 + + + 83 + 245 + + + + + buttonBox + rejected() + XcaDialog + reject() + + + 386 + 260 + + + 430 + 85 + + + + + diff --git a/widgets/CertDetail.cpp b/widgets/CertDetail.cpp index f31ff32d..72dc3520 100644 --- a/widgets/CertDetail.cpp +++ b/widgets/CertDetail.cpp @@ -21,7 +21,6 @@ CertDetail::CertDetail(QWidget *parent) { setupUi(this); setWindowTitle(XCA_TITLE); - descr->setReadOnly(true); showConf = false; } @@ -47,6 +46,7 @@ void CertDetail::setX509super(pki_x509super *x) pki_key *key= x->getRefKey(); if (key) { privKey->setText(key->getIntName()); + privKey->setClickText(key->getSqlItemId().toString()); if (key->isPrivKey()) { privKey->setGreen(); } else { @@ -73,6 +73,11 @@ void CertDetail::setX509super(pki_x509super *x) // Algorithm sigAlgo->setText(x->getSigAlg()); + connect(sigAlgo, SIGNAL(doubleClicked(QString)), + MainWindow::getResolver(), SLOT(searchOid(QString))); + + // Comment + comment->setPlainText(x->getComment()); } void CertDetail::setCert(pki_x509 *cert) @@ -96,25 +101,15 @@ void CertDetail::setCert(pki_x509 *cert) signature->disableToolTip(); } else { signature->setText(cert->getSigner()->getIntName()); + privKey->setClickText(cert->getSqlItemId().toString()); signature->setGreen(); } - // check trust state - trustState->disableToolTip(); - if (cert->getEffTrust() == 0) { - trustState->setText(tr("Not trusted")); - trustState->setRed(); - } - else { - trustState->setText(tr("Trusted")); - trustState->setGreen(); - } - // the serial serialNr->setText(cert->getSerial().toHex()); // details of the issuer - issuer->setX509name(cert->getIssuer()); + issuer->setX509name(cert->getIssuerName()); // The dates notBefore->setText(cert->getNotBefore().toPretty()); @@ -170,7 +165,6 @@ void CertDetail::setReq(pki_x509req *req) signature->setText("PKCS#10"); } signature->disableToolTip(); - trustState->hide(); fingerprints->hide(); validity->hide(); serialLabel->hide(); diff --git a/widgets/CertTreeView.cpp b/widgets/CertTreeView.cpp index 25461223..25a087d5 100644 --- a/widgets/CertTreeView.cpp +++ b/widgets/CertTreeView.cpp @@ -72,8 +72,6 @@ void CertTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, SLOT(manageRevocations())); subCa->setEnabled(cert->canSign()); } - menu->addAction(tr("Trust"), this, - SLOT(setTrust()))->setEnabled(allUnrevoked); if (sameParent && parentCanSign) { QString n = multi ? QString(" [%1]").arg(indexes.size()) : ""; menu->addAction(tr("Renewal") +n, this, SLOT(certRenewal())); @@ -189,11 +187,3 @@ void CertTreeView::unRevoke() if (certs) certs->unRevoke(getSelectedIndexes()); } - -void CertTreeView::setTrust() -{ - if (certs) - certs->setTrust(getSelectedIndexes()); - proxy->invalidate(); -} - diff --git a/widgets/CertTreeView.h b/widgets/CertTreeView.h index 1184b5d6..42b7c9fb 100644 --- a/widgets/CertTreeView.h +++ b/widgets/CertTreeView.h @@ -44,6 +44,5 @@ class CertTreeView: public X509SuperTreeView void caProperties(); void revoke(); void unRevoke(); - void setTrust(); }; #endif diff --git a/widgets/CrlDetail.cpp b/widgets/CrlDetail.cpp index 79fdcb2a..95184d69 100644 --- a/widgets/CrlDetail.cpp +++ b/widgets/CrlDetail.cpp @@ -24,7 +24,6 @@ CrlDetail::CrlDetail(MainWindow *mainwin) setWindowTitle(tr(XCA_TITLE)); image->setPixmap(*MainWindow::revImg); - descr->setReadOnly(true); } void CrlDetail::setCrl(pki_crl *crl) @@ -34,19 +33,18 @@ void CrlDetail::setCrl(pki_crl *crl) iss = crl->getIssuer(); signCheck->disableToolTip(); + signCheck->setClickText(crl->getSigAlg()); if (iss != NULL) { issuerIntName->setText(iss->getIntName()); + issuerIntName->setClickText(iss->getSqlItemId().toString()); issuerIntName->setGreen(); - pki_key *key = iss->getPubKey(); - if (crl->verify(key)) { + if (crl->verify(iss)) { signCheck->setText(crl->getSigAlg()); signCheck->setGreen(); } else { signCheck->setText(tr("Failed")); signCheck->setRed(); } - if (key) - delete key; } else { issuerIntName->setText(tr("Unknown signer")); issuerIntName->setDisabled(true); @@ -55,6 +53,9 @@ void CrlDetail::setCrl(pki_crl *crl) signCheck->setDisabled(true); } + connect(signCheck, SIGNAL(doubleClicked(QString)), + MainWindow::getResolver(), SLOT(searchOid(QString))); + descr->setText(crl->getIntName()); lUpdate->setText(crl->getLastUpdate().toPretty()); lUpdate->setToolTip(crl->getLastUpdate().toPrettyGMT()); @@ -67,4 +68,6 @@ void CrlDetail::setCrl(pki_crl *crl) RevocationList::setupRevocationView(certList, crl->getRevList(), iss); v3extensions->document()->setHtml(crl->printV3ext()); + + comment->setPlainText(crl->getComment()); } diff --git a/widgets/ExportDialog.cpp b/widgets/ExportDialog.cpp index 37467a0a..f39f9814 100644 --- a/widgets/ExportDialog.cpp +++ b/widgets/ExportDialog.cpp @@ -53,16 +53,16 @@ ExportDialog::ExportDialog(MainWindow *mw, QString title, QString filt, 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_trusted] = - tr("Concatenated text format of all trusted certificates 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_trusted] = - tr("All trusted certificates encoded in one PKCS#7 file"); + 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] = diff --git a/widgets/ExportDialog.h b/widgets/ExportDialog.h index a09ab7b2..6f0971ff 100644 --- a/widgets/ExportDialog.h +++ b/widgets/ExportDialog.h @@ -16,8 +16,8 @@ class QPixmap; class exportType { public: - enum etype { Separator, PEM, PEM_chain, PEM_trusted, PEM_all, - DER, PKCS7, PKCS7_chain, PKCS7_trusted, PKCS7_all, + 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, diff --git a/widgets/ImportMulti.cpp b/widgets/ImportMulti.cpp index 641c2032..e24f12c3 100644 --- a/widgets/ImportMulti.cpp +++ b/widgets/ImportMulti.cpp @@ -33,7 +33,7 @@ ImportMulti::ImportMulti(MainWindow *parent) setWindowTitle(XCA_TITLE); image->setPixmap(*MainWindow::certImg); listView->setEditTriggers(QAbstractItemView::NoEditTriggers); - mcont = new db_token(QString(), parent); + mcont = new db_token(parent); listView->setModel(mcont); listView->setIconSize(pki_evp::icon[0]->size()); listView->setSelectionMode(QAbstractItemView::ExtendedSelection); diff --git a/widgets/ItemCombo.h b/widgets/ItemCombo.h new file mode 100644 index 00000000..de89468a --- /dev/null +++ b/widgets/ItemCombo.h @@ -0,0 +1,35 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __ITEMCOMBO_H +#define __ITEMCOMBO_H + +#include +#include + +#include "lib/pki_base.h" + +class itemCombo : public QComboBox +{ + public: + itemCombo(QWidget *parent) : QComboBox(parent) { } + void insertPkiItems(QList items) { + foreach(pki_base *p, items) { + addItem(p->comboText(), QVariant::fromValue(p)); + } + } + pki_base *currentPkiItem() { + return itemData(currentIndex()).value(); + } + int setCurrentPkiItem(pki_base *p) { + int idx = findData(QVariant::fromValue(p)); + setCurrentIndex(idx); + return idx; + } +}; + +#endif diff --git a/widgets/MW_database.cpp b/widgets/MW_database.cpp index 5d372399..87991d15 100644 --- a/widgets/MW_database.cpp +++ b/widgets/MW_database.cpp @@ -15,43 +15,428 @@ #include #include #include +#include #include "lib/db_base.h" #include "lib/func.h" +#include "lib/db.h" #include "widgets/ImportMulti.h" #include "widgets/NewKey.h" -void MainWindow::set_geometry(char *p, db_header_t *head) +QSqlError MainWindow::initSqlDB() { - if (head->version != 1) + QStringList sl; sl + +/* The "32bit hash" in public_keys, x509super, requests, certs and crls + * is used to quickly find items in the DB by reference. + * It consists of the first 4 bytes of a SHA1 hash. + * Collisions are of course possible. + * + * All binaries are stored Base64 encoded in a column of type + * "B64_BLOB" It is defined here as "VARCHAR(10000)" + */ + +#define B64_BLOB "VARCHAR(10000)" + +/* + * The B64(DER(something)) function means DER encode something + * and then Base64 encode that. + * So finally this is PEM without newlines, header and footer + * + * Dates are alway stored as 'CHAR(15)' in the + * ASN.1 Generalized time 'yyyyMMddHHmmssZ' format + */ + +#define DB_DATE "CHAR(15)" + +/* + * Configuration settings from + * the Options dialog, window size, last export directory, + * default key type and size, + * table column (position, sort order, visibility) + */ +<< "CREATE TABLE settings (" + "key CHAR(20) UNIQUE, " + "value VARCHAR(1024))" +<< "INSERT INTO settings (key, value) VALUES ('schema', '1')" + +/* + * All items (keys, tokens, requests, certs, crls, templates) + * are stored here with the primary key and some common data + * The other tables containing the details reference the "id" + * as FOREIGN KEY. + */ +<< "CREATE TABLE items(" + "id SERIAL PRIMARY KEY, " + "name VARCHAR(128), " /* Internal name of the item */ + "type INTEGER, " /* enum pki_type */ + "date "DB_DATE", " /* Time of insertion (creation/import) */ + "comment VARCHAR(2048))" + +/* + * Storage of public keys. Private keys and tokens also store + * their public part here. + */ +<< "CREATE TABLE public_keys (" + "item INTEGER, " /* reference to items(id) */ + "type CHAR(4), " /* RSA DSA EC (as text) */ + "hash INTEGER, " /* 32 bit hash */ + "len INTEGER, " /* key size in bits */ + "public "B64_BLOB", " /* B64(DER(public key)) */ + "FOREIGN KEY (item) REFERENCES items (id))" + +/* + * The private part of RSA, DSA, EC keys. + * references to "items" and "public_keys" + */ +<< "CREATE TABLE private_keys (" + "item INTEGER, " /* reference to items(id) */ + "ownPass INTEGER, " /* Encrypted by DB pwd or own pwd */ + "private "B64_BLOB", " /* B64(Encrypt(DER(private key))) */ + "FOREIGN KEY (item) REFERENCES items (id))" + +/* + * Smart cards or other PKCS#11 tokens + * references to "items" and "public_keys" + */ +<< "CREATE TABLE tokens (" + "item INTEGER, " /* reference to items(id) */ + "card_manufacturer VARCHAR(64), " /* Card location data */ + "card_serial VARCHAR(64), " /* as text */ + "card_model VARCHAR(64), " + "card_label VARCHAR(64), " + "slot_label VARCHAR(64), " + "object_id VARCHAR(64), " /* Unique ID on the token */ + "FOREIGN KEY (item) REFERENCES items (id))" + +/* + * Encryption and hash mechanisms supported by a token + */ +<< "CREATE TABLE token_mechanism (" + "item INTEGER, " /* reference to items(id) */ + "mechanism INTEGER, " /* PKCS#11: CK_MECHANISM_TYPE */ + "FOREIGN KEY (item) REFERENCES items (id))" + +/* + * An X509 Super class, consisting of a + * - Distinguishd name hash + * - Referenced key in the database + * - hash of the public key, used for lookups if there + * is no key to reference + * used by Requests and certificates and the use-counter of keys: + * "SELECT from x509super WHERE key=?" + */ +<< "CREATE TABLE x509super (" + "item INTEGER, " /* reference to items(id) */ + "subj_hash INTEGER, " /* 32 bit hash of the Distinguished name */ + "key INTEGER, " /* reference to the key items(id) */ + "key_hash INTEGER, " /* 32 bit hash of the public key */ + "FOREIGN KEY (item) REFERENCES items (id), " + "FOREIGN KEY (key) REFERENCES items (id)) " + +/* + * PKCS#10 Certificate request details + * also takes information from the "x509super" table. + */ +<< "CREATE TABLE requests (" + "item INTEGER, " /* reference to items(id) */ + "hash INTEGER, " /* 32 bit hash of the request */ + "signed INTEGER, " /* Whether it was once signed. */ + "request "B64_BLOB", " /* B64(DER(PKCS#10 request)) */ + "FOREIGN KEY (item) REFERENCES items (id)) " + +/* + * X509 certificate details + * also takes information from the "x509super" table. + * The content of the columns: hash, iss_hash, serial, ca + * can also be retrieved directly from the certificate, but are good + * to lurk around for faster lookup + */ +<< "CREATE TABLE certs (" + "item INTEGER, " /* reference to items(id) */ + "hash INTEGER, " /* 32 bit hash of the cert */ + "iss_hash INTEGER, " /* 32 bit hash of the issuer DN */ + "serial VARCHAR(64), " /* Serial number of the certificate */ + "issuer INTEGER, " /* The items(id) of the issuer or NULL */ + "ca INTEGER, " /* CA: yes / no from BasicConstraints */ + "crlExpire "DB_DATE", " /* CRL expiry date */ + "crlNo INTEGER, " /* Last CRL Number expiry date */ + "cert "B64_BLOB", " /* B64(DER(certificate)) */ + "FOREIGN KEY (item) REFERENCES items (id), " + "FOREIGN KEY (issuer) REFERENCES items (id)) " + +/* + * Storage of CRLs + */ +<< "CREATE TABLE crls (" + "item INTEGER, " /* reference to items(id) */ + "hash INTEGER, " /* 32 bit hash of the CRL */ + "num INTEGER, " /* Number of revoked certificates */ + "iss_hash INTEGER, " /* 32 bit hash of the issuer DN */ + "issuer INTEGER, " /* The items(id) of the issuer or NULL */ + "crl "B64_BLOB", " /* B64(DER(revocation list)) */ + "FOREIGN KEY (item) REFERENCES items (id), " + "FOREIGN KEY (issuer) REFERENCES items (id)) " + +/* + * Revocations (serial, date, reason, issuer) used to create new + * CRLs. "Manage revocations" + */ +<< "CREATE TABLE revocations (" + "caId INTEGER, " /* reference to certs(item) */ + "serial VARCHAR(64), " /* Serial number of the revoked certificate */ + "date "DB_DATE", " /* Time of creating the revocation */ + "invaldate "DB_DATE", " /* Time of invalidation */ + "crlNo INTEGER, " /* Crl Number of CRL of first appearance */ + "reasonBit INTEGER, " /* Bit number of the revocation reason */ + "FOREIGN KEY (caId) REFERENCES items (id))" + +/* + * Templates + */ +<< "CREATE TABLE templates (" + "item INTEGER, " /* reference to items(id) */ + "version INTEGER, " /* Version of the template format */ + "template "B64_BLOB", " /* The base64 encoded template */ + "FOREIGN KEY (item) REFERENCES items (id))" + + ; + XSqlQuery q; + if (!db.transaction()) + return db.lastError(); + foreach(QString sql, sl) { + fprintf(stderr, "EXEC: '%s'\n", CCHAR(sql)); + if (!q.exec(sql)) { + db.rollback(); + return q.lastError(); + } + } + db.commit(); + return QSqlError(); +} + +QSqlError MainWindow::openSqlDB() +{ + QStringList drivers = QSqlDatabase::drivers(); + foreach( QString driver, drivers) + fprintf(stderr, "DB driver: '%s'\n", CCHAR(driver)); + +#define POSTGRES 1 +#ifndef POSTGRES + db.setDatabaseName(dbfile); +#else + db.setDatabaseName("xca_pg"); + db.setHostName("192.168.140.7"); + db.setUserName("xca"); + db.setPassword("xca"); +#endif + if (db.driverName() == "QSQLITE") { + // chmod 0600 + if (!QFile::exists(dbfile)) { + QFile f(dbfile); + f.open(QIODevice::WriteOnly); + f.setPermissions(QFile::WriteOwner | QFile::ReadOwner); + f.close(); + } + } + if (!db.open()) + return db.lastError(); + QStringList tables = db.tables(); + if (!tables.contains("items")) { + return initSqlDB(); + } + return QSqlError(); +} + +void MainWindow::set_geometry(QString geo) +{ + QStringList sl = geo.split(","); + if (sl.size() != 2) return; - QByteArray ba = QByteArray::fromRawData(p, head->len); - int w, h, i; - w = db::intFromData(ba); - h = db::intFromData(ba); - i = db::intFromData(ba); - resize(w,h); + resize(sl[0].toInt(), sl[1].toInt()); + int i = sl[2].toInt(); if (i != -1) tabView->setCurrentIndex(i); } +void MainWindow::dbSqlError(QSqlError err) +{ + if (!err.isValid()) + err = QSqlDatabase::database().lastError(); + + if (err.isValid()) { + fprintf(stderr, "SQL ERROR: '%s'\n", CCHAR(err.text())); + XCA_WARN(err.text()); + } +} + +bool MainWindow::checkForOldDbFormat() +{ + // 0x ca db 19 69 + static const char magic[] = { 0xca, 0xdb, 0x19, 0x69 }; + char head[4]; + + QFile file(dbfile); + if (!file.open(QIODevice::ReadOnly)) + return 0; + file.read(head, sizeof head); + file.close(); + return !memcmp(head, magic, sizeof head); +} + +int MainWindow::verifyOldDbPass(QString dbname) +{ + // look for the password + QString passhash; + db_header_t head; + class db mydb(dbname); + mydb.first(); + if (!mydb.find(setting, QString("pwhash"))) { + QString val; + char *p; + if ((p = (char *)mydb.load(&head))) { + passhash = p; + free(p); + return initPass(passhash); + } + } + return 2; +} + +void MainWindow::importOldDatabase(QString dbname) +{ + class db mydb(dbname); + unsigned char *p = NULL; + db_header_t head; + pki_base *pki; + db_base *cont; + QList pkitype; pkitype << + smartCard << asym_key << tmpl << x509_req << x509 << revocation; + + storeSetting("pwhash", pki_evp::passHash); + for (int i=0; i < pkitype.count(); i++) { + mydb.first(); + while (mydb.find(pkitype[i], QString()) == 0) { + QString s; + p = mydb.load(&head); + if (!p) { + qWarning("Load was empty !"); + goto next; + } + switch (pkitype[i]) { + case smartCard: + cont = keys; + pki = new pki_scard(""); + break; + case asym_key: + cont = keys; + pki = new pki_evp(); + break; + case x509_req: + cont = reqs; + pki = new pki_x509req(); + break; + case x509: + cont = certs; + pki = new pki_x509(); + break; + case revocation: + cont = crls; + pki = new pki_crl(); + break; + case tmpl: + cont = temps; + pki = new pki_temp(); + break; + default: + goto next; + } + pki->setIntName(QString::fromUtf8(head.name)); + + try { + pki->fromData(p, &head); + } + catch (errorEx &err) { + err.appendString(pki->getIntName()); + Error(err); + delete pki; + pki = NULL; + } + fprintf(stderr, "load old: '%s'\n", CCHAR(pki->getIntName())); + free(p); + if (pki) { + cont->insertPKI(pki); + } +next: + if (mydb.next()) + break; + } + } + QStringList sl; sl << "workingdir" << "pkcs11path" << + "default_hash" << "mandatory_dn" << "explicit_dn" << + "string_opt" << "optionflags1" << "defaultkey"; + + mydb.first(); + while (!mydb.find(setting, QString())) { + QString val; + char *p; + if ((p = (char *)mydb.load(&head))) { + val = p; + free(p); + } + QString set = QString::fromUtf8(head.name); + if (sl.contains(set)) { + if (set == "optionflags1") + set = "optionflags"; + storeSetting(set, val); + } + if (mydb.next()) + break; + } +} + int MainWindow::init_database() { int ret = 2; + QSqlError err; + QString oldDbFile; + qDebug("Opening database: %s", QString2filename(dbfile)); keys = NULL; reqs = NULL; certs = NULL; temps = NULL; crls = NULL; + if (checkForOldDbFormat()) { + QString newname = dbfile; + if (newname.endsWith(".xdb")) + newname = newname.left(newname.length() -4); + newname += "_backup_" + QDateTime::currentDateTime() + .toString("yyyyMMdd_hhmmss") + ".xdb"; + if (!XCA_OKCANCEL(tr("Found an old version of the XCA database. I will make a backup copy called: '%1' and convert the database into the new format").arg(newname))) { + dbfile = ""; + return 1; + } + if (verifyOldDbPass(dbfile) != 1) + return 1; + if (!QFile::rename(dbfile, newname)) { + XCA_WARN(tr("Failed to rename the database file, because the target already exists")); + return 1; + } + oldDbFile = newname; + } Entropy::seed_rng(); + err = openSqlDB(); + dbSqlError(err); certView->setRootIsDecorated(db_x509::treeview); try { - ret = initPass(); - if (ret == 2) - return ret; - keys = new db_key(dbfile, this); - reqs = new db_x509req(dbfile, this); - certs = new db_x509(dbfile, this); - temps = new db_temp(dbfile, this); - crls = new db_crl(dbfile, this); + if (pki_evp::passwd.isEmpty()) { + ret = initPass(); + if (ret == 2) + return ret; + } + keys = new db_key(this); + reqs = new db_x509req(this); + certs = new db_x509(this); + temps = new db_temp(this); + crls = new db_crl(this); certs->updateAfterDbLoad(); } catch (errorEx &err) { @@ -73,15 +458,6 @@ int MainWindow::init_database() workingdir = QDir::currentPath(); setOptFlags((QString())); - connect( keys, SIGNAL(newKey(pki_key *)), - certs, SLOT(newKey(pki_key *)) ); - connect( keys, SIGNAL(delKey(pki_key *)), - certs, SLOT(delKey(pki_key *)) ); - connect( keys, SIGNAL(newKey(pki_key *)), - reqs, SLOT(newKey(pki_key *)) ); - connect( keys, SIGNAL(delKey(pki_key *)), - reqs, SLOT(delKey(pki_key *)) ); - connect( certs, SIGNAL(connNewX509(NewX509 *)), this, SLOT(connNewX509(NewX509 *)) ); connect( reqs, SIGNAL(connNewX509(NewX509 *)), this, @@ -105,57 +481,32 @@ int MainWindow::init_database() certView->setModel(certs); tempView->setModel(temps); crlView->setModel(crls); - try { - db mydb(dbfile); - while (mydb.find(setting, QString()) == 0) { - QString key; - db_header_t head; - char *p = (char *)mydb.load(&head); - if (!p) { - if (mydb.next()) - break; - continue; - } - key = head.name; + if (!oldDbFile.isEmpty()) + importOldDatabase(oldDbFile); - if (key == "workingdir") - workingdir = p; - else if (key == "pkcs11path") - pkcs11path = p; - else if (key == "default_hash") - hashBox::setDefault(p); - else if (key == "mandatory_dn") - mandatory_dn = p; - else if (key == "explicit_dn") - explicit_dn = p; - /* what a stupid idea.... */ - else if (key == "multiple_key_use") - mydb.erase(); - else if (key == "string_opt") - string_opt = p; - else if (key == "suppress") - mydb.erase(); - else if (key == "optionflags1") - setOptFlags((QString(p))); - /* Different optionflags, since setOptFlags() - * does an abort() for unknown flags in - * older versions. *Another stupid idea* - * This is for backward compatibility - */ - else if (key == "optionflags") - setOptFlags_old((QString(p))); - else if (key == "defaultkey") - NewKey::setDefault((QString(p))); - else if (key == "mw_geometry") - set_geometry(p, &head); - free(p); - if (mydb.next()) - break; - } - } catch (errorEx &err) { - Error(err); - return ret; + XSqlQuery query("SELECT key, value FROM settings"); + while (query.next()) { + QString key = query.value(0).toString(); + QString value = query.value(1).toString(); + if (key == "workingdir") + workingdir = value; + else if (key == "pkcs11path") + pkcs11path = value; + else if (key == "default_hash") + hashBox::setDefault(value); + else if (key == "mandatory_dn") + mandatory_dn = value; + else if (key == "explicit_dn") + explicit_dn = value; + else if (key == "string_opt") + string_opt = value; + else if (key == "optionflags") + setOptFlags(value); + else if (key == "defaultkey") + NewKey::setDefault(value); + else if (key == "mw_geometry") + set_geometry(value); } ASN1_STRING_set_default_mask_asc((char*)CCHAR(string_opt)); if (explicit_dn.isEmpty()) @@ -205,6 +556,9 @@ void MainWindow::dump_database() void MainWindow::undelete() { +#warning undelete NOT WORKING! + qDebug("undelete NOT WORKING!"); +#if 0 ImportMulti *dlgi = new ImportMulti(this); db_header_t head; db mydb(dbfile); @@ -242,6 +596,7 @@ void MainWindow::undelete() XCA_INFO(tr("No deleted items found")); } delete dlgi; +#endif } int MainWindow::open_default_db() @@ -290,17 +645,48 @@ void MainWindow::default_database() } +QString MainWindow::getSetting(QString key) +{ + XSqlQuery q; + SQL_PREPARE(q, "SELECT value FROM settings WHERE key=?"); + q.bindValue(0, key); + q.exec(); + if (q.first()) { + return q.value(0).toString(); + } + dbSqlError(q.lastError()); + return QString(); +} + +void MainWindow::storeSetting(QString key, QString value) +{ + XSqlQuery q; + SQL_PREPARE(q, "UPDATE settings SET value=? WHERE key=?"); + q.bindValue(0, value); + q.bindValue(1, key); + q.exec(); + dbSqlError(q.lastError()); + if (q.numRowsAffected() == 1) + return; + SQL_PREPARE(q, "INSERT INTO settings (key, value) VALUES (?, ?)"); + q.bindValue(0, key); + q.bindValue(1, value); + q.exec(); + dbSqlError(q.lastError()); +} + void MainWindow::close_database() { QByteArray ba; - if (!dbfile.isEmpty()) { - ba += db::intToData(size().width()); - ba += db::intToData(size().height()); - ba += db::intToData(tabView->currentIndex()); - db mydb(dbfile); - mydb.set((const unsigned char *)ba.constData(), ba.size(), 1, - setting, "mw_geometry"); - } + if (!db.isOpen()) + return; + + qDebug("Closing database: %s", QString2filename(dbfile)); + QString s = QString("%1,%2,%3") + .arg(size().width()).arg(size().height()) + .arg(tabView->currentIndex()); + storeSetting("mw_geometry", s); + setItemEnabled(false); statusBar()->removeWidget(searchEdit); dbindex->clear(); @@ -322,11 +708,13 @@ void MainWindow::close_database() if (keys) delete(keys); + db_base::flushLookup(); reqs = NULL; certs = NULL; temps = NULL; keys = NULL; + db.close(); pki_evp::passwd.cleanse(); pki_evp::passwd = QByteArray(); @@ -334,19 +722,6 @@ void MainWindow::close_database() return; crls = NULL; - - try { - int ret; - db mydb(dbfile); - ret = mydb.shrink( DBFLAG_OUTDATED | DBFLAG_DELETED ); - if (ret == 1) - XCA_INFO(tr("Errors detected and repaired while deleting outdated items from the database. A backup file was created")); - if (ret == 2) - XCA_INFO(tr("Removing deleted or outdated items from the database failed.")); - } - catch (errorEx &err) { - MainWindow::Error(err); - } update_history(dbfile); pkcs11::remove_libs(); enableTokenMenu(pkcs11::loaded()); diff --git a/widgets/MW_help.cpp b/widgets/MW_help.cpp index 7b26954f..95098e9f 100644 --- a/widgets/MW_help.cpp +++ b/widgets/MW_help.cpp @@ -14,7 +14,7 @@ #ifndef OPENSSL_NO_EC #include #endif -#include "ui_About.h" +#include "XcaDialog.h" #include "ui_Help.h" #include "lib/func.h" #include "lib/entropy.h" @@ -45,8 +45,10 @@ void MainWindow::cmd_help(const char* msg) void MainWindow::about() { - Ui::About ui; - QDialog *about = new QDialog(this, 0); + QTextEdit *textbox = new QTextEdit(NULL); + XcaDialog *about = new XcaDialog(this, x509, textbox, + QString(), QString()); + about->aboutDialog(scardImg); QString openssl, qt, cont, version, brainpool; #ifndef OPENSSL_NO_EC #ifdef NID_brainpoolP160r1 @@ -81,7 +83,6 @@ void MainWindow::about() } else { version = QString("%1
QT version: %2").arg(openssl).arg(qt); } - ui.setupUi(about); Entropy::seed_rng(); cont = QString( "

XCA

" @@ -105,10 +106,7 @@ void MainWindow::about() .arg(version_str(true)).arg(getPrefix()) .arg(getUserSettingsDir()); - about->setWindowTitle(XCA_TITLE); - ui.image->setPixmap( *keyImg ); - ui.image1->setPixmap( *certImg ); - ui.textbox->setHtml(cont); + textbox->setHtml(cont); about->exec(); delete about; } diff --git a/widgets/MW_menu.cpp b/widgets/MW_menu.cpp index c1277e0b..fc8ef053 100644 --- a/widgets/MW_menu.cpp +++ b/widgets/MW_menu.cpp @@ -144,8 +144,6 @@ void MainWindow::init_menu() SLOT(exportIndexHierarchy())); acList += extra->addAction(tr("C&hange DataBase password"), this, SLOT(changeDbPass())); - acList += extra->addAction(tr("&Import old db_dump"), this, - SLOT(import_dbdump())); acList += extra->addAction(tr("&Undelete items"), this, SLOT(undelete())); extra->addAction(tr("Generate DH parameter"), this, @@ -218,44 +216,6 @@ void MainWindow::load_database() changeDB(fname); } -void MainWindow::import_dbdump() -{ - extern int read_dump(const char *, db_base **, char *, int); - Passwd pass; - char buf[50]; - - db_base *dbl[] = { keys, reqs, certs, temps, crls }; - if (!keys) - return; - QString file = QFileDialog::getOpenFileName(this, tr(XCA_TITLE), homedir, - tr("Database dump ( *.dump );; All files ( * )")); - - if (file.isEmpty()) - return; - - pass_info p(tr("Import password"), - tr("Please enter the password of the old database"), this); - if (PwDialog::execute(&p, &pass) != 1) - return; - try { - read_dump(CCHAR(file), dbl, buf, sizeof(buf)); - if (pki_evp::md5passwd(pass) != buf) { - xcaWarning msg(this, tr("Password verification error. Ignore keys ?")); - msg.addButton(QMessageBox::Cancel); - msg.addButton(QMessageBox::Ok)->setText( - tr("Import anyway")); - - if (msg.exec() == QMessageBox::Cancel) - return; - } - pki_evp::oldpasswd = pass; - read_dump(CCHAR(file), dbl, NULL, 0); - pki_evp::oldpasswd.cleanse(); - } catch (errorEx &err) { - Error(err); - } -} - void MainWindow::setOptions() { if (dbfile.isEmpty()) @@ -284,25 +244,18 @@ void MainWindow::setOptions() return; } QString alg = opt->hashAlgo->currentHashName(); - db mydb(dbfile); - mydb.set((const unsigned char *)CCHAR(alg), alg.length()+1, 1, - setting, "default_hash"); + storeSetting("default_hash", alg); hashBox::setDefault(alg); mandatory_dn = opt->getExtDnString(); explicit_dn = opt->getExpDnString(); - mydb.set((const unsigned char *)CCHAR(mandatory_dn), - mandatory_dn.length()+1, 1, setting, "mandatory_dn"); + storeSetting("mandatory_dn", mandatory_dn); if (explicit_dn.isEmpty()) explicit_dn = explicit_dn_default; if (explicit_dn != explicit_dn_default) { - mydb.set((const unsigned char *)CCHAR(explicit_dn), - explicit_dn.length()+1, 1, setting, "explicit_dn"); + storeSetting("explicit_dn", explicit_dn); } else { - mydb.first(); - if (!mydb.find(setting, "explicit_dn")) { - mydb.erase(); - } + XSqlQuery query("DELETE FROM settings WHERE key='explicit_dn'"); } QString flags = getOptFlags(); pki_base::suppress_messages = opt->suppress->checkState(); @@ -313,11 +266,7 @@ void MainWindow::setOptions() if (flags != getOptFlags()) { flags = getOptFlags(); - mydb.set((const unsigned char *)(CCHAR(flags)), - flags.length()+1, 1, setting, "optionflags1"); - mydb.first(); - if (!mydb.find(setting, "suppress")) - mydb.erase(); + storeSetting("optionflags", flags); certView->showHideSections(); reqView->showHideSections(); } @@ -325,14 +274,12 @@ void MainWindow::setOptions() if (opt->getStringOpt() != string_opt) { string_opt = opt->getStringOpt(); ASN1_STRING_set_default_mask_asc((char *)CCHAR(string_opt)); - mydb.set((const unsigned char *)CCHAR(string_opt), - string_opt.length()+1, 1, setting,"string_opt"); + storeSetting("string_opt", string_opt); } QString newpath = opt->getPkcs11Provider(); if (newpath != pkcs11path) { pkcs11path = newpath; - mydb.set((const unsigned char *) CCHAR(pkcs11path), - pkcs11path.length()+1, 1,setting, "pkcs11path"); + storeSetting("pkcs11path", pkcs11path); } enableTokenMenu(pkcs11::loaded()); delete opt; diff --git a/widgets/MainWindow.cpp b/widgets/MainWindow.cpp index 9ba5a241..0b3234c1 100644 --- a/widgets/MainWindow.cpp +++ b/widgets/MainWindow.cpp @@ -38,7 +38,7 @@ #include "lib/func.h" #include "lib/pkcs11.h" #include "lib/builtin_curves.h" -#include "ui_About.h" +#include "XcaDialog.h" #include "PwDialog.h" QPixmap *MainWindow::keyImg = NULL, *MainWindow::csrImg = NULL, @@ -113,6 +113,20 @@ MainWindow::MainWindow(QWidget *parent) wdList << keyButtons << reqButtons << certButtons << tempButtons << crlButtons; + QStringList drivers = QSqlDatabase::drivers(); + foreach(QString driver, drivers) { + QSqlDatabase d = QSqlDatabase::addDatabase(driver, driver +"_C"); + fprintf(stderr, "DB driver: '%s' LastInsertId: %s\n", + CCHAR(driver), d.driver()-> + hasFeature(QSqlDriver::LastInsertId) ? "YES":"NO" ); + } + +#define POSTGRES 1 +#ifndef POSTGRES + db = QSqlDatabase::addDatabase("QSQLITE"); +#else + db = QSqlDatabase::addDatabase("QPSQL7"); +#endif historyMenu = NULL; init_menu(); setItemEnabled(false); @@ -359,7 +373,7 @@ void MainWindow::loadPem() keys->load_default(l); } -bool MainWindow::pastePem(QString text) +bool MainWindow::pastePem(QString text, bool silent) { bool success = false; QByteArray pemdata = text.toLatin1(); @@ -378,7 +392,8 @@ bool MainWindow::pastePem(QString text) dlgi->execute(1); } catch (errorEx &err) { - Error(err); + if (!silent) + Error(err); } if (dlgi) delete dlgi; @@ -389,7 +404,6 @@ bool MainWindow::pastePem(QString text) void MainWindow::pastePem() { - Ui::About ui; QClipboard *cb = QApplication::clipboard(); QString text; @@ -398,25 +412,21 @@ void MainWindow::pastePem() text = cb->text(QClipboard::Clipboard); if (!text.isEmpty()) - if (pastePem(text)) + if (pastePem(text, true)) return; - QDialog *input = new QDialog(this, 0); - ui.setupUi(input); - delete ui.textbox; - QTextEdit *textbox = new QTextEdit(input); - ui.vboxLayout->addWidget(textbox); - ui.button->setText(tr("Import PEM data")); - input->setWindowTitle(XCA_TITLE); + QTextEdit *textbox = new QTextEdit(); textbox->setPlainText(text); + XcaDialog *input = new XcaDialog(this, x509, textbox, + tr("Import PEM data"), QString()); + input->noSpacer(); if (input->exec()) { text = textbox->toPlainText(); if (!text.isEmpty()) pastePem(text); } delete input; - } void MainWindow::initToken() @@ -550,7 +560,6 @@ void MainWindow::manageToken() cert = new pki_x509(""); try { cert->load_token(p11, objects[j]); - cert->setTrust(2); dlgi->addItem(cert); } catch (errorEx &err) { Error(err); @@ -602,36 +611,30 @@ void MainWindow::closeEvent(QCloseEvent *e) QString makeSalt(void) { - unsigned char rand[2]; - char saltbuf[10]; + QString s = "T"; + unsigned char rand[8]; - Entropy::get(rand, 2); - snprintf(saltbuf, 10, "S%02X%02X", rand[0], rand[1]); - return QString(saltbuf); + Entropy::get(rand, sizeof rand); + for (unsigned i=0; i< sizeof rand; i++) + s += QString("%1").arg(rand[i]); + return s; } int MainWindow::checkOldGetNewPass(Passwd &pass) { - QString passHash; - db mydb(dbfile); - - if (!mydb.find(setting, "pwhash")) { - char *cpass; + QString passHash = getSetting("pwhash"); + if (!passHash.isEmpty()) { pass_info p(tr("Current Password"), tr("Please enter the current database password"), this); - if ((cpass = (char *)mydb.load(NULL))) { - passHash = cpass; - free(cpass); - } /* Try empty password */ - if (pki_evp::sha512passwd(pass, passHash) != passHash) { + if (pki_evp::sha512passwT(pass, passHash) != passHash) { /* Not the empty password, check it */ if (PwDialog::execute(&p, &pass, false) != 1) return 0; } - if (pki_evp::sha512passwd(pass, passHash) != passHash) { + if (pki_evp::sha512passwT(pass, passHash) != passHash) { XCA_WARN(tr("The entered password is wrong")); return 0; } @@ -647,106 +650,50 @@ int MainWindow::checkOldGetNewPass(Passwd &pass) void MainWindow::changeDbPass() { Passwd pass; - QString tempn = dbfile + "{recrypt}"; + XSqlQuery q; if (!checkOldGetNewPass(pass)) return; - try { - if (!QFile::copy(dbfile, tempn)) - throw errorEx("Could not create temporary file: " + - tempn); - - QString passhash = updateDbPassword(tempn, pass); - QFile new_file(tempn); - /* closing the database erases 'dbfile' */ - QString dbfile_bkup = dbfile; - close_database(); - db mydb(dbfile_bkup); - if (mydb.mv(new_file)) - throw errorEx(QString("Failed to rename %1 to %2"). - arg(tempn).arg(dbfile_bkup)); - dbfile = dbfile_bkup; - pki_evp::passHash = passhash; - pki_evp::passwd = pass; - init_database(); - } catch (errorEx &ex) { - QFile::remove(tempn); - Error(ex); - } -} - -QString MainWindow::updateDbPassword(QString newdb, Passwd pass) -{ - db mydb(newdb); - QString salt = makeSalt(); - QString passhash = pki_evp::sha512passwd(pass, salt); - mydb.set((const unsigned char *)CCHAR(passhash), - passhash.length()+1, 1, setting, "pwhash"); + QString passhash = pki_evp::sha512passwT(pass, salt); + QList key_list = keys->sqlSELECTpki( + "SELECT item FROM private_keys WHERE ownPass=0"); - QList klist; - mydb.first(); - while (mydb.find(asym_key, QString()) == 0) { - QString s; - pki_evp *key; - unsigned char *p; - db_header_t head; - - p = mydb.load(&head); - if (!p) - throw errorEx("Failed to load item"); - key = new pki_evp(); - if (key->getVersion() < head.version) { - int v = key->getVersion(); - free(p); - delete key; - throw errorEx(QString("Item[%1]: Version %2 " - "> known version: %3 -> ignored") - .arg(head.name).arg(head.version).arg(v) - ); - } - key->setIntName(QString::fromUtf8(head.name)); - - try { - key->fromData(p, &head); - } - catch (errorEx &err) { - err.appendString(key->getIntName()); - free(p); - delete key; - throw err; - } - free(p); - if (key && key->getOwnPass() == pki_key::ptCommon && - !key->isPubKey()) - { + if (!db.transaction()) { + errorEx e(tr("Transaction start failed")); + Error(e); + return; + } + try { + foreach(pki_base *pki, key_list) { + pki_evp *key = static_cast(pki); EVP_PKEY *evp = key->decryptKey(); key->set_evp_key(evp); key->encryptKey(pass.constData()); - klist << key; - } else if (key) - delete key; - - if (mydb.next()) - break; + key->sqlUpdatePrivateKey(); + } + storeSetting("pwhash", passhash); + } catch (errorEx &e) { + Error(e); + db.rollback(); + return; } - for (int i=0; i< klist.count(); i++) { - pki_evp *key = klist[i]; - QByteArray ba = key->toData(); - mydb.set((const unsigned char*)ba.constData(), ba.count(), - key->getVersion(), key->getType(), key->getIntName()); - delete key; - } - return passhash; + db.commit(); + pki_evp::passHash = passhash; + pki_evp::passwd = pass; } int MainWindow::initPass() { - db mydb(dbfile); - char *pass; + QString passhash = getSetting("pwhash"); + return initPass(passhash); +} + +int MainWindow::initPass(QString passhash) +{ pki_evp::passHash = QString(); - QString salt; + QString salt, pass; int ret; pass_info p(tr("New Password"), tr("Please enter a password, " @@ -754,23 +701,17 @@ int MainWindow::initPass() "in the database file:\n%1"). arg(compressFilename(dbfile)), this); - if (!mydb.find(setting, "pwhash")) { - if ((pass = (char *)mydb.load(NULL))) { - pki_evp::passHash = pass; - free(pass); - } - } + pki_evp::passHash = passhash; if (pki_evp::passHash.isEmpty()) { ret = PwDialog::execute(&p, &pki_evp::passwd, true, true); if (ret != 1) return ret; salt = makeSalt(); - pki_evp::passHash = pki_evp::sha512passwd(pki_evp::passwd,salt); - mydb.set((const unsigned char *)CCHAR(pki_evp::passHash), - pki_evp::passHash.length()+1, 1, setting, "pwhash"); + pki_evp::passHash =pki_evp::sha512passwT(pki_evp::passwd,salt); + storeSetting("pwhash", pki_evp::passHash); } else { ret = 0; - while (pki_evp::sha512passwd(pki_evp::passwd, pki_evp::passHash) + while (pki_evp::sha512passwT(pki_evp::passwd, pki_evp::passHash) != pki_evp::passHash) { if (ret) @@ -784,21 +725,25 @@ int MainWindow::initPass() pki_evp::passwd = QByteArray(); return ret; } - if (pki_evp::passHash.left(1) == "S") + if (pki_evp::passHash.startsWith("T")) { + /* Fine, current hash function used. */ continue; + } + /* Start automatic update from sha512 to sha512*8000 + * if the password is correct. The old sha512 hash does + * start with 'S', while the new hash starts with T. */ + /* Start automatic update from md5 to salted sha512 - * if the password is correct. my md5 hash does not - * start with 'S', while my new hash does. */ - if (pki_evp::md5passwd(pki_evp::passwd) == - pki_evp::passHash ) + * if the password is correct. The md5 hash does not + * start with 'S' or 'T, but with a hex-digit */ + if (pki_evp::sha512passwd(pki_evp::passwd, + pki_evp::passHash) == pki_evp::passHash || + pki_evp::md5passwd(pki_evp::passwd) == + pki_evp::passHash) { salt = makeSalt(); - pki_evp::passHash = pki_evp::sha512passwd( + pki_evp::passHash = pki_evp::sha512passwT( pki_evp::passwd, salt); - mydb.set((const unsigned char *)CCHAR( - pki_evp::passHash), - pki_evp::passHash.length() +1, 1, - setting, "pwhash"); } } } @@ -830,22 +775,18 @@ QString MainWindow::getPath() void MainWindow::setPath(QString str) { - db mydb(dbfile); workingdir = str; - mydb.set((const unsigned char *)CCHAR(str), str.length()+1, 1, setting, "workingdir"); -} - -void MainWindow::setDefaultKey(QString str) -{ - db mydb(dbfile); - mydb.set((const unsigned char *)CCHAR(str), str.length()+1, 1, setting, "defaultkey"); + storeSetting("workingdir", str); } void MainWindow::connNewX509(NewX509 *nx) { - connect( nx, SIGNAL(genKey(QString)), keys, SLOT(newItem(QString)) ); - connect( keys, SIGNAL(keyDone(QString)), nx, SLOT(newKeyDone(QString)) ); - connect( nx, SIGNAL(showReq(QString)), reqs, SLOT(showItem(QString))); + connect(nx, SIGNAL(genKey(QString)), + keys, SLOT(newItem(QString))); + connect(keys, SIGNAL(keyDone(pki_key*)), + nx, SLOT(newKeyDone(pki_key*))); + connect(nx, SIGNAL(showReq(pki_base*)), + reqs, SLOT(showPki(pki_base*))); } void MainWindow::importAnything(QString file) @@ -862,22 +803,14 @@ void MainWindow::importAnything(QString file) pki_multi *MainWindow::probeAnything(QString file, int *ret) { + (void)ret; pki_multi *pki = new pki_multi(); try { if (file.endsWith(".xdb")) { - try { - int r; - db *mydb = new db(file); - mydb->verify_magic(); - delete mydb; - r = changeDB(file); - delete pki; - if (ret) - *ret = r; - return NULL; - } catch (errorEx &err) { - } +#warning FIXME OPEN DATABASE + qDebug("FIXME OPEN DATABASE"); + return pki; } pki->probeAnything(file); } catch (errorEx &err) { diff --git a/widgets/MainWindow.h b/widgets/MainWindow.h index 9f728c9e..f294617c 100644 --- a/widgets/MainWindow.h +++ b/widgets/MainWindow.h @@ -24,13 +24,12 @@ #include #include #include +#include #include #include #include #include -#define DBFILE "xca.xdb" - class db_x509; class pki_multi; @@ -81,12 +80,15 @@ class MainWindow: public QMainWindow, public Ui::MainWindow QStringList history; tipMenu *historyMenu; void update_history_menu(); - void set_geometry(char *p, db_header_t *head); + void set_geometry(QString geo); QLineEdit *searchEdit; QStringList urlsToOpen; int checkOldGetNewPass(Passwd &pass); - QString updateDbPassword(QString newdb, Passwd pass); int exportIndex(QString fname, bool hierarchy); + void checkDB(); + QSqlError initSqlDB(); + QSqlError openSqlDB(); + QSqlDatabase db; protected: void init_images(); @@ -115,6 +117,10 @@ class MainWindow: public QMainWindow, public Ui::MainWindow static QString explicit_dn; static QString explicit_dn_default; int exitApp; + QSqlDatabase *getDb() + { + return &db; + } QString dbfile; QLabel *dbindex; @@ -123,6 +129,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void loadSettings(); void saveSettings(); int initPass(); + int initPass(QString passhash); void read_cmdline(int argc, char *argv[]); void load_engine(); static OidResolver *getResolver() @@ -130,6 +137,10 @@ class MainWindow: public QMainWindow, public Ui::MainWindow return resolver; } static void Error(errorEx &err); + static void dbSqlError(QSqlError err = QSqlError()); + static void storeSetting(QString key, QString value); + static QString getSetting(QString key); + void cmd_version(); void cmd_help(const char* msg); @@ -143,10 +154,12 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void dropEvent(QDropEvent *event); void dragEnterEvent(QDragEnterEvent *event); int open_default_db(); - void setDefaultKey(QString def); void load_history(); void update_history(QString file); void initResolver(); + bool checkForOldDbFormat(); + int verifyOldDbPass(QString dbname); + void importOldDatabase(QString dbname); public slots: int init_database(); @@ -158,10 +171,9 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void connNewX509(NewX509 *nx); void about(); void help(); - void import_dbdump(); void undelete(); void loadPem(); - bool pastePem(QString text); + bool pastePem(QString text, bool silent=false); void pastePem(); void changeDbPass(); void openURLs(QStringList &files); diff --git a/widgets/NewCrl.cpp b/widgets/NewCrl.cpp index b2dc39fe..6f3c7401 100644 --- a/widgets/NewCrl.cpp +++ b/widgets/NewCrl.cpp @@ -18,11 +18,9 @@ #include NewCrl::NewCrl(QWidget *parent, pki_x509 *signer) - :QDialog(parent) + :QWidget(parent) { setupUi(this); - setWindowTitle(XCA_TITLE); - image->setPixmap(*MainWindow::revImg); dateBox->setTitle(signer->getIntName()); validNumber->setText(QString::number(signer->getCrlDays())); validRange->setCurrentIndex(0); diff --git a/widgets/NewCrl.h b/widgets/NewCrl.h index c17a4dbd..e9d349af 100644 --- a/widgets/NewCrl.h +++ b/widgets/NewCrl.h @@ -13,7 +13,7 @@ class pki_key; -class NewCrl: public QDialog, public Ui::NewCrl +class NewCrl: public QWidget, public Ui::NewCrl { Q_OBJECT diff --git a/widgets/NewKey.cpp b/widgets/NewKey.cpp index eb76988d..cd28f3e6 100644 --- a/widgets/NewKey.cpp +++ b/widgets/NewKey.cpp @@ -9,9 +9,10 @@ #include "NewKey.h" #include "MainWindow.h" #include "lib/pki_evp.h" -#include "widgets/distname.h" -#include "widgets/clicklabel.h" #include "lib/pkcs11.h" +#include "distname.h" +#include "clicklabel.h" +#include "ItemCombo.h" #include #include #include diff --git a/widgets/NewX509.cpp b/widgets/NewX509.cpp index 8ab2f82f..e0424c94 100644 --- a/widgets/NewX509.cpp +++ b/widgets/NewX509.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "MainWindow.h" #include "v3ext.h" #include "lib/x509name.h" @@ -69,29 +71,30 @@ NewX509::NewX509(QWidget *parent) nsImg->setPixmap(*MainWindow::nsImg); serialNr->setValidator(new QRegExpValidator(QRegExp("[0-9a-fA-F]*"), this)); - QStringList strings; + QList requests; // are there any useable private keys ? - newKeyDone(""); + newKeyDone(NULL); // any PKCS#10 requests to be used ? - strings = MainWindow::reqs->getDesc(); - if (strings.isEmpty()) { + requests = MainWindow::reqs->getAllRequests(); + if (requests.isEmpty()) { fromReqCB->setDisabled(true); fromReqCB->setChecked(false); } else { - reqList->insertItems(0, strings); + reqList->insertPkiItems(requests); } on_fromReqCB_clicked(); // How about signing certificates ? - strings = MainWindow::certs->getSignerDesc(); - if (strings.isEmpty()) { + QList issuers = MainWindow::certs->getAllIssuers(); + if (issuers.isEmpty()) { foreignSignRB->setDisabled(true); } else { - certList->insertItems(0, strings); + certList->insertPkiItems(issuers); } +#warning "Remove WG_QA_SERIAL finally! :-)" #ifdef WG_QA_SERIAL selfQASignRB = new QRadioButton(signerBox); setTabOrder(serialNr, selfQASignRB); @@ -102,14 +105,13 @@ NewX509::NewX509(QWidget *parent) l->insertWidget(1, selfQASignRB); #endif // set dates to now and now + 1 year - validNumber->setText("1"); + validN->setText("1"); validRange->setCurrentIndex(2); on_applyTime_clicked(); // settings for the templates .... - strings.clear(); - strings = MainWindow::temps->getDescPredefs(); - tempList->insertItems(0, strings); + QList templates = MainWindow::temps->getDescPredefs(); + tempList->insertPkiItems(templates); // setup Extended keyusage foreach(int nid, eku_nid) @@ -276,6 +278,30 @@ NewX509::NewX509(QWidget *parent) } if (pki_x509::disable_netscape) tabWidget->removeTab(4); + + // Setup widget <-> Template mapping +#define MAP_LE(name) templateLineEdits[#name] = name; + MAP_LE(subAltName); + MAP_LE(issAltName); + MAP_LE(crlDist); + MAP_LE(nsComment); + MAP_LE(nsBaseUrl); + MAP_LE(nsRevocationUrl); + MAP_LE(nsCARevocationUrl); + MAP_LE(nsRenewalUrl); + MAP_LE(nsCaPolicyUrl); + MAP_LE(nsSslServerName); + MAP_LE(validN); + MAP_LE(basicPath); + +#define MAP_CB(name) templateCheckBoxes[#name] = name; + MAP_CB(bcCritical); + MAP_CB(kuCritical); + MAP_CB(ekuCritical); + MAP_CB(subKey); + MAP_CB(authKey); + MAP_CB(validMidn); + MAP_CB(noWellDefinedExpDate); } void NewX509::setRequest() @@ -344,18 +370,15 @@ void NewX509::setReqAttributes(pki_x509req *req) /* Initialize dialog for Template creation */ void NewX509::setTemp(pki_temp *temp) { - QString text = tr("Create XCA template"); - if (temp->getIntName() != "--") { - description->setText(temp->getIntName()); - description->setDisabled(true); - text = tr("Edit XCA template"); - } - capt->setText(text); + description->setText(temp->getIntName()); + capt->setText(tr("Edit XCA template")); tabWidget->removeTab(0); privKeyBox->setEnabled(false); validityBox->setEnabled(false); setImage(MainWindow::tempImg); pt = tmpl; + fromTemplate(temp); + comment->setPlainText(temp->getComment()); } /* Initialize dialog for Certificate creation */ @@ -381,17 +404,15 @@ void NewX509::defineTemplate(pki_temp *temp) /* Select a Request for signing it */ void NewX509::defineRequest(pki_x509req *req) { - if (!req) - return; fromReqCB->setEnabled(true); fromReqCB->setChecked(true); - QString reqname = req->getIntName(); - reqList->setCurrentIndex(reqList->findText(reqname)); + reqList->setCurrentPkiItem(req); on_fromReqCB_clicked(); } /* Preset all values from another request to create a similar one */ void NewX509::fromX509super(pki_x509super *cert_or_req, bool applyTemp) +void NewX509::fromX509super(pki_x509super *cert_or_req) { pki_temp *temp = new pki_temp(""); temp->fromCert(cert_or_req); @@ -402,8 +423,7 @@ void NewX509::fromX509super(pki_x509super *cert_or_req, bool applyTemp) pki_key *key = cert_or_req->getRefKey(); if (key) { usedKeysToo->setChecked(true); - keyList->setCurrentIndex(private_keys.indexOf( - key->getIntNameWithType())); + keyList->setCurrentPkiItem(key); } hashAlgo->setCurrentMD(cert_or_req->getDigest()); @@ -434,17 +454,14 @@ void NewX509::fromX509super(pki_x509super *cert_or_req, bool applyTemp) /* Preset the signing certificate */ void NewX509::defineSigner(pki_x509 *defcert, bool applyTemp) { - int index; // suggested from: Andrey Brindeew if (defcert && defcert->canSign() ) { - QString name = defcert->getIntName(); - foreignSignRB->setChecked(true); - certList->setEnabled(true); - if ((index = certList->findText(name)) >= 0) { - certList->setCurrentIndex(index); - } - if (applyTemp && !defcert->getTemplate().isEmpty()) { - on_applyTemplate_clicked(); + if (certList->setCurrentPkiItem(defcert) != -1) { + foreignSignRB->setChecked(true); + certList->setEnabled(true); + if (applyTemp && defcert->getTemplate()) { + on_applyTemplate_clicked(); + } } } } @@ -503,39 +520,33 @@ static QString lb2QString(QListWidget *lb) void NewX509::subjectFromTemplate(pki_temp *temp) { if (temp) - setX509name(temp->xname); + setX509name(temp->getSubject()); } + void NewX509::extensionsFromTemplate(pki_temp *temp) { if (!temp) return; - subAltName->setText(temp->subAltName); - issAltName->setText(temp->issAltName); - crlDist->setText(temp->crlDist); - setAuthInfAcc_string(temp->authInfAcc); - nsComment->setText(temp->nsComment); - nsBaseUrl->setText(temp->nsBaseUrl); - nsRevocationUrl->setText(temp->nsRevocationUrl); - nsCARevocationUrl->setText(temp->nsCARevocationUrl); - nsRenewalUrl->setText(temp->nsRenewalUrl); - nsCaPolicyUrl->setText(temp->nsCaPolicyUrl); - nsSslServerName->setText(temp->nsSslServerName); - int2lb(nsCertType, temp->nsCertType); - basicCA->setCurrentIndex(temp->ca); - bcCritical->setChecked(temp->bcCrit); - kuCritical->setChecked(temp->keyUseCrit); - ekuCritical->setChecked(temp->eKeyUseCrit); - subKey->setChecked(temp->subKey); - authKey->setChecked(temp->authKey); - int2lb(keyUsage, temp->keyUse); - QString2lb(ekeyUsage, temp->eKeyUse); - validNumber->setText(QString::number(temp->validN)); - validRange->setCurrentIndex(temp->validM); - midnightCB->setChecked(temp->validMidn); - basicPath->setText(temp->pathLen); - nconf_data->document()->setPlainText(temp->adv_ext); - noWellDefinedExpDate->setChecked(temp->noWellDefined); + + QMapIterator l(templateLineEdits); + while (l.hasNext()) { + l.next(); + l.value()->setText(temp->getSetting(l.key())); + } + QMapIterator i(templateCheckBoxes); + while (i.hasNext()) { + i.next(); + i.value()->setChecked(temp->getSettingInt(i.key())); + } + int2lb(nsCertType, temp->getSettingInt("nsCertType")); + basicCA->setCurrentIndex(temp->getSettingInt("ca")); + int2lb(keyUsage, temp->getSettingInt("keyUse")); + QString2lb(ekeyUsage, temp->getSetting("eKeyUse")); + validRange->setCurrentIndex(temp->getSettingInt("validM")); + nconf_data->document()->setPlainText(temp->getSetting("adv_ext")); + setAuthInfAcc_string(temp->getSetting("authInfAcc")); + on_applyTime_clicked(); } @@ -548,39 +559,35 @@ void NewX509::fromTemplate(pki_temp *temp) void NewX509::toTemplate(pki_temp *temp) { temp->setIntName(description->text()); - temp->xname = getX509name(); - temp->subAltName = subAltName->text(); - temp->issAltName = issAltName->text(); - temp->crlDist = crlDist->text(); - temp->authInfAcc = getAuthInfAcc_string(); - temp->nsComment = nsComment->text(); - temp->nsBaseUrl = nsBaseUrl->text(); - temp->nsRevocationUrl = nsRevocationUrl->text(); - temp->nsCARevocationUrl = nsCARevocationUrl->text(); - temp->nsRenewalUrl = nsRenewalUrl->text(); - temp->nsCaPolicyUrl = nsCaPolicyUrl->text(); - temp->nsSslServerName = nsSslServerName->text(); - temp->nsCertType = lb2int(nsCertType); - temp->ca = basicCA->currentIndex(); - temp->bcCrit = bcCritical->isChecked(); - temp->keyUseCrit = kuCritical->isChecked(); - temp->eKeyUseCrit = ekuCritical->isChecked(); - temp->subKey = subKey->isChecked(); - temp->authKey = authKey->isChecked(); - temp->keyUse = lb2int(keyUsage); - temp->eKeyUse = lb2QString(ekeyUsage); - temp->validN = validNumber->text().toInt(); - temp->validM = validRange->currentIndex(); - temp->pathLen = basicPath->text(); - if (!temp->pathLen.isEmpty()) - temp->pathLen = QString::number(temp->pathLen.toInt()); - temp->validMidn = midnightCB->isChecked(); - if (nconf_data->isReadOnly()) { - temp->adv_ext = v3ext_backup; - } else { - temp->adv_ext = nconf_data->toPlainText(); + temp->setSubject(getX509name()); + + QMapIterator l(templateLineEdits); + while (l.hasNext()) { + l.next(); + temp->setSetting(l.key(), l.value()->text()); } - temp->noWellDefined = noWellDefinedExpDate->isChecked(); + QMapIterator i(templateCheckBoxes); + while (i.hasNext()) { + i.next(); + temp->setSetting(i.key(), i.value()->isChecked()); + } + + temp->setSetting("authInfAcc", getAuthInfAcc_string()); + temp->setSetting("nsCertType", lb2int(nsCertType)); + temp->setSetting("ca", basicCA->currentIndex()); + temp->setSetting("keyUse", lb2int(keyUsage)); + temp->setSetting("eKeyUse", lb2QString(ekeyUsage)); + temp->setSetting("validN", validN->text().toInt()); + temp->setSetting("validM", validRange->currentIndex()); + if (!temp->getSetting("basicPath").isEmpty()) + temp->setSetting("basicPath", temp->getSettingInt("basicPath")); + if (nconf_data->isReadOnly()) { + temp->setSetting("adv_ext", v3ext_backup); + } else { + temp->setSetting("adv_ext", nconf_data->toPlainText()); + } + + temp->setComment(comment->toPlainText()); } void NewX509::on_fromReqCB_clicked() @@ -649,8 +656,7 @@ void NewX509::switchHashAlgo() void NewX509::on_showReqBut_clicked() { - QString req = reqList->currentText(); - emit showReq(req); + emit showReq(reqList->currentPkiItem()); } void NewX509::on_genKeyBut_clicked() @@ -673,7 +679,7 @@ void NewX509::on_certList_currentIndexChanged(int) if (!cert) return; - QString templ = cert->getTemplate(); + pki_temp *templ = cert->getTemplate(); snb = cert->getNotBefore(); sna = cert->getNotAfter(); if (snb > notBefore->getDate()) @@ -681,10 +687,8 @@ void NewX509::on_certList_currentIndexChanged(int) if (sna < notAfter->getDate()) notAfter->setDate(sna); - if (templ.isEmpty()) - return; - - templateChanged(templ); + if (templ) + templateChanged(templ); } @@ -702,33 +706,46 @@ void NewX509::templateChanged(QString tempname) void NewX509::templateChanged(pki_temp *templ) { - QString tempname = templ->getIntName(); - templateChanged(tempname); + tempList->setCurrentPkiItem(templ); } pki_temp *NewX509::currentTemplate() { if (!tempList->isEnabled()) return NULL; - QString name = tempList->currentText(); - if (name.isEmpty()) - return NULL; - return (pki_temp *)MainWindow::temps->getByName(name); + return static_cast(tempList->currentPkiItem()); +} + +void NewX509::selfComment(QString msg) +{ + QString c = comment->toPlainText(); + if (!c.endsWith("\n")) + c += "\n"; + c += QString("(%1)\n").arg(msg); + comment->setPlainText(c); } void NewX509::on_applyTemplate_clicked() { - fromTemplate(currentTemplate()); + pki_temp *t = currentTemplate(); + fromTemplate(t); + selfComment(tr("Template '%1' applied").arg(t->comboText())); } void NewX509::on_applySubject_clicked() { - subjectFromTemplate(currentTemplate()); + pki_temp *t = currentTemplate(); + subjectFromTemplate(t); + selfComment(tr("Subject applied from template '%1'") + .arg(t->comboText())); } void NewX509::on_applyExtensions_clicked() { - extensionsFromTemplate(currentTemplate()); + pki_temp *t = currentTemplate(); + extensionsFromTemplate(t); + selfComment(tr("Extensions applied from template '%1'") + .arg(t->comboText())); } void NewX509::on_foreignSignRB_toggled(bool) @@ -736,51 +753,42 @@ void NewX509::on_foreignSignRB_toggled(bool) switchHashAlgo(); } -void NewX509::newKeyDone(QString name) +void NewX509::newKeyDone(pki_key *nkey) { - QStringList keys; - private_keys = MainWindow::keys->get0KeyDesc(true); - private_keys0 = MainWindow::keys->get0KeyDesc(false); - keyList->clear(); - if (usedKeysToo->isChecked()) - keys = private_keys; - else - keys = private_keys0; - - keyList->insertItems(0, keys); - if (name.isEmpty() && keys.count() >0) - name = keys[0]; - keyList->setCurrentIndex(keys.indexOf(name)); + allKeys = MainWindow::keys->getAllKeys(); + unusedKeys= MainWindow::keys->getUnusedKeys(); + on_usedKeysToo_toggled(true); + if (nkey) { + selfComment(tr("New key '%1' created") + .arg(nkey->comboText())); + keyList->setCurrentPkiItem(nkey); + } else { + keyList->setCurrentIndex(0); + } } void NewX509::on_usedKeysToo_toggled(bool) { - QString cur = keyList->currentText(); - QStringList keys; + pki_base *cur = keyList->currentPkiItem(); keyList->clear(); - if (usedKeysToo->isChecked()) - keys = private_keys; - else - keys = private_keys0; - - keyList->insertItems(0, keys); - keyList->setCurrentIndex(keys.indexOf(cur)); + keyList->insertPkiItems(usedKeysToo->isChecked() ? + allKeys : unusedKeys); + keyList->setCurrentPkiItem(cur); } pki_key *NewX509::getSelectedKey() { - QString name = pki_key::removeTypeFromIntName(keyList->currentText()); - return (pki_key *)MainWindow::keys->getByName(name); + return (pki_key*)keyList->currentPkiItem(); } pki_x509 *NewX509::getSelectedSigner() { - return (pki_x509 *)MainWindow::certs->getByName(certList->currentText()); + return (pki_x509 *)certList->currentPkiItem(); } pki_x509req *NewX509::getSelectedReq() { - return (pki_x509req *)MainWindow::reqs->getByName(reqList->currentText()); + return (pki_x509req *)reqList->currentPkiItem(); } x509name NewX509::getX509name(int _throw) @@ -848,7 +856,7 @@ void NewX509::setX509name(const x509name &n) void NewX509::on_applyTime_clicked() { - notAfter->setDiff(notBefore, validNumber->text().toInt(), + notAfter->setDiff(notBefore, validN->text().toInt(), validRange->currentIndex()); } diff --git a/widgets/NewX509.h b/widgets/NewX509.h index fc1388e5..7407fa95 100644 --- a/widgets/NewX509.h +++ b/widgets/NewX509.h @@ -55,13 +55,17 @@ class NewX509: public QDialog, public Ui::NewX509 enum pki_type pt; void templateChanged(QString templatename); QString mandatoryDnRemain(); - QStringList private_keys, private_keys0, tabnames; + QStringList tabnames; + QList unusedKeys, allKeys; pki_x509 *ctx_cert; QString v3ext_backup; kvmodel *extDNmodel; extList getExtDuplicates(); void checkIcon(const QString &text, int nid, QLabel*img); QString dnEntryByNid(int nid); + void selfComment(QString msg); + QMap templateLineEdits; + QMap templateCheckBoxes; public: QRadioButton *selfQASignRB; @@ -119,7 +123,7 @@ class NewX509: public QDialog, public Ui::NewX509 void on_fromReqCB_clicked(); void on_keyList_currentIndexChanged(const QString &); void on_reqList_currentIndexChanged(const QString &); - void newKeyDone(QString name); + void newKeyDone(pki_key *nkey); void on_applyTime_clicked(); void on_editSubAlt_clicked(); void on_editIssAlt_clicked(); @@ -145,7 +149,7 @@ class NewX509: public QDialog, public Ui::NewX509 signals: void genKey(QString); - void showReq(QString req); + void showReq(pki_base *req); }; #endif diff --git a/widgets/Options.cpp b/widgets/Options.cpp index 2c43d44a..6909caf3 100644 --- a/widgets/Options.cpp +++ b/widgets/Options.cpp @@ -18,7 +18,7 @@ Options::Options(MainWindow *parent) { mw = parent; - setWindowTitle(tr(XCA_TITLE)); + setWindowTitle(XCA_TITLE); setupUi(this); foreach(int nid, *MainWindow::dn_nid) { diff --git a/widgets/PwDialog.cpp b/widgets/PwDialog.cpp index 6e6dbd09..d2868583 100644 --- a/widgets/PwDialog.cpp +++ b/widgets/PwDialog.cpp @@ -39,7 +39,7 @@ int PwDialog::execute(pass_info *p, Passwd *passwd, bool write, bool abort) dlg = new PwDialog(p, write); if (abort) dlg->addAbortButton(); - ret = dlg->exec(); + ret = dlg->exec(); *passwd = dlg->getPass(); delete dlg; return ret; diff --git a/widgets/XcaDialog.h b/widgets/XcaDialog.h new file mode 100644 index 00000000..90e46fae --- /dev/null +++ b/widgets/XcaDialog.h @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __XCADIALOG_H +#define __XCADIALOG_H + +#include +#include +#include "ui_XcaDialog.h" +#include "lib/db.h" +#include "MainWindow.h" + +class XcaDialog : public QDialog, public Ui::XcaDialog +{ + QWidget *widg; + public: + XcaDialog(QWidget *parent, enum pki_type type, QWidget *w, + QString t, QString desc) : QDialog(parent) + { + setWindowTitle(XCA_TITLE); + setupUi(this); + + QPixmap *icon = NULL; + switch (type) { + case asym_key: icon = MainWindow::keyImg; break; + case x509_req: icon = MainWindow::csrImg; break; + case x509: icon = MainWindow::certImg; break; + case revocation: icon = MainWindow::revImg; break; + case tmpl: icon = MainWindow::tempImg; break; + case smartCard: icon = MainWindow::scardImg; break; + default: break; + } + if (icon) + image->setPixmap(*icon); + content->addWidget(w); + widg = w; + title->setText(t); + if (desc.isEmpty()) { + verticalLayout->removeWidget(description); + delete description; + } else { + description->setText(desc); + } + } + void noSpacer() + { + verticalLayout->removeItem(topSpacer); + verticalLayout->removeItem(bottomSpacer); + delete topSpacer; + delete bottomSpacer; + if (widg) + widg->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding); + } + void aboutDialog(QPixmap *lefticon) + { + QPixmap left = *lefticon; + title->setPixmap(left.scaledToHeight(title->height())); + noSpacer(); + resize(560, 400); + buttonBox->setStandardButtons(QDialogButtonBox::Ok); + buttonBox->centerButtons(); + } +}; + +#endif diff --git a/widgets/XcaProxyModel.cpp b/widgets/XcaProxyModel.cpp index 10f31e11..c0013852 100644 --- a/widgets/XcaProxyModel.cpp +++ b/widgets/XcaProxyModel.cpp @@ -15,6 +15,10 @@ bool XcaProxyModel::lessThan(const QModelIndex &left, if (!db) return QSortFilterProxyModel::lessThan(left, right); + if (left.column() < 0 || right.column() < 0) { + qDebug("BAD COLUMN: %d %d\n", left.column(), right.column()); + return true; + } if (db->isNumericCol(left.column()) && db->isNumericCol(right.column())) { diff --git a/widgets/XcaTreeView.cpp b/widgets/XcaTreeView.cpp index d81c5438..d1aed929 100644 --- a/widgets/XcaTreeView.cpp +++ b/widgets/XcaTreeView.cpp @@ -275,6 +275,12 @@ void XcaTreeView::doubleClick(const QModelIndex &m) basemodel->showItem(getIndex(m)); } +void XcaTreeView::editComment(void) +{ + if (basemodel) + basemodel->editComment(currentIndex()); +} + void XcaTreeView::pem2clipboard(void) { if (basemodel) @@ -393,9 +399,10 @@ void XcaTreeView::showContextMenu(QContextMenuEvent *e, menu->addAction(tr("Import"), this, SLOT(load())); menu->addAction(tr("Paste PEM data"), mainwin, SLOT(pastePem())); - if (indexes.size() == 1) + if (indexes.size() == 1) { menu->addAction(tr("Rename"), this, SLOT(editIdx())); - + menu->addAction(tr("Edit comment"), this, SLOT(editComment())); + } if (indexes.size() > 0) { menu->addAction(tr("Delete"), this, SLOT(deleteItems())); subExport = menu->addMenu(tr("Export")); diff --git a/widgets/XcaTreeView.h b/widgets/XcaTreeView.h index d6ac63f1..5216ed8b 100644 --- a/widgets/XcaTreeView.h +++ b/widgets/XcaTreeView.h @@ -64,5 +64,6 @@ class XcaTreeView: public QTreeView void headerDetails(void); void columnRemove(void); void columnsChanged(void); + void editComment(void); }; #endif diff --git a/xca.pro b/xca.pro index ab2ed139..9956f3f3 100644 --- a/xca.pro +++ b/xca.pro @@ -101,10 +101,11 @@ HEADERS += lib/asn1int.h \ widgets/X509SuperTreeView.h \ widgets/XcaHeaderView.h \ widgets/OidResolver.h \ + widgets/ItemCombo.h \ + widgets/XcaDialog.h \ widgets/XcaProxyModel.h -FORMS += ui/About.ui \ - ui/CaProperties.ui \ +FORMS += ui/CaProperties.ui \ ui/CertDetail.ui \ ui/CertExtend.ui \ ui/CrlDetail.ui \ @@ -120,10 +121,10 @@ FORMS += ui/About.ui \ ui/PwDialog.ui \ ui/Revoke.ui \ ui/SelectToken.ui \ - ui/TrustState.ui \ ui/SearchPkcs11.ui \ ui/v3ext.ui \ ui/OidResolver.ui \ + ui/XcaDialog.ui \ ui/RevocationList.ui SOURCES += lib/asn1int.cpp \ @@ -138,7 +139,6 @@ SOURCES += lib/asn1int.cpp \ lib/db_x509req.cpp \ lib/db_x509super.cpp \ lib/func.cpp \ - lib/import.cpp \ lib/load_obj.cpp \ lib/main.cpp \ lib/oid.cpp \