cmssigner/main.cpp
The code below shows how to use Cryptographic Message Syntax (CMS) in a GUI application.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef CERTITEM_H
00023 #define CERTITEM_H
00024
00025 #include <QAbstractListModel>
00026 #include <QSharedDataPointer>
00027
00028 class QString;
00029 class QStringList;
00030
00031 namespace QCA
00032 {
00033 class PrivateKey;
00034 class CertificateChain;
00035 class KeyStoreEntry;
00036 }
00037
00038 class CertItemStore;
00039 class CertItemStorePrivate;
00040 class CertItemPrivateLoaderPrivate;
00041
00042 class CertItem
00043 {
00044 public:
00045 enum StorageType
00046 {
00047 File,
00048 KeyStore
00049 };
00050
00051 CertItem();
00052 CertItem(const CertItem &from);
00053 ~CertItem();
00054 CertItem & operator=(const CertItem &from);
00055
00056 QString name() const;
00057 QCA::CertificateChain certificateChain() const;
00058 bool havePrivate() const;
00059 StorageType storageType() const;
00060 bool isUsable() const;
00061
00062 private:
00063 class Private;
00064 QSharedDataPointer<Private> d;
00065
00066 friend class CertItemStore;
00067 friend class CertItemStorePrivate;
00068 friend class CertItemPrivateLoader;
00069 friend class CertItemPrivateLoaderPrivate;
00070 };
00071
00072 class CertItemStore : public QAbstractListModel
00073 {
00074 Q_OBJECT
00075 public:
00076 enum IconType
00077 {
00078 IconCert,
00079 IconCrl,
00080 IconKeyBundle,
00081 IconPgpPub,
00082 IconPgpSec
00083 };
00084
00085 CertItemStore(QObject *parent = 0);
00086 ~CertItemStore();
00087
00088 int idFromRow(int row) const;
00089 int rowFromId(int id) const;
00090 CertItem itemFromId(int id) const;
00091 CertItem itemFromRow(int row) const;
00092
00093 QList<CertItem> items() const;
00094
00095 QStringList save() const;
00096 bool load(const QStringList &in);
00097
00098
00099 int addFromFile(const QString &fileName);
00100 int addFromKeyStore(const QCA::KeyStoreEntry &entry);
00101 int addUser(const QCA::CertificateChain &chain);
00102
00103 void updateChain(int id, const QCA::CertificateChain &chain);
00104
00105 void removeItem(int id);
00106
00107 void setIcon(IconType type, const QPixmap &icon);
00108
00109
00110 int rowCount(const QModelIndex &parent = QModelIndex()) const;
00111 QVariant data(const QModelIndex &index, int role) const;
00112 Qt::ItemFlags flags(const QModelIndex &index) const;
00113 bool setData(const QModelIndex &index, const QVariant &value, int role);
00114
00115 signals:
00116 void addSuccess(int reqId, int id);
00117 void addFailed(int reqId);
00118
00119 private:
00120 friend class CertItemStorePrivate;
00121 CertItemStorePrivate *d;
00122
00123 friend class CertItemPrivateLoader;
00124 friend class CertItemPrivateLoaderPrivate;
00125 };
00126
00127 class CertItemPrivateLoader : public QObject
00128 {
00129 Q_OBJECT
00130 public:
00131 explicit CertItemPrivateLoader(CertItemStore *store, QObject *parent = 0);
00132 ~CertItemPrivateLoader();
00133
00134 void start(int id);
00135
00136 QCA::PrivateKey privateKey() const;
00137
00138 signals:
00139 void finished();
00140
00141 private:
00142 friend class CertItemPrivateLoaderPrivate;
00143 CertItemPrivateLoaderPrivate *d;
00144 };
00145
00146 #endif
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "certitem.h"
00023
00024 #include <QtCore>
00025 #include <QtGui>
00026 #include <QtCrypto>
00027 #include "prompter.h"
00028
00029 typedef QMap<CertItemStore::IconType,QPixmap> CertItemIconset;
00030
00031
00032
00033
00034 class MyPrompter : public Prompter
00035 {
00036 Q_OBJECT
00037 private:
00038 QMap<QString,QCA::SecureArray> known;
00039 QMap<QString,QCA::SecureArray> maybe;
00040
00041 public:
00042 MyPrompter(QObject *parent = 0) :
00043 Prompter(parent)
00044 {
00045 }
00046
00047 void fileSuccess(const QString &fileName)
00048 {
00049 if(maybe.contains(fileName))
00050 {
00051 known[fileName] = maybe[fileName];
00052 maybe.remove(fileName);
00053 }
00054 }
00055
00056 void fileFailed(const QString &fileName)
00057 {
00058 maybe.remove(fileName);
00059 known.remove(fileName);
00060 }
00061
00062 protected:
00063 virtual QCA::SecureArray knownPassword(const QCA::Event &event)
00064 {
00065 if(event.source() == QCA::Event::Data && !event.fileName().isEmpty())
00066 return known.value(event.fileName());
00067 else
00068 return QCA::SecureArray();
00069 }
00070
00071 virtual void userSubmitted(const QCA::SecureArray &password, const QCA::Event &event)
00072 {
00073 if(event.source() == QCA::Event::Data && !event.fileName().isEmpty())
00074 maybe[event.fileName()] = password;
00075 }
00076 };
00077
00078
00079
00080
00081 static QString escape(const QString &in)
00082 {
00083 QString out;
00084 for(int n = 0; n < in.length(); ++n)
00085 {
00086 if(in[n] == '\\')
00087 out += "\\\\";
00088 else if(in[n] == ':')
00089 out += "\\c";
00090 else if(in[n] == '\n')
00091 out += "\\n";
00092 else
00093 out += in[n];
00094 }
00095 return out;
00096 }
00097
00098 static QString unescape(const QString &in)
00099 {
00100 QString out;
00101 for(int n = 0; n < in.length(); ++n)
00102 {
00103 if(in[n] == '\\')
00104 {
00105 if(n + 1 < in.length())
00106 {
00107 ++n;
00108 if(in[n] == '\\')
00109 out += '\\';
00110 else if(in[n] == 'c')
00111 out += ':';
00112 else if(in[n] == 'n')
00113 out += '\n';
00114 }
00115 }
00116 else
00117 out += in[n];
00118 }
00119 return out;
00120 }
00121
00122 class CertItem::Private : public QSharedData
00123 {
00124 public:
00125 QString name;
00126 QCA::CertificateChain chain;
00127 bool havePrivate;
00128 StorageType storageType;
00129 bool usable;
00130
00131 QString fileName;
00132 QCA::KeyStoreEntry keyStoreEntry;
00133 QString keyStoreEntryString;
00134
00135 Private() :
00136 havePrivate(false),
00137 storageType(File),
00138 usable(false)
00139 {
00140 }
00141
00142 QString toString() const
00143 {
00144 QStringList parts;
00145
00146 parts += name;
00147 parts += QString::number(chain.count());
00148 foreach(const QCA::Certificate &cert, chain)
00149 parts += QCA::Base64().arrayToString(cert.toDER());
00150
00151 if(havePrivate)
00152 {
00153 if(storageType == File)
00154 {
00155 parts += "privateFile";
00156 parts += fileName;
00157 }
00158 else
00159 {
00160 parts += "privateEntry";
00161 if(!keyStoreEntry.isNull())
00162 parts += keyStoreEntry.toString();
00163 else
00164 parts += keyStoreEntryString;
00165 }
00166 }
00167
00168 for(int n = 0; n < parts.count(); ++n)
00169 parts[n] = escape(parts[n]);
00170 return parts.join(":");
00171 }
00172
00173 bool fromString(const QString &in)
00174 {
00175 QStringList parts = in.split(':');
00176 for(int n = 0; n < parts.count(); ++n)
00177 parts[n] = unescape(parts[n]);
00178
00179 if(parts.count() < 3)
00180 return false;
00181
00182 name = parts[0];
00183 int chainCount = parts[1].toInt();
00184 if(chainCount < 1 || chainCount > parts.count() - 2)
00185 return false;
00186 chain.clear();
00187 for(int n = 0; n < chainCount; ++n)
00188 {
00189 QCA::Certificate cert = QCA::Certificate::fromDER(QCA::Base64().stringToArray(parts[n + 2]).toByteArray());
00190 if(cert.isNull())
00191 return false;
00192 chain += cert;
00193 }
00194 int at = chain.count() + 2;
00195
00196 if(at < parts.count())
00197 {
00198 havePrivate = true;
00199 usable = false;
00200
00201 if(parts[at] == "privateFile")
00202 {
00203 storageType = File;
00204 fileName = parts[at + 1];
00205 if(QFile::exists(fileName))
00206 usable = true;
00207 }
00208 else if(parts[at] == "privateEntry")
00209 {
00210 storageType = KeyStore;
00211 keyStoreEntryString = parts[at + 1];
00212 keyStoreEntry = QCA::KeyStoreEntry(keyStoreEntryString);
00213 if(!keyStoreEntry.isNull())
00214 usable = true;
00215 }
00216 else
00217 return false;
00218 }
00219
00220 return true;
00221 }
00222 };
00223
00224 CertItem::CertItem()
00225 {
00226 }
00227
00228 CertItem::CertItem(const CertItem &from) :
00229 d(from.d)
00230 {
00231 }
00232
00233 CertItem::~CertItem()
00234 {
00235 }
00236
00237 CertItem & CertItem::operator=(const CertItem &from)
00238 {
00239 d = from.d;
00240 return *this;
00241 }
00242
00243 QString CertItem::name() const
00244 {
00245 return d->name;
00246 }
00247
00248 QCA::CertificateChain CertItem::certificateChain() const
00249 {
00250 return d->chain;
00251 }
00252
00253 bool CertItem::havePrivate() const
00254 {
00255 return d->havePrivate;
00256 }
00257
00258 CertItem::StorageType CertItem::storageType() const
00259 {
00260 return d->storageType;
00261 }
00262
00263 bool CertItem::isUsable() const
00264 {
00265 return d->usable;
00266 }
00267
00268
00269
00270
00271 static MyPrompter *g_prompter = 0;
00272 static int g_prompter_refs = 0;
00273
00274 class CertItemStorePrivate : public QObject
00275 {
00276 Q_OBJECT
00277 public:
00278 CertItemStore *q;
00279 MyPrompter *prompter;
00280 QList<CertItem> list;
00281 QList<int> idList;
00282 CertItemIconset iconset;
00283 int next_id;
00284 int next_req_id;
00285
00286 class LoaderItem
00287 {
00288 public:
00289 int req_id;
00290 QCA::KeyLoader *keyLoader;
00291 QString fileName;
00292 };
00293
00294 QList<LoaderItem> loaders;
00295
00296 CertItemStorePrivate(CertItemStore *_q) :
00297 QObject(_q),
00298 q(_q),
00299 next_id(0),
00300 next_req_id(0)
00301 {
00302 if(!g_prompter)
00303 {
00304 g_prompter = new MyPrompter;
00305 g_prompter_refs = 1;
00306 }
00307 else
00308 ++g_prompter_refs;
00309
00310 prompter = g_prompter;
00311 }
00312
00313 ~CertItemStorePrivate()
00314 {
00315 foreach(const LoaderItem &i, loaders)
00316 delete i.keyLoader;
00317
00318 --g_prompter_refs;
00319 if(g_prompter_refs == 0)
00320 {
00321 delete g_prompter;
00322 g_prompter = 0;
00323 }
00324 }
00325
00326 QString getUniqueName(const QString &name)
00327 {
00328 int num = 1;
00329 while(1)
00330 {
00331 QString tryname;
00332 if(num == 1)
00333 tryname = name;
00334 else
00335 tryname = name + QString(" (%1)").arg(num);
00336
00337 bool found = false;
00338 foreach(const CertItem &i, list)
00339 {
00340 if(i.name() == tryname)
00341 {
00342 found = true;
00343 break;
00344 }
00345 }
00346 if(!found)
00347 return tryname;
00348
00349 ++num;
00350 }
00351 }
00352
00353 static QString convertErrorToString(QCA::ConvertResult r)
00354 {
00355 QString str;
00356 switch(r)
00357 {
00358 case QCA::ConvertGood: break;
00359 case QCA::ErrorPassphrase: str = tr("Incorrect passphrase.");
00360 case QCA::ErrorFile: str = tr("Unable to open or read file.");
00361 case QCA::ErrorDecode:
00362 default: str = tr("Unable to decode format.");
00363 }
00364 return str;
00365 }
00366
00367 public slots:
00368 void loader_finished()
00369 {
00370 QCA::KeyLoader *keyLoader = (QCA::KeyLoader *)sender();
00371 int at = -1;
00372 for(int n = 0; n < loaders.count(); ++n)
00373 {
00374 if(loaders[n].keyLoader == keyLoader)
00375 {
00376 at = n;
00377 break;
00378 }
00379 }
00380 Q_ASSERT(at != -1);
00381
00382 int req_id = loaders[at].req_id;
00383 QString fileName = loaders[at].fileName;
00384 loaders.removeAt(at);
00385
00386 QCA::ConvertResult r = keyLoader->convertResult();
00387 if(r != QCA::ConvertGood)
00388 {
00389 delete keyLoader;
00390 prompter->fileFailed(fileName);
00391 QMessageBox::information(0, tr("Error"),
00392 tr("Error importing certificate and private key.\nReason: %1").arg(convertErrorToString(r)));
00393 emit q->addFailed(req_id);
00394 return;
00395 }
00396
00397 prompter->fileSuccess(fileName);
00398
00399 QCA::KeyBundle kb = keyLoader->keyBundle();
00400 delete keyLoader;
00401
00402 QCA::CertificateChain chain = kb.certificateChain();
00403 QCA::Certificate cert = chain.primary();
00404
00405 QString name = getUniqueName(cert.commonName());
00406
00407 CertItem i;
00408 i.d = new CertItem::Private;
00409 i.d->name = name;
00410 i.d->chain = chain;
00411 i.d->havePrivate = true;
00412 i.d->storageType = CertItem::File;
00413 i.d->usable = true;
00414 i.d->fileName = fileName;
00415
00416 int id = next_id++;
00417
00418 q->beginInsertRows(QModelIndex(), list.size(), list.size());
00419 list += i;
00420 idList += id;
00421 q->endInsertRows();
00422
00423 emit q->addSuccess(req_id, id);
00424 }
00425 };
00426
00427 CertItemStore::CertItemStore(QObject *parent) :
00428 QAbstractListModel(parent)
00429 {
00430 d = new CertItemStorePrivate(this);
00431 }
00432
00433 CertItemStore::~CertItemStore()
00434 {
00435 delete d;
00436 }
00437
00438 int CertItemStore::idFromRow(int row) const
00439 {
00440 return d->idList[row];
00441 }
00442
00443 int CertItemStore::rowFromId(int id) const
00444 {
00445 for(int n = 0; n < d->idList.count(); ++n)
00446 {
00447 if(d->idList[n] == id)
00448 return n;
00449 }
00450 return -1;
00451 }
00452
00453 CertItem CertItemStore::itemFromId(int id) const
00454 {
00455 return d->list[rowFromId(id)];
00456 }
00457
00458 CertItem CertItemStore::itemFromRow(int row) const
00459 {
00460 return d->list[row];
00461 }
00462
00463 QList<CertItem> CertItemStore::items() const
00464 {
00465 return d->list;
00466 }
00467
00468 QStringList CertItemStore::save() const
00469 {
00470 QStringList out;
00471 foreach(const CertItem &i, d->list)
00472 out += i.d->toString();
00473 return out;
00474 }
00475
00476 bool CertItemStore::load(const QStringList &in)
00477 {
00478 QList<CertItem> addList;
00479 QList<int> addIdList;
00480 foreach(const QString &s, in)
00481 {
00482 CertItem i;
00483 i.d = new CertItem::Private;
00484 if(i.d->fromString(s))
00485 {
00486 addList += i;
00487 addIdList += d->next_id++;
00488 }
00489 }
00490
00491 if(addList.isEmpty())
00492 return true;
00493
00494 beginInsertRows(QModelIndex(), d->list.size(), d->list.size() + addList.count() - 1);
00495 d->list += addList;
00496 d->idList += addIdList;
00497 endInsertRows();
00498
00499 return true;
00500 }
00501
00502 int CertItemStore::addFromFile(const QString &fileName)
00503 {
00504 CertItemStorePrivate::LoaderItem i;
00505 i.req_id = d->next_req_id++;
00506 i.keyLoader = new QCA::KeyLoader(d);
00507 i.fileName = fileName;
00508 connect(i.keyLoader, SIGNAL(finished()), d, SLOT(loader_finished()));
00509 d->loaders += i;
00510 i.keyLoader->loadKeyBundleFromFile(fileName);
00511 return i.req_id;
00512 }
00513
00514 int CertItemStore::addFromKeyStore(const QCA::KeyStoreEntry &entry)
00515 {
00516 QCA::KeyBundle kb = entry.keyBundle();
00517
00518 QCA::CertificateChain chain = kb.certificateChain();
00519 QCA::Certificate cert = chain.primary();
00520
00521 QString name = d->getUniqueName(entry.name());
00522
00523 CertItem i;
00524 i.d = new CertItem::Private;
00525 i.d->name = name;
00526 i.d->chain = chain;
00527 i.d->havePrivate = true;
00528 i.d->storageType = CertItem::KeyStore;
00529 i.d->usable = true;
00530 i.d->keyStoreEntry = entry;
00531
00532 int id = d->next_id++;
00533
00534 beginInsertRows(QModelIndex(), d->list.size(), d->list.size());
00535 d->list += i;
00536 d->idList += id;
00537 endInsertRows();
00538
00539 int req_id = d->next_req_id++;
00540 QMetaObject::invokeMethod(this, "addSuccess", Qt::QueuedConnection, Q_ARG(int, req_id), Q_ARG(int, id));
00541 return req_id;
00542 }
00543
00544 int CertItemStore::addUser(const QCA::CertificateChain &chain)
00545 {
00546 QCA::Certificate cert = chain.primary();
00547
00548 QString name = d->getUniqueName(cert.commonName());
00549
00550 CertItem i;
00551 i.d = new CertItem::Private;
00552 i.d->name = name;
00553 i.d->chain = chain;
00554
00555 int id = d->next_id++;
00556
00557 beginInsertRows(QModelIndex(), d->list.size(), d->list.size());
00558 d->list += i;
00559 d->idList += id;
00560 endInsertRows();
00561
00562 int req_id = d->next_req_id++;
00563 QMetaObject::invokeMethod(this, "addSuccess", Qt::QueuedConnection, Q_ARG(int, req_id), Q_ARG(int, id));
00564 return req_id;
00565 }
00566
00567 void CertItemStore::updateChain(int id, const QCA::CertificateChain &chain)
00568 {
00569 int at = rowFromId(id);
00570 d->list[at].d->chain = chain;
00571 }
00572
00573 void CertItemStore::removeItem(int id)
00574 {
00575 int at = rowFromId(id);
00576
00577 beginRemoveRows(QModelIndex(), at, at);
00578 d->list.removeAt(at);
00579 d->idList.removeAt(at);
00580 endRemoveRows();
00581 }
00582
00583 void CertItemStore::setIcon(IconType type, const QPixmap &icon)
00584 {
00585 d->iconset[type] = icon;
00586 }
00587
00588 int CertItemStore::rowCount(const QModelIndex &parent) const
00589 {
00590 Q_UNUSED(parent);
00591 return d->list.count();
00592 }
00593
00594 QVariant CertItemStore::data(const QModelIndex &index, int role) const
00595 {
00596 if(!index.isValid())
00597 return QVariant();
00598
00599 int at = index.row();
00600 QList<CertItem> &list = d->list;
00601
00602 if(at >= list.count())
00603 return QVariant();
00604
00605 if(role == Qt::DisplayRole)
00606 {
00607 QString str = list[at].name();
00608 if(list[at].havePrivate() && !list[at].isUsable())
00609 str += QString(" ") + tr("(not usable)");
00610 return str;
00611 }
00612 else if(role == Qt::EditRole)
00613 return list[at].name();
00614 else if(role == Qt::DecorationRole)
00615 {
00616 if(list[at].havePrivate())
00617 return d->iconset[CertItemStore::IconKeyBundle];
00618 else
00619 return d->iconset[CertItemStore::IconCert];
00620 }
00621 else
00622 return QVariant();
00623 }
00624
00625 Qt::ItemFlags CertItemStore::flags(const QModelIndex &index) const
00626 {
00627 if(!index.isValid())
00628 return Qt::ItemIsEnabled;
00629
00630 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
00631 }
00632
00633 bool CertItemStore::setData(const QModelIndex &index, const QVariant &value, int role)
00634 {
00635 if(index.isValid() && role == Qt::EditRole)
00636 {
00637 QString str = value.toString();
00638 d->list[index.row()].d->name = str;
00639 emit dataChanged(index, index);
00640 return true;
00641 }
00642 return false;
00643 }
00644
00645
00646
00647
00648 class CertItemPrivateLoaderPrivate : public QObject
00649 {
00650 Q_OBJECT
00651 public:
00652 CertItemPrivateLoader *q;
00653 CertItemStore *store;
00654 QCA::KeyLoader *loader;
00655 QString fileName;
00656 QCA::PrivateKey key;
00657
00658 CertItemPrivateLoaderPrivate(CertItemPrivateLoader *_q) :
00659 QObject(_q),
00660 q(_q)
00661 {
00662 }
00663
00664 public slots:
00665 void loader_finished()
00666 {
00667 QCA::ConvertResult r = loader->convertResult();
00668 if(r != QCA::ConvertGood)
00669 {
00670 delete loader;
00671 loader = 0;
00672 store->d->prompter->fileFailed(fileName);
00673 QMessageBox::information(0, tr("Error"),
00674 tr("Error accessing private key.\nReason: %1").arg(CertItemStorePrivate::convertErrorToString(r)));
00675 emit q->finished();
00676 return;
00677 }
00678
00679 store->d->prompter->fileSuccess(fileName);
00680
00681 key = loader->keyBundle().privateKey();
00682 delete loader;
00683 loader = 0;
00684 emit q->finished();
00685 }
00686 };
00687
00688 CertItemPrivateLoader::CertItemPrivateLoader(CertItemStore *store, QObject *parent) :
00689 QObject(parent)
00690 {
00691 d = new CertItemPrivateLoaderPrivate(this);
00692 d->store = store;
00693 }
00694
00695 CertItemPrivateLoader::~CertItemPrivateLoader()
00696 {
00697 delete d;
00698 }
00699
00700 void CertItemPrivateLoader::start(int id)
00701 {
00702 CertItem i = d->store->itemFromId(id);
00703
00704 if(i.storageType() == CertItem::KeyStore)
00705 {
00706 d->key = i.d->keyStoreEntry.keyBundle().privateKey();
00707 QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
00708 return;
00709 }
00710
00711 d->key = QCA::PrivateKey();
00712 d->fileName = i.d->fileName;
00713 d->loader = new QCA::KeyLoader(d);
00714 connect(d->loader, SIGNAL(finished()), d, SLOT(loader_finished()));
00715 d->loader->loadKeyBundleFromFile(d->fileName);
00716 }
00717
00718 QCA::PrivateKey CertItemPrivateLoader::privateKey() const
00719 {
00720 return d->key;
00721 }
00722
00723 #include "certitem.moc"
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef CERTVIEWDLG_H
00023 #define CERTVIEWDLG_H
00024
00025 #include <QDialog>
00026
00027 namespace QCA
00028 {
00029 class CertificateChain;
00030 }
00031
00032 class CertViewDlg : public QDialog
00033 {
00034 Q_OBJECT
00035 public:
00036 explicit CertViewDlg(const QCA::CertificateChain &chain, QWidget *parent = 0);
00037 ~CertViewDlg();
00038
00039 private:
00040 class Private;
00041 Private *d;
00042 };
00043
00044 #endif
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "certviewdlg.h"
00023
00024 #include <QtCore>
00025 #include <QtGui>
00026 #include <QtCrypto>
00027 #include "ui_certview.h"
00028
00029
00030 class InfoType
00031 {
00032 public:
00033 QCA::CertificateInfoType type;
00034 QString varname;
00035 QString shortname;
00036 QString name;
00037 QString desc;
00038
00039 InfoType()
00040 {
00041 }
00042
00043 InfoType(QCA::CertificateInfoType _type, const QString &_varname, const QString &_shortname, const QString &_name, const QString &_desc) :
00044 type(_type),
00045 varname(_varname),
00046 shortname(_shortname),
00047 name(_name),
00048 desc(_desc)
00049 {
00050 }
00051 };
00052
00053 static QList<InfoType> makeInfoTypeList(bool legacyEmail = false)
00054 {
00055 QList<InfoType> out;
00056 out += InfoType(QCA::CommonName, "CommonName", "CN", CertViewDlg::tr("Common Name (CN)"), "Full name, domain, anything");
00057 out += InfoType(QCA::Email, "Email", "", CertViewDlg::tr("Email Address"), "");
00058 if(legacyEmail)
00059 out += InfoType(QCA::EmailLegacy, "EmailLegacy", "", CertViewDlg::tr("PKCS#9 Email Address"), "");
00060 out += InfoType(QCA::Organization, "Organization", "O", CertViewDlg::tr("Organization (O)"), "Company, group, etc");
00061 out += InfoType(QCA::OrganizationalUnit, "OrganizationalUnit", "OU", CertViewDlg::tr("Organizational Unit (OU)"), "Division/branch of organization");
00062 out += InfoType(QCA::Locality, "Locality", "", CertViewDlg::tr("Locality (L)"), "City, shire, part of a state");
00063 out += InfoType(QCA::State, "State", "", CertViewDlg::tr("State (ST)"), "State within the country");
00064 out += InfoType(QCA::Country, "Country", "C", CertViewDlg::tr("Country Code (C)"), "2-letter code");
00065 out += InfoType(QCA::IncorporationLocality, "IncorporationLocality", "", CertViewDlg::tr("Incorporation Locality"), "For EV certificates");
00066 out += InfoType(QCA::IncorporationState, "IncorporationState", "", CertViewDlg::tr("Incorporation State"), "For EV certificates");
00067 out += InfoType(QCA::IncorporationCountry, "IncorporationCountry", "", CertViewDlg::tr("Incorporation Country"), "For EV certificates");
00068 out += InfoType(QCA::URI, "URI", "", CertViewDlg::tr("URI"), "");
00069 out += InfoType(QCA::DNS, "DNS", "", CertViewDlg::tr("Domain Name"), "Domain (dnsName)");
00070 out += InfoType(QCA::IPAddress, "IPAddress", "", CertViewDlg::tr("IP Adddress"), "");
00071 out += InfoType(QCA::XMPP, "XMPP", "", CertViewDlg::tr("XMPP Address (JID)"), "From RFC 3920 (id-on-xmppAddr)");
00072 return out;
00073 }
00074
00075 static QString try_print_info(const QString &name, const QStringList &values)
00076 {
00077 QString out;
00078 if(!values.isEmpty())
00079 {
00080 QString value = values.join(", ");
00081 out = QString(" ") + CertViewDlg::tr("%1: %2").arg(name, value) + '\n';
00082 }
00083 return out;
00084 }
00085
00086 static QString print_info(const QString &title, const QCA::CertificateInfo &info)
00087 {
00088 QString out;
00089 QList<InfoType> list = makeInfoTypeList();
00090 out += title + '\n';
00091 foreach(const InfoType &t, list)
00092 out += try_print_info(t.name, info.values(t.type));
00093 return out;
00094 }
00095
00096 static QString cert_info_string(const QCA::Certificate &cert)
00097 {
00098 QString out;
00099 out += CertViewDlg::tr("Serial Number: %1").arg(cert.serialNumber().toString()) + '\n';
00100 out += print_info(CertViewDlg::tr("Subject"), cert.subjectInfo());
00101 out += print_info(CertViewDlg::tr("Issuer"), cert.issuerInfo());
00102 out += CertViewDlg::tr("Validity") + '\n';
00103 out += QString(" ") + CertViewDlg::tr("Not before: %1").arg(cert.notValidBefore().toString()) + '\n';
00104 out += QString(" ") + CertViewDlg::tr("Not after: %1").arg(cert.notValidAfter().toString()) + '\n';
00105 return out;
00106 }
00107
00108 class CertViewDlg::Private : public QObject
00109 {
00110 Q_OBJECT
00111 public:
00112 CertViewDlg *q;
00113 Ui_CertView ui;
00114 QCA::CertificateChain chain;
00115
00116 Private(CertViewDlg *_q) :
00117 QObject(_q),
00118 q(_q)
00119 {
00120 ui.setupUi(q);
00121 connect(ui.cb_chain, SIGNAL(activated(int)), SLOT(cb_activated(int)));
00122 ui.lb_info->setTextInteractionFlags(Qt::TextSelectableByMouse);
00123 }
00124
00125 void update()
00126 {
00127 QStringList names = QCA::makeFriendlyNames(chain);
00128 ui.cb_chain->clear();
00129 foreach(const QString &s, names)
00130 ui.cb_chain->insertItem(ui.cb_chain->count(), s);
00131 updateInfo();
00132 }
00133
00134 void updateInfo()
00135 {
00136 int x = ui.cb_chain->currentIndex();
00137 if(x == -1)
00138 {
00139 ui.lb_info->setText("");
00140 return;
00141 }
00142
00143 ui.lb_info->setText(cert_info_string(chain[x]));
00144 }
00145
00146 private slots:
00147 void cb_activated(int)
00148 {
00149 updateInfo();
00150 }
00151 };
00152
00153 CertViewDlg::CertViewDlg(const QCA::CertificateChain &chain, QWidget *parent) :
00154 QDialog(parent)
00155 {
00156 d = new Private(this);
00157 d->chain = chain;
00158 d->update();
00159 }
00160
00161 CertViewDlg::~CertViewDlg()
00162 {
00163 delete d;
00164 }
00165
00166 #include "certviewdlg.moc"
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef KEYSELECTDLG_H
00023 #define KEYSELECTDLG_H
00024
00025 #include <QDialog>
00026
00027 class QPixmap;
00028
00029 namespace QCA
00030 {
00031 class CertificateChain;
00032 class KeyStoreEntry;
00033 }
00034
00035 class KeySelectDlg : public QDialog
00036 {
00037 Q_OBJECT
00038 public:
00039 enum IconType
00040 {
00041 IconCert,
00042 IconCrl,
00043 IconKeyBundle,
00044 IconPgpPub,
00045 IconPgpSec
00046 };
00047
00048 KeySelectDlg(QWidget *parent = 0);
00049 ~KeySelectDlg();
00050
00051 void setIcon(IconType type, const QPixmap &icon);
00052
00053 signals:
00054 void selected(const QCA::KeyStoreEntry &entry);
00055 void viewCertificate(const QCA::CertificateChain &chain);
00056
00057 protected slots:
00058 virtual void accept();
00059
00060 private:
00061 class Private;
00062 friend class Private;
00063 Private *d;
00064 };
00065
00066 #endif
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "keyselectdlg.h"
00023
00024 #include <QtCore>
00025 #include <QtGui>
00026 #include <QtCrypto>
00027 #include "ui_keyselect.h"
00028
00029 #define ONLY_SHOW_KEYBUNDLE
00030
00031 typedef QMap<KeySelectDlg::IconType,QPixmap> KeyStoreIconset;
00032
00033 class KeyStoreItemShared
00034 {
00035 public:
00036 KeyStoreIconset iconset;
00037 QString notAvailableString;
00038 };
00039
00040 class KeyStoreItem : public QStandardItem
00041 {
00042 public:
00043 enum Type
00044 {
00045 Store = UserType,
00046 Entry
00047 };
00048
00049 enum Role
00050 {
00051 NameRole = Qt::UserRole,
00052 SubTypeRole,
00053 AvailabilityRole,
00054 PositionRole
00055 };
00056
00057 QPixmap entryTypeToIcon(QCA::KeyStoreEntry::Type type) const
00058 {
00059 QPixmap out;
00060 if(!_shared)
00061 return out;
00062 const KeyStoreIconset &iconset = _shared->iconset;
00063 switch(type)
00064 {
00065 case QCA::KeyStoreEntry::TypeKeyBundle: out = iconset[KeySelectDlg::IconKeyBundle]; break;
00066 case QCA::KeyStoreEntry::TypeCertificate: out = iconset[KeySelectDlg::IconCert]; break;
00067 case QCA::KeyStoreEntry::TypeCRL: out = iconset[KeySelectDlg::IconCrl]; break;
00068 case QCA::KeyStoreEntry::TypePGPSecretKey: out = iconset[KeySelectDlg::IconPgpSec]; break;
00069 case QCA::KeyStoreEntry::TypePGPPublicKey: out = iconset[KeySelectDlg::IconPgpPub]; break;
00070 default: break;
00071 }
00072 return out;
00073 }
00074
00075 Type _type;
00076 KeyStoreItemShared *_shared;
00077
00078 QCA::KeyStore *keyStore;
00079 QCA::KeyStoreEntry keyStoreEntry;
00080
00081 KeyStoreItem(Type type, KeyStoreItemShared *shared) :
00082 _type(type),
00083 _shared(shared)
00084 {
00085 setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
00086 }
00087
00088 void setStore(const QString &name, QCA::KeyStore::Type type)
00089 {
00090 setData(name, NameRole);
00091 setData((int)type, SubTypeRole);
00092 }
00093
00094 void setEntry(const QString &name, QCA::KeyStoreEntry::Type type, bool available, int pos)
00095 {
00096 setData(name, NameRole);
00097 setData((int)type, SubTypeRole);
00098 setData(available, AvailabilityRole);
00099 setData(pos, PositionRole);
00100 }
00101
00102 virtual QVariant data(int role) const
00103 {
00104 if(role == Qt::DisplayRole)
00105 {
00106 if(_type == Store)
00107 {
00108 return data(NameRole).toString();
00109 }
00110 else if(_type == Entry)
00111 {
00112 QString str = data(NameRole).toString();
00113 if(_shared && !data(AvailabilityRole).toBool())
00114 str += QString(" ") + _shared->notAvailableString;
00115 return str;
00116 }
00117 else
00118 return QStandardItem::data(role);
00119 }
00120 else if(role == Qt::DecorationRole)
00121 {
00122 if(_type == Entry)
00123 {
00124 QCA::KeyStoreEntry::Type type = (QCA::KeyStoreEntry::Type)data(SubTypeRole).toInt();
00125 return entryTypeToIcon(type);
00126 }
00127 else
00128 return QStandardItem::data(role);
00129 }
00130 else
00131 return QStandardItem::data(role);
00132 }
00133
00134 virtual int type() const
00135 {
00136 return _type;
00137 }
00138
00139 virtual QStandardItem *clone() const
00140 {
00141 return new KeyStoreItem(*this);
00142 }
00143 };
00144
00145 class KeyStoreModel : public QStandardItemModel
00146 {
00147 Q_OBJECT
00148 public:
00149 KeyStoreItemShared shared;
00150
00151 QCA::KeyStoreManager ksm;
00152
00153 KeyStoreModel(QObject *parent = 0) :
00154 QStandardItemModel(parent), ksm(this)
00155 {
00156 shared.notAvailableString = tr("(not available)");
00157
00158
00159 QCA::KeyStoreManager::start();
00160
00161 connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ks_available(const QString &)));
00162 QStringList list = ksm.keyStores();
00163 foreach(const QString &s, list)
00164 ks_available(s);
00165
00166 setSortRole(KeyStoreItem::PositionRole);
00167 }
00168
00169 KeyStoreItem *itemFromStore(QCA::KeyStore *ks) const
00170 {
00171 for(int n = 0; n < rowCount(); ++n)
00172 {
00173 KeyStoreItem *i = (KeyStoreItem *)item(n);
00174 if(i->keyStore == ks)
00175 return i;
00176 }
00177 return 0;
00178 }
00179
00180 private slots:
00181 void ks_available(const QString &keyStoreId)
00182 {
00183 QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm);
00184
00185 #ifdef ONLY_SHOW_KEYBUNDLE
00186
00187 if(!ks->holdsIdentities() || ks->type() == QCA::KeyStore::PGPKeyring)
00188 return;
00189 #endif
00190
00191 connect(ks, SIGNAL(updated()), SLOT(ks_updated()));
00192 connect(ks, SIGNAL(unavailable()), SLOT(ks_unavailable()));
00193
00194 KeyStoreItem *store_item = new KeyStoreItem(KeyStoreItem::Store, &shared);
00195 store_item->setStore(ks->name(), ks->type());
00196 store_item->keyStore = ks;
00197 ks->startAsynchronousMode();
00198 appendRow(store_item);
00199 }
00200
00201 void ks_updated()
00202 {
00203 QCA::KeyStore *ks = (QCA::KeyStore *)sender();
00204 KeyStoreItem *store_item = itemFromStore(ks);
00205 Q_ASSERT(store_item);
00206
00207 QList<QCA::KeyStoreEntry> newEntries = ks->entryList();
00208
00209 #ifdef ONLY_SHOW_KEYBUNDLE
00210
00211 for(int n = 0; n < newEntries.count(); ++n)
00212 {
00213 if(newEntries[n].type() != QCA::KeyStoreEntry::TypeKeyBundle)
00214 {
00215 newEntries.removeAt(n);
00216 --n;
00217 }
00218 }
00219 #endif
00220
00221
00222 store_item->setStore(ks->name(), ks->type());
00223
00224
00225 for(int n = 0; n < store_item->rowCount(); ++n)
00226 {
00227 KeyStoreItem *i = (KeyStoreItem *)store_item->child(n);
00228
00229
00230 bool found = false;
00231 foreach(const QCA::KeyStoreEntry &ne, newEntries)
00232 {
00233 if(ne.id() == i->keyStoreEntry.id())
00234 {
00235 found = true;
00236 break;
00237 }
00238 }
00239
00240
00241 if(!found)
00242 {
00243 store_item->removeRow(n);
00244 --n;
00245 }
00246 }
00247
00248
00249 for(int n = 0; n < newEntries.count(); ++n)
00250 {
00251 const QCA::KeyStoreEntry &ne = newEntries[n];
00252
00253
00254 KeyStoreItem *entry_item = 0;
00255 for(int k = 0; k < store_item->rowCount(); ++k)
00256 {
00257 KeyStoreItem *i = (KeyStoreItem *)store_item->child(k);
00258 if(i->keyStoreEntry.id() == ne.id())
00259 {
00260 entry_item = i;
00261 break;
00262 }
00263 }
00264
00265
00266 if(!entry_item)
00267 {
00268 entry_item = new KeyStoreItem(KeyStoreItem::Entry, &shared);
00269 entry_item->keyStoreEntry = ne;
00270 entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n);
00271 store_item->appendRow(entry_item);
00272 }
00273
00274 else
00275 {
00276 entry_item->keyStoreEntry = ne;
00277 entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n);
00278 }
00279 }
00280
00281 store_item->sortChildren(0);
00282 }
00283
00284 void ks_unavailable()
00285 {
00286 QCA::KeyStore *ks = (QCA::KeyStore *)sender();
00287 KeyStoreItem *store_item = itemFromStore(ks);
00288 Q_ASSERT(store_item);
00289
00290 store_item->removeRows(0, store_item->rowCount());
00291 removeRow(store_item->row());
00292 delete ks;
00293 }
00294 };
00295
00296 class KeySelectDlg::Private : public QObject
00297 {
00298 Q_OBJECT
00299 public:
00300 KeySelectDlg *q;
00301 Ui_KeySelect ui;
00302 KeyStoreModel *model;
00303 QCA::KeyStoreEntry cur_entry;
00304 QAction *actionView;
00305
00306 Private(KeySelectDlg *_q) :
00307 QObject(_q),
00308 q(_q)
00309 {
00310 ui.setupUi(q);
00311
00312 model = new KeyStoreModel(this);
00313 connect(&model->ksm, SIGNAL(busyStarted()), SLOT(ksm_busyStarted()));
00314 connect(&model->ksm, SIGNAL(busyFinished()), SLOT(ksm_busyFinished()));
00315 if(model->ksm.isBusy())
00316 ksm_busyStarted();
00317
00318 ui.lv_stores->header()->hide();
00319 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
00320 ui.lv_stores->setModel(model);
00321 ui.lv_stores->setContextMenuPolicy(Qt::CustomContextMenu);
00322 connect(ui.lv_stores->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(stores_selectionChanged(const QItemSelection &, const QItemSelection &)));
00323 connect(ui.lv_stores, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(stores_customContextMenuRequested(const QPoint &)));
00324
00325 actionView = new QAction(tr("&View"), this);
00326 connect(actionView, SIGNAL(triggered()), SLOT(view()));
00327 actionView->setEnabled(false);
00328 }
00329
00330 private slots:
00331 void ksm_busyStarted()
00332 {
00333 ui.lb_busy->setText(tr("Looking for devices..."));
00334 }
00335
00336 void ksm_busyFinished()
00337 {
00338 ui.lb_busy->setText("");
00339 }
00340
00341 void stores_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
00342 {
00343 Q_UNUSED(deselected);
00344
00345 KeyStoreItem *i = 0;
00346 if(!selected.indexes().isEmpty())
00347 {
00348 QModelIndex index = selected.indexes().first();
00349 i = (KeyStoreItem *)model->itemFromIndex(index);
00350 }
00351
00352 bool viewable = false;
00353 bool choosable = false;
00354 if(i && i->type() == KeyStoreItem::Entry)
00355 {
00356 QCA::KeyStoreEntry entry = i->keyStoreEntry;
00357 if(entry.type() == QCA::KeyStoreEntry::TypeKeyBundle)
00358 {
00359 viewable = true;
00360 choosable = true;
00361 cur_entry = entry;
00362 }
00363 }
00364
00365 if(!choosable)
00366 cur_entry = QCA::KeyStoreEntry();
00367
00368 actionView->setEnabled(viewable);
00369
00370 QPushButton *ok = ui.buttonBox->button(QDialogButtonBox::Ok);
00371 if(choosable && !ok->isEnabled())
00372 ok->setEnabled(true);
00373 else if(!choosable && ok->isEnabled())
00374 ok->setEnabled(false);
00375 }
00376
00377 void stores_customContextMenuRequested(const QPoint &pos)
00378 {
00379 QItemSelection selection = ui.lv_stores->selectionModel()->selection();
00380 if(selection.indexes().isEmpty())
00381 return;
00382
00383 QModelIndex index = selection.indexes().first();
00384 KeyStoreItem *i = (KeyStoreItem *)model->itemFromIndex(index);
00385 if(i && i->type() == KeyStoreItem::Entry)
00386 {
00387 QMenu menu(q);
00388 menu.addAction(actionView);
00389 menu.exec(ui.lv_stores->viewport()->mapToGlobal(pos));
00390 }
00391 }
00392
00393 void view()
00394 {
00395 emit q->viewCertificate(cur_entry.keyBundle().certificateChain());
00396 }
00397 };
00398
00399 KeySelectDlg::KeySelectDlg(QWidget *parent) :
00400 QDialog(parent)
00401 {
00402 d = new Private(this);
00403 }
00404
00405 KeySelectDlg::~KeySelectDlg()
00406 {
00407 delete d;
00408 }
00409
00410 void KeySelectDlg::setIcon(IconType type, const QPixmap &icon)
00411 {
00412 d->model->shared.iconset[type] = icon;
00413 }
00414
00415 void KeySelectDlg::accept()
00416 {
00417 QCA::KeyStoreEntry entry = d->cur_entry;
00418 QDialog::accept();
00419 emit selected(entry);
00420 }
00421
00422 #include "keyselectdlg.moc"
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef PROMPTER_H
00023 #define PROMPTER_H
00024
00025 #include <QObject>
00026
00027 namespace QCA
00028 {
00029 class SecureArray;
00030 class Event;
00031 }
00032
00033 class Prompter : public QObject
00034 {
00035 Q_OBJECT
00036 public:
00037 Prompter(QObject *parent = 0);
00038 ~Prompter();
00039
00040 protected:
00041
00042
00043 virtual QCA::SecureArray knownPassword(const QCA::Event &event);
00044
00045
00046
00047
00048
00049 virtual void userSubmitted(const QCA::SecureArray &password, const QCA::Event &event);
00050
00051 private:
00052 class Private;
00053 friend class Private;
00054 Private *d;
00055 };
00056
00057 #endif
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "prompter.h"
00023
00024 #include <QtCore>
00025 #include <QtGui>
00026 #include <QtCrypto>
00027
00028 class Prompter::Private : public QObject
00029 {
00030 Q_OBJECT
00031 public:
00032 Prompter *q;
00033
00034 class Item
00035 {
00036 public:
00037 int id;
00038 QCA::Event event;
00039 };
00040
00041 QCA::EventHandler handler;
00042 QList<Item> pending;
00043 bool prompting;
00044 QMessageBox *token_prompt;
00045 bool auto_accept;
00046
00047 QCA::KeyStoreManager ksm;
00048 QList<QCA::KeyStore*> keyStores;
00049
00050 Private(Prompter *_q) :
00051 QObject(_q),
00052 q(_q),
00053 handler(this),
00054 prompting(false),
00055 token_prompt(0),
00056 ksm(this)
00057 {
00058 connect(&handler, SIGNAL(eventReady(int, const QCA::Event &)), SLOT(ph_eventReady(int, const QCA::Event &)));
00059 handler.start();
00060
00061 connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ks_available(const QString &)));
00062 foreach(const QString &keyStoreId, ksm.keyStores())
00063 ks_available(keyStoreId);
00064 }
00065
00066 ~Private()
00067 {
00068 qDeleteAll(keyStores);
00069
00070 while(!pending.isEmpty())
00071 handler.reject(pending.takeFirst().id);
00072 }
00073
00074 private slots:
00075 void ph_eventReady(int id, const QCA::Event &event)
00076 {
00077 Item i;
00078 i.id = id;
00079 i.event = event;
00080 pending += i;
00081 nextEvent();
00082 }
00083
00084 void nextEvent()
00085 {
00086 if(prompting || pending.isEmpty())
00087 return;
00088
00089 prompting = true;
00090
00091 const Item &i = pending.first();
00092 const int &id = i.id;
00093 const QCA::Event &event = i.event;
00094
00095 if(event.type() == QCA::Event::Password)
00096 {
00097 QCA::SecureArray known = q->knownPassword(event);
00098 if(!known.isEmpty())
00099 {
00100 handler.submitPassword(id, known);
00101 goto end;
00102 }
00103
00104 QString type = Prompter::tr("password");
00105 if(event.passwordStyle() == QCA::Event::StylePassphrase)
00106 type = Prompter::tr("passphrase");
00107 else if(event.passwordStyle() == QCA::Event::StylePIN)
00108 type = Prompter::tr("PIN");
00109
00110 QString str;
00111 if(event.source() == QCA::Event::KeyStore)
00112 {
00113 QString name;
00114 QCA::KeyStoreEntry entry = event.keyStoreEntry();
00115 if(!entry.isNull())
00116 {
00117 name = entry.name();
00118 }
00119 else
00120 {
00121 if(event.keyStoreInfo().type() == QCA::KeyStore::SmartCard)
00122 name = Prompter::tr("the '%1' token").arg(event.keyStoreInfo().name());
00123 else
00124 name = event.keyStoreInfo().name();
00125 }
00126 str = Prompter::tr("Enter %1 for %2").arg(type, name);
00127 }
00128 else if(!event.fileName().isEmpty())
00129 {
00130 QFileInfo fi(event.fileName());
00131 str = Prompter::tr("Enter %1 for %2:").arg(type, fi.fileName());
00132 }
00133 else
00134 str = Prompter::tr("Enter %1:").arg(type);
00135
00136 bool ok;
00137 QString pass = QInputDialog::getText(0, QApplication::instance()->applicationName() + ": " + tr("Prompt"), str, QLineEdit::Password, QString(), &ok);
00138 if(ok)
00139 {
00140 QCA::SecureArray password = pass.toUtf8();
00141 q->userSubmitted(password, event);
00142 handler.submitPassword(id, password);
00143 }
00144 else
00145 handler.reject(id);
00146 }
00147 else if(event.type() == QCA::Event::Token)
00148 {
00149
00150
00151
00152 bool found = false;
00153
00154
00155 if(event.keyStoreEntry().isNull())
00156 {
00157 foreach(QCA::KeyStore *ks, keyStores)
00158 {
00159 if(ks->id() == event.keyStoreInfo().id())
00160 {
00161 found = true;
00162 break;
00163 }
00164 }
00165 }
00166
00167 else
00168 {
00169 QCA::KeyStoreEntry kse = event.keyStoreEntry();
00170
00171 QCA::KeyStore *ks = 0;
00172 foreach(QCA::KeyStore *i, keyStores)
00173 {
00174 if(i->id() == event.keyStoreInfo().id())
00175 {
00176 ks = i;
00177 break;
00178 }
00179 }
00180 if(ks)
00181 {
00182 QList<QCA::KeyStoreEntry> list = ks->entryList();
00183 foreach(const QCA::KeyStoreEntry &e, list)
00184 {
00185 if(e.id() == kse.id() && kse.isAvailable())
00186 {
00187 found = true;
00188 break;
00189 }
00190 }
00191 }
00192 }
00193 if(found)
00194 {
00195
00196 handler.tokenOkay(id);
00197 return;
00198 }
00199
00200 QCA::KeyStoreEntry entry = event.keyStoreEntry();
00201 QString name;
00202 if(!entry.isNull())
00203 {
00204 name = Prompter::tr("Please make %1 (of %2) available").arg(entry.name(), entry.storeName());
00205 }
00206 else
00207 {
00208 name = Prompter::tr("Please insert the '%1' token").arg(event.keyStoreInfo().name());
00209 }
00210
00211 QString str = Prompter::tr("%1 and click OK.").arg(name);
00212
00213 QMessageBox msgBox(QMessageBox::Information, QApplication::instance()->applicationName() + ": " + tr("Prompt"), str, QMessageBox::Ok | QMessageBox::Cancel, 0);
00214 token_prompt = &msgBox;
00215 auto_accept = false;
00216 if(msgBox.exec() == QMessageBox::Ok || auto_accept)
00217 handler.tokenOkay(id);
00218 else
00219 handler.reject(id);
00220 token_prompt = 0;
00221 }
00222 else
00223 handler.reject(id);
00224
00225 end:
00226 pending.removeFirst();
00227 prompting = false;
00228
00229 if(!pending.isEmpty())
00230 QMetaObject::invokeMethod(this, "nextEvent", Qt::QueuedConnection);
00231 }
00232
00233 void ks_available(const QString &keyStoreId)
00234 {
00235 QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm);
00236 connect(ks, SIGNAL(updated()), SLOT(ks_updated()));
00237 connect(ks, SIGNAL(unavailable()), SLOT(ks_unavailable()));
00238 keyStores += ks;
00239 ks->startAsynchronousMode();
00240
00241
00242 if(token_prompt && pending.first().event.type() == QCA::Event::Token && pending.first().event.keyStoreEntry().isNull())
00243 {
00244
00245 if(pending.first().event.keyStoreInfo().id() == keyStoreId)
00246 {
00247
00248 auto_accept = true;
00249 token_prompt->accept();
00250 }
00251 }
00252 }
00253
00254 void ks_unavailable()
00255 {
00256 QCA::KeyStore *ks = (QCA::KeyStore *)sender();
00257 keyStores.removeAll(ks);
00258 delete ks;
00259 }
00260
00261 void ks_updated()
00262 {
00263 QCA::KeyStore *ks = (QCA::KeyStore *)sender();
00264
00265
00266 if(token_prompt && pending.first().event.type() == QCA::Event::Token && !pending.first().event.keyStoreEntry().isNull())
00267 {
00268 QCA::KeyStoreEntry kse = pending.first().event.keyStoreEntry();
00269
00270
00271 if(pending.first().event.keyStoreInfo().id() == ks->id())
00272 {
00273
00274 bool avail = false;
00275 QList<QCA::KeyStoreEntry> list = ks->entryList();
00276 foreach(const QCA::KeyStoreEntry &e, list)
00277 {
00278 if(e.id() == kse.id())
00279 {
00280 avail = kse.isAvailable();
00281 break;
00282 }
00283 }
00284 if(avail)
00285 {
00286
00287 auto_accept = true;
00288 token_prompt->accept();
00289 }
00290 }
00291 }
00292 }
00293 };
00294
00295 Prompter::Prompter(QObject *parent) :
00296 QObject(parent)
00297 {
00298 d = new Private(this);
00299 }
00300
00301 Prompter::~Prompter()
00302 {
00303 delete d;
00304 }
00305
00306 QCA::SecureArray Prompter::knownPassword(const QCA::Event &event)
00307 {
00308 Q_UNUSED(event);
00309 return QCA::SecureArray();
00310 }
00311
00312 void Prompter::userSubmitted(const QCA::SecureArray &password, const QCA::Event &event)
00313 {
00314 Q_UNUSED(password);
00315 Q_UNUSED(event);
00316 }
00317
00318 #include "prompter.moc"
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <QtCore>
00023 #include <QtGui>
00024 #include <QtCrypto>
00025
00026 #include "ui_mainwin.h"
00027 #include "certviewdlg.h"
00028 #include "keyselectdlg.h"
00029 #include "pkcs11configdlg/pkcs11configdlg.h"
00030 #include "certitem.h"
00031
00032 #define VERSION "1.0.0"
00033
00034 class Icons
00035 {
00036 public:
00037 QPixmap cert, crl, keybundle, pgppub, pgpsec;
00038 };
00039
00040 Icons *g_icons = 0;
00041
00042
00043
00044
00045 class Operation : public QObject
00046 {
00047 Q_OBJECT
00048 public:
00049 Operation(QObject *parent = 0) :
00050 QObject(parent)
00051 {
00052 }
00053
00054 signals:
00055 void error(const QString &str);
00056 };
00057
00058 static QString validityToString(QCA::Validity v)
00059 {
00060 QString s;
00061 switch(v)
00062 {
00063 case QCA::ValidityGood:
00064 s = Operation::tr("Validated");
00065 break;
00066 case QCA::ErrorRejected:
00067 s = Operation::tr("Root CA is marked to reject the specified purpose");
00068 break;
00069 case QCA::ErrorUntrusted:
00070 s = Operation::tr("Certificate not trusted for the required purpose");
00071 break;
00072 case QCA::ErrorSignatureFailed:
00073 s = Operation::tr("Invalid signature");
00074 break;
00075 case QCA::ErrorInvalidCA:
00076 s = Operation::tr("Invalid CA certificate");
00077 break;
00078 case QCA::ErrorInvalidPurpose:
00079 s = Operation::tr("Invalid certificate purpose");
00080 break;
00081 case QCA::ErrorSelfSigned:
00082 s = Operation::tr("Certificate is self-signed");
00083 break;
00084 case QCA::ErrorRevoked:
00085 s = Operation::tr("Certificate has been revoked");
00086 break;
00087 case QCA::ErrorPathLengthExceeded:
00088 s = Operation::tr("Maximum certificate chain length exceeded");
00089 break;
00090 case QCA::ErrorExpired:
00091 s = Operation::tr("Certificate has expired");
00092 break;
00093 case QCA::ErrorExpiredCA:
00094 s = Operation::tr("CA has expired");
00095 break;
00096 case QCA::ErrorValidityUnknown:
00097 default:
00098 s = Operation::tr("General certificate validation error");
00099 break;
00100 }
00101 return s;
00102 }
00103
00104 static QString smErrorToString(QCA::SecureMessage::Error e)
00105 {
00106 QString s;
00107 switch(e)
00108 {
00109 case QCA::SecureMessage::ErrorPassphrase:
00110 s = Operation::tr("Invalid passphrase.");
00111 break;
00112 case QCA::SecureMessage::ErrorFormat:
00113 s = Operation::tr("Bad input format.");
00114 break;
00115 case QCA::SecureMessage::ErrorSignerExpired:
00116 s = Operation::tr("Signer key is expired.");
00117 break;
00118 case QCA::SecureMessage::ErrorSignerInvalid:
00119 s = Operation::tr("Signer key is invalid.");
00120 break;
00121 case QCA::SecureMessage::ErrorEncryptExpired:
00122 s = Operation::tr("Encrypting key is expired.");
00123 break;
00124 case QCA::SecureMessage::ErrorEncryptUntrusted:
00125 s = Operation::tr("Encrypting key is untrusted.");
00126 break;
00127 case QCA::SecureMessage::ErrorEncryptInvalid:
00128 s = Operation::tr("Encrypting key is invalid.");
00129 break;
00130 case QCA::SecureMessage::ErrorNeedCard:
00131 s = Operation::tr("Card was needed but not found.");
00132 break;
00133 case QCA::SecureMessage::ErrorCertKeyMismatch:
00134 s = Operation::tr("Certificate and private key don't match.");
00135 break;
00136 case QCA::SecureMessage::ErrorUnknown:
00137 default:
00138 s = Operation::tr("General error.");
00139 break;
00140 }
00141 return s;
00142 }
00143
00144 static QString smsIdentityToString(const QCA::SecureMessageSignature &sig)
00145 {
00146 QString s;
00147 switch(sig.identityResult())
00148 {
00149 case QCA::SecureMessageSignature::Valid:
00150 break;
00151 case QCA::SecureMessageSignature::InvalidSignature:
00152 s = Operation::tr("Invalid signature");
00153 break;
00154 case QCA::SecureMessageSignature::InvalidKey:
00155 s = Operation::tr("Invalid key: %1").arg(validityToString(sig.keyValidity()));
00156 break;
00157 case QCA::SecureMessageSignature::NoKey:
00158 s = Operation::tr("Key not found");
00159 break;
00160 default:
00161 s = Operation::tr("Unknown");
00162 break;
00163 }
00164 return s;
00165 }
00166
00167 class SignOperation : public Operation
00168 {
00169 Q_OBJECT
00170 private:
00171 QByteArray in;
00172 CertItemStore *store;
00173 int id;
00174 QCA::CMS *cms;
00175 CertItemPrivateLoader *loader;
00176 QCA::SecureMessage *msg;
00177 int pending;
00178
00179 public:
00180 SignOperation(const QByteArray &_in, CertItemStore *_store, int _id, QCA::CMS *_cms, QObject *parent = 0) :
00181 Operation(parent),
00182 in(_in),
00183 store(_store),
00184 id(_id),
00185 cms(_cms),
00186 msg(0)
00187 {
00188 loader = new CertItemPrivateLoader(store, this);
00189 connect(loader, SIGNAL(finished()), SLOT(loader_finished()));
00190 loader->start(id);
00191 }
00192
00193 signals:
00194 void loadError();
00195 void finished(const QString &sig);
00196
00197 private slots:
00198 void loader_finished()
00199 {
00200 QCA::PrivateKey privateKey = loader->privateKey();
00201 delete loader;
00202 loader = 0;
00203
00204 if(privateKey.isNull())
00205 {
00206 emit loadError();
00207 return;
00208 }
00209
00210 CertItem item = store->itemFromId(id);
00211
00212 QCA::SecureMessageKey signer;
00213 signer.setX509CertificateChain(item.certificateChain());
00214 signer.setX509PrivateKey(privateKey);
00215
00216 msg = new QCA::SecureMessage(cms);
00217 connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int)));
00218 connect(msg, SIGNAL(finished()), SLOT(msg_finished()));
00219 msg->setFormat(QCA::SecureMessage::Ascii);
00220 msg->setSigner(signer);
00221 msg->startSign(QCA::SecureMessage::Detached);
00222
00223 pending = 0;
00224 update();
00225 }
00226
00227 void update()
00228 {
00229 QByteArray buf = in.mid(0, 16384 - pending);
00230 in = in.mid(buf.size());
00231 pending += buf.size();
00232 msg->update(buf);
00233 }
00234
00235 void msg_bytesWritten(int x)
00236 {
00237 pending -= x;
00238
00239 if(in.isEmpty() && pending == 0)
00240 msg->end();
00241 else
00242 update();
00243 }
00244
00245 void msg_finished()
00246 {
00247 if(!msg->success())
00248 {
00249 QString str = smErrorToString(msg->errorCode());
00250 delete msg;
00251 msg = 0;
00252 emit error(tr("Error during sign operation.\nReason: %1").arg(str));
00253 return;
00254 }
00255
00256 QByteArray result = msg->signature();
00257 delete msg;
00258 msg = 0;
00259 emit finished(QString::fromLatin1(result));
00260 }
00261 };
00262
00263 class VerifyOperation : public Operation
00264 {
00265 Q_OBJECT
00266 private:
00267 QByteArray in, sig;
00268 QCA::CMS *cms;
00269 QCA::SecureMessage *msg;
00270 int pending;
00271
00272 public:
00273 QCA::SecureMessageSignature signer;
00274
00275 VerifyOperation(const QByteArray &_in, const QByteArray &_sig, QCA::CMS *_cms, QObject *parent = 0) :
00276 Operation(parent),
00277 in(_in),
00278 sig(_sig),
00279 cms(_cms),
00280 msg(0)
00281 {
00282 msg = new QCA::SecureMessage(cms);
00283 connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int)));
00284 connect(msg, SIGNAL(finished()), SLOT(msg_finished()));
00285 msg->setFormat(QCA::SecureMessage::Ascii);
00286 msg->startVerify(sig);
00287
00288 pending = 0;
00289 update();
00290 }
00291
00292 signals:
00293 void finished();
00294
00295 private slots:
00296 void update()
00297 {
00298 QByteArray buf = in.mid(0, 16384 - pending);
00299 in = in.mid(buf.size());
00300 pending += buf.size();
00301 msg->update(buf);
00302 }
00303
00304 void msg_bytesWritten(int x)
00305 {
00306 pending -= x;
00307
00308 if(in.isEmpty() && pending == 0)
00309 msg->end();
00310 else
00311 update();
00312 }
00313
00314 void msg_finished()
00315 {
00316 if(!msg->success())
00317 {
00318 QString str = smErrorToString(msg->errorCode());
00319 delete msg;
00320 msg = 0;
00321 emit error(tr("Error during verify operation.\nReason: %1").arg(str));
00322 return;
00323 }
00324
00325 signer = msg->signer();
00326 delete msg;
00327 msg = 0;
00328
00329 if(signer.identityResult() != QCA::SecureMessageSignature::Valid)
00330 {
00331 QString str = smsIdentityToString(signer);
00332 emit error(tr("Verification failed!\nReason: %1").arg(str));
00333 return;
00334 }
00335
00336 emit finished();
00337 }
00338 };
00339
00340
00341
00342
00343 static QString get_fingerprint(const QCA::Certificate &cert)
00344 {
00345 QString hex = QCA::Hash("sha1").hashToString(cert.toDER());
00346 QString out;
00347 for(int n = 0; n < hex.count(); ++n)
00348 {
00349 if(n != 0 && n % 2 == 0)
00350 out += ':';
00351 out += hex[n];
00352 }
00353 return out;
00354 }
00355
00356 class MainWin : public QMainWindow
00357 {
00358 Q_OBJECT
00359 private:
00360 Ui_MainWin ui;
00361 CertItemStore *users, *roots;
00362 QCA::CMS *cms;
00363 Operation *op;
00364 QAction *actionView, *actionRename, *actionRemove;
00365 QCA::Certificate self_signed_verify_cert;
00366 int auto_import_req_id;
00367
00368 public:
00369 MainWin(QWidget *parent = 0) :
00370 QMainWindow(parent),
00371 op(0),
00372 auto_import_req_id(-1)
00373 {
00374 ui.setupUi(this);
00375
00376 g_icons = new Icons;
00377 g_icons->cert = QPixmap(":/gfx/icons/cert16.png");
00378 g_icons->crl = QPixmap(":/gfx/icons/crl16.png");
00379 g_icons->keybundle = QPixmap(":/gfx/icons/keybundle16.png");
00380 g_icons->pgppub = QPixmap(":/gfx/icons/publickey16.png");
00381 g_icons->pgpsec = QPixmap(":/gfx/icons/keypair16.png");
00382 if(g_icons->cert.isNull() || g_icons->crl.isNull() || g_icons->keybundle.isNull() || g_icons->pgppub.isNull() || g_icons->pgpsec.isNull())
00383 printf("Warning: not all icons loaded\n");
00384
00385 users = new CertItemStore(this);
00386 roots = new CertItemStore(this);
00387
00388 setIcons(users);
00389 setIcons(roots);
00390
00391 connect(users, SIGNAL(addSuccess(int, int)), SLOT(users_addSuccess(int, int)));
00392 connect(users, SIGNAL(addFailed(int)), SLOT(users_addFailed(int)));
00393
00394 actionView = new QAction(tr("&View"), this);
00395 actionRename = new QAction(tr("Re&name"), this);
00396 actionRemove = new QAction(tr("Rem&ove"), this);
00397
00398 connect(ui.actionLoadIdentityFile, SIGNAL(triggered()), SLOT(load_file()));
00399 connect(ui.actionLoadIdentityEntry, SIGNAL(triggered()), SLOT(load_device()));
00400 connect(ui.actionLoadAuthority, SIGNAL(triggered()), SLOT(load_root()));
00401 connect(ui.actionConfigurePkcs11, SIGNAL(triggered()), SLOT(mod_config()));
00402 connect(ui.actionQuit, SIGNAL(triggered()), SLOT(close()));
00403 connect(ui.actionAbout, SIGNAL(triggered()), SLOT(about()));
00404 connect(ui.pb_sign, SIGNAL(clicked()), SLOT(do_sign()));
00405 connect(ui.pb_verify, SIGNAL(clicked()), SLOT(do_verify()));
00406
00407 connect(actionView, SIGNAL(triggered()), SLOT(item_view()));
00408 connect(actionRename, SIGNAL(triggered()), SLOT(item_rename()));
00409 connect(actionRemove, SIGNAL(triggered()), SLOT(item_remove()));
00410
00411 ui.pb_sign->setEnabled(false);
00412
00413 ui.lv_users->setModel(users);
00414 connect(ui.lv_users->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(users_selectionChanged(const QItemSelection &, const QItemSelection &)));
00415
00416 ui.lv_users->setContextMenuPolicy(Qt::CustomContextMenu);
00417 connect(ui.lv_users, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(users_customContextMenuRequested(const QPoint &)));
00418
00419 ui.lv_authorities->setModel(roots);
00420
00421 ui.lv_authorities->setContextMenuPolicy(Qt::CustomContextMenu);
00422 connect(ui.lv_authorities, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(roots_customContextMenuRequested(const QPoint &)));
00423
00424 cms = new QCA::CMS(this);
00425
00426 QStringList ulist, rlist;
00427 {
00428 QSettings settings("Affinix", "CMS Signer");
00429 ulist = settings.value("users").toStringList();
00430 rlist = settings.value("roots").toStringList();
00431 }
00432
00433 users->load(ulist);
00434 roots->load(rlist);
00435 }
00436
00437 ~MainWin()
00438 {
00439 QStringList ulist = users->save();
00440 QStringList rlist = roots->save();
00441
00442 QSettings settings("Affinix", "CMS Signer");
00443 settings.setValue("users", ulist);
00444 settings.setValue("roots", rlist);
00445
00446 delete g_icons;
00447 g_icons = 0;
00448 }
00449
00450 void setIcons(CertItemStore *store)
00451 {
00452 store->setIcon(CertItemStore::IconCert, g_icons->cert);
00453 store->setIcon(CertItemStore::IconCrl, g_icons->crl);
00454 store->setIcon(CertItemStore::IconKeyBundle, g_icons->keybundle);
00455 store->setIcon(CertItemStore::IconPgpPub, g_icons->pgppub);
00456 store->setIcon(CertItemStore::IconPgpSec, g_icons->pgpsec);
00457 }
00458
00459 QCA::CertificateCollection allCerts()
00460 {
00461 QCA::CertificateCollection col;
00462
00463
00464 col += QCA::systemStore();
00465
00466
00467 foreach(const CertItem &i, roots->items())
00468 col.addCertificate(i.certificateChain().primary());
00469
00470
00471 foreach(const CertItem &i, users->items())
00472 {
00473 foreach(const QCA::Certificate &cert, i.certificateChain())
00474 col.addCertificate(cert);
00475 }
00476
00477 return col;
00478 }
00479
00480 QCA::CertificateChain complete(const QCA::CertificateChain &chain)
00481 {
00482 return chain.complete(allCerts().certificates());
00483 }
00484
00485 private slots:
00486 void load_file()
00487 {
00488 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Identities (*.p12 *.pfx)"));
00489 if(fileName.isEmpty())
00490 return;
00491
00492 setEnabled(false);
00493 users->addFromFile(fileName);
00494 }
00495
00496 void load_device()
00497 {
00498 KeySelectDlg *w = new KeySelectDlg(this);
00499 w->setAttribute(Qt::WA_DeleteOnClose, true);
00500 w->setWindowModality(Qt::WindowModal);
00501 connect(w, SIGNAL(selected(const QCA::KeyStoreEntry &)), SLOT(load_device_finished(const QCA::KeyStoreEntry &)));
00502 connect(w, SIGNAL(viewCertificate(const QCA::CertificateChain &)), SLOT(keyselect_viewCertificate(const QCA::CertificateChain &)));
00503 w->setIcon(KeySelectDlg::IconCert, g_icons->cert);
00504 w->setIcon(KeySelectDlg::IconCrl, g_icons->crl);
00505 w->setIcon(KeySelectDlg::IconKeyBundle, g_icons->keybundle);
00506 w->setIcon(KeySelectDlg::IconPgpPub, g_icons->pgppub);
00507 w->setIcon(KeySelectDlg::IconPgpSec, g_icons->pgpsec);
00508 w->show();
00509 }
00510
00511 void load_device_finished(const QCA::KeyStoreEntry &entry)
00512 {
00513 users->addFromKeyStore(entry);
00514 }
00515
00516 void load_root()
00517 {
00518 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Certificates (*.pem *.crt)"));
00519 if(fileName.isEmpty())
00520 return;
00521
00522 QCA::Certificate cert = QCA::Certificate::fromPEMFile(fileName);
00523 if(cert.isNull())
00524 {
00525 QMessageBox::information(this, tr("Error"), tr("Error opening certificate file."));
00526 return;
00527 }
00528
00529 roots->addUser(cert);
00530 }
00531
00532 void users_addSuccess(int req_id, int id)
00533 {
00534 if(req_id == auto_import_req_id)
00535 {
00536 auto_import_req_id = -1;
00537
00538 CertItem i = users->itemFromId(id);
00539
00540 QMessageBox::information(this, tr("User added"), tr(
00541 "This signature was made by a previously unknown user, and so the "
00542 "user has now been added to the keyring as \"%1\"."
00543 ).arg(i.name()));
00544
00545 verify_next();
00546 return;
00547 }
00548
00549 ui.lv_users->selectionModel()->select(users->index(users->rowFromId(id)), QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
00550
00551 setEnabled(true);
00552 }
00553
00554 void users_addFailed(int req_id)
00555 {
00556 Q_UNUSED(req_id);
00557
00558 setEnabled(true);
00559 }
00560
00561 void mod_config()
00562 {
00563 if(!Pkcs11ConfigDlg::isSupported())
00564 {
00565 QMessageBox::information(this, tr("Error"), tr("No provider available supporting standard PKCS#11 configuration."));
00566 return;
00567 }
00568
00569 Pkcs11ConfigDlg *w = new Pkcs11ConfigDlg(this);
00570 w->setAttribute(Qt::WA_DeleteOnClose, true);
00571 w->setWindowModality(Qt::WindowModal);
00572 w->show();
00573 }
00574
00575 void users_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
00576 {
00577 Q_UNUSED(deselected);
00578
00579 int at = -1;
00580 if(!selected.indexes().isEmpty())
00581 {
00582 QModelIndex index = selected.indexes().first();
00583 at = index.row();
00584 }
00585
00586 bool usable = false;
00587 if(at != -1 && users->itemFromRow(at).isUsable())
00588 usable = true;
00589
00590 if(usable && !ui.pb_sign->isEnabled())
00591 ui.pb_sign->setEnabled(true);
00592 else if(!usable && ui.pb_sign->isEnabled())
00593 ui.pb_sign->setEnabled(false);
00594 }
00595
00596 void item_view()
00597 {
00598 if(ui.lv_users->hasFocus())
00599 {
00600 QItemSelection selection = ui.lv_users->selectionModel()->selection();
00601 if(selection.indexes().isEmpty())
00602 return;
00603 QModelIndex index = selection.indexes().first();
00604 users_view(index.row());
00605 }
00606 else
00607 {
00608 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00609 if(selection.indexes().isEmpty())
00610 return;
00611 QModelIndex index = selection.indexes().first();
00612 roots_view(index.row());
00613 }
00614 }
00615
00616 void item_rename()
00617 {
00618 if(ui.lv_users->hasFocus())
00619 {
00620 QItemSelection selection = ui.lv_users->selectionModel()->selection();
00621 if(selection.indexes().isEmpty())
00622 return;
00623 QModelIndex index = selection.indexes().first();
00624 users_rename(index.row());
00625 }
00626 else
00627 {
00628 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00629 if(selection.indexes().isEmpty())
00630 return;
00631 QModelIndex index = selection.indexes().first();
00632 roots_rename(index.row());
00633 }
00634 }
00635
00636 void item_remove()
00637 {
00638 if(ui.lv_users->hasFocus())
00639 {
00640 QItemSelection selection = ui.lv_users->selectionModel()->selection();
00641 if(selection.indexes().isEmpty())
00642 return;
00643 QModelIndex index = selection.indexes().first();
00644 users_remove(index.row());
00645 }
00646 else
00647 {
00648 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00649 if(selection.indexes().isEmpty())
00650 return;
00651 QModelIndex index = selection.indexes().first();
00652 roots_remove(index.row());
00653 }
00654 }
00655
00656 void users_view(int at)
00657 {
00658 CertItem i = users->itemFromRow(at);
00659 CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this);
00660 w->setAttribute(Qt::WA_DeleteOnClose, true);
00661 w->show();
00662 }
00663
00664 void users_rename(int at)
00665 {
00666 QModelIndex index = users->index(at);
00667 ui.lv_users->setFocus();
00668 ui.lv_users->setCurrentIndex(index);
00669 ui.lv_users->selectionModel()->select(index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
00670 ui.lv_users->edit(index);
00671 }
00672
00673 void users_remove(int at)
00674 {
00675 users->removeItem(users->idFromRow(at));
00676 }
00677
00678 void roots_view(int at)
00679 {
00680 CertItem i = roots->itemFromRow(at);
00681 CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this);
00682 w->setAttribute(Qt::WA_DeleteOnClose, true);
00683 w->show();
00684 }
00685
00686 void roots_rename(int at)
00687 {
00688 QModelIndex index = roots->index(at);
00689 ui.lv_authorities->setFocus();
00690 ui.lv_authorities->setCurrentIndex(index);
00691 ui.lv_authorities->selectionModel()->select(index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
00692 ui.lv_authorities->edit(index);
00693 }
00694
00695 void roots_remove(int at)
00696 {
00697 roots->removeItem(roots->idFromRow(at));
00698 }
00699
00700 void keyselect_viewCertificate(const QCA::CertificateChain &chain)
00701 {
00702 CertViewDlg *w = new CertViewDlg(complete(chain), (QWidget *)sender());
00703 w->setAttribute(Qt::WA_DeleteOnClose, true);
00704 w->show();
00705 }
00706
00707 void users_customContextMenuRequested(const QPoint &pos)
00708 {
00709 QItemSelection selection = ui.lv_users->selectionModel()->selection();
00710 if(selection.indexes().isEmpty())
00711 return;
00712
00713 QMenu menu(this);
00714 menu.addAction(actionView);
00715 menu.addAction(actionRename);
00716 menu.addAction(actionRemove);
00717 menu.exec(ui.lv_users->viewport()->mapToGlobal(pos));
00718 }
00719
00720 void roots_customContextMenuRequested(const QPoint &pos)
00721 {
00722 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00723 if(selection.indexes().isEmpty())
00724 return;
00725
00726 QMenu menu(this);
00727 menu.addAction(actionView);
00728 menu.addAction(actionRename);
00729 menu.addAction(actionRemove);
00730 menu.exec(ui.lv_authorities->viewport()->mapToGlobal(pos));
00731 }
00732
00733 void do_sign()
00734 {
00735 QItemSelection selection = ui.lv_users->selectionModel()->selection();
00736 if(selection.indexes().isEmpty())
00737 return;
00738 QModelIndex index = selection.indexes().first();
00739 int at = index.row();
00740
00741 setEnabled(false);
00742
00743 op = new SignOperation(ui.te_data->toPlainText().toUtf8(), users, users->idFromRow(at), cms, this);
00744 connect(op, SIGNAL(loadError()), SLOT(sign_loadError()));
00745 connect(op, SIGNAL(finished(const QString &)), SLOT(sign_finished(const QString &)));
00746 connect(op, SIGNAL(error(const QString &)), SLOT(sign_error(const QString &)));
00747 }
00748
00749 void do_verify()
00750 {
00751
00752 QCA::CertificateCollection col;
00753
00754
00755 col += QCA::systemStore();
00756
00757
00758 foreach(const CertItem &i, roots->items())
00759 col.addCertificate(i.certificateChain().primary());
00760
00761
00762
00763
00764 foreach(const CertItem &i, users->items())
00765 {
00766 QCA::Certificate cert = i.certificateChain().primary();
00767 if(cert.isSelfSigned())
00768 col.addCertificate(cert);
00769 }
00770
00771
00772 if(!self_signed_verify_cert.isNull())
00773 {
00774 col.addCertificate(self_signed_verify_cert);
00775 self_signed_verify_cert = QCA::Certificate();
00776 }
00777
00778 cms->setTrustedCertificates(col);
00779
00780 setEnabled(false);
00781
00782 op = new VerifyOperation(ui.te_data->toPlainText().toUtf8(), ui.te_sig->toPlainText().toUtf8(), cms, this);
00783 connect(op, SIGNAL(finished()), SLOT(verify_finished()));
00784 connect(op, SIGNAL(error(const QString &)), SLOT(verify_error(const QString &)));
00785 }
00786
00787 void about()
00788 {
00789 int ver = qcaVersion();
00790 int maj = (ver >> 16) & 0xff;
00791 int min = (ver >> 8) & 0xff;
00792 int bug = ver & 0xff;
00793 QString verstr;
00794 verstr.sprintf("%d.%d.%d", maj, min, bug);
00795
00796 QString str;
00797 str += tr("CMS Signer version %1 by Justin Karneges").arg(VERSION) + '\n';
00798 str += tr("A simple tool for creating and verifying digital signatures.") + '\n';
00799 str += '\n';
00800 str += tr("Using QCA version %1").arg(verstr) + '\n';
00801 str += '\n';
00802 str += tr("Icons by Jason Kim") + '\n';
00803
00804 QCA::ProviderList list = QCA::providers();
00805 foreach(QCA::Provider *p, list)
00806 {
00807 QString credit = p->credit();
00808 if(!credit.isEmpty())
00809 {
00810 str += '\n';
00811 str += credit;
00812 }
00813 }
00814
00815 QMessageBox::about(this, tr("About CMS Signer"), str);
00816 }
00817
00818 void sign_loadError()
00819 {
00820 delete op;
00821 op = 0;
00822
00823 setEnabled(true);
00824 }
00825
00826 void sign_finished(const QString &sig)
00827 {
00828 delete op;
00829 op = 0;
00830
00831 ui.te_sig->setPlainText(sig);
00832
00833 setEnabled(true);
00834 }
00835
00836 void sign_error(const QString &msg)
00837 {
00838 delete op;
00839 op = 0;
00840
00841 setEnabled(true);
00842
00843 QMessageBox::information(this, tr("Error"), msg);
00844 }
00845
00846 void verify_finished()
00847 {
00848 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
00849 delete op;
00850 op = 0;
00851
00852
00853 QCA::SecureMessageKey skey = signer.key();
00854 if(!skey.isNull())
00855 {
00856 QCA::CertificateChain chain = skey.x509CertificateChain();
00857
00858 int at = -1;
00859 QList<CertItem> items = users->items();
00860 for(int n = 0; n < items.count(); ++n)
00861 {
00862 const CertItem &i = items[n];
00863 if(i.certificateChain().primary() == chain.primary())
00864 {
00865 at = n;
00866 break;
00867 }
00868 }
00869
00870
00871 if(at == -1)
00872 {
00873 auto_import_req_id = users->addUser(chain);
00874 return;
00875 }
00876
00877 else
00878 {
00879 users->updateChain(users->idFromRow(at), chain);
00880 }
00881 }
00882
00883 verify_next();
00884 }
00885
00886 void verify_next()
00887 {
00888 setEnabled(true);
00889
00890 QMessageBox::information(this, tr("Verify"), tr("Signature verified successfully."));
00891 }
00892
00893 void verify_error(const QString &msg)
00894 {
00895 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
00896 delete op;
00897 op = 0;
00898
00899 QCA::SecureMessageKey skey = signer.key();
00900 if(signer.keyValidity() == QCA::ErrorSelfSigned && !skey.isNull())
00901 {
00902 QCA::CertificateChain chain = skey.x509CertificateChain();
00903 if(chain.count() == 1 && chain.primary().isSelfSigned())
00904 {
00905 QCA::Certificate cert = chain.primary();
00906
00907 int ret = QMessageBox::warning(this, tr("Self-signed certificate"), tr(
00908 "<qt>The signature is made by an unknown user, and the certificate is self-signed.<br>\n"
00909 "<br>\n"
00910 "<nobr>Common Name: %1</nobr><br>\n"
00911 "<nobr>SHA1 Fingerprint: %2</nobr><br>\n"
00912 "<br>\n"
00913 "Trust the certificate?</qt>"
00914 ).arg(cert.commonName(), get_fingerprint(cert)),
00915 QMessageBox::Yes | QMessageBox::No,
00916 QMessageBox::No);
00917
00918 if(ret == QMessageBox::Yes)
00919 {
00920 self_signed_verify_cert = cert;
00921 do_verify();
00922 return;
00923 }
00924 }
00925 }
00926
00927 setEnabled(true);
00928
00929 QMessageBox::information(this, tr("Error"), msg);
00930 }
00931 };
00932
00933 int main(int argc, char **argv)
00934 {
00935 QCA::Initializer qcaInit;
00936 QApplication qapp(argc, argv);
00937
00938 qapp.setApplicationName(MainWin::tr("CMS Signer"));
00939
00940 if(!QCA::isSupported("cert,crl,cms"))
00941 {
00942 QMessageBox::critical(0, qapp.applicationName() + ": " + MainWin::tr("Error"),
00943 MainWin::tr("No support for CMS is available. Please install an appropriate QCA plugin, such as qca-ossl."));
00944 return 1;
00945 }
00946
00947 QCA::KeyStoreManager::start();
00948
00949 MainWin mainWin;
00950 mainWin.show();
00951 return qapp.exec();
00952 }
00953
00954 #include "main.moc"
Generated on Thu Sep 6 19:13:35 2007 for Qt Cryptographic Architecture by
1.5.2