/*! @file @id $Id$ */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 #ifndef __Tokentool_HXX__ #define __Tokentool_HXX__ #include #include #include #include #include #include #include #include #include #include #include #include inline QString qs(const std::string& s) { return QString::fromStdString(s); } template QString qs(const cryptoki::FixString& s) { return QString::fromStdString(s); } class Progress: public QProgressBar { public: Progress() { reset(); } Progress& steps(int incr) { setMaximum(maximum()+incr); setVisible(value()=maximum()) { setMaximum(0); setValue(0); } return *this; } Progress& reset() { setMinimum(0); setMaximum(0); setValue(0); setVisible(false); return *this; } }; class tokentool: public QMainWindow, protected Ui::tokentool { Q_OBJECT; public: tokentool(std::string lib="libcvP11.so", QWidget* p=0): QMainWindow(p), _slot(0), _progress(new Progress) { try { setupUi(this); statusBar()->addPermanentWidget(_progress, 2); show(); _progress->steps(3); _cryptoki = std::auto_ptr(new cryptoki::Library(lib)); ++*_progress; _certificates->addAction(actionDeleteSelectedCertificate); libraryInfo(lib); ++*_progress; on_actionRescan_triggered(); ++*_progress; } catch (...) { QMessageBox::critical(this, tr("Initialization Failed"), tr("SmardCard Initialization Failed")); } } private Q_SLOTS: void on_actionRescan_triggered() { qDebug()<<__PRETTY_FUNCTION__; static bool lock(false); if (lock) return; lock = true; try { _slot = 0; _slots->clear(); _slotList = _cryptoki->slotList(false); _progress->steps(_slotList.size()); for (cryptoki::SlotList::iterator it(_slotList.begin()); it!=_slotList.end(); ++it) { qDebug()<<"Add Slot"; QAction* a(_slots->addAction(qs(it->slotinfo().slotDescription))); a->setCheckable(true); a->setData((qulonglong)&*it); assert(connect(a, SIGNAL(triggered(bool)), SLOT(chosen(bool)))); if (!_slot) a->trigger(); ++*_progress; } qDebug()<<"DONE"; } catch (...) {} // ignore lock = false; on__certificates_itemSelectionChanged(); } void on_actionDeleteSelectedCertificate_triggered() { QList items(_certificates->selectedItems()); if (items.size()>0) deleteCert(items[0]); } void on__certificates_itemSelectionChanged() { actionDeleteSelectedCertificate ->setEnabled(_certificates->selectedItems().size() &&!_pin->text().isEmpty()); } void on__pin_textChanged(const QString&) { on__certificates_itemSelectionChanged(); } void chosen(bool) { _pin->clear(); QAction* a(qobject_cast(sender())); a->setChecked(true); QMenu* m(qobject_cast(a->parent())); QObjectList actions(m->children()); for (QObjectList::iterator it(actions.begin());it!=actions.end(); ++it) if (qobject_cast(*it)!=a) qobject_cast(*it)->setChecked(false); _slot = (cryptoki::Slot*)a->data().toLongLong(); setup(); } void setup() { try { _progress->steps(3); slotInfo(); ++*_progress; tokenInfo(); ++*_progress; certificates(); ++*_progress; objects(); } catch (...) { _progress->reset(); on_actionRescan_triggered(); } } void libraryInfo(std::string lib) { _soname->setText(qs(lib)); cryptoki::Info inf(_cryptoki->info()); _libraryCryptokiVersion->setText(QString("%1.%2") .arg(inf.cryptokiVersion.major) .arg(inf.cryptokiVersion.minor)); _libraryManufacturerID->setText(qs(inf.manufacturerID)); _libraryDescription->setText(qs(inf.libraryDescription)); _libraryVersion->setText(QString("%1.%2") .arg(inf.libraryVersion.major) .arg(inf.libraryVersion.minor)); } void slotInfo() { try { if (!_slot) return; _hardware->setTabEnabled(1, true); cryptoki::SlotInfo slotInfo(_slot->slotinfo()); _slotDescription->setText(qs(slotInfo.slotDescription)); _slotManufacturerID->setText(qs(slotInfo.manufacturerID)); _slotHardwareVersion->setText(QString("%1.%2") .arg(slotInfo.hardwareVersion.major) .arg(slotInfo.hardwareVersion.minor)); _slotFirmwareVersion->setText(QString("%1.%2") .arg(slotInfo.firmwareVersion.major) .arg(slotInfo.firmwareVersion.minor)); _tokenPresent->setEnabled(slotInfo.flags&CKF_TOKEN_PRESENT); _removableDevice->setEnabled(slotInfo.flags&CKF_REMOVABLE_DEVICE); _hwSlot->setEnabled(slotInfo.flags&CKF_HW_SLOT); } catch (...) { _hardware->setTabEnabled(1, false); } } void tokenInfo() { try { if (!_slot) return; _hardware->setTabEnabled(2, true); _hardware->setTabEnabled(3, true); cryptoki::TokenInfo tokenInfo(_slot->tokeninfo()); _tokenLabel->setText(qs(tokenInfo.label)); _tokenManufacturerID->setText(qs(tokenInfo.manufacturerID)); _tokenModel->setText(qs(tokenInfo.model)); _tokenSerialNumber->setText(qs(tokenInfo.serialNumber)); _tokenSessionCount->setText(QString("%2/%1") .arg(qs(cryptoki::string (tokenInfo.maxSessionCount))) .arg(qs(cryptoki::string (tokenInfo.sessionCount)))); _tokenRWSessionCount->setText(QString("%2/%1") .arg(qs(cryptoki::string (tokenInfo.maxRwSessionCount))) .arg(qs(cryptoki::string (tokenInfo.rwSessionCount)))); _tokenPinLen->setText(QString("%2-%1") .arg(tokenInfo.maxPinLen) .arg(tokenInfo.minPinLen)); _tokenPublicMemory->setText(QString("%2/%1") .arg(qs(cryptoki::string (tokenInfo.totalPublicMemory))) .arg(qs(cryptoki::string (tokenInfo.freePublicMemory)))); _tokenPrivateMemory->setText(QString("%2/%1") .arg(qs(cryptoki::string (tokenInfo.totalPrivateMemory))) .arg(qs(cryptoki::string (tokenInfo.freePrivateMemory)))); _tokenHardwareVersion->setText(QString("%1.%2") .arg(tokenInfo.hardwareVersion.major) .arg(tokenInfo.hardwareVersion.minor)); _tokenFirmwareVersion->setText(QString("%1.%2") .arg(tokenInfo.firmwareVersion.major) .arg(tokenInfo.firmwareVersion.minor)); _tokenUTCTime->setText(qs(tokenInfo.utcTime)); _tokenUTCTime->setVisible(tokenInfo.flags&CKF_CLOCK_ON_TOKEN); _rng->setEnabled(tokenInfo.flags&CKF_RNG); _writeProtected->setEnabled(tokenInfo.flags&CKF_WRITE_PROTECTED); _loginRequired->setEnabled(tokenInfo.flags&CKF_LOGIN_REQUIRED); _userPinInitialized->setEnabled (tokenInfo.flags&CKF_USER_PIN_INITIALIZED); _restoreKeyNotNeeded->setEnabled (tokenInfo.flags&CKF_RESTORE_KEY_NOT_NEEDED); _clockOnToken->setEnabled(tokenInfo.flags&CKF_CLOCK_ON_TOKEN); _protectedAuthenticationPath->setEnabled (tokenInfo.flags&CKF_PROTECTED_AUTHENTICATION_PATH); _dualCryptoOperations->setEnabled (tokenInfo.flags&CKF_DUAL_CRYPTO_OPERATIONS); _tokenInitialized->setEnabled(tokenInfo.flags&CKF_TOKEN_INITIALIZED); _secondaryAuthentication->setEnabled (tokenInfo.flags&CKF_SECONDARY_AUTHENTICATION); _userPinCountLow->setEnabled(tokenInfo.flags&CKF_USER_PIN_COUNT_LOW); _userPinFinalTry->setEnabled(tokenInfo.flags&CKF_USER_PIN_FINAL_TRY); _userPinLocked->setEnabled(tokenInfo.flags&CKF_USER_PIN_LOCKED); _userPinToBeChanged->setEnabled (tokenInfo.flags&CKF_USER_PIN_TO_BE_CHANGED); _soPinCountLow->setEnabled(tokenInfo.flags&CKF_SO_PIN_COUNT_LOW); _soPinFinalTry->setEnabled(tokenInfo.flags&CKF_SO_PIN_FINAL_TRY); _soPinLocked->setEnabled(tokenInfo.flags&CKF_SO_PIN_LOCKED); _soPinToBeChanged->setEnabled(tokenInfo.flags&CKF_SO_PIN_TO_BE_CHANGED); } catch (...) { _hardware->setTabEnabled(2, false); _hardware->setTabEnabled(3, false); } } void certificates() { try { _certificates->clear(); if (!_slot) return; _certificates->setEnabled(true); cryptoki::Session session(*_slot); cryptoki::ObjectList certs (session.find(cryptoki::Attribute(CKA_CLASS) .from(CKO_CERTIFICATE))); _progress->steps(certs.size()); for (cryptoki::ObjectList::iterator cert(certs.begin()); cert!=certs.end(); ++cert) { std::string data(cert->attribute(CKA_VALUE).value); QByteArray der(QByteArray(data.data(), data.size())); QSslCertificate c(der, QSsl::Der); addCertificate(cert->attribute(CKA_LABEL).value, crypto::hex(cert->attribute(CKA_ID).value), c); ++*_progress; } } catch (...) { _certificates->setEnabled(false); } } void objects() { try { _objects->clear(); if (!_slot) return; _objects->setEnabled(true); cryptoki::Session session(*_slot); cryptoki::ObjectList objs(session.find()); _progress->steps(objs.size()); for (cryptoki::ObjectList::iterator obj(objs.begin()); obj!=objs.end(); ++obj) { _objects->addTopLevelItem (new QTreeWidgetItem (QStringList() <attribute(CKA_LABEL).value) <attribute(CKA_ID).value)))); ++*_progress; } _objects->resizeColumnToContents(0); _objects->resizeColumnToContents(1); } catch (...) { _objects->setEnabled(false); } } void addCertificate(const std::string& label, const std::string& id, const QSslCertificate& cert) { if (cert.isNull()) return; QString txt; QSslKey pubkey(cert.publicKey()); QTreeWidgetItem *twi(0); QTreeWidgetItem* c(new QTreeWidgetItem(QStringList()<setData(0, Qt::UserRole, qs(id)); _certificates->addTopLevelItem(c); c->addChild (new QTreeWidgetItem (QStringList()<addChild (new QTreeWidgetItem (QStringList()<addChild (new QTreeWidgetItem (QStringList()<addChild (new QTreeWidgetItem (QStringList()<addChild (new QTreeWidgetItem (QStringList()<addChild (twi = new QTreeWidgetItem (QStringList()<addChild (new QTreeWidgetItem (QStringList()<setExpanded(true); c->addChild (twi = new QTreeWidgetItem (QStringList()<addChild (new QTreeWidgetItem (QStringList()<setExpanded(true); c->addChild (twi = new QTreeWidgetItem (QStringList()<addChild (new QTreeWidgetItem // not used: oid (QStringList()<<(v.first.isEmpty() ? ext.name() : tr("%1[%2]", "element of a certificate extension map;" " %1: extension name, %2: map entry name") .arg(ext.name()).arg(v.first))<setExpanded(true); c->addChild (twi = new QTreeWidgetItem (QStringList()<addChild(new QTreeWidgetItem(QStringList()<setExpanded(true); /// @bug error: ‘const class QSslCertificate’ has no member named ‘isSelfSigned’ // if (cert.isSelfSigned()) // for (int i=0; icolumnCount(); ++i) // c->setBackground(i, Qt::darkYellow); if (cert.isBlacklisted()) for (int i=0; icolumnCount(); ++i) c->setBackground(i, Qt::red); // c->addChild // ((it = new QTreeWidgetItem(QStringList()<=QSslCertificate::Organization; // si=(QSslCertificate::SubjectInfo)((int)si-1)) // if (!cert.subjectInfo(si).isEmpty()) { // it->addChild // ((new QTreeWidgetItem(subjectInfo(si) // <setExpanded(true); // QMultiMap // #if QT_VERSION <0x050000 // asns(cert.alternateSubjectNames()) // #else // asns(cert.subjectAlternativeNames()) // #endif // ; // for (QMultiMap::iterator // asn(asns.begin()); asn!=asns.end(); ++asn) // it->addChild // ((new QTreeWidgetItem // (QStringList()<addChild // ((it = new QTreeWidgetItem(QStringList()<=QSslCertificate::Organization; // si=(QSslCertificate::SubjectInfo)((int)si-1)) // if (!cert.issuerInfo(si).isEmpty()) // it->addChild // ((new QTreeWidgetItem(subjectInfo(si) // <setExpanded(true); _certificates->resizeColumnToContents(0); _certificates->resizeColumnToContents(1); } private: QMultiMap stringify(const QVariant& v) { QMultiMap res; switch (v.type()) { case QVariant::ByteArray: { bool nonprint(false); QString txt(QString::fromUtf8(v.toByteArray())); for (QChar& c: txt) { if (!c.isPrint()) if (c=='\n'||c=='\r') { c = '\n'; } else { txt.replace(c, tr("[%1]", "stringified representation of nonprintable character;" " %1: value in hex") .arg(QString::fromLocal8Bit(QString(c).toUtf8().toHex()))); nonprint = true; } } res.insert(QString(), txt); } break; case QVariant::List: for (const QVariant& vv: v.toList()) res.insert(QString(), QStringList(stringify(vv).values()).join('\n')); break; case QVariant::Map: for (auto vv: v.toMap().toStdMap()) res.insert(vv.first, QStringList(stringify(vv.second).values()).join('\n')); break; case QVariant::StringList: for (const auto& vv: v.toStringList()) res.insert(QString(), vv); break; case QVariant::String: res.insert(QString(), v.toString()); break; default: res.insert(v.typeName(), v.toString()); } return res; } void deleteCert(QTreeWidgetItem* item) { if (!_slot) return; if (_pin->text().isEmpty()) { QMessageBox::critical(this, tr("PIN required"), tr("Please enter PIN")); return; } if (item->parent()) return deleteCert(item->parent()); QByteArray qid(QByteArray::fromHex(item->data(0, Qt::UserRole) .toByteArray())); std::string id(qid.data(), qid.size()); cryptoki::Session session(*_slot, true); try { session.login(_pin->text().toStdString()); } catch (...) { QMessageBox::critical(this, tr("Login Failed"), tr("Wrong PIN")); return; } cryptoki::ObjectList objs (session.find(cryptoki::AttributeList() <(CKO_CERTIFICATE) <destroy(); } catch (const std::exception& e) { QMessageBox::critical(this, tr("Delete Failed"), tr("Certificate Deletion Failes")); } setup(); } // QString alternateName(QSsl::AlternateNameEntryType an) { // switch (an) { // case QSsl::EmailEntry: return tr("E-Mail"); // case QSsl::DnsEntry: return tr("URL"); // } // return tr("error", "unknown certificate subject alternate name"); // } QStringList subjectInfo(QSslCertificate::SubjectInfo si) { QStringList res; switch (si) { case QSslCertificate::Organization: res< _cryptoki; cryptoki::SlotList _slotList; cryptoki::Slot* _slot; Progress* _progress; }; #endif