diff --git a/Makefile b/Makefile index 66a1a967..5b941281 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,6 @@ $(DMGSTAGE): xca$(SUFFIX) xca_db_stat$(SUFFIX) ln -s xca.html $(DMGSTAGE)/manual/index.html $(MACDEPLOYQT) $(DMGSTAGE)/xca.app codesign -s "Open Source Developer, Christian Hohnstaedt" $(DMGSTAGE)/xca.app - tar zcf $(MACTARGET).tar.gz $(DMGSTAGE) xca.dmg: $(MACTARGET).dmg diff --git a/Rules.mak b/Rules.mak index e76f3d45..d21a9218 100644 --- a/Rules.mak +++ b/Rules.mak @@ -8,7 +8,7 @@ CPPFLAGS += -I$(TOPDIR) -I$(BUILD) -I$(BUILD)/ui all: .build-stamp .build-stamp: $(OBJS) - echo $(patsubst %, $(shell pwd)/%, $(OBJS)) > $@ + for i in $(patsubst %, $(shell pwd)/%, $(OBJS)); do echo $$i; done > $@ @$(PRINT) " DONE [$(BASENAME)]" SRCS=$(patsubst %.o, %.cpp, $(OBJS)) diff --git a/lib/db_base.cpp b/lib/db_base.cpp index 3f984af6..2829bc34 100644 --- a/lib/db_base.cpp +++ b/lib/db_base.cpp @@ -97,7 +97,7 @@ int db_base::handleBadEntry(unsigned char *p, db_header_t *head) size_t l; db_header_t h; - FILE *fp = fopen(QString2filename(s), "w"); + FILE *fp = fopen(QString2filename(s), "wb"); if (!fp) { throw errorEx(tr("Error opening file: '%1': %2"). arg(s).arg(strerror(errno)), class_name); @@ -287,47 +287,41 @@ void db_base::insertPKI(pki_base *pki) emit columnsContentChanged(); } -void db_base::delete_ask() +QString db_base::pem2QString(QModelIndexList indexes) { - if (!currentIdx.isValid()) - return; - pki_base *pki = static_cast(currentIdx.internalPointer()); - - if (!XCA_OKCANCEL(pki->getMsg(pki_base::msg_delete).arg(pki->getIntName()))) - return; - - deletePKI(); -} - -void db_base::pem2clipboard() -{ - long l; - const char *p; exportType::etype format; QString msg; + + format = clipboardFormat(indexes); + foreach(QModelIndex idx, indexes) { + long l; + const char *p; + BIO *bio = BIO_new(BIO_s_mem()); + pki_base *pki = static_cast + (idx.internalPointer()); + pki->pem(bio, format); + openssl_error(); + l = BIO_get_mem_data(bio, &p); + msg += QString::fromUtf8(p, l); + BIO_free(bio); + } + return msg; +} + +void db_base::pem2clipboard(QModelIndexList indexes) +{ + QString msg = pem2QString(indexes); QClipboard *cb = QApplication::clipboard(); - BIO *bio = BIO_new(BIO_s_mem()); - if (!currentIdx.isValid()) - return; - pki_base *pki = static_cast(currentIdx.internalPointer()); - format = clipboardFormat(); - pki->pem(bio, format); - openssl_error(); - l = BIO_get_mem_data(bio, &p); - msg = QString::fromUtf8(p, l); - BIO_free(bio); if (cb->supportsSelection()) cb->setText(msg, QClipboard::Selection); else cb->setText(msg); } -void db_base::deletePKI() +void db_base::deletePKI(QModelIndex idx) { - if (!currentIdx.isValid()) - return; - pki_base *pki = static_cast(currentIdx.internalPointer()); + pki_base *pki = static_cast(idx.internalPointer()); try { try { pki->deleteFromToken(); @@ -335,7 +329,7 @@ void db_base::deletePKI() MainWindow::Error(err); } - remFromCont(currentIdx); + remFromCont(idx); db mydb(dbName); mydb.find(pki->getType(), pki->getIntName()); @@ -358,84 +352,9 @@ void db_base::updatePKI(pki_base *pki) } } -void db_base::deleteSelectedItems(XcaTreeView* view) -{ - QModelIndexList indexes = view->getSelectedIndexes(); - QModelIndex index; - QString items, msg; - int count = 0; - pki_base *pki = NULL; - - if (indexes.count() == 0) - return; - - foreach(index, indexes) { - pki = static_cast(index.internalPointer()); - items += "'" + pki->getIntName() + "' "; - count++; - } - if (count == 1) - msg = pki->getMsg(pki_base::msg_delete).arg(pki->getIntName()); - else - msg = pki->getMsg(pki_base::msg_delete_multi).arg(count). - arg(items); - - if (!XCA_OKCANCEL(msg)) - return; - - foreach(index, indexes) { - currentIdx = index; - deletePKI(); - } - currentIdx = QModelIndex(); -} - -void db_base::showSelectedItems(XcaTreeView* view) -{ - QModelIndexList indexes = view->getSelectedIndexes(); - QModelIndex index; - QString items; - - foreach(index, indexes) { - currentIdx = index; - showItem(); - } - currentIdx = QModelIndex(); -} - - -void db_base::storeSelectedItems(XcaTreeView* view) -{ - QModelIndexList list = view->getSelectedIndexes(); - if (list.size() == 0) - return; - if (!currentIdx.isValid()) - currentIdx = list[0]; - store(list); -} - -void db_base::store(QModelIndexList list) -{ - QModelIndex index; - QString items; - - foreach(index, list) { - if (index.column() != 0) - continue; - try { - currentIdx = index; - store(); - } catch (errorEx &err) { - MainWindow::Error(err); - } - - } - currentIdx = QModelIndex(); -} - void db_base::showItem(const QModelIndex &index) { - showPki(static_cast(index.internalPointer())); + showPki(static_cast(index.internalPointer())); } void db_base::showItem(const QString name) @@ -542,6 +461,8 @@ QModelIndex db_base::index(int row, int column, const QModelIndex &parent) QModelIndex db_base::index(pki_base *pki) const { + if (!pki) + return QModelIndex(); return createIndex(pki->row(), 0, pki); } @@ -688,18 +609,45 @@ void db_base::load_default(load_base &load) delete dlgi; } -void db_base::edit() +void db_base::store(QModelIndexList indexes) { - if (!currentIdx.isValid()) - return; - emit editItem(currentIdx); -} + int ret; -void db_base::showItem() -{ - if (!currentIdx.isValid()) + xcaWarning msg(mainwin, tr("How to export the %1 selected items"). + arg(indexes.size())); + msg.addButton(QMessageBox::Ok)->setText(tr("All in one PEM file")); + msg.addButton(QMessageBox::Apply)->setText(tr("Each item in one file")); + msg.addButton(QMessageBox::Cancel); + ret = msg.exec(); + if (ret == QMessageBox::Apply) { + foreach(QModelIndex i, indexes) + store(i); return; - showItem(currentIdx); + } else if (ret != QMessageBox::Ok) { + return; + } + + QString fn = mainwin->getPath() + QDir::separator() + "export.pem"; + QString s = QFileDialog::getSaveFileName(mainwin, + tr("Save %1 items in one file as").arg(indexes.size()), fn, + tr("PEM Files( *.pem );; All files ( * )")); + if (s.isEmpty()) + return; + s = QDir::convertSeparators(s); + mainwin->setPath(s.mid(0, s.lastIndexOf(QRegExp("[/\\\\]")) )); + try { + QString pem = pem2QString(indexes); + FILE *fp = fopen(QString2filename(s), "wb"); + if (!fp) { + throw errorEx(tr("Error opening file: '%1': %2"). + arg(s).arg(strerror(errno)), class_name); + } + fwrite(pem.toAscii(), pem.size(), 1, fp); + fclose(fp); + } + catch (errorEx &err) { + MainWindow::Error(err); + } } bool db_base::columnHidden(int col) const @@ -723,86 +671,3 @@ bool db_base::isNumericCol(int col) const { return allHeaders[col]->isNumeric(); } - -void db_base::showHeaderMenu(QContextMenuEvent *e, int sect) -{ - contextMenu(e, NULL, sect); -} - -void db_base::contextMenu(QContextMenuEvent *e, QMenu *parent, int) -{ - int shown = 0; - tipMenu *menu, *dn, *v3ext, *current, *v3ns; - QAction *a, *sep; - dbheader *hd; - - menu = new tipMenu(QString(), mainwin); - dn = new tipMenu(tr("Subject entries"), mainwin); - v3ext = new tipMenu(tr("X509v3 Extensions"), mainwin); - v3ns = new tipMenu(tr("Netscape extensions"), mainwin); - menu->addAction(tr("Reset"), this, SLOT(columnResetDefaults())); - sep = menu->addSeparator(); - foreach(hd, allHeaders) { - switch (hd->type) { - case dbheader::hd_x509name: - current = dn; - break; - case dbheader::hd_v3ext: - current = v3ext; - break; - case dbheader::hd_v3ext_ns: - if (pki_x509::disable_netscape) - continue; - current = v3ns; - break; - default: - current = menu; - break; - } - a = current->addAction(hd->getName()); - a->setCheckable(true); - a->setChecked(hd->show); - a->setToolTip(hd->getTooltip()); - hd->action = a; - } - if (!dn->isEmpty() || !v3ext->isEmpty()) - menu->insertSeparator(sep); - - if (!dn->isEmpty()) - menu->insertMenu(sep, dn); - else - delete dn; - - if (!v3ext->isEmpty()) { - if (!v3ns->isEmpty()) { - v3ext->addSeparator(); - v3ext->addMenu(v3ns); - } else { - delete v3ns; - } - menu->insertMenu(sep, v3ext); - } else { - delete v3ext; - delete v3ns; - } - if (parent) { - parent->addAction(tr("Paste PEM data"), mainwin, - SLOT(pastePem())); - parent->addMenu(menu)->setText(tr("Columns")); - parent->exec(e->globalPos()); - } else { - menu->exec(e->globalPos()); - } - foreach(hd, allHeaders) { - if (hd->action) - hd->show = hd->action->isChecked(); - shown += hd->show ? 1 : 0; - hd->action = NULL; - } - if (!shown) - allHeaders[0]->show = true; - delete menu; - if (parent) - delete parent; - emit updateHeader(); -} diff --git a/lib/db_base.h b/lib/db_base.h index 503b1d1e..fb2ce66d 100644 --- a/lib/db_base.h +++ b/lib/db_base.h @@ -45,7 +45,8 @@ class db_base: public QAbstractItemModel virtual dbheaderList getHeaders(); int colResizing; int handleBadEntry(unsigned char *p, db_header_t *head); - virtual exportType::etype clipboardFormat() { + virtual exportType::etype clipboardFormat(QModelIndexList indexes) + { return exportType::Separator; } @@ -69,9 +70,6 @@ class db_base: public QAbstractItemModel QPixmap *loadImg(const char *name); void writeAll(void); void dump(QString dirname); - virtual void showContextMenu(QContextMenuEvent * , - const QModelIndex &) {}; - QModelIndex index(int row, int column, const QModelIndex &parent)const; QModelIndex index(pki_base *pki)const; QModelIndex parent(const QModelIndex &index) const; @@ -82,18 +80,13 @@ class db_base: public QAbstractItemModel int role) const; Qt::ItemFlags flags(const QModelIndex &index) const; bool setData(const QModelIndex &index, const QVariant &value, int role); - void deleteSelectedItems(XcaTreeView* view); - void showSelectedItems(XcaTreeView *view); - void storeSelectedItems(XcaTreeView *view); + void deleteSelectedItems(QModelIndexList indexes); void load_default(load_base &load); void insertChild(pki_base *parent, pki_base *child); void createSuccess(pki_base *pki); - void showHeaderMenu(QContextMenuEvent *e, int sect); bool columnHidden(int col) const; bool isNumericCol(int col) const; void saveHeaderState(); - void contextMenu(QContextMenuEvent *e, - QMenu *parent = NULL, int sect = -1); void initHeaderView(QHeaderView *hv); void setVisualIndex(int i, int visualIndex); bool fixedHeaderSize(int sect); @@ -105,31 +98,31 @@ class db_base: public QAbstractItemModel { colResizing--; } - virtual void store(QModelIndexList list); + virtual void store(QModelIndexList indexes); + virtual void store(QModelIndex index) { }; + dbheaderList getAllHeaders() { + return allHeaders; + } + void pem2clipboard(QModelIndexList indexes); + QString pem2QString(QModelIndexList indexes); + + void deletePKI(QModelIndex idx); public slots: - void deletePKI(); - void delete_ask(); - void edit(); + virtual void newItem() { } + virtual void load() { } void columnResetDefaults(); - virtual void showItem(); - virtual void store() - { - store(QModelIndexList()); - }; virtual void showPki(pki_base *) {}; virtual void showItem(const QModelIndex &index); virtual void showItem(const QString keyname); void sectionResized(int i, int, int newSize); - void sortIndicatorChanged(int logicalIndex, Qt::SortOrder order); - void pem2clipboard(); + void sortIndicatorChanged(int, Qt::SortOrder); signals: void connNewX509(NewX509 *dlg); void resetHeader(); void updateHeader(); void columnsContentChanged(); - void editItem(const QModelIndex &); }; #endif diff --git a/lib/db_crl.cpp b/lib/db_crl.cpp index e948a02f..86e90d08 100644 --- a/lib/db_crl.cpp +++ b/lib/db_crl.cpp @@ -78,20 +78,27 @@ void db_crl::inToCont(pki_base *pki) { pki_crl *crl = (pki_crl *)pki; if (crl->getIssuer() == NULL) { - pki_x509 *iss = NULL, *last = NULL; + pki_x509 *iss = NULL, *last = NULL, *newest = NULL; x509name issname = crl->getSubject(); while ((iss = mainwin->certs->getBySubject(issname, last)) != NULL) { pki_key *key = iss->getPubKey(); - if (key) { - if (crl->verify(key)) { - delete key; - break; - } + if (!key) + continue; + + if (!crl->verify(key)) { delete key; + continue; } + delete key; last = iss; + if (!newest) { + newest = iss; + } else { + if (newest->getNotAfter() < iss->getNotAfter()) + newest = iss; + } } - crl->setIssuer(iss); + crl->setIssuer(newest); } db_base::inToCont(pki); } @@ -128,14 +135,13 @@ void db_crl::showPki(pki_base *pki) } } -void db_crl::store() +void db_crl::store(QModelIndex index) { QList types; - if (!currentIdx.isValid()) + if (!index.isValid()) return; - - pki_crl *crl = static_cast(currentIdx.internalPointer()); + pki_crl *crl = static_cast(index.internalPointer()); if (!crl) return; @@ -160,6 +166,40 @@ void db_crl::store() delete dlg; } +void db_crl::updateRevocations(pki_x509 *cert) +{ + x509name issname = cert->getSubject(); + x509revList revlist; + pki_crl *latest = NULL; + + FOR_ALL_pki(crl, pki_crl) { + if (!(issname == crl->getSubject())) + continue; + pki_key *key = cert->getPubKey(); + if (!key) + continue; + if (!crl->verify(key)) { + delete key; + continue; + } + delete key; + pki_x509 *old = crl->getIssuer(); + if (!old) { + crl->setIssuer(cert); + } else if (old != cert) { + if (old->getNotAfter() < cert->getNotAfter()) + crl->setIssuer(cert); + } + if (!latest || (latest->getCrlNumber() < crl->getCrlNumber())) + latest = crl; + } + if (latest) { + revlist = latest->getRevList(); + cert->mergeRevList(revlist); + cert->setCrlNumber(latest->getCrlNumber()); + } +} + void db_crl::newItem(pki_x509 *cert) { if (!cert) @@ -214,23 +254,3 @@ void db_crl::newItem(pki_x509 *cert) delete dlg; return; } - -void db_crl::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) -{ - QMenu *menu = new QMenu(mainwin); - currentIdx = index; - QMenu *subExport; - - menu->addAction(tr("Import"), this, SLOT(load())); - if (index != QModelIndex()) { - menu->addAction(tr("Rename"), this, SLOT(edit())); - subExport = menu->addMenu(tr("Export")); - subExport->addAction(tr("Clipboard"), this, - SLOT(pem2clipboard())); - subExport->addAction(tr("File"), this, SLOT(store())); - menu->addAction(tr("Delete"), this, SLOT(delete_ask())); - } - contextMenu(e, menu); - currentIdx = QModelIndex(); - return; -} diff --git a/lib/db_crl.h b/lib/db_crl.h index e70f5fb6..7c9a67ca 100644 --- a/lib/db_crl.h +++ b/lib/db_crl.h @@ -27,15 +27,15 @@ class db_crl: public db_x509name void revokeCerts(pki_crl *crl); void inToCont(pki_base *pki); pki_base *insert(pki_base *item); - void showContextMenu(QContextMenuEvent *e, const QModelIndex &index); void removeSigner(pki_base *signer); - public slots: - void store(); + void store(QModelIndex index); void load(); void showPki(pki_base *pki); - void newItem(pki_x509 *cert); - signals: void updateCertView(); + void updateRevocations(pki_x509 *cert); + + public slots: + void newItem(pki_x509 *cert); }; #endif diff --git a/lib/db_key.cpp b/lib/db_key.cpp index 1bea204b..21878ba7 100644 --- a/lib/db_key.cpp +++ b/lib/db_key.cpp @@ -82,7 +82,7 @@ QStringList db_key::get0KeyDesc(bool all) void db_key::remFromCont(QModelIndex &idx) { db_base::remFromCont(idx); - pki_base *pki = static_cast(currentIdx.internalPointer()); + pki_base *pki = static_cast(idx.internalPointer()); emit delKey((pki_key *)pki); } @@ -109,9 +109,7 @@ pki_base* db_key::insert(pki_base *item) XCA_INFO( tr("The database already contains the public part of the imported key as\n'%1\nand will be completed by the new, private part of the key").arg(oldkey->getIntName())); lkey->setIntName(oldkey->getIntName()); - currentIdx = index(oldkey->row(), 0, QModelIndex()); - deletePKI(); - currentIdx = QModelIndex(); + deletePKI(index(oldkey->row(), 0, QModelIndex())); } } insertPKI(lkey); @@ -187,35 +185,6 @@ void db_key::load(void) load_default(l); } -void db_key::toToken() -{ - pki_key *key = static_cast(currentIdx.internalPointer()); - if (!key || !pkcs11::loaded() || key->isToken()) - return; - - pki_scard *card = NULL; - try { - pkcs11 p11; - slotid slot; - - if (!p11.selectToken(&slot, mainwin)) - return; - card = new pki_scard(key->getIntName()); - card->store_token(slot, key->decryptKey()); - QString msg = tr("Shall the original key '%1' be replaced by the key on the token?\nThis will delete the key '%1' and make it unexportable"). - arg(key->getIntName()); - if (XCA_YESNO(msg)) { - deletePKI(); - insertPKI(card); - card = NULL; - } - } catch (errorEx &err) { - mainwin->Error(err); - } - if (card) - delete card; -} - void db_key::showPki(pki_base *pki) { pki_evp *key = (pki_evp *)pki; @@ -226,77 +195,35 @@ void db_key::showPki(pki_base *pki) delete dlg; } } - -void db_key::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) +exportType::etype db_key::clipboardFormat(QModelIndexList indexes) { - QMenu *menu = new QMenu(mainwin); - QMenu *subExport; - - currentIdx = index; - - pki_key *key = static_cast(currentIdx.internalPointer()); - - menu->addAction(tr("New Key"), this, SLOT(newItem())); - menu->addAction(tr("Import"), this, SLOT(load())); - if (index != QModelIndex()) { - menu->addAction(tr("Rename"), this, SLOT(edit())); - menu->addAction(tr("Show Details"), this, SLOT(showItem())); - menu->addAction(tr("Delete"), this, SLOT(delete_ask())); - subExport = menu->addMenu(tr("Export")); - subExport->addAction(tr("Clipboard"), this, - SLOT(pem2clipboard())); - subExport->addAction(tr("File"), this, SLOT(store())); - if (key->isPrivKey() && !key->isToken()) { - switch (key->getOwnPass()) { - case pki_key::ptCommon: - menu->addAction(tr("Change password"), this, - SLOT(setOwnPass())); - break; - case pki_key::ptPrivate: - menu->addAction(tr("Reset password"), this, - SLOT(resetOwnPass())); - break; - } - } - if (key->isToken() && pkcs11::loaded()) { - menu->addAction(tr("Change PIN"), this, - SLOT(changePin())); - menu->addAction(tr("Init PIN with SO PIN (PUK)"), this, - SLOT(initPin())); - menu->addAction(tr("Change SO PIN (PUK)"), this, - SLOT(changeSoPin())); - } - if (!key->isToken() && pkcs11::loaded()) { - menu->addAction(tr("Store on Security token"), - this, SLOT(toToken())); - } - } - contextMenu(e, menu); - currentIdx = QModelIndex(); - return; -} - -exportType::etype db_key::clipboardFormat() -{ - QString title = tr("Export public key [%1]"); QList types; + bool allPriv = true; + bool allRSADSA = true; - pki_key *key =static_cast(currentIdx.internalPointer()); + foreach(QModelIndex idx, indexes) { + pki_key *key = static_cast + (idx.internalPointer()); + if (key->isPubKey() || key->isToken()) + allPriv = false; + if (key->getKeyType() != EVP_PKEY_RSA && + key->getKeyType() != EVP_PKEY_DSA) + allRSADSA = false; + } + if (!allPriv && !allRSADSA) + return exportType::PEM_key; types << exportType(exportType::PEM_key, "pem", tr("PEM public")); - if (key->getKeyType() == EVP_PKEY_RSA || - key->getKeyType() == EVP_PKEY_DSA) + if (allRSADSA) types << exportType(exportType::SSH2_public, "pub", tr("SSH2 public")); - if (!key->isPubKey() && !key->isToken()) { + if (allPriv) types << exportType(exportType::PEM_private, "pem", tr("PEM private")); - title = tr("Export private key [%1]"); - } + ExportDialog *dlg = new ExportDialog(mainwin, - title.arg(key->getTypeString()), QString(), key, - key->isToken() ? MainWindow::scardImg : MainWindow::keyImg, - types); + tr("Export keys to CLipboard"), QString(), NULL, + MainWindow::keyImg, types); dlg->filename->setText(tr("Clipboard")); dlg->filename->setEnabled(false); @@ -308,16 +235,16 @@ exportType::etype db_key::clipboardFormat() return dlg->type(); } -void db_key::store() +void db_key::store(QModelIndex index) { const EVP_CIPHER *enc = NULL; QString title = tr("Export public key [%1]"); QList types; - if (!currentIdx.isValid()) + if (!index.isValid()) return; - pki_key *key =static_cast(currentIdx.internalPointer()); + pki_key *key =static_cast(index.internalPointer()); pki_evp *privkey = (pki_evp *)key; types << @@ -395,84 +322,15 @@ void db_key::store() delete dlg; } -void db_key::setOwnPass() -{ - try { - __setOwnPass(pki_key::ptPrivate); - } - catch (errorEx &err) { - mainwin->Error(err); - } -} - -void db_key::resetOwnPass() -{ - try { - __setOwnPass(pki_key::ptCommon); - } - catch (errorEx &err) { - mainwin->Error(err); - } -} - -void db_key::__setOwnPass(enum pki_key::passType x) +void db_key::setOwnPass(QModelIndex idx, enum pki_key::passType x) { pki_evp *targetKey; - if (!currentIdx.isValid()) - return; - targetKey = static_cast(currentIdx.internalPointer()); + if (!idx.isValid()) + return; + targetKey = static_cast(idx.internalPointer()); if (targetKey->isToken()) { throw errorEx(tr("Tried to change password of a token")); } targetKey->setOwnPass(x); updatePKI(targetKey); } - -void db_key::changePin() -{ - pki_scard *scard; - if (!currentIdx.isValid()) - return; - scard = static_cast(currentIdx.internalPointer()); - try { - if (!scard->isToken()) { - throw errorEx(tr("Tried to change PIN of a key")); - } - scard->changePin(); - } catch (errorEx &err) { - mainwin->Error(err); - } -} - -void db_key::initPin() -{ - pki_scard *scard; - if (!currentIdx.isValid()) - return; - scard = static_cast(currentIdx.internalPointer()); - try { - if (!scard->isToken()) { - throw errorEx(tr("Tried to init PIN of a key")); - } - scard->initPin(); - } catch (errorEx &err) { - mainwin->Error(err); - } -} - -void db_key::changeSoPin() -{ - pki_scard *scard; - if (!currentIdx.isValid()) - return; - scard = static_cast(currentIdx.internalPointer()); - try { - if (!scard->isToken()) { - throw errorEx(tr("Tried to change SO PIN of a key")); - } - scard->changeSoPin(); - } catch (errorEx &err) { - mainwin->Error(err); - } -} - diff --git a/lib/db_key.h b/lib/db_key.h index 2b904054..8022f2cd 100644 --- a/lib/db_key.h +++ b/lib/db_key.h @@ -20,11 +20,10 @@ class QContextMenuEvent; class db_key: public db_base { Q_OBJECT + protected: virtual dbheaderList getHeaders(); - exportType::etype clipboardFormat(); - private: - void __setOwnPass(enum pki_key::passType); + exportType::etype clipboardFormat(QModelIndexList indexes); public: db_key(QString db, MainWindow *mw); QStringList getPrivateDesc(); @@ -34,20 +33,14 @@ class db_key: public db_base void remFromCont(QModelIndex &idx); pki_base* insert(pki_base *item); void writeAll(); - void showContextMenu(QContextMenuEvent * e, const QModelIndex &index); + void setOwnPass(QModelIndex idx, enum pki_key::passType); public slots: void newItem(); void newItem(QString name); void load(); - void store(); + void store(QModelIndex index); void showPki(pki_base *pki); - void setOwnPass(); - void resetOwnPass(); - void changePin(); - void initPin(); - void changeSoPin(); - void toToken(); signals: void delKey(pki_key *delkey); diff --git a/lib/db_temp.cpp b/lib/db_temp.cpp index da583c33..64108d96 100644 --- a/lib/db_temp.cpp +++ b/lib/db_temp.cpp @@ -145,36 +145,9 @@ void db_temp::newItem() } delete temp; } - -void db_temp::changeTemp() -{ - if (!currentIdx.isValid()) - return; - pki_temp *temp = static_cast(currentIdx.internalPointer()); - alterTemp(temp); -} - -void db_temp::duplicateTemp() -{ - if (!currentIdx.isValid()) - return; - pki_temp *temp = static_cast(currentIdx.internalPointer()); - pki_temp *newtemp = new pki_temp(temp); - newtemp->setIntName(newtemp->getIntName() + " " + tr("copy")); - insertPKI(newtemp); -} - -bool db_temp::alterTemp(pki_temp *temp) -{ - if (!runTempDlg(temp)) - return false; - updatePKI(temp); - return true; -} - void db_temp::showPki(pki_base *pki) { - alterTemp((pki_temp *)pki); + alterTemp(static_cast(pki)); } void db_temp::load() @@ -183,11 +156,12 @@ void db_temp::load() load_default(l); } -void db_temp::store() +void db_temp::store(QModelIndex index) { - if (!currentIdx.isValid()) + if (!index.isValid()) return; - pki_temp *temp = static_cast(currentIdx.internalPointer()); + + pki_temp *temp = static_cast(index.internalPointer()); QString fn = mainwin->getPath() + QDir::separator() + temp->getUnderlinedName() + ".xca"; @@ -206,48 +180,10 @@ void db_temp::store() } } -void db_temp::certFromTemp() +bool db_temp::alterTemp(pki_temp *temp) { - if (!currentIdx.isValid()) - return; - pki_temp *temp = static_cast(currentIdx.internalPointer()); - emit newCert(temp); -} - -void db_temp::reqFromTemp() -{ - if (!currentIdx.isValid()) - return; - pki_temp *temp = static_cast(currentIdx.internalPointer()); - emit newReq(temp); -} - -void db_temp::alterTemp() -{ - if (!currentIdx.isValid()) - return; - pki_temp *temp = static_cast(currentIdx.internalPointer()); - alterTemp(temp); -} - -void db_temp::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) -{ - QMenu *menu = new QMenu(mainwin); - currentIdx = index; - - menu->addAction(tr("New Template"), this, SLOT(newItem())); - menu->addAction(tr("Import"), this, SLOT(load())); - if (index != QModelIndex()) { - menu->addAction(tr("Rename"), this, SLOT(edit())); - menu->addAction(tr("Export"), this, SLOT(store())); - menu->addAction(tr("Change"), this, SLOT(alterTemp())); - menu->addAction(tr("Delete"), this, SLOT(delete_ask())); - menu->addAction(tr("Duplicate"), this, SLOT(duplicateTemp())); - menu->addAction(tr("Create certificate"), this, - SLOT(certFromTemp())); - menu->addAction(tr("Create request"), this, SLOT(reqFromTemp())); - } - contextMenu(e, menu); - currentIdx = QModelIndex(); - return; + if (!runTempDlg(temp)) + return false; + updatePKI(temp); + return true; } diff --git a/lib/db_temp.h b/lib/db_temp.h index 1882b371..fb754919 100644 --- a/lib/db_temp.h +++ b/lib/db_temp.h @@ -15,8 +15,6 @@ #include #include -class Mainwin; - class db_temp: public db_x509name { Q_OBJECT @@ -31,23 +29,12 @@ class db_temp: public db_x509name pki_base *newPKI(db_header_t *head = NULL); bool runTempDlg(pki_temp *temp); bool alterTemp(pki_temp *temp); - void showContextMenu(QContextMenuEvent *e, const QModelIndex &index); + void fillContextMenu(QMenu *menu, const QModelIndex &index); pki_base *getByName(QString desc); QStringList getDescPredefs(); - - public slots: void newItem(); - void changeTemp(); void showPki(pki_base *pki); void load(); - void store(); - void certFromTemp(); - void reqFromTemp(); - void alterTemp(); - void duplicateTemp(); - signals: - void newReq(pki_temp *); - void newCert(pki_temp *); - + void store(QModelIndex index); }; #endif diff --git a/lib/db_x509.cpp b/lib/db_x509.cpp index df3817cf..83025109 100644 --- a/lib/db_x509.cpp +++ b/lib/db_x509.cpp @@ -39,7 +39,6 @@ db_x509::db_x509(QString DBfile, MainWindow *mw) void db_x509::updateAfterCrlLoad(pki_x509 *pki) { if (pki->revList.merged) { - fprintf(stderr, "Update '%s'\n", CCHAR(pki->getIntName())); updatePKI(pki); pki->revList.merged = false; } @@ -115,7 +114,7 @@ QStringList db_x509::getSignerDesc() void db_x509::remFromCont(QModelIndex &idx) { int row; - pki_base *pki = static_cast(currentIdx.internalPointer()); + pki_base *pki = static_cast(idx.internalPointer()); pki_base *parent_pki = pki->getParent(); row = pki->row(); pki_x509 *child; @@ -155,8 +154,6 @@ void db_x509::changeView() return; temproot = new pki_base(); - mainwin->certView->hide(); - mainwin->certView->setModel(NULL); beginRemoveRows(QModelIndex(), 0, rows -1); pki_base *pki = rootItem; pki_base *parent; @@ -181,8 +178,6 @@ void db_x509::changeView() inToCont(pki); } delete temproot; - mainwin->certView->setModel(this); - mainwin->certView->show(); } void db_x509::calcEffTrust() @@ -191,6 +186,23 @@ void db_x509::calcEffTrust() pki->calcEffTrust(); } +static bool recursiveSigning(pki_x509 *cert, pki_x509 *client) +{ + /* recursive signing check */ + for (pki_x509 *s = cert->getSigner(); s; s = s->getSigner()) { + if (s == s->getSigner()) { + return false; + } + if (s == client) { + printf("Recursive signing: '%s' <-> '%s'\n", + CCHAR(s->getIntName()), + CCHAR(cert->getIntName())); + return true; + } + } + return false; +} + void db_x509::inToCont(pki_base *pki) { pki_x509 *cert = (pki_x509*)pki; @@ -198,47 +210,68 @@ void db_x509::inToCont(pki_base *pki) cert->delSigner(cert->getSigner()); findSigner(cert); pki_base *root = cert->getSigner(); - if (!treeview || root == cert) + if (!treeview || root == cert || root == NULL) root = rootItem; + fprintf(stderr, "INSERT '%s' below '%s'\n", + CCHAR(cert->getIntName()), + CCHAR(root->getIntName())); - insertChild(root, pki); - /* search for dangling certificates, which signer this is */ + insertChild(root, cert); + + QList childs; + /* Search for another certificate (name and key) + * and use its childs if we are newer */ FOR_ALL_pki(client, pki_x509) { - if (client->getSigner() == NULL) { - if (client->verify(cert) && treeview ) { - int row = client->row(); - pki_x509 *s; - /* recursive signing check */ - for (s = cert; s; s = s->getSigner()) { - if (s == s->getSigner()) { - s = NULL; - break; - } - if (s == client) { - printf("Recursive signing: '%s' <-> '%s'\n", - CCHAR(client->getIntName()), - CCHAR(cert->getIntName())); - break; - } - } - if (s) - continue; - beginRemoveRows(QModelIndex(), row, row); - rootItem->takeChild(client); - endRemoveRows(); - - insertChild(pki, client); - client = (pki_x509*)rootItem; - } + if (client == cert) + continue; + if (!client->compareNameAndKey(cert)) + continue; + if (cert->getNotAfter() < client->getNotAfter()) + continue; + fprintf(stderr, "Other CA '%s' is older then us '%s'\n", + CCHAR(client->getIntName()), + CCHAR(cert->getIntName())); + foreach(pki_base *_child, client->childItems) { + pki_x509 *child = static_cast(_child); + child->delSigner(client); + childs << child; } } + /* Search rootItem childs, whether they are ours */ + foreach(pki_base *_child, rootItem->childItems) { + pki_x509 *child = static_cast(_child); + if (child == cert || child->getSigner() == child) + continue; + if (child->verify_only(cert)) + childs << child; + } + /* move collected childs to us */ + foreach(pki_x509 *child, childs) { + int row; + if (recursiveSigning(cert, child)) + continue; + if (!child->verify(cert)) + continue; + fprintf(stderr, "MOVE Child '%s' from '%s' to '%s'\n", + CCHAR(child->getIntName()), + CCHAR(child->getParent()->getIntName()), + CCHAR(cert->getIntName())); + row = child->row(); + beginRemoveRows(index(child), row, row); + child->getParent()->takeChild(child); + endRemoveRows(); + if (treeview) + 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) { + foreach(pki_x509super *r, reqs) { ((pki_x509req*)r)->setDone(); } } @@ -348,6 +381,9 @@ 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; } @@ -358,18 +394,6 @@ void db_x509::load(void) load_default(c); } -void db_x509::loadPKCS12() -{ - load_pkcs12 l; - load_default(l); -} - -void db_x509::loadPKCS7() -{ - load_pkcs7 l; - load_default(l); -} - pki_x509 *db_x509::get1SelectedCert() { QModelIndexList indexes = mainwin->certView->getSelectedIndexes(); @@ -584,110 +608,29 @@ void db_x509::showPki(pki_base *pki) 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) ), + 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::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) -{ - QMenu *menu = new QMenu(mainwin); - QMenu *subExport, *subCa, *transform; - QAction *action; - QList scardItems; - - bool parentCanSign, canSign, hasScard; - currentIdx = index; - pki_key *privkey; - - pki_x509 *cert = static_cast(index.internalPointer()); - pki_x509 *parent; - - menu->addAction(tr("New Certificate"), this, SLOT(newItem())); - menu->addAction(tr("Import"), this, SLOT(load())); - menu->addAction(tr("Import PKCS#12"), this, SLOT(loadPKCS12())); - menu->addAction(tr("Import from PKCS#7"), this, SLOT(loadPKCS7())); - if (index != QModelIndex()) { - privkey = cert->getRefKey(); - parent = cert->getSigner(); - parentCanSign = parent && parent->canSign() && (parent != cert); - canSign = cert->canSign(); - - menu->addAction(tr("Rename"), this, SLOT(edit())); - menu->addAction(tr("Show Details"), this, SLOT(showItem())); - subExport = menu->addMenu(tr("Export")); - subExport->addAction(tr("Clipboard"), this, - SLOT(pem2clipboard())); - subExport->addAction(tr("File"), this, SLOT(store())); - scardItems += subExport->addAction(tr("Security token"), - this, SLOT(toToken())); - scardItems += subExport->addAction(tr("Other token"), - this, SLOT(toOtherToken())); - subExport->addAction(tr("OpenSSL config"), - this, SLOT(toOpenssl())); - - transform = menu->addMenu(tr("Transform")); - transform->addAction(tr("Public Key"), - this, SLOT(extractPubkey()))-> - setEnabled(!privkey); - transform->addAction(tr("Request"), - this, SLOT(toRequest()))-> - setEnabled(privkey && privkey->isPrivKey()); - transform->addAction(tr("Similar Certificate"), - this, SLOT(toCertificate())); - transform->addAction(tr("Template"), this, SLOT(toTemplate())); - - menu->addAction(tr("Delete"), this, SLOT(delete_ask())); - scardItems += menu->addAction( - tr("Delete from Security token"), - this, SLOT(deleteFromToken())); - menu->addAction(tr("Trust"), this,SLOT(setTrust()))-> - setEnabled(!cert->isRevoked()); - menu->addSeparator(); - subCa = menu->addMenu(tr("CA")); - subCa->addAction(tr("Properties"), this, SLOT(caProperties())); - subCa->addAction(tr("Generate CRL"), this, SLOT(genCrl())); - subCa->addAction(tr("Manage revocations"), - this, SLOT(manageRevocations())); - subCa->setEnabled(canSign); - menu->addSeparator(); - menu->addAction(tr("Renewal"), this, SLOT(extendCert()))-> - setEnabled(parentCanSign); - if (cert->isRevoked()) { - menu->addAction(tr("Unrevoke"), - this, SLOT(unRevoke()))-> - setEnabled(parentCanSign); - } else { - menu->addAction(tr("Revoke"), this, SLOT(revoke()))-> - setEnabled(parentCanSign); - } - hasScard = pkcs11::loaded(); - - foreach(action, scardItems) - action->setEnabled(hasScard); - } - contextMenu(e, menu); - currentIdx = QModelIndex(); - return; -} - void db_x509::store(QModelIndexList list) { QStringList filt; bool append, chain; QList types, usual; - if (!currentIdx.isValid()) + if (list.size() == 0) return; - pki_x509 *crt = static_cast(currentIdx.internalPointer()); + pki_x509 *crt = static_cast(list[0].internalPointer()); pki_x509 *oldcrt = NULL; if (!crt) return; + pki_key *privkey = crt->getRefKey(); pki_evp *pkey; chain = crt->getSigner() && crt->getSigner() != crt; @@ -905,33 +848,9 @@ void db_x509::writePKCS7(pki_x509 *cert, QString s, exportType::etype type, } -void db_x509::setMultiTrust(QAbstractItemView* view) +void db_x509::manageRevocations(QModelIndex idx) { - QItemSelectionModel *selectionModel = view->selectionModel(); - QModelIndexList indexes = selectionModel->selectedIndexes(); - QString items; - - foreach(currentIdx, indexes) { - setTrust(); - } - currentIdx = QModelIndex(); -} - -void db_x509::deleteFromToken() -{ - if (!currentIdx.isValid()) - return; - pki_x509 *pki = static_cast(currentIdx.internalPointer()); - try { - pki->deleteFromToken(); - } catch (errorEx &err) { - mainwin->Error(err); - } -} - -void db_x509::manageRevocations() -{ - pki_x509 *cert = static_cast(currentIdx.internalPointer()); + pki_x509 *cert = static_cast(idx.internalPointer()); if (!cert) return; RevocationList *dlg = new RevocationList(mainwin); @@ -941,51 +860,71 @@ void db_x509::manageRevocations() if (dlg->exec()) { cert->setRevocations(dlg->getRevList()); updatePKI(cert); + emit columnsContentChanged(); } } -void db_x509::setTrust() +void db_x509::setTrust(QModelIndexList indexes) { - int state, newstate = 0; + int newstate = -1; Ui::TrustState ui; - pki_x509 *cert = static_cast(currentIdx.internalPointer()); - if (!cert) + 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); - state = cert->getTrust(); - if (cert->getSigner() == cert) { - if (state == 1) - state = 0; - ui.trust1->setDisabled(true); + 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 (state == 0 ) ui.trust0->setChecked(true); - if (state == 1 ) ui.trust1->setChecked(true); - if (state == 2 ) ui.trust2->setChecked(true); - if (dlg->exec()) { - if (ui.trust0->isChecked()) newstate = 0; - if (ui.trust1->isChecked()) newstate = 1; - if (ui.trust2->isChecked()) newstate = 2; - if (newstate!=state) { + 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); } } - delete dlg; } -void db_x509::extendCert() +void db_x509::certRenewal(QModelIndexList indexes) { pki_x509 *oldcert = NULL, *signer = NULL, *newcert =NULL; pki_key *signkey = NULL; a1time time; a1int serial; CertExtend *dlg = NULL; + x509rev r; + bool doRevoke = false; + + if (indexes.size() == 0) + return; + QModelIndex idx = indexes[0]; try { - oldcert = static_cast(currentIdx.internalPointer()); + oldcert = static_cast(idx.internalPointer()); if (!oldcert || !(signer = oldcert->getSigner()) || !(signkey = signer->getRefKey()) || @@ -997,27 +936,37 @@ void db_x509::extendCert() delete dlg; return; } - newcert = new pki_x509(oldcert); - serial = getUniqueSerial(signer); + if (dlg->revoke->isChecked()) { + Revocation *revoke = new Revocation(mainwin, indexes); + doRevoke = revoke->exec(); + r = revoke->getRevocation(); + delete revoke; + } + foreach(idx, indexes) { + oldcert = static_cast + (idx.internalPointer()); + newcert = new pki_x509(oldcert); + serial = getUniqueSerial(signer); + newcert->setRevoked(x509rev()); - // change date and serial - newcert->setSerial(serial); - newcert->setNotBefore(dlg->notBefore->getDate()); - a1time a; - if (dlg->noWellDefinedExpDate->isChecked()) - a.setUndefined(); - else - a = dlg->notAfter->getDate(); + // change date and serial + newcert->setSerial(serial); + newcert->setNotBefore(dlg->notBefore->getDate()); + a1time a; + if (dlg->noWellDefinedExpDate->isChecked()) + a.setUndefined(); + else + a = dlg->notAfter->getDate(); - newcert->setNotAfter(a); + newcert->setNotAfter(a); - // and finally sign the cert - newcert->sign(signkey, oldcert->getDigest()); - newcert = (pki_x509 *)insert(newcert); - createSuccess(newcert); - - if (dlg->revoke->isChecked()) - revoke(); + // and finally sign the cert + newcert->sign(signkey, oldcert->getDigest()); + newcert = (pki_x509 *)insert(newcert); + createSuccess(newcert); + } + if (doRevoke) + do_revoke(indexes, r); } catch (errorEx &err) { MainWindow::Error(err); @@ -1026,66 +975,98 @@ void db_x509::extendCert() } if (dlg) delete dlg; + emit columnsContentChanged(); } -void db_x509::revoke() +void db_x509::revoke(QModelIndexList indexes) { - pki_x509 *cert = static_cast(currentIdx.internalPointer()); - if (!cert) + if (indexes.size() == 0) return; - Revocation *revoke = new Revocation(mainwin, cert); + Revocation *revoke = new Revocation(mainwin, indexes); if (revoke->exec()) { - const x509rev r = revoke->getRevocation(); - cert->setRevoked(r); - pki_x509 *iss = cert->getSigner(); - if (iss) { - x509revList rl(r); - iss->mergeRevList(rl); - updatePKI(iss); + do_revoke(indexes, revoke->getRevocation()); + } + emit columnsContentChanged(); +} + +void db_x509::do_revoke(QModelIndexList indexes, const x509rev &r) +{ + pki_x509 *parent = NULL, *cert, *iss; + x509revList revlist; + + foreach(QModelIndex idx, indexes) { + cert = static_cast(idx.internalPointer()); + iss = cert->getSigner(); + if (parent == NULL) { + parent = iss; + } else if (parent != iss) { + parent = NULL; + break; } } + if (!parent) { + qWarning("%s(%d): Certs have different/no signer\n", + __func__, __LINE__); + } + foreach(QModelIndex idx, indexes) { + pki_x509 *cert = static_cast(idx.internalPointer()); + x509rev rev(r); + rev.setSerial(cert->getSerial()); + cert->setRevoked(rev); + revlist << rev; + } + parent->mergeRevList(revlist); + updatePKI(parent); } -void db_x509::unRevoke() +void db_x509::unRevoke(QModelIndexList indexes) { - pki_x509 *cert = static_cast(currentIdx.internalPointer()); - pki_x509 *sig; - int idx; - x509rev rev; + pki_x509 *parent = NULL; + foreach(QModelIndex idx, indexes) { + pki_x509 *cert = static_cast(idx.internalPointer()); + if (!cert) + return; + pki_x509 *iss = cert->getSigner(); + if (parent == NULL) { + parent = iss; + } else if (parent != iss) { + parent = NULL; + break; + } + } + if (!parent) { + qWarning("%s(%d): Certs have different/no signer\n", + __func__, __LINE__); + } + foreach(QModelIndex idx, indexes) { + pki_x509 *cert = static_cast(idx.internalPointer()); + int idx; + x509rev rev; - if (!cert) - return; - sig = cert->getSigner(); - if (!sig) - return; - cert->setRevoked(x509rev()); - rev.setSerial(cert->getSerial()); - idx = sig->revList.indexOf(rev); - if (idx != -1) - sig->revList.takeAt(idx); - updatePKI(sig); + cert->setRevoked(x509rev()); + rev.setSerial(cert->getSerial()); + idx = parent->revList.indexOf(rev); + if (idx != -1) + parent->revList.takeAt(idx); + } + updatePKI(parent); + emit columnsContentChanged(); } -void db_x509::genCrl() +void db_x509::toCertificate(QModelIndex index) { - pki_x509 *cert = static_cast(currentIdx.internalPointer()); - mainwin->crls->newItem(cert); -} - -void db_x509::toCertificate() -{ - pki_x509 *cert = static_cast(currentIdx.internalPointer()); + pki_x509 *cert = static_cast(index.internalPointer()); if (!cert) return; if (!cert->getRefKey() && cert->getSigner() != cert) - extractPubkey(); + extractPubkey(index); newCert(cert); } -void db_x509::toRequest() +void db_x509::toRequest(QModelIndex idx) { - pki_x509 *cert = static_cast(currentIdx.internalPointer()); + pki_x509 *cert = static_cast(idx.internalPointer()); if (!cert) return; @@ -1102,9 +1083,9 @@ void db_x509::toRequest() } } -void db_x509::myToToken(bool alwaysSelect) +void db_x509::toToken(QModelIndex idx, bool alwaysSelect) { - pki_x509 *cert = static_cast(currentIdx.internalPointer()); + pki_x509 *cert = static_cast(idx.internalPointer()); if (!cert) return; try { @@ -1114,23 +1095,15 @@ void db_x509::myToToken(bool alwaysSelect) } } -void db_x509::toToken() -{ - myToToken(false); -} - -void db_x509::toOtherToken() -{ - myToToken(true); -} - -void db_x509::caProperties() +void db_x509::caProperties(QModelIndex idx) { Ui::CaProperties ui; int i; - pki_x509 *cert = static_cast(currentIdx.internalPointer()); + + pki_x509 *cert = static_cast(idx.internalPointer()); if (!cert) return; + QDialog *dlg = new QDialog(mainwin); ui.setupUi(dlg); ui.serial->setText(cert->getCaSerial().toHex()); diff --git a/lib/db_x509.h b/lib/db_x509.h index 44823c15..6242bfa1 100644 --- a/lib/db_x509.h +++ b/lib/db_x509.h @@ -54,34 +54,29 @@ class db_x509: public db_x509super void writePKCS12(pki_x509 *cert, QString s, bool chain); void writePKCS7(pki_x509 *cert, QString s, exportType::etype type, QModelIndexList list); - void showContextMenu(QContextMenuEvent *e, const QModelIndex &index); + void fillContextMenu(QMenu *menu, const QModelIndex &index); void inToCont(pki_base *pki); void changeView(); a1int getUniqueSerial(pki_x509 *signer); - void myToToken(bool alwaysSelect); + void toToken(QModelIndex idx, bool alwaysSelect); + void toRequest(QModelIndex idx); void store(QModelIndexList list); + void showPki(pki_base *pki); + void load(); + void caProperties(QModelIndex idx); + void toCertificate(QModelIndex index); + void manageRevocations(QModelIndex idx); + void certRenewal(QModelIndexList indexes); + void revoke(QModelIndexList indexes); + void do_revoke(QModelIndexList indexes, const x509rev &r); + void unRevoke(QModelIndexList indexes); + void setTrust(QModelIndexList indexes); public slots: - void load(void); - void newItem(void); - void showPki(pki_base *pki); - void setMultiTrust(QAbstractItemView* view); - void setTrust(); - void deleteFromToken(); - void extendCert(); - void revoke(); - void unRevoke(); - void genCrl(); - void caProperties(); - void toRequest(); - void toCertificate(); - void toToken(); - void toOtherToken(); + void newItem(); + void newCert(pki_temp *); void newCert(pki_x509req *); - void loadPKCS12(); - void loadPKCS7(); - void manageRevocations(); }; #endif diff --git a/lib/db_x509req.cpp b/lib/db_x509req.cpp index f09133ff..78637a56 100644 --- a/lib/db_x509req.cpp +++ b/lib/db_x509req.cpp @@ -55,6 +55,11 @@ pki_base *db_x509req::insert(pki_base *item) return req; } +void db_x509req::newItem() +{ + newItem(NULL, NULL); +} + void db_x509req::newItem(pki_temp *temp, pki_x509req *orig) { pki_x509req *req = NULL; @@ -67,7 +72,7 @@ void db_x509req::newItem(pki_temp *temp, pki_x509req *orig) dlg->fromX509super(orig); } dlg->setRequest(); - if (! dlg->exec()){ + if (!dlg->exec()){ delete dlg; return; } @@ -90,10 +95,9 @@ void db_x509req::newItem(pki_temp *temp, pki_x509req *orig) } } -void db_x509req::toRequest(void) +void db_x509req::toRequest(QModelIndex index) { - pki_x509req *req = static_cast - (currentIdx.internalPointer()); + pki_x509req *req = static_cast(index.internalPointer()); if (!req) return; newItem(NULL, req); @@ -136,16 +140,14 @@ void db_x509req::showPki(pki_base *pki) } } -void db_x509req::store() +void db_x509req::store(QModelIndex index) { QList types; - if (!currentIdx.isValid()) - return; - - pki_x509req *req = static_cast(currentIdx.internalPointer()); + pki_x509req *req = static_cast(index.internalPointer()); if (!req) return; + types << exportType(exportType::PEM, "pem", "PEM") << exportType(exportType::DER, "der", "DER"); @@ -167,51 +169,8 @@ void db_x509req::store() delete dlg; } - -void db_x509req::signReq() +void db_x509req::signReq(QModelIndex index) { - if (!currentIdx.isValid()) - return; - - pki_x509req *req = static_cast(currentIdx.internalPointer()); + pki_x509req *req = static_cast(index.internalPointer()); emit newCert(req); } - -void db_x509req::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) -{ - QMenu *menu = new QMenu(mainwin); - QMenu *subExport, *transform; - currentIdx = index; - - pki_x509req *req = static_cast(index.internalPointer()); - - menu->addAction(tr("New Request"), this, SLOT(newItem())); - menu->addAction(tr("Import"), this, SLOT(load())); - if (index != QModelIndex()) { - menu->addAction(tr("Rename"), this, SLOT(edit())); - menu->addAction(tr("Show Details"), this, SLOT(showItem())); - menu->addAction(tr("Sign"), this, SLOT(signReq())); - - subExport = menu->addMenu(tr("Export")); - subExport->addAction(tr("Clipboard"), this, - SLOT(pem2clipboard())); - subExport->addAction(tr("File"), this, SLOT(store())); - subExport->addAction(tr("OpenSSL config"), this, - SLOT(toOpenssl())); - subExport->setEnabled(!req->isSpki()); - - transform = menu->addMenu(tr("Transform")); - transform->addAction(tr("Template"), this, - SLOT(toTemplate()))-> - setEnabled(!req->isSpki()); - transform->addAction(tr("Public Key"), this, - SLOT(extractPubkey()))-> - setEnabled(!req->getRefKey()); - transform->addAction(tr("Similar Request"), - this, SLOT(toRequest())); - menu->addAction(tr("Delete"), this, SLOT(delete_ask())); - } - contextMenu(e, menu); - currentIdx = QModelIndex(); - return; -} diff --git a/lib/db_x509req.h b/lib/db_x509req.h index 2205d850..aedae4b3 100644 --- a/lib/db_x509req.h +++ b/lib/db_x509req.h @@ -24,16 +24,18 @@ class db_x509req: public db_x509super db_x509req(QString DBfile, MainWindow *mw); pki_base* insert(pki_base *item); pki_base *newPKI(db_header_t *head = NULL); - void showContextMenu(QContextMenuEvent *e, const QModelIndex &index); + void fillContextMenu(QMenu *menu, const QModelIndex &index); void inToCont(pki_base *pki); + void store(QModelIndex index); + void signReq(QModelIndex index); + void toRequest(QModelIndex index); + void load(); + void showPki(pki_base *pki); public slots: - void newItem(pki_temp *temp = NULL, pki_x509req *orig = NULL); - void load(); - void store(); - void showPki(pki_base *pki); - void signReq(); - void toRequest(void); + void newItem(pki_temp *temp, pki_x509req *orig = NULL); + void newItem(); + signals: void newCert(pki_x509req *req); }; diff --git a/lib/db_x509super.cpp b/lib/db_x509super.cpp index 8d8b9328..eaaae4dd 100644 --- a/lib/db_x509super.cpp +++ b/lib/db_x509super.cpp @@ -112,10 +112,11 @@ QList db_x509super::findByPubKey(pki_key *refkey) return list; } -void db_x509super::extractPubkey() +void db_x509super::extractPubkey(QModelIndex index) { pki_key *key; - pki_x509super *pki = static_cast(currentIdx.internalPointer()); + pki_x509super *pki = static_cast + (index.internalPointer()); if (!pki) return; key = pki->getPubKey(); @@ -130,9 +131,9 @@ void db_x509super::extractPubkey() XCA_INFO(key->getMsg(pki_base::msg_import).arg(pki->getIntName())); } -void db_x509super::toOpenssl() const +void db_x509super::toOpenssl(QModelIndex index) const { - pki_x509super *pki = static_cast(currentIdx.internalPointer()); + pki_x509super *pki = static_cast(index.internalPointer()); QString fn = mainwin->getPath() + QDir::separator() + pki->getUnderlinedName() + ".conf"; QString fname = QFileDialog::getSaveFileName(mainwin, @@ -145,9 +146,9 @@ void db_x509super::toOpenssl() const pki->opensslConf(fname); } -void db_x509super::toTemplate() +void db_x509super::toTemplate(QModelIndex index) { - pki_x509super *pki = static_cast(currentIdx.internalPointer()); + pki_x509super *pki = static_cast(index.internalPointer()); if (!pki) return; diff --git a/lib/db_x509super.h b/lib/db_x509super.h index c452dd70..d64e4952 100644 --- a/lib/db_x509super.h +++ b/lib/db_x509super.h @@ -34,13 +34,13 @@ class db_x509super: public db_x509name db_x509super(QString db, 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 extractPubkey(); - void toTemplate(); - void toOpenssl() const; }; #endif diff --git a/lib/pki_crl.cpp b/lib/pki_crl.cpp index ec047128..1be5b392 100644 --- a/lib/pki_crl.cpp +++ b/lib/pki_crl.cpp @@ -269,10 +269,10 @@ bool pki_crl::verify(pki_key *key) { bool ret=false; if (crl && crl->crl && key) { - ret = (X509_CRL_verify(crl , key->getPubKey()) == 1); + ret = (X509_CRL_verify(crl, key->getPubKey()) == 1); pki_ign_openssl_error(); } - return ret ; + return ret; } void pki_crl::setCrlNumber(a1int num) @@ -284,6 +284,14 @@ void pki_crl::setCrlNumber(a1int num) pki_openssl_error(); } +a1int pki_crl::getCrlNumber() +{ + a1int num; + if (!getCrlNumber(&num)) + num.set(0L); + return num; +} + bool pki_crl::getCrlNumber(a1int *num) { int j; diff --git a/lib/pki_crl.h b/lib/pki_crl.h index 7ea75cc6..dd553412 100644 --- a/lib/pki_crl.h +++ b/lib/pki_crl.h @@ -68,6 +68,7 @@ class pki_crl: public pki_x509name QByteArray i2d(); void setCrlNumber(a1int num); bool getCrlNumber(a1int *num); + a1int getCrlNumber(); BIO *pem(BIO *, int); bool visible(); }; diff --git a/lib/pki_multi.cpp b/lib/pki_multi.cpp index 6ee13d68..38ccbc72 100644 --- a/lib/pki_multi.cpp +++ b/lib/pki_multi.cpp @@ -13,6 +13,7 @@ #include "pki_pkcs7.h" #include "pki_pkcs12.h" #include "pki_crl.h" +#include "pki_temp.h" #include "load_obj.h" #include "exception.h" #include "func.h" @@ -40,12 +41,12 @@ pki_base *pki_multi::pull() return multi.takeFirst(); } +#define D5 "-----" +#define BEGIN D5 "BEGIN " /* General PEM loader */ static pki_base *pkiByPEM(QString text, int *skip) { int pos; -#define D5 "-----" -#define BEGIN D5 "BEGIN " pos = text.indexOf(BEGIN); if (pos <0) { if (skip) @@ -74,6 +75,9 @@ static pki_base *pkiByPEM(QString text, int *skip) if (text.startsWith(PEM_STRING_X509_CRL D5)) return new pki_crl(); + if (text.startsWith(PEM_STRING_XCA_TEMPLATE D5)) + return new pki_temp(); + if (text.startsWith(PEM_STRING_EVP_PKEY D5) || text.startsWith(PEM_STRING_PUBLIC D5) || text.startsWith(PEM_STRING_RSA D5) || @@ -155,7 +159,8 @@ void pki_multi::probeAnything(const QString fname) load_base *lb; QList lbs; - lbs << new load_cert() << new load_pkcs7() << new load_pkcs12() << + lbs << new load_pem() << + new load_cert() << new load_pkcs7() << new load_pkcs12() << new load_crl() << new load_req() << new load_key() << new load_temp(); diff --git a/lib/pki_temp.cpp b/lib/pki_temp.cpp index 2e8730e4..903e639b 100644 --- a/lib/pki_temp.cpp +++ b/lib/pki_temp.cpp @@ -251,7 +251,7 @@ void pki_temp::fromData(const unsigned char *p, int size, int version) eKeyUseCrit = db::boolFromData(ba); subKey = db::boolFromData(ba); authKey = db::boolFromData(ba); - ca = db:: intFromData(ba); + ca = db::intFromData(ba); if (version > 5) { pathLen = db::stringFromData(ba); } else { @@ -330,25 +330,113 @@ QByteArray pki_temp::toData() return ba; } -void pki_temp::writeDefault(const QString fname) +QByteArray pki_temp::toExportData() { - writeTemp(fname + QDir::separator() + getIntName() + ".xca"); + QByteArray data, header; + data = toData(); + header = db::intToData(data.count()); + header += db::intToData(dataVersion); + header += data; + return header; } void pki_temp::writeTemp(QString fname) { - QByteArray data, header; FILE *fp = fopen(QString2filename(fname),"wb"); if (fp == NULL) { fopen_error(fname); return; } - data = toData(); - header = db::intToData(data.count()); - header += db::intToData(dataVersion); - header += data; - fwrite_ba(fp, header, fname); + fwrite_ba(fp, toExportData(), fname); + fclose(fp); +} + +void pki_temp::writeDefault(const QString fname) +{ + writeTemp(fname + QDir::separator() + getIntName() + ".xca"); +} + +BIO *pki_temp::pem(BIO *b, int format) +{ + QByteArray ba = toExportData(); + if (!b) + b = BIO_new(BIO_s_mem()); + PEM_write_bio(b, PEM_STRING_XCA_TEMPLATE, "", + (const unsigned char*)ba.constData(), ba.size()); + pki_openssl_error(); + return b; +} + +void pki_temp::fromExportData(QByteArray data) +{ + int size, version; + const int hsize = sizeof(uint32_t); + bool oldimport = false; + + if (data.size() < hsize) { + 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); + } +} + +void pki_temp::try_fload(QString fname, const char *mode) +{ + FILE *fp = fopen(QString2filename(fname), mode); + char buf[4096]; + QByteArray ba; + BIO *b; + + if (fp == NULL) { + fopen_error(fname); + return; + } + b = BIO_new(BIO_s_file()); + pki_openssl_error(); + BIO_set_fp(b,fp,BIO_NOCLOSE); + try { + fromPEM_BIO(b, fname); + BIO_free(b); + return; + } catch (errorEx &err) { + BIO_free(b); + fseek(fp, 0, SEEK_SET); + } + while (1) { + size_t ret = fread(buf, 1, sizeof buf, fp); + ba.append(buf, ret); + if (ret < sizeof buf) + break; + } + int err = ferror(fp); + fclose(fp); + if (err) { + my_error(tr("Template file content error (too small): %1"). + arg(fname)); + } + fromExportData(ba); + setIntName(rmslashdot(fname)); fclose(fp); } @@ -367,58 +455,30 @@ void pki_temp::fload(QString fname) } } -void pki_temp::try_fload(QString fname, const char *mode) +void pki_temp::fromPEM_BIO(BIO *bio, QString name) { - int size, s, version; - const int hsize = 2 * sizeof(uint32_t); - char buf[hsize]; - unsigned char *p; - FILE *fp = fopen(QString2filename(fname), mode); - bool oldimport = false; + QByteArray ba; + QString msg; + char *nm = NULL, *header = NULL; + unsigned char *data = NULL; + long len; - if (fp == NULL) { - fopen_error(fname); - return; + PEM_read_bio(bio, &nm, &header, &data, &len); + + pki_openssl_error(); + + if (!strcmp(nm, PEM_STRING_XCA_TEMPLATE)) { + ba = QByteArray::fromRawData((char*)data, len); + fromExportData(ba); + setIntName(rmslashdot(name)); + } else { + msg = tr("Not an XCA Template, but '%1'").arg(nm); } - if (fread(buf, hsize, 1, fp) != 1) { - fclose(fp); - my_error(tr("Template file content error (too small): %1"). - arg(fname)); - } - - QByteArray header(buf, hsize); - QByteArray backup = header; - - size = db::intFromData(header); - version = db::intFromData(header); - - if (size > 65535 || size <0) { - /* oldimport templates are prepended by its size in host endianess. - Set fp after the first int and recover the size */ - fseek(fp, sizeof(int), SEEK_SET); - size = intFromData(backup); - if (size > 65535 || size <0) { - fclose(fp); - my_error(tr("Template file content error (bad size): %1 ").arg(fname)); - } - oldimport = true; - } - p = (unsigned char *)OPENSSL_malloc(size); - if (p) { - if ((s=fread(p, 1, size, fp)) != size) { - OPENSSL_free(p); - fclose(fp); - my_error(tr("Template file content error (bad length) :%1").arg(fname)); - } - } - if (oldimport) - oldFromData(p, size); - else - fromData(p, size, version); - OPENSSL_free(p); - - setIntName(rmslashdot(fname)); - fclose(fp); + OPENSSL_free(nm); + OPENSSL_free(header); + OPENSSL_free(data); + if (!msg.isEmpty()) + my_error(msg); } pki_temp::~pki_temp() @@ -447,7 +507,7 @@ QVariant pki_temp::getIcon(dbheader *hd) return hd->id == HD_internal_name ? QVariant(*icon) : QVariant(); } -void pki_temp::oldFromData(unsigned char *p, int size) +void pki_temp::oldFromData(const unsigned char *p, int size) { int version; diff --git a/lib/pki_temp.h b/lib/pki_temp.h index abba81d9..850009c4 100644 --- a/lib/pki_temp.h +++ b/lib/pki_temp.h @@ -13,6 +13,9 @@ #include "asn1time.h" #include "pki_x509.h" +#define D5 "-----" +#define PEM_STRING_XCA_TEMPLATE "XCA TEMPLATE" + class pki_temp: public pki_x509name { Q_OBJECT @@ -41,7 +44,7 @@ class pki_temp: public pki_x509name ~pki_temp(); void fromData(const unsigned char *p, int size, int version); void fromData(const unsigned char *p, db_header_t *head ); - void oldFromData(unsigned char *p, int size); + void oldFromData(const unsigned char *p, int size); QByteArray toData(); bool compare(pki_base *ref); @@ -50,6 +53,10 @@ class pki_temp: public pki_x509name QVariant getIcon(dbheader *hd); virtual QString getMsg(msg_type msg); x509name getSubject() const; + BIO *pem(BIO *b, int format); + QByteArray toExportData(); + void fromPEM_BIO(BIO *, QString); + void fromExportData(QByteArray data); }; #endif diff --git a/lib/pki_x509.cpp b/lib/pki_x509.cpp index 90da0282..031334c3 100644 --- a/lib/pki_x509.cpp +++ b/lib/pki_x509.cpp @@ -194,17 +194,6 @@ a1int pki_x509::hashInfo(const EVP_MD *md) const return a; } -a1int pki_x509::getQASerial(const a1int &secret) const -{ - ASN1_INTEGER *hold = cert->cert_info->serialNumber; - cert->cert_info->serialNumber = secret.get(); - a1int ret = hashInfo(EVP_md5()); - ASN1_INTEGER_free(cert->cert_info->serialNumber); - cert->cert_info->serialNumber = hold; - pki_openssl_error(); - return ret; -} - void pki_x509::load_token(pkcs11 &p11, CK_OBJECT_HANDLE object) { QString desc; @@ -382,11 +371,6 @@ int pki_x509::renameOnToken(slotid slot, QString name) return 1; } -bool pki_x509::verifyQASerial(const a1int &secret) const -{ - return getQASerial(secret) == getSerial(); -} - void pki_x509::setNotBefore(const a1time &a) { a1time t(a); @@ -615,13 +599,9 @@ bool pki_x509::cmpIssuerAndSerial(pki_x509 *refcert) } -bool pki_x509::verify(pki_x509 *signer) +bool pki_x509::verify_only(pki_x509 *signer) { - if (psigner == signer) - return true; - if ((psigner != NULL )||( signer == NULL)) - return false; - X509_NAME *subject = X509_get_subject_name(signer->cert); + X509_NAME *subject = X509_get_subject_name(signer->cert); X509_NAME *issuer = X509_get_issuer_name(cert); pki_openssl_error(); if (X509_NAME_cmp(subject, issuer)) { @@ -634,7 +614,16 @@ bool pki_x509::verify(pki_x509 *signer) } int i = X509_verify(cert, pub); pki_ign_openssl_error(); - if (i>0) { + return i>0; +} + +bool pki_x509::verify(pki_x509 *signer) +{ + if (psigner == signer) + return true; + if ((psigner != NULL) || (signer == NULL)) + return false; + if (verify_only(signer)) { int idx; x509rev r; r.setSerial(getSerial()); @@ -675,6 +664,25 @@ pki_key *pki_x509::getPubKey() const return key; } +bool pki_x509::compareNameAndKey(pki_x509 *other) +{ + X509_NAME *subject = X509_get_subject_name(other->cert); + X509_NAME *issuer = X509_get_issuer_name(cert); + pki_openssl_error(); + if (!subject || !issuer) + return false; + if (X509_NAME_cmp(subject, issuer)) + return false; + EVP_PKEY *pub1 = X509_get_pubkey(cert); + EVP_PKEY *pub2 = X509_get_pubkey(other->cert); + pki_ign_openssl_error(); + if (!pub1 || !pub2) + return false; + int r = EVP_PKEY_cmp(pub1, pub2); + pki_openssl_error(); + return r == 1; +} + void pki_x509::setPubKey(pki_key *key) { X509_set_pubkey(cert, key->getPubKey()); diff --git a/lib/pki_x509.h b/lib/pki_x509.h index db884811..836818c6 100644 --- a/lib/pki_x509.h +++ b/lib/pki_x509.h @@ -57,8 +57,6 @@ class pki_x509 : public pki_x509super void fromPEM_BIO(BIO *bio, QString name); void writeDefault(const QString fname); a1int hashInfo(const EVP_MD *md) const; - a1int getQASerial(const a1int &secret) const; - bool verifyQASerial(const a1int &secret) const; void setSerial(const a1int &serial); a1int getSerial() const; void setNotBefore(const a1time &a); @@ -77,6 +75,7 @@ class pki_x509 : public pki_x509super bool canSign(); void writeCert(const QString fname, bool PEM, bool append = false); bool verify(pki_x509 *signer); + bool verify_only(pki_x509 *signer); pki_key *getPubKey() const; void setPubKey(pki_key *key); pki_x509 *getSigner(); @@ -113,6 +112,11 @@ class pki_x509 : public pki_x509super { return ++crlNumber; } + void setCrlNumber(a1int n) + { + if (n > crlNumber) + crlNumber = n; + } void setTemplate(QString s) { if (s.length() > 0) @@ -164,6 +168,7 @@ class pki_x509 : public pki_x509super revList.merge(l); } void setRevocations(const x509revList &rl); + bool compareNameAndKey(pki_x509 *other); }; #endif diff --git a/lib/pki_x509super.h b/lib/pki_x509super.h index c6c94eae..713c2134 100644 --- a/lib/pki_x509super.h +++ b/lib/pki_x509super.h @@ -52,6 +52,10 @@ class pki_x509super : public pki_x509name }; virtual QString getSigAlg(); virtual const EVP_MD *getDigest(); + virtual bool isSpki() const + { + return false; + } pki_key *getRefKey() const; void setRefKey(pki_key *ref); void delRefKey(pki_key *ref); diff --git a/ui/ExportDialog.ui b/ui/ExportDialog.ui index 476f704e..5de1762d 100644 --- a/ui/ExportDialog.ui +++ b/ui/ExportDialog.ui @@ -6,8 +6,8 @@ 0 0 - 653 - 370 + 589 + 331 diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui index 2493b627..f239898c 100644 --- a/ui/MainWindow.ui +++ b/ui/MainWindow.ui @@ -12,30 +12,21 @@ - - 6 - - - 9 - - 0 + 2 Private Keys - - 6 - 8 - + @@ -133,14 +124,11 @@ Certificate signing requests - - 6 - 8 - + @@ -157,9 +145,6 @@ QFrame::Sunken - - 6 - 8 @@ -237,14 +222,11 @@ Certificates - - 6 - 8 - + @@ -255,9 +237,6 @@ QFrame::Sunken - - 6 - 11 @@ -356,14 +335,11 @@ Templates - - 6 - 8 - + true @@ -378,9 +354,6 @@ QFrame::Sunken - - 6 - 11 @@ -458,12 +431,6 @@ Revocation lists - - 6 - - - 9 - @@ -476,12 +443,6 @@ QFrame::Sunken - - 6 - - - 9 - @@ -554,8 +515,489 @@ XcaTreeView QTreeView
widgets/XcaTreeView.h
+ + newItem() + load() + storeItems() + showItems() + deleteItems() + + + + KeyTreeView + QTreeView +
widgets/KeyTreeView.h
+
+ + TempTreeView + QTreeView +
widgets/TempTreeView.h
+
+ + ReqTreeView + QTreeView +
widgets/ReqTreeView.h
+
+ + CertTreeView + QTreeView +
widgets/CertTreeView.h
+ + loadPKCS12() + loadPKCS7() + changeView() +
- + + + BNimportKey + clicked() + keyView + load() + + + 505 + 129 + + + 382 + 135 + + + + + BNnewKey + clicked() + keyView + newItem() + + + 488 + 67 + + + 392 + 67 + + + + + BNexportKey + clicked() + keyView + storeItems() + + + 526 + 99 + + + 393 + 99 + + + + + BNdetailsKey + clicked() + keyView + showItems() + + + 473 + 200 + + + 405 + 200 + + + + + BNdeleteKey + clicked() + keyView + deleteItems() + + + 470 + 229 + + + 404 + 230 + + + + + BNnewReq + clicked() + reqView + newItem() + + + 496 + 57 + + + 371 + 58 + + + + + BNexportReq + clicked() + reqView + storeItems() + + + 489 + 91 + + + 400 + 95 + + + + + BNimportReq + clicked() + reqView + load() + + + 500 + 123 + + + 412 + 130 + + + + + BNdetailsReq + clicked() + reqView + showItems() + + + 497 + 157 + + + 419 + 166 + + + + + BNdeleteReq + clicked() + reqView + deleteItems() + + + 475 + 196 + + + 399 + 196 + + + + + BNnewCert + clicked() + certView + newItem() + + + 478 + 63 + + + 398 + 63 + + + + + BNexportCert + clicked() + certView + storeItems() + + + 499 + 97 + + + 401 + 99 + + + + + BNimportCert + clicked() + certView + load() + + + 475 + 127 + + + 401 + 128 + + + + + BNdetailsCert + clicked() + certView + showItems() + + + 486 + 162 + + + 395 + 165 + + + + + BNdeleteCert + clicked() + certView + deleteItems() + + + 482 + 203 + + + 357 + 207 + + + + + BNnewTemp + clicked() + tempView + newItem() + + + 513 + 60 + + + 363 + 62 + + + + + BNchangeTemp + clicked() + tempView + showItems() + + + 481 + 94 + + + 415 + 97 + + + + + BNdeleteTemp + clicked() + tempView + deleteItems() + + + 482 + 126 + + + 428 + 126 + + + + + BNimportTemp + clicked() + tempView + load() + + + 487 + 165 + + + 407 + 165 + + + + + BNexportTemp + clicked() + tempView + storeItems() + + + 488 + 201 + + + 428 + 201 + + + + + BNexportCrl + clicked() + crlView + storeItems() + + + 472 + 70 + + + 381 + 70 + + + + + BNimportCrl + clicked() + crlView + load() + + + 496 + 99 + + + 382 + 99 + + + + + BNdetailsCrl + clicked() + crlView + showItems() + + + 477 + 131 + + + 391 + 131 + + + + + BNdeleteCrl + clicked() + crlView + deleteItems() + + + 471 + 173 + + + 386 + 172 + + + + + BNimportPKCS12 + clicked() + certView + loadPKCS12() + + + 504 + 239 + + + 420 + 234 + + + + + BNimportPKCS7 + clicked() + certView + loadPKCS7() + + + 544 + 265 + + + 406 + 260 + + + + + BNimportPFX + clicked() + certView + loadPKCS12() + + + 483 + 170 + + + 230 + 263 + + + + + BNviewState + clicked() + certView + changeView() + + + 472 + 304 + + + 402 + 301 + + + + diff --git a/ui/RevocationList.ui b/ui/RevocationList.ui index 48dcf0e0..5fdcc6f2 100644 --- a/ui/RevocationList.ui +++ b/ui/RevocationList.ui @@ -124,7 +124,7 @@ - QDialogButtonBox::Abort|QDialogButtonBox::Ok + QDialogButtonBox::Cancel|QDialogButtonBox::Ok diff --git a/ui/Revoke.ui b/ui/Revoke.ui index f74d1bf5..ea40dadb 100644 --- a/ui/Revoke.ui +++ b/ui/Revoke.ui @@ -164,8 +164,8 @@ accept() - 236 - 185 + 242 + 277 157 @@ -180,12 +180,28 @@ localTime(int) - 397 - 122 + 398 + 194 389 - 93 + 167 + + + + + buttonBox + rejected() + Revoke + reject() + + + 97 + 268 + + + 109 + 59 diff --git a/widgets/CertTreeView.cpp b/widgets/CertTreeView.cpp new file mode 100644 index 00000000..b619f94a --- /dev/null +++ b/widgets/CertTreeView.cpp @@ -0,0 +1,198 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include "lib/pki_x509.h" +#include "CertTreeView.h" +#include "MainWindow.h" +#include +#include +#include + +void CertTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes) +{ + QMenu *subCa; + bool parentCanSign, multi, hasScard, sameParent, + allRevoked, allUnrevoked; + pki_key *privkey; + + X509SuperTreeView::fillContextMenu(menu, subExport, index, indexes); + + menu->addAction(tr("Import PKCS#12"), this, SLOT(loadPKCS12())); + menu->addAction(tr("Import from PKCS#7"), this, SLOT(loadPKCS7())); + + if (indexes.size() == 0) + return; + + pki_x509 *cert = static_cast(index.internalPointer()); + pki_x509 *parent; + + privkey = cert->getRefKey(); + parent = cert->getSigner(); + parentCanSign = parent && parent->canSign() && (parent != cert); + hasScard = pkcs11::loaded(); + + multi = indexes.size() > 1; + + allUnrevoked = allRevoked = sameParent = true; + foreach(QModelIndex i, indexes) { + pki_x509 *c = static_cast + (i.internalPointer()); + if (c->getSigner() != parent) + sameParent = false; + if (c->isRevoked()) + allUnrevoked = false; + else + allRevoked = false; + } + + if (!multi) { + transform->addAction(tr("Request"), this, SLOT(toRequest()))-> + setEnabled(privkey && privkey->isPrivKey()); + subExport->addAction(tr("Security token"), this, + SLOT(toToken()))->setEnabled(hasScard); + subExport->addAction(tr("Other token"), this, + SLOT(toOtherToken()))->setEnabled(hasScard); + + transform->addAction(tr("Similar Certificate"), this, + SLOT(toCertificate())); + + menu->addAction(tr("Delete from Security token"), this, + SLOT(deleteFromToken()))->setEnabled(hasScard); + + subCa = menu->addMenu(tr("CA")); + subCa->addAction(tr("Properties"), this, SLOT(caProperties())); + subCa->addAction(tr("Generate CRL"), this, SLOT(genCrl())); + subCa->addAction(tr("Manage revocations"), this, + 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())); + if (allUnrevoked) + menu->addAction(tr("Revoke") +n, this, SLOT(revoke())); + if (allRevoked) + menu->addAction(tr("Unrevoke") +n, this, + SLOT(unRevoke())); + } +} + +void CertTreeView::changeView() +{ + if (!certs) + return; + + db_x509 *c = certs; + + hide(); + setModel(); + + c->changeView(); + + setModel(c); + show(); + setRootIsDecorated(db_x509::treeview); +} + +void CertTreeView::toRequest() +{ + if (certs) + certs->toRequest(currentIndex()); +} + +void CertTreeView::toToken() +{ + if (certs) + certs->toToken(currentIndex(), false); +} + +void CertTreeView::toOtherToken() +{ + if (certs) + certs->toToken(currentIndex(), true); +} + +void CertTreeView::loadPKCS12() +{ + if (certs) { + load_pkcs12 l; + certs->load_default(l); + } +} + +void CertTreeView::loadPKCS7() +{ + if (certs) { + load_pkcs7 l; + certs->load_default(l); + } +} + +void CertTreeView::genCrl() +{ + pki_x509 *cert = static_cast + (currentIndex().internalPointer()); + mainwin->crls->newItem(cert); +} + +void CertTreeView::toCertificate() +{ + if (certs) + certs->toCertificate(currentIndex()); +} + +void CertTreeView::deleteFromToken() +{ + pki_x509 *cert = static_cast + (currentIndex().internalPointer()); + try { + cert->deleteFromToken(); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + +void CertTreeView::manageRevocations() +{ + if (certs) + certs->manageRevocations(currentIndex()); +} + +void CertTreeView::caProperties() +{ + if (certs) + certs->caProperties(currentIndex()); +} + +void CertTreeView::certRenewal() +{ + if (certs) + certs->certRenewal(getSelectedIndexes()); +} + +void CertTreeView::revoke() +{ + if (certs) + certs->revoke(getSelectedIndexes()); +} + +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 new file mode 100644 index 00000000..1184b5d6 --- /dev/null +++ b/widgets/CertTreeView.h @@ -0,0 +1,49 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __CERTTREEVIEW_H +#define __CERTTREEVIEW_H + +#include "X509SuperTreeView.h" +#include "lib/db_x509.h" + +class CertTreeView: public X509SuperTreeView +{ + Q_OBJECT + db_x509 *certs; + + public: + CertTreeView(QWidget *parent) : X509SuperTreeView(parent) + { + certs = NULL; + } + void fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes); + void setModel(db_x509 *model=NULL) + { + certs = model; + X509SuperTreeView::setModel(model); + } + + public slots: + void changeView(); + void toRequest(); + void toCertificate(); + void toToken(); + void toOtherToken(); + void genCrl(); + void loadPKCS7(); + void loadPKCS12(); + void deleteFromToken(); + void manageRevocations(); + void certRenewal(); + void caProperties(); + void revoke(); + void unRevoke(); + void setTrust(); +}; +#endif diff --git a/widgets/ExportDialog.cpp b/widgets/ExportDialog.cpp index 421a59cf..8c5a4582 100644 --- a/widgets/ExportDialog.cpp +++ b/widgets/ExportDialog.cpp @@ -24,13 +24,16 @@ ExportDialog::ExportDialog(MainWindow *mw, QString title, QString filt, setupUi(this); mainwin = mw; setWindowTitle(XCA_TITLE); - descr->setText(pki->getIntName()); + if (pki) + descr->setText(pki->getIntName()); descr->setReadOnly(true); image->setPixmap(*img); label->setText(title); - QString fn = mainwin->getPath() + QDir::separator() + - pki->getUnderlinedName() + "." + types[0].extension; - filename->setText(fn); + if (pki) { + QString fn = mainwin->getPath() + QDir::separator() + + pki->getUnderlinedName() + "." + types[0].extension; + filename->setText(fn); + } filter = filt + ";;" + tr("All files ( * )"); foreach(exportType t, types) { diff --git a/widgets/KeyTreeView.cpp b/widgets/KeyTreeView.cpp new file mode 100644 index 00000000..8985e7b3 --- /dev/null +++ b/widgets/KeyTreeView.cpp @@ -0,0 +1,158 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include "lib/pki_scard.h" +#include "XcaTreeView.h" +#include "MainWindow.h" +#include +#include +#include + +void KeyTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes) +{ + bool multi = indexes.size() > 1; + + pki_key *key = static_cast(index.internalPointer()); + + if (index == QModelIndex()) + return; + + if (!multi && key && key->isPrivKey() && !key->isToken()) { + switch (key->getOwnPass()) { + case pki_key::ptCommon: + menu->addAction(tr("Change password"), this, + SLOT(setOwnPass())); + break; + case pki_key::ptPrivate: + menu->addAction(tr("Reset password"), this, + SLOT(resetOwnPass())); + break; + } + } + + if (!pkcs11::loaded() || multi) + return; + + if (key->isToken()) { + menu->addAction(tr("Change PIN"), this, + SLOT(changePin())); + menu->addAction(tr("Init PIN with SO PIN (PUK)"), this, + SLOT(initPin())); + menu->addAction(tr("Change SO PIN (PUK)"), this, + SLOT(changeSoPin())); + } else { + menu->addAction(tr("Store on Security token"), + this, SLOT(toToken())); + } +} + +void KeyTreeView::setOwnPass() +{ + try { + keys->setOwnPass(currentIndex(), pki_key::ptPrivate); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + +void KeyTreeView::resetOwnPass() +{ + try { + keys->setOwnPass(currentIndex(), pki_key::ptCommon); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + +void KeyTreeView::changePin() +{ + pki_scard *scard; + QModelIndex currentIdx = currentIndex(); + + if (!currentIdx.isValid()) + return; + scard = static_cast(currentIdx.internalPointer()); + try { + if (!scard->isToken()) { + throw errorEx(tr("Tried to change PIN of a key")); + } + scard->changePin(); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + +void KeyTreeView::initPin() +{ + pki_scard *scard; + QModelIndex currentIdx = currentIndex(); + + if (!currentIdx.isValid()) + return; + scard = static_cast(currentIdx.internalPointer()); + try { + if (!scard->isToken()) { + throw errorEx(tr("Tried to init PIN of a key")); + } + scard->initPin(); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + +void KeyTreeView::changeSoPin() +{ + pki_scard *scard; + QModelIndex currentIdx = currentIndex(); + + if (!currentIdx.isValid()) + return; + scard = static_cast(currentIdx.internalPointer()); + try { + if (!scard->isToken()) { + throw errorEx(tr("Tried to change SO PIN of a key")); + } + scard->changeSoPin(); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + +void KeyTreeView::toToken() +{ + QModelIndex currentIdx = currentIndex(); + + if (!currentIdx.isValid()) + return; + + pki_key *key = static_cast(currentIdx.internalPointer()); + if (!key || !pkcs11::loaded() || key->isToken()) + return; + + pki_scard *card = NULL; + try { + pkcs11 p11; + slotid slot; + + if (!p11.selectToken(&slot, mainwin)) + return; + card = new pki_scard(key->getIntName()); + card->store_token(slot, key->decryptKey()); + QString msg = tr("Shall the original key '%1' be replaced by the key on the token?\nThis will delete the key '%1' and make it unexportable"). + arg(key->getIntName()); + if (XCA_YESNO(msg)) { + keys->deletePKI(currentIdx); + keys->insertPKI(card); + card = NULL; + } + } catch (errorEx &err) { + mainwin->Error(err); + } + if (card) + delete card; +} diff --git a/widgets/KeyTreeView.h b/widgets/KeyTreeView.h new file mode 100644 index 00000000..8f3b8e62 --- /dev/null +++ b/widgets/KeyTreeView.h @@ -0,0 +1,40 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2006 - 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __KEYTREEVIEW_H +#define __KEYTREEVIEW_H + +#include "XcaTreeView.h" +#include "lib/db_key.h" + +class KeyTreeView: public XcaTreeView +{ + Q_OBJECT + db_key *keys; + + public: + KeyTreeView(QWidget *parent) : XcaTreeView(parent) + { + keys = NULL; + } + void fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes); + void setModel(db_key *model=NULL) + { + keys = model; + XcaTreeView::setModel(model); + } + + public slots: + void resetOwnPass(); + void setOwnPass(); + void changePin(); + void initPin(); + void changeSoPin(); + void toToken(); +}; +#endif diff --git a/widgets/MW_database.cpp b/widgets/MW_database.cpp index 91f67f44..879c3452 100644 --- a/widgets/MW_database.cpp +++ b/widgets/MW_database.cpp @@ -89,9 +89,9 @@ int MainWindow::init_database() connect( reqs, SIGNAL(newCert(pki_x509req *)), certs, SLOT(newCert(pki_x509req *)) ); - connect( temps, SIGNAL(newCert(pki_temp *)), + connect( tempView, SIGNAL(newCert(pki_temp *)), certs, SLOT(newCert(pki_temp *)) ); - connect( temps, SIGNAL(newReq(pki_temp *)), + connect( tempView, SIGNAL(newReq(pki_temp *)), reqs, SLOT(newItem(pki_temp *)) ); keyView->setIconSize(pki_evp::icon[0]->size()); @@ -298,11 +298,11 @@ void MainWindow::close_database() statusBar()->removeWidget(searchEdit); dbindex->clear(); - keyView->setModel(NULL); - reqView->setModel(NULL); - certView->setModel(NULL); - tempView->setModel(NULL); - crlView->setModel(NULL); + keyView->setModel(); + reqView->setModel(); + certView->setModel(); + tempView->setModel(); + crlView->setModel(); if (crls) delete(crls); @@ -406,188 +406,3 @@ void MainWindow::update_history(QString fname) file.close(); update_history_menu(); } - -/* Asymetric Key buttons */ -void MainWindow::on_BNnewKey_clicked(void) -{ - if (keys) - keys->newItem(); -} -void MainWindow::on_BNdeleteKey_clicked(void) -{ - if (keys) - keys->deleteSelectedItems(keyView); -} -void MainWindow::on_BNdetailsKey_clicked(void) -{ - if (keys) - keys->showSelectedItems(keyView); -} -void MainWindow::on_BNimportKey_clicked(void) -{ - if (keys) - keys->load(); -} -void MainWindow::on_BNexportKey_clicked(void) -{ - if (keys) - keys->storeSelectedItems(keyView); -} - -void MainWindow::on_keyView_doubleClicked(const QModelIndex &m) -{ - if (keys) - keys->showItem(keyView->getIndex(m)); -} - -void MainWindow::on_reqView_doubleClicked(const QModelIndex &m) -{ - if (reqs) - reqs->showItem(reqView->getIndex(m)); -} - -void MainWindow::on_certView_doubleClicked(const QModelIndex &m) -{ - if (certs) - certs->showItem(certView->getIndex(m)); -} - -void MainWindow::on_tempView_doubleClicked(const QModelIndex &m) -{ - if (temps) - temps->showItem(tempView->getIndex(m)); -} - -void MainWindow::on_crlView_doubleClicked(const QModelIndex &m) -{ - if (crls) - crls->showItem(crlView->getIndex(m)); -} - -void MainWindow::on_BNimportPFX_clicked(void) -{ - if (certs) - certs->loadPKCS12(); -} - -/* Certificate request buttons */ -void MainWindow::on_BNnewReq_clicked(void) -{ - if (reqs) - reqs->newItem(); -} -void MainWindow::on_BNdeleteReq_clicked(void) -{ - if (reqs) - reqs->deleteSelectedItems(reqView); -} -void MainWindow::on_BNdetailsReq_clicked(void) -{ - if (reqs) - reqs->showSelectedItems(reqView); -} -void MainWindow::on_BNimportReq_clicked(void) -{ - if (reqs) - reqs->load(); -} -void MainWindow::on_BNexportReq_clicked(void) -{ - if(reqs) - reqs->storeSelectedItems(reqView); -} - -/* Certificate buttons */ -void MainWindow::on_BNnewCert_clicked(void) -{ - if (certs) - certs->newItem(); -} -void MainWindow::on_BNdeleteCert_clicked(void) -{ - if (certs) - certs->deleteSelectedItems(certView); -} -void MainWindow::on_BNdetailsCert_clicked(void) -{ - if (certs) - certs->showSelectedItems(certView); -} -void MainWindow::on_BNimportCert_clicked(void) -{ - if (certs) - certs->load(); -} -void MainWindow::on_BNexportCert_clicked(void) -{ - if(certs) - certs->storeSelectedItems(certView); -} - -void MainWindow::on_BNimportPKCS12_clicked(void) -{ - if(certs) - certs->loadPKCS12(); -} - -void MainWindow::on_BNimportPKCS7_clicked(void) -{ - if(certs) - certs->loadPKCS7(); -} - -void MainWindow::on_BNviewState_clicked(void) -{ - if(certs) - certs->changeView(); - certView->setRootIsDecorated(db_x509::treeview); -} - -/* Template buttons */ -void MainWindow::on_BNdeleteTemp_clicked(void) -{ - if (temps) - temps->deleteSelectedItems(tempView); -} -void MainWindow::on_BNchangeTemp_clicked(void) -{ - if (temps) - temps->showSelectedItems(tempView); -} -void MainWindow::on_BNimportTemp_clicked(void) -{ - if (temps) - temps->load(); -} -void MainWindow::on_BNexportTemp_clicked(void) -{ - if(temps) - temps->storeSelectedItems(tempView); -} -void MainWindow::on_BNnewTemp_clicked(void) -{ - if (temps) - temps->newItem(); -} - -/* CRL buttons */ -void MainWindow::on_BNdeleteCrl_clicked(void) -{ - if (crls) - crls->deleteSelectedItems(crlView); -} -void MainWindow::on_BNimportCrl_clicked(void) -{ - if (crls) - crls->load(); -} -void MainWindow::on_BNexportCrl_clicked(void) -{ - if (crls) - crls->storeSelectedItems(crlView); -} -void MainWindow::on_BNdetailsCrl_clicked(void) -{ - if(crls) - crls->showSelectedItems(crlView); -} diff --git a/widgets/MW_menu.cpp b/widgets/MW_menu.cpp index 44773470..26c2314d 100644 --- a/widgets/MW_menu.cpp +++ b/widgets/MW_menu.cpp @@ -119,24 +119,15 @@ void MainWindow::init_menu() file->addAction(a); import = menuBar()->addMenu(tr("I&mport")); - import->addAction(tr("Keys"), this, - SLOT(on_BNimportKey_clicked()) ); - import->addAction(tr("Requests"), this, - SLOT(on_BNimportReq_clicked()) ); - import->addAction(tr("Certificates"), this, - SLOT(on_BNimportCert_clicked()) ); - import->addAction(tr("PKCS#12"), this, - SLOT(on_BNimportPKCS12_clicked()) ); - import->addAction(tr("PKCS#7"), this, - SLOT(on_BNimportPKCS7_clicked()) ); - import->addAction(tr("Template"), this, - SLOT(on_BNimportTemp_clicked()) ); - import->addAction(tr("Revocation list"), this, - SLOT(on_BNimportCrl_clicked()) ); - import->addAction(tr("PEM file"), this, - SLOT(loadPem()) ); - import->addAction(tr("paste PEM file"), this, - SLOT(pastePem()) ); + import->addAction(tr("Keys"), keyView, SLOT(load()) ); + import->addAction(tr("Requests"), reqView, SLOT(load()) ); + import->addAction(tr("Certificates"), certView, SLOT(load()) ); + import->addAction(tr("PKCS#12"), certView, SLOT(loadPKCS12()) ); + import->addAction(tr("PKCS#7"), certView, SLOT(loadPKCS7()) ); + import->addAction(tr("Template"), tempView, SLOT(load()) ); + import->addAction(tr("Revocation list"), crlView, SLOT(load())); + import->addAction(tr("PEM file"), this, SLOT(loadPem()) ); + import->addAction(tr("paste PEM file"), this, SLOT(pastePem())); token = menuBar()->addMenu(tr("&Token")); token->addAction(tr("&Manage Security token"), this, diff --git a/widgets/MainWindow.cpp b/widgets/MainWindow.cpp index 6cebb065..55a0cd52 100644 --- a/widgets/MainWindow.cpp +++ b/widgets/MainWindow.cpp @@ -139,22 +139,11 @@ MainWindow::MainWindow(QWidget *parent) searchEdit = new QLineEdit(); - connect(searchEdit, SIGNAL(textChanged(const QString &)), - keyView, SLOT(setFilter(const QString&))); - connect(searchEdit, SIGNAL(textChanged(const QString &)), - reqView, SLOT(setFilter(const QString&))); - connect(searchEdit, SIGNAL(textChanged(const QString &)), - certView, SLOT(setFilter(const QString&))); - connect(searchEdit, SIGNAL(textChanged(const QString &)), - tempView, SLOT(setFilter(const QString&))); - connect(searchEdit, SIGNAL(textChanged(const QString &)), - crlView, SLOT(setFilter(const QString&))); - - keyView->setModel(keys); - reqView->setModel(reqs); - certView->setModel(certs); - tempView->setModel(temps); - crlView->setModel(crls); + keyView->setMainwin(this, searchEdit); + reqView->setMainwin(this, searchEdit); + certView->setMainwin(this, searchEdit); + tempView->setMainwin(this, searchEdit); + crlView->setMainwin(this, searchEdit); } void MainWindow::dropEvent(QDropEvent *event) diff --git a/widgets/MainWindow.h b/widgets/MainWindow.h index f05d9787..ad917f81 100644 --- a/widgets/MainWindow.h +++ b/widgets/MainWindow.h @@ -168,44 +168,5 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void initPin(); void generateDHparam(); void open_database(QAction* a); - - void on_keyView_doubleClicked(const QModelIndex &m); - void on_reqView_doubleClicked(const QModelIndex &m); - void on_certView_doubleClicked(const QModelIndex &m); - void on_tempView_doubleClicked(const QModelIndex &m); - void on_crlView_doubleClicked(const QModelIndex &m); - - void on_BNnewKey_clicked(); - void on_BNdeleteKey_clicked(); - void on_BNdetailsKey_clicked(); - void on_BNimportKey_clicked(); - void on_BNexportKey_clicked(); - void on_BNimportPFX_clicked(); - - void on_BNnewReq_clicked(); - void on_BNdeleteReq_clicked(); - void on_BNdetailsReq_clicked(); - void on_BNimportReq_clicked(); - void on_BNexportReq_clicked(); - - void on_BNnewCert_clicked(); - void on_BNdeleteCert_clicked(); - void on_BNdetailsCert_clicked(); - void on_BNimportCert_clicked(); - void on_BNexportCert_clicked(); - void on_BNimportPKCS12_clicked(); - void on_BNimportPKCS7_clicked(); - void on_BNviewState_clicked(); - - void on_BNnewTemp_clicked(); - void on_BNdeleteTemp_clicked(); - void on_BNchangeTemp_clicked(); - void on_BNimportTemp_clicked(); - void on_BNexportTemp_clicked(); - - void on_BNdeleteCrl_clicked(); - void on_BNdetailsCrl_clicked(); - void on_BNimportCrl_clicked(); - void on_BNexportCrl_clicked(); }; #endif diff --git a/widgets/Makefile b/widgets/Makefile index df38e348..4d660994 100644 --- a/widgets/Makefile +++ b/widgets/Makefile @@ -7,7 +7,8 @@ endif MOC_NAMES=MainWindow KeyDetail clicklabel XcaTreeView NewX509 \ validity v3ext distname CertDetail CertExtend PwDialog \ ImportMulti CrlDetail ExportDialog hashBox Options NewKey kvView \ - NewCrl SearchPkcs11 RevocationList + NewCrl SearchPkcs11 RevocationList XcaProxyModel XcaHeaderView \ + KeyTreeView TempTreeView ReqTreeView X509SuperTreeView CertTreeView NAMES=$(MOC_NAMES) NewX509_ext MW_menu MW_help MW_database OBJS=$(patsubst %,moc_%.o,$(MOC_NAMES)) $(patsubst %,%.o,$(NAMES)) diff --git a/widgets/ReqTreeView.cpp b/widgets/ReqTreeView.cpp new file mode 100644 index 00000000..428191b4 --- /dev/null +++ b/widgets/ReqTreeView.cpp @@ -0,0 +1,40 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include "lib/pki_x509req.h" +#include "ReqTreeView.h" +#include "MainWindow.h" +#include +#include +#include + +void ReqTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes) +{ + X509SuperTreeView::fillContextMenu(menu, subExport, index, indexes); + + if (indexes.size() != 1) + return; + + menu->addAction(tr("Sign"), this, SLOT(signReq())); + if (transform) { + transform->addAction(tr("Similar Request"), this, + SLOT(toRequest())); + } +} + +void ReqTreeView::toRequest() +{ + if (reqs) + reqs->toRequest(currentIndex()); +} + +void ReqTreeView::signReq() +{ + if (reqs) + reqs->signReq(currentIndex()); +} diff --git a/widgets/ReqTreeView.h b/widgets/ReqTreeView.h new file mode 100644 index 00000000..7fe16ff8 --- /dev/null +++ b/widgets/ReqTreeView.h @@ -0,0 +1,36 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __REQTREEVIEW_H +#define __REQTREEVIEW_H + +#include "X509SuperTreeView.h" +#include "lib/db_x509req.h" + +class ReqTreeView: public X509SuperTreeView +{ + Q_OBJECT + db_x509req *reqs; + + public: + ReqTreeView(QWidget *parent) : X509SuperTreeView(parent) + { + reqs = NULL; + } + void fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes); + void setModel(db_x509req *model=NULL) + { + reqs = model; + X509SuperTreeView::setModel(model); + } + + public slots: + void toRequest(); + void signReq(); +}; +#endif diff --git a/widgets/RevocationList.cpp b/widgets/RevocationList.cpp index da368213..48a5a323 100644 --- a/widgets/RevocationList.cpp +++ b/widgets/RevocationList.cpp @@ -10,22 +10,50 @@ #include "lib/asn1int.h" #include "lib/pki_x509.h" -enum revCol { Cserial, Cdate, Creason, CiDate }; +enum revCol { Cnumber, Cserial, Cdate, Creason, CiDate }; + +class revListItem : public QTreeWidgetItem +{ + public: + revListItem(QTreeWidget *w) : QTreeWidgetItem(w) { }; + bool operator < (const QTreeWidgetItem &other) const + { + int col = treeWidget()->sortColumn(); + switch (col) { + case Cserial: { + a1int ithis, iother; + ithis.setHex(text(Cserial)); + iother.setHex(other.text(Cserial)); + return ithis < iother; + } + case Cnumber: + return text(Cnumber).toLong() < + other.text(Cnumber).toLong(); + default: + return QTreeWidgetItem::operator < (other); + } + } +}; static void addRevItem(QTreeWidget *certList, const x509rev &revit, - const pki_x509 *iss) + int no, const pki_x509 *iss) { - QTreeWidgetItem *current; + revListItem *current; pki_x509 *rev; a1time a; rev = iss->getBySerial(revit.getSerial()); - current = new QTreeWidgetItem(certList); + current = new revListItem(certList); if (rev != NULL) { current->setToolTip(Cserial, rev->getIntName() ); } - current->setText(Cserial, revit.getSerial().toHex()) ; + current->setText(Cnumber, QString("%1").arg(no)); + current->setText(Cserial, revit.getSerial().toHex()); current->setText(Cdate, revit.getDate().toSortable()); current->setText(Creason, revit.getReason()); + + current->setTextAlignment(Cnumber, Qt::AlignRight); + current->setTextAlignment(Cserial, Qt::AlignRight); + a = revit.getInvalDate(); if (!a.isUndefined()) current->setText(CiDate, a.toSortable()); @@ -39,7 +67,7 @@ void RevocationList::setupRevocationView(QTreeWidget *certList, certList->clear(); - sl << tr("Serial") << tr("Revocation") << tr("Reason") << + sl << tr("No.") << tr("Serial") << tr("Revocation") << tr("Reason") << tr("Invalidation"); cols = sl.size(); @@ -47,9 +75,11 @@ void RevocationList::setupRevocationView(QTreeWidget *certList, certList->setHeaderLabels(sl); certList->setItemsExpandable(false); certList->setRootIsDecorated(false); + certList->sortItems(Cnumber, Qt::AscendingOrder); + i=1; foreach(x509rev revit, revList) { - addRevItem(certList, revit, iss); + addRevItem(certList, revit, i++, iss); } for (i=0; iresizeColumnToContents(i); @@ -88,11 +118,11 @@ const x509revList &RevocationList::getRevList() void RevocationList::on_addRev_clicked(void) { - Revocation *revoke = new Revocation(this, NULL); + Revocation *revoke = new Revocation(this, QModelIndexList()); if (revoke->exec()) { x509rev revit = revoke->getRevocation(); revList << revit; - addRevItem(certList, revit, issuer); + addRevItem(certList, revit, revList.size(), issuer); } } @@ -114,14 +144,32 @@ void RevocationList::on_delRev_clicked(void) revList.takeAt(idx); } -Revocation::Revocation(QWidget *w, pki_x509 *r) : QDialog(w) +Revocation::Revocation(QWidget *w, QModelIndexList indexes) : QDialog(w) { setupUi(this); setWindowTitle(XCA_TITLE); reason->addItems(x509rev::crlreasons()); invalid->setNow(); - if (r) { - serial->setText(r->getSerial().toHex()); + + if (indexes.size() > 1) { + QList serials; + QStringList sl; + serial->setText(QString("Batch revocation of %1 Certificates"). + arg(indexes.size())); + foreach(QModelIndex idx, indexes) { + pki_x509 *cert = static_cast + (idx.internalPointer()); + serials << cert->getSerial(); + } + qSort(serials.begin(), serials.end()); + foreach(a1int a, serials) + sl << a.toHex(); + serial->setToolTip(sl.join("\n")); + serial->setEnabled(false); + } else if (indexes.size() == 1) { + pki_x509 *cert = static_cast + (indexes[0].internalPointer()); + serial->setText(cert->getSerial().toHex()); serial->setEnabled(false); } } diff --git a/widgets/RevocationList.h b/widgets/RevocationList.h index 8da33ea1..0e39af23 100644 --- a/widgets/RevocationList.h +++ b/widgets/RevocationList.h @@ -11,6 +11,7 @@ #include "ui_RevocationList.h" #include "ui_Revoke.h" #include "lib/x509rev.h" +#include class pki_x509; @@ -42,7 +43,7 @@ class Revocation: public QDialog, public Ui::Revoke Q_OBJECT public: - Revocation(QWidget *w, pki_x509 *r); + Revocation(QWidget *w, QModelIndexList indexes); x509rev getRevocation(); }; #endif diff --git a/widgets/TempTreeView.cpp b/widgets/TempTreeView.cpp new file mode 100644 index 00000000..e71f47ff --- /dev/null +++ b/widgets/TempTreeView.cpp @@ -0,0 +1,55 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include "lib/pki_temp.h" +#include "XcaTreeView.h" +#include "MainWindow.h" +#include +#include +#include + +void TempTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes) +{ + if (indexes.size() != 1) + return; + menu->addAction(tr("Duplicate"), this, SLOT(duplicateTemp())); + menu->addAction(tr("Create certificate"), this, SLOT(certFromTemp())); + menu->addAction(tr("Create request"), this, SLOT(reqFromTemp())); +} + +void TempTreeView::duplicateTemp() +{ + QModelIndex currentIdx = currentIndex(); + + if (!currentIdx.isValid()) + return; + pki_temp *temp = static_cast(currentIdx.internalPointer()); + pki_temp *newtemp = new pki_temp(temp); + newtemp->setIntName(newtemp->getIntName() + " " + tr("copy")); + temps->insertPKI(newtemp); +} + +void TempTreeView::certFromTemp() +{ + QModelIndex currentIdx = currentIndex(); + + if (!currentIdx.isValid()) + return; + pki_temp *temp = static_cast(currentIdx.internalPointer()); + emit newCert(temp); +} + +void TempTreeView::reqFromTemp() +{ + QModelIndex currentIdx = currentIndex(); + + if (!currentIdx.isValid()) + return; + pki_temp *temp = static_cast(currentIdx.internalPointer()); + emit newReq(temp); +} diff --git a/widgets/TempTreeView.h b/widgets/TempTreeView.h new file mode 100644 index 00000000..afee95d2 --- /dev/null +++ b/widgets/TempTreeView.h @@ -0,0 +1,40 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2006 - 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __TEMPTREEVIEW_H +#define __TEMPTREEVIEW_H + +#include "XcaTreeView.h" +#include "lib/db_temp.h" + +class TempTreeView: public XcaTreeView +{ + Q_OBJECT + db_temp *temps; + + public: + TempTreeView(QWidget *parent) : XcaTreeView(parent) + { + temps = NULL; + } + void fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes); + void setModel(db_temp *model=NULL) + { + temps = model; + XcaTreeView::setModel(model); + } + + public slots: + void certFromTemp(); + void reqFromTemp(); + void duplicateTemp(); + signals: + void newReq(pki_temp *); + void newCert(pki_temp *); +}; +#endif diff --git a/widgets/X509SuperTreeView.cpp b/widgets/X509SuperTreeView.cpp new file mode 100644 index 00000000..0326b08f --- /dev/null +++ b/widgets/X509SuperTreeView.cpp @@ -0,0 +1,56 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include "lib/pki_x509req.h" +#include "X509SuperTreeView.h" +#include "MainWindow.h" +#include +#include +#include + +void X509SuperTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes) +{ + pki_x509super *x = static_cast + (index.internalPointer()); + transform = NULL; + + if (indexes.size() != 1) + return; + + subExport->addAction(tr("OpenSSL config"), this, SLOT(toOpenssl())); + subExport->setEnabled(!x->isSpki()); + transform = menu->addMenu(tr("Transform")); + transform->addAction(tr("Template"), this, + SLOT(toTemplate()))->setEnabled(!x->isSpki()); + transform->addAction(tr("Public Key"), this, + SLOT(extractPubkey()))->setEnabled(!x->getRefKey()); +} + +void X509SuperTreeView::extractPubkey() +{ + QModelIndex idx = currentIndex(); + + if (idx.isValid() && x509super) + x509super->extractPubkey(idx); +} + +void X509SuperTreeView::toTemplate() +{ + QModelIndex idx = currentIndex(); + + if (idx.isValid() && x509super) + x509super->toTemplate(idx); +} + +void X509SuperTreeView::toOpenssl() +{ + QModelIndex idx = currentIndex(); + + if (idx.isValid() && x509super) + x509super->toOpenssl(idx); +} diff --git a/widgets/X509SuperTreeView.h b/widgets/X509SuperTreeView.h new file mode 100644 index 00000000..2531f10b --- /dev/null +++ b/widgets/X509SuperTreeView.h @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2006 - 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __X509SUPERTREEVIEW_H +#define __X509SUPERTREEVIEW_H + +#include "XcaTreeView.h" +#include "lib/db_x509req.h" + +class X509SuperTreeView: public XcaTreeView +{ + Q_OBJECT + db_x509super *x509super; + + public: + QMenu *transform; + X509SuperTreeView(QWidget *parent) : XcaTreeView(parent) + { + x509super = NULL; + } + void fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes); + void setModel(db_x509super *model=NULL) + { + x509super = model; + XcaTreeView::setModel(model); + } + + public slots: + void extractPubkey(); + void toTemplate(); + void toOpenssl(); +}; +#endif diff --git a/widgets/XcaHeaderView.cpp b/widgets/XcaHeaderView.cpp new file mode 100644 index 00000000..85db2488 --- /dev/null +++ b/widgets/XcaHeaderView.cpp @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include "XcaHeaderView.h" +#include "XcaTreeView.h" + +XcaHeaderView::XcaHeaderView() + :QHeaderView(Qt::Horizontal) +{ + setMovable(true); +} + +void XcaHeaderView::contextMenuEvent(QContextMenuEvent *e) +{ + XcaTreeView *tv = static_cast(parentWidget()); + if (tv) + tv->headerEvent(e, logicalIndexAt(e->pos())); +} + +void XcaHeaderView::resetMoves() +{ + for (int i=0; i + +class XcaHeaderView: public QHeaderView +{ + Q_OBJECT + + public: + XcaHeaderView(); + void contextMenuEvent(QContextMenuEvent *e); + + public slots: + void resetMoves(); +}; +#endif diff --git a/widgets/XcaProxyModel.cpp b/widgets/XcaProxyModel.cpp new file mode 100644 index 00000000..10f31e11 --- /dev/null +++ b/widgets/XcaProxyModel.cpp @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2006 - 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include "XcaProxyModel.h" +#include "lib/db_base.h" + +bool XcaProxyModel::lessThan(const QModelIndex &left, + const QModelIndex &right) const +{ + db_base *db = (db_base *)sourceModel(); + if (!db) + return QSortFilterProxyModel::lessThan(left, right); + + if (db->isNumericCol(left.column()) && + db->isNumericCol(right.column())) + { + int diff; + QString l = sourceModel()->data(left).toString(); + QString r = sourceModel()->data(right).toString(); + diff = l.size() - r.size(); + if (diff<0) + return true; + else if (diff>0) + return false; + else + return l < r; + } + return QSortFilterProxyModel::lessThan(left, right); +} + +bool XcaProxyModel::filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const +{ + QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent); + return sourceModel()->data(idx, Qt::UserRole).toBool(); +} + +QVariant XcaProxyModel::data(const QModelIndex &index, int role) const +{ + QModelIndex i; + QString number; + + if (index.column() != 1) + return QSortFilterProxyModel::data(index, role); + + /* Row number */ + switch (role) { + case Qt::EditRole: + case Qt::DisplayRole: + for (i = index; i.isValid(); i = i.parent()) + number += QString(" %1").arg(i.row()+1); + return QVariant(number); + default: + return QSortFilterProxyModel::data(index, role); + } + return QVariant(); +} + diff --git a/widgets/XcaProxyModel.h b/widgets/XcaProxyModel.h new file mode 100644 index 00000000..33f35d41 --- /dev/null +++ b/widgets/XcaProxyModel.h @@ -0,0 +1,27 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2006 - 2015 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __XCAPROXYMODEL_H +#define __XCAPROXYMODEL_H + +#include +#include +#include + +class XcaProxyModel: public QSortFilterProxyModel +{ + Q_OBJECT + public: + XcaProxyModel(QWidget *parent = 0) + :QSortFilterProxyModel(parent) { } + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + bool filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const; + QVariant data(const QModelIndex &index, int role) const; +}; + +#endif diff --git a/widgets/XcaTreeView.cpp b/widgets/XcaTreeView.cpp index ff06c484..9c91e64c 100644 --- a/widgets/XcaTreeView.cpp +++ b/widgets/XcaTreeView.cpp @@ -6,12 +6,14 @@ */ +#include "XcaHeaderView.h" #include "XcaTreeView.h" -#include "lib/db_base.h" +#include "XcaProxyModel.h" +#include "MainWindow.h" #include #include -#include #include +#include #include #include @@ -19,6 +21,7 @@ XcaTreeView::XcaTreeView(QWidget *parent) :QTreeView(parent) { + mainwin = NULL; setHeader(new XcaHeaderView()); setAlternatingRowColors(true); setSelectionMode(QAbstractItemView::ExtendedSelection); @@ -34,6 +37,8 @@ XcaTreeView::XcaTreeView(QWidget *parent) basemodel = NULL; connect(header(), SIGNAL(sectionHandleDoubleClicked(int)), this, SLOT(resizeColumnToContents(int))); + connect(this, SIGNAL(doubleClicked(const QModelIndex &)), + this, SLOT(doubleClick(const QModelIndex &))); header()->setClickable(true); } @@ -48,9 +53,7 @@ void XcaTreeView::contextMenuEvent(QContextMenuEvent * e) if (!basemodel) return; index = indexAt(e->pos()); - /* unselect all but the current on context menu */ - setCurrentIndex(index); - basemodel->showContextMenu(e, getIndex(index)); + showContextMenu(e, getIndex(index)); } void XcaTreeView::showHideSections() @@ -69,12 +72,18 @@ void XcaTreeView::showHideSections() columnsResize(); } +void XcaTreeView::setMainwin(MainWindow *mw, QLineEdit *filter) +{ + mainwin = mw; + connect(filter, SIGNAL(textChanged(const QString &)), + this, SLOT(setFilter(const QString&))); +} + void XcaTreeView::setModel(QAbstractItemModel *model) { QByteArray ba; basemodel = (db_base *)model; - proxy->setSourceModel(model); QTreeView::setModel(proxy); @@ -83,8 +92,6 @@ void XcaTreeView::setModel(QAbstractItemModel *model) header(), SLOT(resetMoves())); connect(basemodel, SIGNAL(resetHeader()), this, SLOT(columnsResize())); - connect(basemodel, SIGNAL(updateHeader()), - this, SLOT(showHideSections())); connect(header(), SIGNAL(sectionMoved(int,int,int)), this, SLOT(sectionMoved(int,int,int))); connect(header(), SIGNAL(sectionResized(int,int,int)), @@ -95,8 +102,6 @@ void XcaTreeView::setModel(QAbstractItemModel *model) this, SLOT(columnsResize())); connect(basemodel, SIGNAL(columnsContentChanged()), proxy, SLOT(invalidate())); - connect(basemodel, SIGNAL(editItem(const QModelIndex &)), - this, SLOT(editIdx(const QModelIndex &))); basemodel->initHeaderView(header()); } @@ -105,7 +110,7 @@ void XcaTreeView::setModel(QAbstractItemModel *model) void XcaTreeView::headerEvent(QContextMenuEvent *e, int col) { - basemodel->showHeaderMenu(e, col); + contextMenu(e, NULL, col); } QModelIndex XcaTreeView::getIndex(const QModelIndex &index) @@ -158,90 +163,216 @@ void XcaTreeView::sectionMoved(int, int, int) } } -void XcaTreeView::editIdx(const QModelIndex &idx) +QModelIndex XcaTreeView::currentIndex() { - edit(proxy->mapFromSource(idx)); + QModelIndex idx = QTreeView::currentIndex(); + idx = getIndex(idx); + idx = basemodel->index(idx.row(), 0, idx.parent()); + if (!idx.isValid()) { + QModelIndexList l = getSelectedIndexes(); + if (l.size() > 0) + idx = l[0]; + } + return idx; +} + +void XcaTreeView::editIdx() +{ + edit(getProxyIndex(currentIndex())); } void XcaTreeView::setFilter(const QString &pattern) { - pki_base::limitPattern = QRegExp(pattern, + pki_base::limitPattern = QRegExp(pattern, Qt::CaseInsensitive, QRegExp::Wildcard); // Only to tell the model about the changed filter - proxy->setFilterFixedString(pattern); + proxy->setFilterFixedString(pattern); } -XcaProxyModel::XcaProxyModel(QWidget *parent) - :QSortFilterProxyModel(parent) +void XcaTreeView::deleteItems(void) { -} + QModelIndex index; + QModelIndexList indexes = getSelectedIndexes(); + QString items, msg; + int count = 0; + pki_base *pki = NULL; -bool XcaProxyModel::lessThan(const QModelIndex &left, - const QModelIndex &right) const -{ - db_base *db = (db_base *)sourceModel(); - if (!db) - return QSortFilterProxyModel::lessThan(left, right); + if (indexes.count() == 0 || !basemodel) + return; - if (db->isNumericCol(left.column()) && - db->isNumericCol(right.column())) - { - int diff; - QString l = sourceModel()->data(left).toString(); - QString r = sourceModel()->data(right).toString(); - diff = l.size() - r.size(); - if (diff<0) - return true; - else if (diff>0) - return false; - else - return l < r; + foreach(index, indexes) { + pki = static_cast(index.internalPointer()); + items += "'" + pki->getIntName() + "' "; + count++; } - return QSortFilterProxyModel::lessThan(left, right); -} -bool XcaProxyModel::filterAcceptsRow(int sourceRow, - const QModelIndex &sourceParent) const -{ - QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent); - return sourceModel()->data(idx, Qt::UserRole).toBool(); -} + if (count == 1) + msg = pki->getMsg(pki_base::msg_delete).arg(pki->getIntName()); + else + msg = pki->getMsg(pki_base::msg_delete_multi).arg(count). + arg(items); -QVariant XcaProxyModel::data(const QModelIndex &index, int role) const -{ - QModelIndex i; - QString number; + if (!XCA_OKCANCEL(msg)) + return; - if (index.column() != 1) - return QSortFilterProxyModel::data(index, role); - - /* Row number */ - switch (role) { - case Qt::EditRole: - case Qt::DisplayRole: - for (i = index; i.isValid(); i = i.parent()) - number += QString(" %1").arg(i.row()+1); - return QVariant(number); - default: - return QSortFilterProxyModel::data(index, role); + foreach(index, indexes) { + basemodel->deletePKI(index); } - return QVariant(); } -void XcaHeaderView::contextMenuEvent(QContextMenuEvent * e) +void XcaTreeView::storeItems(void) { - XcaTreeView *tv = (XcaTreeView *)parentWidget(); - if (tv) - tv->headerEvent(e, logicalIndexAt(e->pos())); -} - -void XcaHeaderView::resetMoves() -{ - for (int i=0; istore(indexes[0]); return; + default: basemodel->store(getSelectedIndexes()); + return; + } + } catch (errorEx &err) { + MainWindow::Error(err); } } - resizeSections(QHeaderView::ResizeToContents); +} + +void XcaTreeView::showItems(void) +{ + if (basemodel) { + QModelIndexList indexes = getSelectedIndexes(); + foreach(QModelIndex index, indexes) + basemodel->showItem(index); + } +} + +void XcaTreeView::newItem(void) +{ + if (basemodel) + basemodel->newItem(); +} + +void XcaTreeView::load(void) +{ + if (basemodel) + basemodel->load(); +} + +void XcaTreeView::doubleClick(const QModelIndex &m) +{ + if (basemodel) + basemodel->showItem(getIndex(m)); +} + +void XcaTreeView::pem2clipboard(void) +{ + if (basemodel) + basemodel->pem2clipboard(getSelectedIndexes()); +} + +void XcaTreeView::contextMenu(QContextMenuEvent *e, QMenu *parent, int) +{ + int shown = 0; + tipMenu *menu, *dn, *v3ext, *current, *v3ns; + QAction *a, *sep; + dbheader *hd; + dbheaderList allHeaders = basemodel->getAllHeaders(); + + menu = new tipMenu(QString(), mainwin); + dn = new tipMenu(tr("Subject entries"), mainwin); + v3ext = new tipMenu(tr("X509v3 Extensions"), mainwin); + v3ns = new tipMenu(tr("Netscape extensions"), mainwin); + menu->addAction(tr("Reset"), basemodel, SLOT(columnResetDefaults())); + sep = menu->addSeparator(); + foreach(hd, allHeaders) { + switch (hd->type) { + case dbheader::hd_x509name: + current = dn; + break; + case dbheader::hd_v3ext: + current = v3ext; + break; + case dbheader::hd_v3ext_ns: + if (pki_x509::disable_netscape) + continue; + current = v3ns; + break; + default: + current = menu; + break; + } + a = current->addAction(hd->getName()); + a->setCheckable(true); + a->setChecked(hd->show); + a->setToolTip(hd->getTooltip()); + hd->action = a; + } + if (!dn->isEmpty() || !v3ext->isEmpty()) + menu->insertSeparator(sep); + + if (!dn->isEmpty()) + menu->insertMenu(sep, dn); + else + delete dn; + + if (!v3ext->isEmpty()) { + if (!v3ns->isEmpty()) { + v3ext->addSeparator(); + v3ext->addMenu(v3ns); + } else { + delete v3ns; + } + menu->insertMenu(sep, v3ext); + } else { + delete v3ext; + delete v3ns; + } + if (parent) { + parent->addSeparator(); + parent->addMenu(menu)->setText(tr("Columns")); + parent->exec(e->globalPos()); + } else { + menu->exec(e->globalPos()); + } + foreach(hd, allHeaders) { + if (hd->action) + hd->show = hd->action->isChecked(); + shown += hd->show ? 1 : 0; + hd->action = NULL; + } + if (!shown) + allHeaders[0]->show = true; + delete menu; + if (parent) + delete parent; + showHideSections(); +} + +void XcaTreeView::showContextMenu(QContextMenuEvent *e, + const QModelIndex &idx) +{ + QMenu *menu = new QMenu(mainwin); + QMenu *subExport = NULL; + QModelIndexList indexes = getSelectedIndexes(); + QModelIndex index; + + index = idx.isValid() ? idx : currentIndex(); + menu->addAction(tr("New"), this, SLOT(newItem())); + menu->addAction(tr("Import"), this, SLOT(load())); + menu->addAction(tr("Paste PEM data"), mainwin, SLOT(pastePem())); + + if (indexes.size() == 1) + menu->addAction(tr("Rename"), this, SLOT(editIdx())); + + if (indexes.size() > 0) { + menu->addAction(tr("Delete"), this, SLOT(deleteItems())); + subExport = menu->addMenu(tr("Export")); + subExport->addAction(tr("Clipboard"), this, + SLOT(pem2clipboard())); + subExport->addAction(tr("File"), this, SLOT(storeItems())); + } + + fillContextMenu(menu, subExport, index, indexes); + + contextMenu(e, menu); } diff --git a/widgets/XcaTreeView.h b/widgets/XcaTreeView.h index c77a423e..b310c75f 100644 --- a/widgets/XcaTreeView.h +++ b/widgets/XcaTreeView.h @@ -8,27 +8,14 @@ #ifndef __XCATREEVIEW_H #define __XCATREEVIEW_H +#include "lib/db_base.h" #include #include #include #include -#include "lib/db_base.h" -class db_base; - -class XcaHeaderView: public QHeaderView -{ - Q_OBJECT - public: - XcaHeaderView() - :QHeaderView(Qt::Horizontal) - { - setMovable(true); - } - void contextMenuEvent(QContextMenuEvent *e); - public slots: - void resetMoves(); -}; +class MainWindow; +class QLineEdit; class XcaTreeView: public QTreeView { @@ -36,33 +23,38 @@ class XcaTreeView: public QTreeView protected: db_base *basemodel; QSortFilterProxyModel *proxy; + MainWindow *mainwin; + public: XcaTreeView(QWidget *parent = 0); - ~XcaTreeView(); + virtual ~XcaTreeView(); void contextMenuEvent(QContextMenuEvent *e); - void setModel(QAbstractItemModel *model); + virtual void setModel(QAbstractItemModel *model=NULL); + void setMainwin(MainWindow *mw, QLineEdit *filter); QModelIndex getIndex(const QModelIndex &index); QModelIndex getProxyIndex(const QModelIndex &index); QModelIndexList getSelectedIndexes(); void headerEvent(QContextMenuEvent *e, int col); + QModelIndex currentIndex(); + void showContextMenu(QContextMenuEvent *e, + const QModelIndex &index); + virtual void fillContextMenu(QMenu *menu, QMenu *subExport, + const QModelIndex &index, QModelIndexList indexes) {} + void contextMenu(QContextMenuEvent *e, + QMenu *parent = NULL, int sect = -1); public slots: void showHideSections(); void sectionMoved(int idx, int oldI, int newI); void columnsResize(); - void editIdx(const QModelIndex &idx); + void editIdx(); void setFilter(const QString &pattern); + void deleteItems(void); + void storeItems(void); + void showItems(void); + void newItem(void); + void doubleClick(const QModelIndex &m); + void load(void); + void pem2clipboard(void); }; - -class XcaProxyModel: public QSortFilterProxyModel -{ - Q_OBJECT - public: - XcaProxyModel(QWidget *parent = 0); - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - bool filterAcceptsRow(int sourceRow, - const QModelIndex &sourceParent) const; - QVariant data(const QModelIndex &index, int role) const; -}; - #endif diff --git a/xca.pro b/xca.pro index 29d31291..72b4c85e 100644 --- a/xca.pro +++ b/xca.pro @@ -82,7 +82,14 @@ HEADERS += local.h \ widgets/validity.h \ widgets/SearchPkcs11.h \ widgets/RevocationList.h \ - widgets/XcaTreeView.h + widgets/XcaTreeView.h \ + widgets/CertTreeView.h \ + widgets/KeyTreeView.h \ + widgets/ReqTreeView.h \ + widgets/TempTreeView.h \ + widgets/X509SuperTreeView.h \ + widgets/XcaHeaderView.h \ + widgets/XcaProxyModel.h FORMS += ui/About.ui \ ui/CaProperties.ui \ @@ -168,6 +175,13 @@ SOURCES += lib/asn1int.cpp \ widgets/validity.cpp \ widgets/SearchPkcs11.cpp \ widgets/RevocationList.cpp \ - widgets/XcaTreeView.cpp + widgets/XcaTreeView.cpp \ + widgets/CertTreeView.cpp \ + widgets/KeyTreeView.cpp \ + widgets/ReqTreeView.cpp \ + widgets/TempTreeView.cpp \ + widgets/X509SuperTreeView.cpp \ + widgets/XcaHeaderView.cpp \ + widgets/XcaProxyModel.cpp TRANSLATIONS += lang/xca_de.ts lang/xca_es.ts lang/xca_ru.ts lang/xca.ts lang/xca_tr.ts lang/xca_fr.ts lang/xca_hr.ts