cmssigner/main.cpp

The code below shows how to use Cryptographic Message Syntax (CMS) in a GUI application.
00001 /*
00002  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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; // private key storage type
00060         bool isUsable() const; // file/provider present
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         // returns a reqId
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         // reimplemented
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         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  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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 // MyPrompter
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 // CertItem
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 // KeyStoreEntry
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 // CertItemStore
00270 //----------------------------------------------------------------------------
00271 class CertItemStorePrivate : public QObject
00272 {
00273         Q_OBJECT
00274 public:
00275         CertItemStore *q;
00276         MyPrompter *prompter;
00277         QList<CertItem> list;
00278         QList<int> idList;
00279         CertItemIconset iconset;
00280         int next_id;
00281         int next_req_id;
00282 
00283         class LoaderItem
00284         {
00285         public:
00286                 int req_id;
00287                 QCA::KeyLoader *keyLoader;
00288                 QString fileName;
00289         };
00290 
00291         QList<LoaderItem> loaders;
00292 
00293         CertItemStorePrivate(CertItemStore *_q) :
00294                 QObject(_q),
00295                 q(_q),
00296                 next_id(0),
00297                 next_req_id(0)
00298         {
00299                 prompter = new MyPrompter(this);
00300         }
00301 
00302         ~CertItemStorePrivate()
00303         {
00304                 foreach(const LoaderItem &i, loaders)
00305                         delete i.keyLoader;
00306         }
00307 
00308         QString getUniqueName(const QString &name)
00309         {
00310                 int num = 1;
00311                 while(1)
00312                 {
00313                         QString tryname;
00314                         if(num == 1)
00315                                 tryname = name;
00316                         else
00317                                 tryname = name + QString(" (%1)").arg(num);
00318 
00319                         bool found = false;
00320                         foreach(const CertItem &i, list)
00321                         {
00322                                 if(i.name() == tryname)
00323                                 {
00324                                         found = true;
00325                                         break;
00326                                 }
00327                         }
00328                         if(!found)
00329                                 return tryname;
00330 
00331                         ++num;
00332                 }
00333         }
00334 
00335         static QString convertErrorToString(QCA::ConvertResult r)
00336         {
00337                 QString str;
00338                 switch(r)
00339                 {
00340                         case QCA::ConvertGood:      break;
00341                         case QCA::ErrorPassphrase:  str = tr("Incorrect passphrase.");
00342                         case QCA::ErrorFile:        str = tr("Unable to open or read file.");
00343                         case QCA::ErrorDecode:
00344                         default:                    str = tr("Unable to decode format.");
00345                 }
00346                 return str;
00347         }
00348 
00349 public slots:
00350         void loader_finished()
00351         {
00352                 QCA::KeyLoader *keyLoader = (QCA::KeyLoader *)sender();
00353                 int at = -1;
00354                 for(int n = 0; n < loaders.count(); ++n)
00355                 {
00356                         if(loaders[n].keyLoader == keyLoader)
00357                         {
00358                                 at = n;
00359                                 break;
00360                         }
00361                 }
00362                 Q_ASSERT(at != -1);
00363 
00364                 int req_id = loaders[at].req_id;
00365                 QString fileName = loaders[at].fileName;
00366                 loaders.removeAt(at);
00367 
00368                 QCA::ConvertResult r = keyLoader->convertResult();
00369                 if(r != QCA::ConvertGood)
00370                 {
00371                         delete keyLoader;
00372                         prompter->fileFailed(fileName);
00373                         QMessageBox::information(0, tr("Error"),
00374                                 tr("Error importing certificate and private key.\nReason: %1").arg(convertErrorToString(r)));
00375                         emit q->addFailed(req_id);
00376                         return;
00377                 }
00378 
00379                 prompter->fileSuccess(fileName);
00380 
00381                 QCA::KeyBundle kb = keyLoader->keyBundle();
00382                 delete keyLoader;
00383 
00384                 QCA::CertificateChain chain = kb.certificateChain();
00385                 QCA::Certificate cert = chain.primary();
00386 
00387                 QString name = getUniqueName(cert.commonName());
00388 
00389                 CertItem i;
00390                 i.d = new CertItem::Private;
00391                 i.d->name = name;
00392                 i.d->chain = chain;
00393                 i.d->havePrivate = true;
00394                 i.d->storageType = CertItem::File;
00395                 i.d->usable = true;
00396                 i.d->fileName = fileName;
00397 
00398                 int id = next_id++;
00399 
00400                 q->beginInsertRows(QModelIndex(), list.size(), list.size());
00401                 list += i;
00402                 idList += id;
00403                 q->endInsertRows();
00404 
00405                 emit q->addSuccess(req_id, id);
00406         }
00407 };
00408 
00409 CertItemStore::CertItemStore(QObject *parent) :
00410         QAbstractListModel(parent)
00411 {
00412         d = new CertItemStorePrivate(this);
00413 }
00414 
00415 CertItemStore::~CertItemStore()
00416 {
00417         delete d;
00418 }
00419 
00420 int CertItemStore::idFromRow(int row) const
00421 {
00422         return d->idList[row];
00423 }
00424 
00425 int CertItemStore::rowFromId(int id) const
00426 {
00427         for(int n = 0; n < d->idList.count(); ++n)
00428         {
00429                 if(d->idList[n] == id)
00430                         return n;
00431         }
00432         return -1;
00433 }
00434 
00435 CertItem CertItemStore::itemFromId(int id) const
00436 {
00437         return d->list[rowFromId(id)];
00438 }
00439 
00440 CertItem CertItemStore::itemFromRow(int row) const
00441 {
00442         return d->list[row];
00443 }
00444 
00445 QList<CertItem> CertItemStore::items() const
00446 {
00447         return d->list;
00448 }
00449 
00450 QStringList CertItemStore::save() const
00451 {
00452         QStringList out;
00453         foreach(const CertItem &i, d->list)
00454                 out += i.d->toString();
00455         return out;
00456 }
00457 
00458 bool CertItemStore::load(const QStringList &in)
00459 {
00460         QList<CertItem> addList;
00461         QList<int> addIdList;
00462         foreach(const QString &s, in)
00463         {
00464                 CertItem i;
00465                 i.d = new CertItem::Private;
00466                 if(i.d->fromString(s))
00467                 {
00468                         addList += i;
00469                         addIdList += d->next_id++;
00470                 }
00471         }
00472 
00473         if(addList.isEmpty())
00474                 return true;
00475 
00476         beginInsertRows(QModelIndex(), d->list.size(), d->list.size() + addList.count() - 1);
00477         d->list += addList;
00478         d->idList += addIdList;
00479         endInsertRows();
00480 
00481         return true;
00482 }
00483 
00484 int CertItemStore::addFromFile(const QString &fileName)
00485 {
00486         CertItemStorePrivate::LoaderItem i;
00487         i.req_id = d->next_req_id++;
00488         i.keyLoader = new QCA::KeyLoader(d);
00489         i.fileName = fileName;
00490         connect(i.keyLoader, SIGNAL(finished()), d, SLOT(loader_finished()));
00491         d->loaders += i;
00492         i.keyLoader->loadKeyBundleFromFile(fileName);
00493         return i.req_id;
00494 }
00495 
00496 int CertItemStore::addFromKeyStore(const QCA::KeyStoreEntry &entry)
00497 {
00498         QCA::KeyBundle kb = entry.keyBundle();
00499 
00500         QCA::CertificateChain chain = kb.certificateChain();
00501         QCA::Certificate cert = chain.primary();
00502 
00503         QString name = d->getUniqueName(entry.name());
00504 
00505         CertItem i;
00506         i.d = new CertItem::Private;
00507         i.d->name = name;
00508         i.d->chain = chain;
00509         i.d->havePrivate = true;
00510         i.d->storageType = CertItem::KeyStore;
00511         i.d->usable = true;
00512         i.d->keyStoreEntry = entry;
00513 
00514         int id = d->next_id++;
00515 
00516         beginInsertRows(QModelIndex(), d->list.size(), d->list.size());
00517         d->list += i;
00518         d->idList += id;
00519         endInsertRows();
00520 
00521         int req_id = d->next_req_id++;
00522         QMetaObject::invokeMethod(this, "addSuccess", Qt::QueuedConnection, Q_ARG(int, req_id), Q_ARG(int, id));
00523         return req_id;
00524 }
00525 
00526 int CertItemStore::addUser(const QCA::CertificateChain &chain)
00527 {
00528         QCA::Certificate cert = chain.primary();
00529 
00530         QString name = d->getUniqueName(cert.commonName());
00531 
00532         CertItem i;
00533         i.d = new CertItem::Private;
00534         i.d->name = name;
00535         i.d->chain = chain;
00536 
00537         int id = d->next_id++;
00538 
00539         beginInsertRows(QModelIndex(), d->list.size(), d->list.size());
00540         d->list += i;
00541         d->idList += id;
00542         endInsertRows();
00543 
00544         int req_id = d->next_req_id++;
00545         QMetaObject::invokeMethod(this, "addSuccess", Qt::QueuedConnection, Q_ARG(int, req_id), Q_ARG(int, id));
00546         return req_id;
00547 }
00548 
00549 void CertItemStore::updateChain(int id, const QCA::CertificateChain &chain)
00550 {
00551 }
00552 
00553 void CertItemStore::removeItem(int id)
00554 {
00555         int at = rowFromId(id);
00556 
00557         beginRemoveRows(QModelIndex(), at, at);
00558         d->list.removeAt(at);
00559         d->idList.removeAt(at);
00560         endRemoveRows();
00561 }
00562 
00563 void CertItemStore::setIcon(IconType type, const QPixmap &icon)
00564 {
00565         d->iconset[type] = icon;
00566 }
00567 
00568 int CertItemStore::rowCount(const QModelIndex &parent) const
00569 {
00570         Q_UNUSED(parent);
00571         return d->list.count();
00572 }
00573 
00574 QVariant CertItemStore::data(const QModelIndex &index, int role) const
00575 {
00576         if(!index.isValid())
00577                 return QVariant();
00578 
00579         int at = index.row();
00580         QList<CertItem> &list = d->list;
00581 
00582         if(at >= list.count())
00583                 return QVariant();
00584 
00585         if(role == Qt::DisplayRole)
00586         {
00587                 QString str = list[at].name();
00588                 if(list[at].havePrivate() && !list[at].isUsable())
00589                         str += QString(" ") + tr("(not usable)");
00590                 return str;
00591         }
00592         else if(role == Qt::EditRole)
00593                 return list[at].name();
00594         else if(role == Qt::DecorationRole)
00595         {
00596                 if(list[at].havePrivate())
00597                         return d->iconset[CertItemStore::IconKeyBundle];
00598                 else
00599                         return d->iconset[CertItemStore::IconCert];
00600         }
00601         else
00602                 return QVariant();
00603 }
00604 
00605 Qt::ItemFlags CertItemStore::flags(const QModelIndex &index) const
00606 {
00607         if(!index.isValid())
00608                 return Qt::ItemIsEnabled;
00609 
00610         return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
00611 }
00612 
00613 bool CertItemStore::setData(const QModelIndex &index, const QVariant &value, int role)
00614 {
00615         if(index.isValid() && role == Qt::EditRole)
00616         {
00617                 QString str = value.toString();
00618                 d->list[index.row()].d->name = str;
00619                 emit dataChanged(index, index);
00620                 return true;
00621         }
00622         return false;
00623 }
00624 
00625 //----------------------------------------------------------------------------
00626 // CertItemPrivateLoader
00627 //----------------------------------------------------------------------------
00628 class CertItemPrivateLoaderPrivate : public QObject
00629 {
00630         Q_OBJECT
00631 public:
00632         CertItemPrivateLoader *q;
00633         CertItemStore *store;
00634         QCA::KeyLoader *loader;
00635         QString fileName;
00636         QCA::PrivateKey key;
00637 
00638         CertItemPrivateLoaderPrivate(CertItemPrivateLoader *_q) :
00639                 QObject(_q),
00640                 q(_q)
00641         {
00642         }
00643 
00644 public slots:
00645         void loader_finished()
00646         {
00647                 QCA::ConvertResult r = loader->convertResult();
00648                 if(r != QCA::ConvertGood)
00649                 {
00650                         delete loader;
00651                         loader = 0;
00652                         store->d->prompter->fileFailed(fileName);
00653                         QMessageBox::information(0, tr("Error"),
00654                                 tr("Error accessing private key.\nReason: %1").arg(CertItemStorePrivate::convertErrorToString(r)));
00655                         emit q->finished();
00656                         return;
00657                 }
00658 
00659                 store->d->prompter->fileSuccess(fileName);
00660 
00661                 key = loader->keyBundle().privateKey();
00662                 delete loader;
00663                 loader = 0;
00664                 emit q->finished();
00665         }
00666 };
00667 
00668 CertItemPrivateLoader::CertItemPrivateLoader(CertItemStore *store, QObject *parent) :
00669         QObject(parent)
00670 {
00671         d = new CertItemPrivateLoaderPrivate(this);
00672         d->store = store;
00673 }
00674 
00675 CertItemPrivateLoader::~CertItemPrivateLoader()
00676 {
00677         delete d;
00678 }
00679 
00680 void CertItemPrivateLoader::start(int id)
00681 {
00682         CertItem i = d->store->itemFromId(id);
00683 
00684         if(i.storageType() == CertItem::KeyStore)
00685         {
00686                 d->key = i.d->keyStoreEntry.keyBundle().privateKey();
00687                 QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
00688                 return;
00689         }
00690 
00691         d->key = QCA::PrivateKey();
00692         d->fileName = i.d->fileName;
00693         d->loader = new QCA::KeyLoader(d);
00694         connect(d->loader, SIGNAL(finished()), d, SLOT(loader_finished()));
00695         d->loader->loadKeyBundleFromFile(d->fileName);
00696 }
00697 
00698 QCA::PrivateKey CertItemPrivateLoader::privateKey() const
00699 {
00700         return d->key;
00701 }
00702 
00703 #include "certitem.moc"
00001 /*
00002  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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         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  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00020 */
00021 
00022 #include "certviewdlg.h"
00023 
00024 #include <QtCore>
00025 #include <QtGui>
00026 #include <QtCrypto>
00027 #include "ui_certview.h"
00028 
00029 // from qcatool
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  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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                 // make sure keystores are started
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                 // only list stores containing keybundles (non-pgp identities)
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                 // ignore entries that are not keybundles
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; // adjust position
00217                         }
00218                 }
00219 #endif
00220 
00221                 // update the store item itself
00222                 store_item->setStore(ks->name(), ks->type());
00223 
00224                 // handle removed child entries
00225                 for(int n = 0; n < store_item->rowCount(); ++n)
00226                 {
00227                         KeyStoreItem *i = (KeyStoreItem *)store_item->child(n);
00228 
00229                         // is the existing entry in the new list?
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                         // if not, remove it
00241                         if(!found)
00242                         {
00243                                 store_item->removeRow(n);
00244                                 --n; // adjust position
00245                         }
00246                 }
00247 
00248                 // handle added/updated child entries
00249                 for(int n = 0; n < newEntries.count(); ++n)
00250                 {
00251                         const QCA::KeyStoreEntry &ne = newEntries[n];
00252 
00253                         // was this entry in the original list?
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                         // if not, add it
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                         // if so, update it
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  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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         // called with every password event, to check for a known value.
00042         //   reimplement it to provide known/cached passwords.
00043         virtual QCA::SecureArray knownPassword(const QCA::Event &event);
00044 
00045         // called when a user-entered password is submitted.  note that this
00046         //   does not mean the password was correct.  to know if the password
00047         //   was correct, you'll have to match up the event information with
00048         //   the operation that triggered it.
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  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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                         // even though we're being prompted for a missing token,
00150                         //   we should still check if the token is present, due to
00151                         //   a possible race between insert and token request.
00152                         bool found = false;
00153 
00154                         // token-only
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                         // token-entry
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                                 // auto-accept
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                 // are we currently in a token-only prompt?
00242                 if(token_prompt && pending.first().event.type() == QCA::Event::Token && pending.first().event.keyStoreEntry().isNull())
00243                 {
00244                         // was the token we're looking for just inserted?
00245                         if(pending.first().event.keyStoreInfo().id() == keyStoreId)
00246                         {
00247                                 // auto-accept
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                 // are we currently in a token-entry prompt?
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                         // was the token of the entry we're looking for updated?
00271                         if(pending.first().event.keyStoreInfo().id() == ks->id())
00272                         {
00273                                 // is the entry available?
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                                         // auto-accept
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  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00020 */
00021 
00022 #include <QtCore>
00023 #include <QtGui>
00024 #include <QtCrypto>
00025 
00026 #include "ui_mainwin.h"
00027 #include "prompter.h"
00028 #include "certviewdlg.h"
00029 #include "keyselectdlg.h"
00030 #include "pkcs11configdlg/pkcs11configdlg.h"
00031 #include "certitem.h"
00032 
00033 #define VERSION "1.0.0"
00034 
00035 class Icons
00036 {
00037 public:
00038         QPixmap cert, crl, keybundle, pgppub, pgpsec;
00039 };
00040 
00041 Icons *g_icons = 0;
00042 
00043 //----------------------------------------------------------------------------
00044 // Operation
00045 //----------------------------------------------------------------------------
00046 class Operation : public QObject
00047 {
00048         Q_OBJECT
00049 public:
00050         Operation(QObject *parent = 0) :
00051                 QObject(parent)
00052         {
00053         }
00054 
00055 signals:
00056         void error(const QString &str);
00057 };
00058 
00059 static QString validityToString(QCA::Validity v)
00060 {
00061         QString s;
00062         switch(v)
00063         {
00064                 case QCA::ValidityGood:
00065                         s = Operation::tr("Validated");
00066                         break;
00067                 case QCA::ErrorRejected:
00068                         s = Operation::tr("Root CA is marked to reject the specified purpose");
00069                         break;
00070                 case QCA::ErrorUntrusted:
00071                         s = Operation::tr("Certificate not trusted for the required purpose");
00072                         break;
00073                 case QCA::ErrorSignatureFailed:
00074                         s = Operation::tr("Invalid signature");
00075                         break;
00076                 case QCA::ErrorInvalidCA:
00077                         s = Operation::tr("Invalid CA certificate");
00078                         break;
00079                 case QCA::ErrorInvalidPurpose:
00080                         s = Operation::tr("Invalid certificate purpose");
00081                         break;
00082                 case QCA::ErrorSelfSigned:
00083                         s = Operation::tr("Certificate is self-signed");
00084                         break;
00085                 case QCA::ErrorRevoked:
00086                         s = Operation::tr("Certificate has been revoked");
00087                         break;
00088                 case QCA::ErrorPathLengthExceeded:
00089                         s = Operation::tr("Maximum certificate chain length exceeded");
00090                         break;
00091                 case QCA::ErrorExpired:
00092                         s = Operation::tr("Certificate has expired");
00093                         break;
00094                 case QCA::ErrorExpiredCA:
00095                         s = Operation::tr("CA has expired");
00096                         break;
00097                 case QCA::ErrorValidityUnknown:
00098                 default:
00099                         s = Operation::tr("General certificate validation error");
00100                         break;
00101         }
00102         return s;
00103 }
00104 
00105 static QString smErrorToString(QCA::SecureMessage::Error e)
00106 {
00107         QString s;
00108         switch(e)
00109         {
00110                 case QCA::SecureMessage::ErrorPassphrase:
00111                         s = Operation::tr("Invalid passphrase.");
00112                         break;
00113                 case QCA::SecureMessage::ErrorFormat:
00114                         s = Operation::tr("Bad input format.");
00115                         break;
00116                 case QCA::SecureMessage::ErrorSignerExpired:
00117                         s = Operation::tr("Signer key is expired.");
00118                         break;
00119                 case QCA::SecureMessage::ErrorSignerInvalid:
00120                         s = Operation::tr("Signer key is invalid.");
00121                         break;
00122                 case QCA::SecureMessage::ErrorEncryptExpired:
00123                         s = Operation::tr("Encrypting key is expired.");
00124                         break;
00125                 case QCA::SecureMessage::ErrorEncryptUntrusted:
00126                         s = Operation::tr("Encrypting key is untrusted.");
00127                         break;
00128                 case QCA::SecureMessage::ErrorEncryptInvalid:
00129                         s = Operation::tr("Encrypting key is invalid.");
00130                         break;
00131                 case QCA::SecureMessage::ErrorNeedCard:
00132                         s = Operation::tr("Card was needed but not found.");
00133                         break;
00134                 case QCA::SecureMessage::ErrorCertKeyMismatch:
00135                         s = Operation::tr("Certificate and private key don't match.");
00136                         break;
00137                 case QCA::SecureMessage::ErrorUnknown:
00138                 default:
00139                         s = Operation::tr("General error.");
00140                         break;
00141         }
00142         return s;
00143 }
00144 
00145 static QString smsIdentityToString(const QCA::SecureMessageSignature &sig)
00146 {
00147         QString s;
00148         switch(sig.identityResult())
00149         {
00150                 case QCA::SecureMessageSignature::Valid:
00151                         break;
00152                 case QCA::SecureMessageSignature::InvalidSignature:
00153                         s = Operation::tr("Invalid signature");
00154                         break;
00155                 case QCA::SecureMessageSignature::InvalidKey:
00156                         s = Operation::tr("Invalid key: %1").arg(validityToString(sig.keyValidity()));
00157                         break;
00158                 case QCA::SecureMessageSignature::NoKey:
00159                         s = Operation::tr("Key not found");
00160                         break;
00161                 default: // this should not really be possible
00162                         s = Operation::tr("Unknown");
00163                         break;
00164         }
00165         return s;
00166 }
00167 
00168 class SignOperation : public Operation
00169 {
00170         Q_OBJECT
00171 private:
00172         QByteArray in;
00173         CertItemStore *store;
00174         int id;
00175         QCA::CMS *cms;
00176         CertItemPrivateLoader *loader;
00177         QCA::SecureMessage *msg;
00178         int pending;
00179 
00180 public:
00181         SignOperation(const QByteArray &_in, CertItemStore *_store, int _id, QCA::CMS *_cms, QObject *parent = 0) :
00182                 Operation(parent),
00183                 in(_in),
00184                 store(_store),
00185                 id(_id),
00186                 cms(_cms),
00187                 msg(0)
00188         {
00189                 loader = new CertItemPrivateLoader(store, this);
00190                 connect(loader, SIGNAL(finished()), SLOT(loader_finished()));
00191                 loader->start(id);
00192         }
00193 
00194 signals:
00195         void loadError();
00196         void finished(const QString &sig);
00197 
00198 private slots:
00199         void loader_finished()
00200         {
00201                 QCA::PrivateKey privateKey = loader->privateKey();
00202                 delete loader;
00203                 loader = 0;
00204 
00205                 if(privateKey.isNull())
00206                 {
00207                         emit loadError();
00208                         return;
00209                 }
00210 
00211                 CertItem item = store->itemFromId(id);
00212 
00213                 QCA::SecureMessageKey signer;
00214                 signer.setX509CertificateChain(item.certificateChain());
00215                 signer.setX509PrivateKey(privateKey);
00216 
00217                 msg = new QCA::SecureMessage(cms);
00218                 connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int)));
00219                 connect(msg, SIGNAL(finished()), SLOT(msg_finished()));
00220                 msg->setFormat(QCA::SecureMessage::Ascii);
00221                 msg->setSigner(signer);
00222                 msg->startSign(QCA::SecureMessage::Detached);
00223 
00224                 pending = 0;
00225                 update();
00226         }
00227 
00228         void update()
00229         {
00230                 QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks
00231                 in = in.mid(buf.size());
00232                 pending += buf.size();
00233                 msg->update(buf);
00234         }
00235 
00236         void msg_bytesWritten(int x)
00237         {
00238                 pending -= x;
00239 
00240                 if(in.isEmpty() && pending == 0)
00241                         msg->end();
00242                 else
00243                         update();
00244         }
00245 
00246         void msg_finished()
00247         {
00248                 if(!msg->success())
00249                 {
00250                         QString str = smErrorToString(msg->errorCode());
00251                         delete msg;
00252                         msg = 0;
00253                         emit error(tr("Error during sign operation.\nReason: %1").arg(str));
00254                         return;
00255                 }
00256 
00257                 QByteArray result = msg->signature();
00258                 delete msg;
00259                 msg = 0;
00260                 emit finished(QString::fromLatin1(result));
00261         }
00262 };
00263 
00264 class VerifyOperation : public Operation
00265 {
00266         Q_OBJECT
00267 private:
00268         QByteArray in, sig;
00269         QCA::CMS *cms;
00270         QCA::SecureMessage *msg;
00271         int pending;
00272 
00273 public:
00274         QCA::SecureMessageSignature signer;
00275 
00276         VerifyOperation(const QByteArray &_in, const QByteArray &_sig, QCA::CMS *_cms, QObject *parent = 0) :
00277                 Operation(parent),
00278                 in(_in),
00279                 sig(_sig),
00280                 cms(_cms),
00281                 msg(0)
00282         {
00283                 msg = new QCA::SecureMessage(cms);
00284                 connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int)));
00285                 connect(msg, SIGNAL(finished()), SLOT(msg_finished()));
00286                 msg->setFormat(QCA::SecureMessage::Ascii);
00287                 msg->startVerify(sig);
00288 
00289                 pending = 0;
00290                 update();
00291         }
00292 
00293 signals:
00294         void finished();
00295 
00296 private slots:
00297         void update()
00298         {
00299                 QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks
00300                 in = in.mid(buf.size());
00301                 pending += buf.size();
00302                 msg->update(buf);
00303         }
00304 
00305         void msg_bytesWritten(int x)
00306         {
00307                 pending -= x;
00308 
00309                 if(in.isEmpty() && pending == 0)
00310                         msg->end();
00311                 else
00312                         update();
00313         }
00314 
00315         void msg_finished()
00316         {
00317                 if(!msg->success())
00318                 {
00319                         QString str = smErrorToString(msg->errorCode());
00320                         delete msg;
00321                         msg = 0;
00322                         emit error(tr("Error during verify operation.\nReason: %1").arg(str));
00323                         return;
00324                 }
00325 
00326                 signer = msg->signer();
00327                 delete msg;
00328                 msg = 0;
00329 
00330                 if(signer.identityResult() != QCA::SecureMessageSignature::Valid)
00331                 {
00332                         QString str = smsIdentityToString(signer);
00333                         emit error(tr("Verification failed!\nReason: %1").arg(str));
00334                         return;
00335                 }
00336 
00337                 emit finished();
00338         }
00339 };
00340 
00341 //----------------------------------------------------------------------------
00342 // MainWin
00343 //----------------------------------------------------------------------------
00344 static QString get_fingerprint(const QCA::Certificate &cert)
00345 {
00346         QString hex = QCA::Hash("sha1").hashToString(cert.toDER());
00347         QString out;
00348         for(int n = 0; n < hex.count(); ++n)
00349         {
00350                 if(n != 0 && n % 2 == 0)
00351                         out += ':';
00352                 out += hex[n];
00353         }
00354         return out;
00355 }
00356 
00357 class MainWin : public QMainWindow
00358 {
00359         Q_OBJECT
00360 private:
00361         Ui_MainWin ui;
00362         CertItemStore *users, *roots;
00363         QCA::CMS *cms;
00364         Operation *op;
00365         QAction *actionView, *actionRename, *actionRemove;
00366         QCA::Certificate self_signed_verify_cert;
00367         int auto_import_req_id;
00368 
00369 public:
00370         MainWin(QWidget *parent = 0) :
00371                 QMainWindow(parent),
00372                 op(0),
00373                 auto_import_req_id(-1)
00374         {
00375                 ui.setupUi(this);
00376 
00377                 g_icons = new Icons;
00378                 g_icons->cert = QPixmap(":/gfx/icons/cert16.png");
00379                 g_icons->crl = QPixmap(":/gfx/icons/crl16.png");
00380                 g_icons->keybundle = QPixmap(":/gfx/icons/keybundle16.png");
00381                 g_icons->pgppub = QPixmap(":/gfx/icons/publickey16.png");
00382                 g_icons->pgpsec = QPixmap(":/gfx/icons/keypair16.png");
00383                 if(g_icons->cert.isNull() || g_icons->crl.isNull() || g_icons->keybundle.isNull() || g_icons->pgppub.isNull() || g_icons->pgpsec.isNull())
00384                         printf("Warning: not all icons loaded\n");
00385 
00386                 users = new CertItemStore(this);
00387                 roots = new CertItemStore(this);
00388 
00389                 setIcons(users);
00390                 setIcons(roots);
00391 
00392                 connect(users, SIGNAL(addSuccess(int, int)), SLOT(users_addSuccess(int, int)));
00393                 connect(users, SIGNAL(addFailed(int)), SLOT(users_addFailed(int)));
00394 
00395                 actionView = new QAction(tr("&View"), this);
00396                 actionRename = new QAction(tr("Re&name"), this);
00397                 actionRemove = new QAction(tr("Rem&ove"), this);
00398 
00399                 connect(ui.actionLoadIdentityFile, SIGNAL(triggered()), SLOT(load_file()));
00400                 connect(ui.actionLoadIdentityEntry, SIGNAL(triggered()), SLOT(load_device()));
00401                 connect(ui.actionLoadAuthority, SIGNAL(triggered()), SLOT(load_root()));
00402                 connect(ui.actionConfigurePkcs11, SIGNAL(triggered()), SLOT(mod_config()));
00403                 connect(ui.actionQuit, SIGNAL(triggered()), SLOT(close()));
00404                 connect(ui.actionAbout, SIGNAL(triggered()), SLOT(about()));
00405                 connect(ui.pb_sign, SIGNAL(clicked()), SLOT(do_sign()));
00406                 connect(ui.pb_verify, SIGNAL(clicked()), SLOT(do_verify()));
00407 
00408                 connect(actionView, SIGNAL(triggered()), SLOT(item_view()));
00409                 connect(actionRename, SIGNAL(triggered()), SLOT(item_rename()));
00410                 connect(actionRemove, SIGNAL(triggered()), SLOT(item_remove()));
00411 
00412                 ui.pb_sign->setEnabled(false);
00413 
00414                 ui.lv_users->setModel(users);
00415                 connect(ui.lv_users->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(users_selectionChanged(const QItemSelection &, const QItemSelection &)));
00416 
00417                 ui.lv_users->setContextMenuPolicy(Qt::CustomContextMenu);
00418                 connect(ui.lv_users, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(users_customContextMenuRequested(const QPoint &)));
00419 
00420                 ui.lv_authorities->setModel(roots);
00421 
00422                 ui.lv_authorities->setContextMenuPolicy(Qt::CustomContextMenu);
00423                 connect(ui.lv_authorities, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(roots_customContextMenuRequested(const QPoint &)));
00424 
00425                 cms = new QCA::CMS(this);
00426 
00427                 QStringList ulist, rlist;
00428                 {
00429                         QSettings settings("Affinix", "CMS Signer");
00430                         ulist = settings.value("users").toStringList();
00431                         rlist = settings.value("roots").toStringList();
00432                 }
00433 
00434                 users->load(ulist);
00435                 roots->load(rlist);
00436         }
00437 
00438         ~MainWin()
00439         {
00440                 QStringList ulist = users->save();
00441                 QStringList rlist = roots->save();
00442 
00443                 QSettings settings("Affinix", "CMS Signer");
00444                 settings.setValue("users", ulist);
00445                 settings.setValue("roots", rlist);
00446 
00447                 delete g_icons;
00448                 g_icons = 0;
00449         }
00450 
00451         void setIcons(CertItemStore *store)
00452         {
00453                 store->setIcon(CertItemStore::IconCert, g_icons->cert);
00454                 store->setIcon(CertItemStore::IconCrl, g_icons->crl);
00455                 store->setIcon(CertItemStore::IconKeyBundle, g_icons->keybundle);
00456                 store->setIcon(CertItemStore::IconPgpPub, g_icons->pgppub);
00457                 store->setIcon(CertItemStore::IconPgpSec, g_icons->pgpsec);
00458         }
00459 
00460         QCA::CertificateCollection allCerts()
00461         {
00462                 QCA::CertificateCollection col;
00463 
00464                 // system store
00465                 col += QCA::systemStore();
00466 
00467                 // additional roots configured in application
00468                 foreach(const CertItem &i, roots->items())
00469                         col.addCertificate(i.certificateChain().primary());
00470 
00471                 // user chains
00472                 foreach(const CertItem &i, users->items())
00473                 {
00474                         foreach(const QCA::Certificate &cert, i.certificateChain())
00475                                 col.addCertificate(cert);
00476                 }
00477 
00478                 return col;
00479         }
00480 
00481         QCA::CertificateChain complete(const QCA::CertificateChain &chain)
00482         {
00483                 return chain.complete(allCerts().certificates());
00484         }
00485 
00486 private slots:
00487         void load_file()
00488         {
00489                 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Identities (*.p12 *.pfx)"));
00490                 if(fileName.isEmpty())
00491                         return;
00492 
00493                 setEnabled(false);
00494                 users->addFromFile(fileName);
00495         }
00496 
00497         void load_device()
00498         {
00499                 KeySelectDlg *w = new KeySelectDlg(this);
00500                 w->setAttribute(Qt::WA_DeleteOnClose, true);
00501                 w->setWindowModality(Qt::WindowModal);
00502                 connect(w, SIGNAL(selected(const QCA::KeyStoreEntry &)), SLOT(load_device_finished(const QCA::KeyStoreEntry &)));
00503                 connect(w, SIGNAL(viewCertificate(const QCA::CertificateChain &)), SLOT(keyselect_viewCertificate(const QCA::CertificateChain &)));
00504                 w->setIcon(KeySelectDlg::IconCert, g_icons->cert);
00505                 w->setIcon(KeySelectDlg::IconCrl, g_icons->crl);
00506                 w->setIcon(KeySelectDlg::IconKeyBundle, g_icons->keybundle);
00507                 w->setIcon(KeySelectDlg::IconPgpPub, g_icons->pgppub);
00508                 w->setIcon(KeySelectDlg::IconPgpSec, g_icons->pgpsec);
00509                 w->show();
00510         }
00511 
00512         void load_device_finished(const QCA::KeyStoreEntry &entry)
00513         {
00514                 users->addFromKeyStore(entry);
00515         }
00516 
00517         void load_root()
00518         {
00519                 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Certificates (*.pem *.crt)"));
00520                 if(fileName.isEmpty())
00521                         return;
00522 
00523                 QCA::Certificate cert = QCA::Certificate::fromPEMFile(fileName);
00524                 if(cert.isNull())
00525                 {
00526                         QMessageBox::information(this, tr("Error"), tr("Error opening certificate file."));
00527                         return;
00528                 }
00529 
00530                 roots->addUser(cert);
00531         }
00532 
00533         void users_addSuccess(int req_id, int id)
00534         {
00535                 if(req_id == auto_import_req_id)
00536                 {
00537                         auto_import_req_id = -1;
00538 
00539                         CertItem i = users->itemFromId(id);
00540 
00541                         QMessageBox::information(this, tr("User added"), tr(
00542                                 "This signature was made by a previously unknown user, and so the "
00543                                 "user has now been added to the keyring as \"%1\"."
00544                                 ).arg(i.name()));
00545 
00546                         verify_next();
00547                         return;
00548                 }
00549 
00550                 ui.lv_users->selectionModel()->select(users->index(users->rowFromId(id)), QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
00551 
00552                 setEnabled(true);
00553         }
00554 
00555         void users_addFailed(int req_id)
00556         {
00557                 Q_UNUSED(req_id);
00558 
00559                 setEnabled(true);
00560         }
00561 
00562         void mod_config()
00563         {
00564                 if(!Pkcs11ConfigDlg::isSupported())
00565                 {
00566                         QMessageBox::information(this, tr("Error"), tr("No provider available supporting standard PKCS#11 configuration."));
00567                         return;
00568                 }
00569 
00570                 Pkcs11ConfigDlg *w = new Pkcs11ConfigDlg(this);
00571                 w->setAttribute(Qt::WA_DeleteOnClose, true);
00572                 w->setWindowModality(Qt::WindowModal);
00573                 w->show();
00574         }
00575 
00576         void users_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
00577         {
00578                 Q_UNUSED(deselected);
00579 
00580                 int at = -1;
00581                 if(!selected.indexes().isEmpty())
00582                 {
00583                         QModelIndex index = selected.indexes().first();
00584                         at = index.row();
00585                 }
00586 
00587                 bool usable = false;
00588                 if(at != -1 && users->itemFromRow(at).isUsable())
00589                         usable = true;
00590 
00591                 if(usable && !ui.pb_sign->isEnabled())
00592                         ui.pb_sign->setEnabled(true);
00593                 else if(!usable && ui.pb_sign->isEnabled())
00594                         ui.pb_sign->setEnabled(false);
00595         }
00596 
00597         void item_view()
00598         {
00599                 if(ui.lv_users->hasFocus())
00600                 {
00601                         QItemSelection selection = ui.lv_users->selectionModel()->selection();
00602                         if(selection.indexes().isEmpty())
00603                                 return;
00604                         QModelIndex index = selection.indexes().first();
00605                         users_view(index.row());
00606                 }
00607                 else // lv_authorities
00608                 {
00609                         QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00610                         if(selection.indexes().isEmpty())
00611                                 return;
00612                         QModelIndex index = selection.indexes().first();
00613                         roots_view(index.row());
00614                 }
00615         }
00616 
00617         void item_rename()
00618         {
00619                 if(ui.lv_users->hasFocus())
00620                 {
00621                         QItemSelection selection = ui.lv_users->selectionModel()->selection();
00622                         if(selection.indexes().isEmpty())
00623                                 return;
00624                         QModelIndex index = selection.indexes().first();
00625                         users_rename(index.row());
00626                 }
00627                 else // lv_authorities
00628                 {
00629                         QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00630                         if(selection.indexes().isEmpty())
00631                                 return;
00632                         QModelIndex index = selection.indexes().first();
00633                         roots_rename(index.row());
00634                 }
00635         }
00636 
00637         void item_remove()
00638         {
00639                 if(ui.lv_users->hasFocus())
00640                 {
00641                         QItemSelection selection = ui.lv_users->selectionModel()->selection();
00642                         if(selection.indexes().isEmpty())
00643                                 return;
00644                         QModelIndex index = selection.indexes().first();
00645                         users_remove(index.row());
00646                 }
00647                 else // lv_authorities
00648                 {
00649                         QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00650                         if(selection.indexes().isEmpty())
00651                                 return;
00652                         QModelIndex index = selection.indexes().first();
00653                         roots_remove(index.row());
00654                 }
00655         }
00656 
00657         void users_view(int at)
00658         {
00659                 CertItem i = users->itemFromRow(at);
00660                 CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this);
00661                 w->setAttribute(Qt::WA_DeleteOnClose, true);
00662                 w->show();
00663         }
00664 
00665         void users_rename(int at)
00666         {
00667                 QModelIndex index = users->index(at);
00668                 ui.lv_users->setFocus();
00669                 ui.lv_users->setCurrentIndex(index);
00670                 ui.lv_users->selectionModel()->select(index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
00671                 ui.lv_users->edit(index);
00672         }
00673 
00674         void users_remove(int at)
00675         {
00676                 users->removeItem(users->idFromRow(at));
00677         }
00678 
00679         void roots_view(int at)
00680         {
00681                 CertItem i = roots->itemFromRow(at);
00682                 CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this);
00683                 w->setAttribute(Qt::WA_DeleteOnClose, true);
00684                 w->show();
00685         }
00686 
00687         void roots_rename(int at)
00688         {
00689                 QModelIndex index = roots->index(at);
00690                 ui.lv_authorities->setFocus();
00691                 ui.lv_authorities->setCurrentIndex(index);
00692                 ui.lv_authorities->selectionModel()->select(index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
00693                 ui.lv_authorities->edit(index);
00694         }
00695 
00696         void roots_remove(int at)
00697         {
00698                 roots->removeItem(roots->idFromRow(at));
00699         }
00700 
00701         void keyselect_viewCertificate(const QCA::CertificateChain &chain)
00702         {
00703                 CertViewDlg *w = new CertViewDlg(complete(chain), (QWidget *)sender());
00704                 w->setAttribute(Qt::WA_DeleteOnClose, true);
00705                 w->show();
00706         }
00707 
00708         void users_customContextMenuRequested(const QPoint &pos)
00709         {
00710                 QItemSelection selection = ui.lv_users->selectionModel()->selection();
00711                 if(selection.indexes().isEmpty())
00712                         return;
00713 
00714                 QMenu menu(this);
00715                 menu.addAction(actionView);
00716                 menu.addAction(actionRename);
00717                 menu.addAction(actionRemove);
00718                 menu.exec(ui.lv_users->viewport()->mapToGlobal(pos));
00719         }
00720 
00721         void roots_customContextMenuRequested(const QPoint &pos)
00722         {
00723                 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
00724                 if(selection.indexes().isEmpty())
00725                         return;
00726 
00727                 QMenu menu(this);
00728                 menu.addAction(actionView);
00729                 menu.addAction(actionRename);
00730                 menu.addAction(actionRemove);
00731                 menu.exec(ui.lv_authorities->viewport()->mapToGlobal(pos));
00732         }
00733 
00734         void do_sign()
00735         {
00736                 QItemSelection selection = ui.lv_users->selectionModel()->selection();
00737                 if(selection.indexes().isEmpty())
00738                         return;
00739                 QModelIndex index = selection.indexes().first();
00740                 int at = index.row();
00741 
00742                 setEnabled(false);
00743 
00744                 op = new SignOperation(ui.te_data->toPlainText().toUtf8(), users, users->idFromRow(at), cms, this);
00745                 connect(op, SIGNAL(loadError()), SLOT(sign_loadError()));
00746                 connect(op, SIGNAL(finished(const QString &)), SLOT(sign_finished(const QString &)));
00747                 connect(op, SIGNAL(error(const QString &)), SLOT(sign_error(const QString &)));
00748         }
00749 
00750         void do_verify()
00751         {
00752                 // prepare root certs
00753                 QCA::CertificateCollection col;
00754 
00755                 // system store
00756                 col += QCA::systemStore();
00757 
00758                 // additional roots configured in application
00759                 foreach(const CertItem &i, roots->items())
00760                         col.addCertificate(i.certificateChain().primary());
00761 
00762                 // consider self-signed users as roots
00763                 // (it is therefore not possible with this application to
00764                 // have people in your keyring that you don't trust)
00765                 foreach(const CertItem &i, users->items())
00766                 {
00767                         QCA::Certificate cert = i.certificateChain().primary();
00768                         if(cert.isSelfSigned())
00769                                 col.addCertificate(cert);
00770                 }
00771 
00772                 // the self signed verify cert, if applicable
00773                 if(!self_signed_verify_cert.isNull())
00774                 {
00775                         col.addCertificate(self_signed_verify_cert);
00776                         self_signed_verify_cert = QCA::Certificate();
00777                 }
00778 
00779                 cms->setTrustedCertificates(col);
00780 
00781                 setEnabled(false);
00782 
00783                 op = new VerifyOperation(ui.te_data->toPlainText().toUtf8(), ui.te_sig->toPlainText().toUtf8(), cms, this);
00784                 connect(op, SIGNAL(finished()), SLOT(verify_finished()));
00785                 connect(op, SIGNAL(error(const QString &)), SLOT(verify_error(const QString &)));
00786         }
00787 
00788         void about()
00789         {
00790                 int ver = qcaVersion();
00791                 int maj = (ver >> 16) & 0xff;
00792                 int min = (ver >> 8) & 0xff;
00793                 int bug = ver & 0xff;
00794                 QString verstr;
00795                 verstr.sprintf("%d.%d.%d", maj, min, bug);
00796 
00797                 QString str;
00798                 str += tr("CMS Signer version %1 by Justin Karneges").arg(VERSION) + '\n';
00799                 str += tr("A simple tool for creating and verifying digital signatures.") + '\n';
00800                 str += '\n';
00801                 str += tr("Using QCA version %1").arg(verstr) + '\n';
00802                 str += '\n';
00803                 str += tr("Icons by Jason Kim") + '\n';
00804 
00805                 QCA::ProviderList list = QCA::providers();
00806                 foreach(QCA::Provider *p, list)
00807                 {
00808                         QString credit = p->credit();
00809                         if(!credit.isEmpty())
00810                         {
00811                                 str += '\n';
00812                                 str += credit;
00813                         }
00814                 }
00815 
00816                 QMessageBox::about(this, tr("About CMS Signer"), str);
00817         }
00818 
00819         void sign_loadError()
00820         {
00821                 delete op;
00822                 op = 0;
00823 
00824                 setEnabled(true);
00825         }
00826 
00827         void sign_finished(const QString &sig)
00828         {
00829                 delete op;
00830                 op = 0;
00831 
00832                 ui.te_sig->setPlainText(sig);
00833 
00834                 setEnabled(true);
00835         }
00836 
00837         void sign_error(const QString &msg)
00838         {
00839                 delete op;
00840                 op = 0;
00841 
00842                 setEnabled(true);
00843 
00844                 QMessageBox::information(this, tr("Error"), msg);
00845         }
00846 
00847         void verify_finished()
00848         {
00849                 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
00850                 delete op;
00851                 op = 0;
00852 
00853                 // import the cert?
00854                 QCA::SecureMessageKey skey = signer.key();
00855                 if(!skey.isNull())
00856                 {
00857                         QCA::CertificateChain chain = skey.x509CertificateChain();
00858 
00859                         int at = -1;
00860                         QList<CertItem> items = users->items();
00861                         for(int n = 0; n < items.count(); ++n)
00862                         {
00863                                 const CertItem &i = items[n];
00864                                 if(i.certificateChain().primary() == chain.primary())
00865                                 {
00866                                         at = n;
00867                                         break;
00868                                 }
00869                         }
00870 
00871                         // add
00872                         if(at == -1)
00873                         {
00874                                 auto_import_req_id = users->addUser(chain);
00875                                 return;
00876                         }
00877                         // update
00878                         else
00879                         {
00880                                 users->updateChain(users->idFromRow(at), chain);
00881                         }
00882                 }
00883 
00884                 verify_next();
00885         }
00886 
00887         void verify_next()
00888         {
00889                 setEnabled(true);
00890 
00891                 QMessageBox::information(this, tr("Verify"), tr("Signature verified successfully."));
00892         }
00893 
00894         void verify_error(const QString &msg)
00895         {
00896                 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
00897                 delete op;
00898                 op = 0;
00899 
00900                 QCA::SecureMessageKey skey = signer.key();
00901                 if(signer.keyValidity() == QCA::ErrorSelfSigned && !skey.isNull())
00902                 {
00903                         QCA::CertificateChain chain = skey.x509CertificateChain();
00904                         if(chain.count() == 1 && chain.primary().isSelfSigned())
00905                         {
00906                                 QCA::Certificate cert = chain.primary();
00907 
00908                                 int ret = QMessageBox::warning(this, tr("Self-signed certificate"), tr(
00909                                         "<qt>The signature is made by an unknown user, and the certificate is self-signed.<br>\n"
00910                                         "<br>\n"
00911                                         "<nobr>Common Name: %1</nobr><br>\n"
00912                                         "<nobr>SHA1 Fingerprint: %2</nobr><br>\n"
00913                                         "<br>\n"
00914                                         "Trust the certificate?</qt>"
00915                                         ).arg(cert.commonName(), get_fingerprint(cert)),
00916                                         QMessageBox::Yes | QMessageBox::No,
00917                                         QMessageBox::No);
00918 
00919                                 if(ret == QMessageBox::Yes)
00920                                 {
00921                                         self_signed_verify_cert = cert;
00922                                         do_verify();
00923                                         return;
00924                                 }
00925                         }
00926                 }
00927 
00928                 setEnabled(true);
00929 
00930                 QMessageBox::information(this, tr("Error"), msg);
00931         }
00932 };
00933 
00934 int main(int argc, char **argv)
00935 {
00936         QCA::Initializer qcaInit;
00937         QApplication qapp(argc, argv);
00938 
00939         qapp.setApplicationName(MainWin::tr("CMS Signer"));
00940 
00941         if(!QCA::isSupported("cert,crl,cms"))
00942         {
00943                 QMessageBox::critical(0, qapp.applicationName() + ": " + MainWin::tr("Error"),
00944                         MainWin::tr("No support for CMS is available.  Please install an appropriate QCA plugin, such as qca-ossl."));
00945                 return 1;
00946         }
00947 
00948         QCA::KeyStoreManager::start();
00949 
00950         MainWin mainWin;
00951         mainWin.show();
00952         return qapp.exec();
00953 }
00954 
00955 #include "main.moc"

Generated on Tue Aug 28 08:19:58 2007 for Qt Cryptographic Architecture by  doxygen 1.5.2