File indexing completed on 2024-09-08 04:18:39
0001 /* 0002 Copyright (C) 2007 Justin Karneges <justin@affinix.com> 0003 0004 Permission is hereby granted, free of charge, to any person obtaining a copy 0005 of this software and associated documentation files (the "Software"), to deal 0006 in the Software without restriction, including without limitation the rights 0007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0008 copies of the Software, and to permit persons to whom the Software is 0009 furnished to do so, subject to the following conditions: 0010 0011 The above copyright notice and this permission notice shall be included in 0012 all copies or substantial portions of the Software. 0013 0014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0017 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 0018 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 0019 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0020 */ 0021 0022 #include <QFileDialog> 0023 #include <QMessageBox> 0024 #include <QtCore> 0025 #include <QtCrypto> 0026 #include <QtGui> 0027 0028 #include "certitem.h" 0029 #include "certviewdlg.h" 0030 #include "keyselectdlg.h" 0031 #include "pkcs11configdlg/pkcs11configdlg.h" 0032 #include "ui_mainwin.h" 0033 0034 #ifdef QT_STATICPLUGIN 0035 #include "import_plugins.h" 0036 #endif 0037 0038 #define VERSION "1.0.0" 0039 0040 class Icons 0041 { 0042 public: 0043 QPixmap cert, crl, keybundle, pgppub, pgpsec; 0044 }; 0045 0046 Icons *g_icons = 0; 0047 0048 //---------------------------------------------------------------------------- 0049 // Operation 0050 //---------------------------------------------------------------------------- 0051 class Operation : public QObject 0052 { 0053 Q_OBJECT 0054 public: 0055 Operation(QObject *parent = 0) 0056 : QObject(parent) 0057 { 0058 } 0059 0060 Q_SIGNALS: 0061 void error(const QString &str); 0062 }; 0063 0064 static QString validityToString(QCA::Validity v) 0065 { 0066 QString s; 0067 switch (v) { 0068 case QCA::ValidityGood: 0069 s = Operation::tr("Validated"); 0070 break; 0071 case QCA::ErrorRejected: 0072 s = Operation::tr("Root CA is marked to reject the specified purpose"); 0073 break; 0074 case QCA::ErrorUntrusted: 0075 s = Operation::tr("Certificate not trusted for the required purpose"); 0076 break; 0077 case QCA::ErrorSignatureFailed: 0078 s = Operation::tr("Invalid signature"); 0079 break; 0080 case QCA::ErrorInvalidCA: 0081 s = Operation::tr("Invalid CA certificate"); 0082 break; 0083 case QCA::ErrorInvalidPurpose: 0084 s = Operation::tr("Invalid certificate purpose"); 0085 break; 0086 case QCA::ErrorSelfSigned: 0087 s = Operation::tr("Certificate is self-signed"); 0088 break; 0089 case QCA::ErrorRevoked: 0090 s = Operation::tr("Certificate has been revoked"); 0091 break; 0092 case QCA::ErrorPathLengthExceeded: 0093 s = Operation::tr("Maximum certificate chain length exceeded"); 0094 break; 0095 case QCA::ErrorExpired: 0096 s = Operation::tr("Certificate has expired"); 0097 break; 0098 case QCA::ErrorExpiredCA: 0099 s = Operation::tr("CA has expired"); 0100 break; 0101 case QCA::ErrorValidityUnknown: 0102 default: 0103 s = Operation::tr("General certificate validation error"); 0104 break; 0105 } 0106 return s; 0107 } 0108 0109 static QString smErrorToString(QCA::SecureMessage::Error e) 0110 { 0111 QString s; 0112 switch (e) { 0113 case QCA::SecureMessage::ErrorPassphrase: 0114 s = Operation::tr("Invalid passphrase."); 0115 break; 0116 case QCA::SecureMessage::ErrorFormat: 0117 s = Operation::tr("Bad input format."); 0118 break; 0119 case QCA::SecureMessage::ErrorSignerExpired: 0120 s = Operation::tr("Signer key is expired."); 0121 break; 0122 case QCA::SecureMessage::ErrorSignerInvalid: 0123 s = Operation::tr("Signer key is invalid."); 0124 break; 0125 case QCA::SecureMessage::ErrorEncryptExpired: 0126 s = Operation::tr("Encrypting key is expired."); 0127 break; 0128 case QCA::SecureMessage::ErrorEncryptUntrusted: 0129 s = Operation::tr("Encrypting key is untrusted."); 0130 break; 0131 case QCA::SecureMessage::ErrorEncryptInvalid: 0132 s = Operation::tr("Encrypting key is invalid."); 0133 break; 0134 case QCA::SecureMessage::ErrorNeedCard: 0135 s = Operation::tr("Card was needed but not found."); 0136 break; 0137 case QCA::SecureMessage::ErrorCertKeyMismatch: 0138 s = Operation::tr("Certificate and private key don't match."); 0139 break; 0140 case QCA::SecureMessage::ErrorUnknown: 0141 default: 0142 s = Operation::tr("General error."); 0143 break; 0144 } 0145 return s; 0146 } 0147 0148 static QString smsIdentityToString(const QCA::SecureMessageSignature &sig) 0149 { 0150 QString s; 0151 switch (sig.identityResult()) { 0152 case QCA::SecureMessageSignature::Valid: 0153 break; 0154 case QCA::SecureMessageSignature::InvalidSignature: 0155 s = Operation::tr("Invalid signature"); 0156 break; 0157 case QCA::SecureMessageSignature::InvalidKey: 0158 s = Operation::tr("Invalid key: %1").arg(validityToString(sig.keyValidity())); 0159 break; 0160 case QCA::SecureMessageSignature::NoKey: 0161 s = Operation::tr("Key not found"); 0162 break; 0163 default: // this should not really be possible 0164 s = Operation::tr("Unknown"); 0165 break; 0166 } 0167 return s; 0168 } 0169 0170 class SignOperation : public Operation 0171 { 0172 Q_OBJECT 0173 private: 0174 QByteArray in; 0175 CertItemStore *store; 0176 int id; 0177 QCA::CMS *cms; 0178 CertItemPrivateLoader *loader; 0179 QCA::SecureMessage *msg; 0180 int pending; 0181 0182 public: 0183 SignOperation(const QByteArray &_in, CertItemStore *_store, int _id, QCA::CMS *_cms, QObject *parent = 0) 0184 : Operation(parent) 0185 , in(_in) 0186 , store(_store) 0187 , id(_id) 0188 , cms(_cms) 0189 , msg(0) 0190 { 0191 loader = new CertItemPrivateLoader(store, this); 0192 connect(loader, SIGNAL(finished()), SLOT(loader_finished())); 0193 loader->start(id); 0194 } 0195 0196 Q_SIGNALS: 0197 void loadError(); 0198 void finished(const QString &sig); 0199 0200 private Q_SLOTS: 0201 void loader_finished() 0202 { 0203 QCA::PrivateKey privateKey = loader->privateKey(); 0204 delete loader; 0205 loader = 0; 0206 0207 if (privateKey.isNull()) { 0208 emit loadError(); 0209 return; 0210 } 0211 0212 CertItem item = store->itemFromId(id); 0213 0214 QCA::SecureMessageKey signer; 0215 signer.setX509CertificateChain(item.certificateChain()); 0216 signer.setX509PrivateKey(privateKey); 0217 0218 msg = new QCA::SecureMessage(cms); 0219 connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int))); 0220 connect(msg, SIGNAL(finished()), SLOT(msg_finished())); 0221 msg->setFormat(QCA::SecureMessage::Ascii); 0222 msg->setSigner(signer); 0223 msg->startSign(QCA::SecureMessage::Detached); 0224 0225 pending = 0; 0226 update(); 0227 } 0228 0229 void update() 0230 { 0231 QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks 0232 in = in.mid(buf.size()); 0233 pending += buf.size(); 0234 msg->update(buf); 0235 } 0236 0237 void msg_bytesWritten(int x) 0238 { 0239 pending -= x; 0240 0241 if (in.isEmpty() && pending == 0) 0242 msg->end(); 0243 else 0244 update(); 0245 } 0246 0247 void msg_finished() 0248 { 0249 if (!msg->success()) { 0250 QString str = smErrorToString(msg->errorCode()); 0251 delete msg; 0252 msg = 0; 0253 emit error(tr("Error during sign operation.\nReason: %1").arg(str)); 0254 return; 0255 } 0256 0257 QByteArray result = msg->signature(); 0258 delete msg; 0259 msg = 0; 0260 emit finished(QString::fromLatin1(result)); 0261 } 0262 }; 0263 0264 class VerifyOperation : public Operation 0265 { 0266 Q_OBJECT 0267 private: 0268 QByteArray in, sig; 0269 QCA::CMS *cms; 0270 QCA::SecureMessage *msg; 0271 int pending; 0272 0273 public: 0274 QCA::SecureMessageSignature signer; 0275 0276 VerifyOperation(const QByteArray &_in, const QByteArray &_sig, QCA::CMS *_cms, QObject *parent = 0) 0277 : Operation(parent) 0278 , in(_in) 0279 , sig(_sig) 0280 , cms(_cms) 0281 , msg(0) 0282 { 0283 msg = new QCA::SecureMessage(cms); 0284 connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int))); 0285 connect(msg, SIGNAL(finished()), SLOT(msg_finished())); 0286 msg->setFormat(QCA::SecureMessage::Ascii); 0287 msg->startVerify(sig); 0288 0289 pending = 0; 0290 update(); 0291 } 0292 0293 Q_SIGNALS: 0294 void finished(); 0295 0296 private Q_SLOTS: 0297 void update() 0298 { 0299 QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks 0300 in = in.mid(buf.size()); 0301 pending += buf.size(); 0302 msg->update(buf); 0303 } 0304 0305 void msg_bytesWritten(int x) 0306 { 0307 pending -= x; 0308 0309 if (in.isEmpty() && pending == 0) 0310 msg->end(); 0311 else 0312 update(); 0313 } 0314 0315 void msg_finished() 0316 { 0317 if (!msg->success()) { 0318 QString str = smErrorToString(msg->errorCode()); 0319 delete msg; 0320 msg = 0; 0321 emit error(tr("Error during verify operation.\nReason: %1").arg(str)); 0322 return; 0323 } 0324 0325 signer = msg->signer(); 0326 delete msg; 0327 msg = 0; 0328 0329 if (signer.identityResult() != QCA::SecureMessageSignature::Valid) { 0330 QString str = smsIdentityToString(signer); 0331 emit error(tr("Verification failed!\nReason: %1").arg(str)); 0332 return; 0333 } 0334 0335 emit finished(); 0336 } 0337 }; 0338 0339 //---------------------------------------------------------------------------- 0340 // MainWin 0341 //---------------------------------------------------------------------------- 0342 static QString get_fingerprint(const QCA::Certificate &cert) 0343 { 0344 QString hex = QCA::Hash("sha1").hashToString(cert.toDER()); 0345 QString out; 0346 for (int n = 0; n < hex.count(); ++n) { 0347 if (n != 0 && n % 2 == 0) 0348 out += ':'; 0349 out += hex[n]; 0350 } 0351 return out; 0352 } 0353 0354 class MainWin : public QMainWindow 0355 { 0356 Q_OBJECT 0357 private: 0358 Ui_MainWin ui; 0359 CertItemStore *users, *roots; 0360 QCA::CMS *cms; 0361 Operation *op; 0362 QAction *actionView, *actionRename, *actionRemove; 0363 QCA::Certificate self_signed_verify_cert; 0364 int auto_import_req_id; 0365 0366 public: 0367 MainWin(QWidget *parent = 0) 0368 : QMainWindow(parent) 0369 , op(0) 0370 , auto_import_req_id(-1) 0371 { 0372 ui.setupUi(this); 0373 0374 g_icons = new Icons; 0375 g_icons->cert = QPixmap(":/gfx/icons/cert16.png"); 0376 g_icons->crl = QPixmap(":/gfx/icons/crl16.png"); 0377 g_icons->keybundle = QPixmap(":/gfx/icons/keybundle16.png"); 0378 g_icons->pgppub = QPixmap(":/gfx/icons/publickey16.png"); 0379 g_icons->pgpsec = QPixmap(":/gfx/icons/keypair16.png"); 0380 if (g_icons->cert.isNull() || g_icons->crl.isNull() || g_icons->keybundle.isNull() || 0381 g_icons->pgppub.isNull() || g_icons->pgpsec.isNull()) 0382 printf("Warning: not all icons loaded\n"); 0383 0384 users = new CertItemStore(this); 0385 roots = new CertItemStore(this); 0386 0387 setIcons(users); 0388 setIcons(roots); 0389 0390 connect(users, SIGNAL(addSuccess(int, int)), SLOT(users_addSuccess(int, int))); 0391 connect(users, SIGNAL(addFailed(int)), SLOT(users_addFailed(int))); 0392 0393 actionView = new QAction(tr("&View"), this); 0394 actionRename = new QAction(tr("Re&name"), this); 0395 actionRemove = new QAction(tr("Rem&ove"), this); 0396 0397 connect(ui.actionLoadIdentityFile, SIGNAL(triggered()), SLOT(load_file())); 0398 connect(ui.actionLoadIdentityEntry, SIGNAL(triggered()), SLOT(load_device())); 0399 connect(ui.actionLoadAuthority, SIGNAL(triggered()), SLOT(load_root())); 0400 connect(ui.actionConfigurePkcs11, SIGNAL(triggered()), SLOT(mod_config())); 0401 connect(ui.actionQuit, SIGNAL(triggered()), SLOT(close())); 0402 connect(ui.actionAbout, SIGNAL(triggered()), SLOT(about())); 0403 connect(ui.pb_sign, SIGNAL(clicked()), SLOT(do_sign())); 0404 connect(ui.pb_verify, SIGNAL(clicked()), SLOT(do_verify())); 0405 0406 connect(actionView, SIGNAL(triggered()), SLOT(item_view())); 0407 connect(actionRename, SIGNAL(triggered()), SLOT(item_rename())); 0408 connect(actionRemove, SIGNAL(triggered()), SLOT(item_remove())); 0409 0410 ui.pb_sign->setEnabled(false); 0411 0412 ui.lv_users->setModel(users); 0413 connect(ui.lv_users->selectionModel(), 0414 SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), 0415 SLOT(users_selectionChanged(const QItemSelection &, const QItemSelection &))); 0416 0417 ui.lv_users->setContextMenuPolicy(Qt::CustomContextMenu); 0418 connect(ui.lv_users, 0419 SIGNAL(customContextMenuRequested(const QPoint &)), 0420 SLOT(users_customContextMenuRequested(const QPoint &))); 0421 0422 ui.lv_authorities->setModel(roots); 0423 0424 ui.lv_authorities->setContextMenuPolicy(Qt::CustomContextMenu); 0425 connect(ui.lv_authorities, 0426 SIGNAL(customContextMenuRequested(const QPoint &)), 0427 SLOT(roots_customContextMenuRequested(const QPoint &))); 0428 0429 cms = new QCA::CMS(this); 0430 0431 QStringList ulist, rlist; 0432 { 0433 QSettings settings("Affinix", "CMS Signer"); 0434 ulist = settings.value("users").toStringList(); 0435 rlist = settings.value("roots").toStringList(); 0436 } 0437 0438 users->load(ulist); 0439 roots->load(rlist); 0440 } 0441 0442 ~MainWin() 0443 { 0444 QStringList ulist = users->save(); 0445 QStringList rlist = roots->save(); 0446 0447 QSettings settings("Affinix", "CMS Signer"); 0448 settings.setValue("users", ulist); 0449 settings.setValue("roots", rlist); 0450 0451 delete g_icons; 0452 g_icons = 0; 0453 } 0454 0455 void setIcons(CertItemStore *store) 0456 { 0457 store->setIcon(CertItemStore::IconCert, g_icons->cert); 0458 store->setIcon(CertItemStore::IconCrl, g_icons->crl); 0459 store->setIcon(CertItemStore::IconKeyBundle, g_icons->keybundle); 0460 store->setIcon(CertItemStore::IconPgpPub, g_icons->pgppub); 0461 store->setIcon(CertItemStore::IconPgpSec, g_icons->pgpsec); 0462 } 0463 0464 QCA::CertificateCollection allCerts() 0465 { 0466 QCA::CertificateCollection col; 0467 0468 // system store 0469 col += QCA::systemStore(); 0470 0471 // additional roots configured in application 0472 foreach (const CertItem &i, roots->items()) 0473 col.addCertificate(i.certificateChain().primary()); 0474 0475 // user chains 0476 foreach (const CertItem &i, users->items()) { 0477 foreach (const QCA::Certificate &cert, i.certificateChain()) 0478 col.addCertificate(cert); 0479 } 0480 0481 return col; 0482 } 0483 0484 QCA::CertificateChain complete(const QCA::CertificateChain &chain) 0485 { 0486 return chain.complete(allCerts().certificates()); 0487 } 0488 0489 private Q_SLOTS: 0490 void load_file() 0491 { 0492 QString fileName = 0493 QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Identities (*.p12 *.pfx)")); 0494 if (fileName.isEmpty()) 0495 return; 0496 0497 setEnabled(false); 0498 users->addFromFile(fileName); 0499 } 0500 0501 void load_device() 0502 { 0503 KeySelectDlg *w = new KeySelectDlg(this); 0504 w->setAttribute(Qt::WA_DeleteOnClose, true); 0505 w->setWindowModality(Qt::WindowModal); 0506 connect( 0507 w, SIGNAL(selected(const QCA::KeyStoreEntry &)), SLOT(load_device_finished(const QCA::KeyStoreEntry &))); 0508 connect(w, 0509 SIGNAL(viewCertificate(const QCA::CertificateChain &)), 0510 SLOT(keyselect_viewCertificate(const QCA::CertificateChain &))); 0511 w->setIcon(KeySelectDlg::IconCert, g_icons->cert); 0512 w->setIcon(KeySelectDlg::IconCrl, g_icons->crl); 0513 w->setIcon(KeySelectDlg::IconKeyBundle, g_icons->keybundle); 0514 w->setIcon(KeySelectDlg::IconPgpPub, g_icons->pgppub); 0515 w->setIcon(KeySelectDlg::IconPgpSec, g_icons->pgpsec); 0516 w->show(); 0517 } 0518 0519 void load_device_finished(const QCA::KeyStoreEntry &entry) 0520 { 0521 users->addFromKeyStore(entry); 0522 } 0523 0524 void load_root() 0525 { 0526 QString fileName = 0527 QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Certificates (*.pem *.crt)")); 0528 if (fileName.isEmpty()) 0529 return; 0530 0531 QCA::Certificate cert = QCA::Certificate::fromPEMFile(fileName); 0532 if (cert.isNull()) { 0533 QMessageBox::information(this, tr("Error"), tr("Error opening certificate file.")); 0534 return; 0535 } 0536 0537 roots->addUser(cert); 0538 } 0539 0540 void users_addSuccess(int req_id, int id) 0541 { 0542 if (req_id == auto_import_req_id) { 0543 auto_import_req_id = -1; 0544 0545 CertItem i = users->itemFromId(id); 0546 0547 QMessageBox::information(this, 0548 tr("User added"), 0549 tr("This signature was made by a previously unknown user, and so the " 0550 "user has now been added to the keyring as \"%1\".") 0551 .arg(i.name())); 0552 0553 verify_next(); 0554 return; 0555 } 0556 0557 ui.lv_users->selectionModel()->select(users->index(users->rowFromId(id)), 0558 QItemSelectionModel::Clear | QItemSelectionModel::Select | 0559 QItemSelectionModel::Current); 0560 0561 setEnabled(true); 0562 } 0563 0564 void users_addFailed(int req_id) 0565 { 0566 Q_UNUSED(req_id); 0567 0568 setEnabled(true); 0569 } 0570 0571 void mod_config() 0572 { 0573 if (!Pkcs11ConfigDlg::isSupported()) { 0574 QMessageBox::information( 0575 this, tr("Error"), tr("No provider available supporting standard PKCS#11 configuration.")); 0576 return; 0577 } 0578 0579 Pkcs11ConfigDlg *w = new Pkcs11ConfigDlg(this); 0580 w->setAttribute(Qt::WA_DeleteOnClose, true); 0581 w->setWindowModality(Qt::WindowModal); 0582 w->show(); 0583 } 0584 0585 void users_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) 0586 { 0587 Q_UNUSED(deselected); 0588 0589 int at = -1; 0590 if (!selected.indexes().isEmpty()) { 0591 QModelIndex index = selected.indexes().first(); 0592 at = index.row(); 0593 } 0594 0595 bool usable = false; 0596 if (at != -1 && users->itemFromRow(at).isUsable()) 0597 usable = true; 0598 0599 if (usable && !ui.pb_sign->isEnabled()) 0600 ui.pb_sign->setEnabled(true); 0601 else if (!usable && ui.pb_sign->isEnabled()) 0602 ui.pb_sign->setEnabled(false); 0603 } 0604 0605 void item_view() 0606 { 0607 if (ui.lv_users->hasFocus()) { 0608 QItemSelection selection = ui.lv_users->selectionModel()->selection(); 0609 if (selection.indexes().isEmpty()) 0610 return; 0611 QModelIndex index = selection.indexes().first(); 0612 users_view(index.row()); 0613 } else // lv_authorities 0614 { 0615 QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); 0616 if (selection.indexes().isEmpty()) 0617 return; 0618 QModelIndex index = selection.indexes().first(); 0619 roots_view(index.row()); 0620 } 0621 } 0622 0623 void item_rename() 0624 { 0625 if (ui.lv_users->hasFocus()) { 0626 QItemSelection selection = ui.lv_users->selectionModel()->selection(); 0627 if (selection.indexes().isEmpty()) 0628 return; 0629 QModelIndex index = selection.indexes().first(); 0630 users_rename(index.row()); 0631 } else // lv_authorities 0632 { 0633 QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); 0634 if (selection.indexes().isEmpty()) 0635 return; 0636 QModelIndex index = selection.indexes().first(); 0637 roots_rename(index.row()); 0638 } 0639 } 0640 0641 void item_remove() 0642 { 0643 if (ui.lv_users->hasFocus()) { 0644 QItemSelection selection = ui.lv_users->selectionModel()->selection(); 0645 if (selection.indexes().isEmpty()) 0646 return; 0647 QModelIndex index = selection.indexes().first(); 0648 users_remove(index.row()); 0649 } else // lv_authorities 0650 { 0651 QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); 0652 if (selection.indexes().isEmpty()) 0653 return; 0654 QModelIndex index = selection.indexes().first(); 0655 roots_remove(index.row()); 0656 } 0657 } 0658 0659 void users_view(int at) 0660 { 0661 CertItem i = users->itemFromRow(at); 0662 CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this); 0663 w->setAttribute(Qt::WA_DeleteOnClose, true); 0664 w->show(); 0665 } 0666 0667 void users_rename(int at) 0668 { 0669 QModelIndex index = users->index(at); 0670 ui.lv_users->setFocus(); 0671 ui.lv_users->setCurrentIndex(index); 0672 ui.lv_users->selectionModel()->select( 0673 index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current); 0674 ui.lv_users->edit(index); 0675 } 0676 0677 void users_remove(int at) 0678 { 0679 users->removeItem(users->idFromRow(at)); 0680 } 0681 0682 void roots_view(int at) 0683 { 0684 CertItem i = roots->itemFromRow(at); 0685 CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this); 0686 w->setAttribute(Qt::WA_DeleteOnClose, true); 0687 w->show(); 0688 } 0689 0690 void roots_rename(int at) 0691 { 0692 QModelIndex index = roots->index(at); 0693 ui.lv_authorities->setFocus(); 0694 ui.lv_authorities->setCurrentIndex(index); 0695 ui.lv_authorities->selectionModel()->select( 0696 index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current); 0697 ui.lv_authorities->edit(index); 0698 } 0699 0700 void roots_remove(int at) 0701 { 0702 roots->removeItem(roots->idFromRow(at)); 0703 } 0704 0705 void keyselect_viewCertificate(const QCA::CertificateChain &chain) 0706 { 0707 CertViewDlg *w = new CertViewDlg(complete(chain), (QWidget *)sender()); 0708 w->setAttribute(Qt::WA_DeleteOnClose, true); 0709 w->show(); 0710 } 0711 0712 void users_customContextMenuRequested(const QPoint &pos) 0713 { 0714 QItemSelection selection = ui.lv_users->selectionModel()->selection(); 0715 if (selection.indexes().isEmpty()) 0716 return; 0717 0718 QMenu menu(this); 0719 menu.addAction(actionView); 0720 menu.addAction(actionRename); 0721 menu.addAction(actionRemove); 0722 menu.exec(ui.lv_users->viewport()->mapToGlobal(pos)); 0723 } 0724 0725 void roots_customContextMenuRequested(const QPoint &pos) 0726 { 0727 QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); 0728 if (selection.indexes().isEmpty()) 0729 return; 0730 0731 QMenu menu(this); 0732 menu.addAction(actionView); 0733 menu.addAction(actionRename); 0734 menu.addAction(actionRemove); 0735 menu.exec(ui.lv_authorities->viewport()->mapToGlobal(pos)); 0736 } 0737 0738 void do_sign() 0739 { 0740 QItemSelection selection = ui.lv_users->selectionModel()->selection(); 0741 if (selection.indexes().isEmpty()) 0742 return; 0743 QModelIndex index = selection.indexes().first(); 0744 int at = index.row(); 0745 0746 setEnabled(false); 0747 0748 op = new SignOperation(ui.te_data->toPlainText().toUtf8(), users, users->idFromRow(at), cms, this); 0749 connect(op, SIGNAL(loadError()), SLOT(sign_loadError())); 0750 connect(op, SIGNAL(finished(const QString &)), SLOT(sign_finished(const QString &))); 0751 connect(op, SIGNAL(error(const QString &)), SLOT(sign_error(const QString &))); 0752 } 0753 0754 void do_verify() 0755 { 0756 // prepare root certs 0757 QCA::CertificateCollection col; 0758 0759 // system store 0760 col += QCA::systemStore(); 0761 0762 // additional roots configured in application 0763 foreach (const CertItem &i, roots->items()) 0764 col.addCertificate(i.certificateChain().primary()); 0765 0766 // consider self-signed users as roots 0767 // (it is therefore not possible with this application to 0768 // have people in your keyring that you don't trust) 0769 foreach (const CertItem &i, users->items()) { 0770 QCA::Certificate cert = i.certificateChain().primary(); 0771 if (cert.isSelfSigned()) 0772 col.addCertificate(cert); 0773 } 0774 0775 // the self signed verify cert, if applicable 0776 if (!self_signed_verify_cert.isNull()) { 0777 col.addCertificate(self_signed_verify_cert); 0778 self_signed_verify_cert = QCA::Certificate(); 0779 } 0780 0781 cms->setTrustedCertificates(col); 0782 0783 setEnabled(false); 0784 0785 op = new VerifyOperation(ui.te_data->toPlainText().toUtf8(), ui.te_sig->toPlainText().toUtf8(), cms, this); 0786 connect(op, SIGNAL(finished()), SLOT(verify_finished())); 0787 connect(op, SIGNAL(error(const QString &)), SLOT(verify_error(const QString &))); 0788 } 0789 0790 void about() 0791 { 0792 int ver = qcaVersion(); 0793 int maj = (ver >> 16) & 0xff; 0794 int min = (ver >> 8) & 0xff; 0795 int bug = ver & 0xff; 0796 QString verstr; 0797 verstr.sprintf("%d.%d.%d", maj, min, bug); 0798 0799 QString str; 0800 str += tr("CMS Signer version %1 by Justin Karneges").arg(VERSION) + '\n'; 0801 str += tr("A simple tool for creating and verifying digital signatures.") + '\n'; 0802 str += '\n'; 0803 str += tr("Using QCA version %1").arg(verstr) + '\n'; 0804 str += '\n'; 0805 str += tr("Icons by Jason Kim") + '\n'; 0806 0807 QCA::ProviderList list = QCA::providers(); 0808 foreach (QCA::Provider *p, list) { 0809 QString credit = p->credit(); 0810 if (!credit.isEmpty()) { 0811 str += '\n'; 0812 str += credit; 0813 } 0814 } 0815 0816 QMessageBox::about(this, tr("About CMS Signer"), str); 0817 } 0818 0819 void sign_loadError() 0820 { 0821 delete op; 0822 op = 0; 0823 0824 setEnabled(true); 0825 } 0826 0827 void sign_finished(const QString &sig) 0828 { 0829 delete op; 0830 op = 0; 0831 0832 ui.te_sig->setPlainText(sig); 0833 0834 setEnabled(true); 0835 } 0836 0837 void sign_error(const QString &msg) 0838 { 0839 delete op; 0840 op = 0; 0841 0842 setEnabled(true); 0843 0844 QMessageBox::information(this, tr("Error"), msg); 0845 } 0846 0847 void verify_finished() 0848 { 0849 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer; 0850 delete op; 0851 op = 0; 0852 0853 // import the cert? 0854 QCA::SecureMessageKey skey = signer.key(); 0855 if (!skey.isNull()) { 0856 QCA::CertificateChain chain = skey.x509CertificateChain(); 0857 0858 int at = -1; 0859 QList<CertItem> items = users->items(); 0860 for (int n = 0; n < items.count(); ++n) { 0861 const CertItem &i = items[n]; 0862 if (i.certificateChain().primary() == chain.primary()) { 0863 at = n; 0864 break; 0865 } 0866 } 0867 0868 // add 0869 if (at == -1) { 0870 auto_import_req_id = users->addUser(chain); 0871 return; 0872 } 0873 // update 0874 else { 0875 users->updateChain(users->idFromRow(at), chain); 0876 } 0877 } 0878 0879 verify_next(); 0880 } 0881 0882 void verify_next() 0883 { 0884 setEnabled(true); 0885 0886 QMessageBox::information(this, tr("Verify"), tr("Signature verified successfully.")); 0887 } 0888 0889 void verify_error(const QString &msg) 0890 { 0891 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer; 0892 delete op; 0893 op = 0; 0894 0895 QCA::SecureMessageKey skey = signer.key(); 0896 if (signer.keyValidity() == QCA::ErrorSelfSigned && !skey.isNull()) { 0897 QCA::CertificateChain chain = skey.x509CertificateChain(); 0898 if (chain.count() == 1 && chain.primary().isSelfSigned()) { 0899 QCA::Certificate cert = chain.primary(); 0900 0901 int ret = QMessageBox::warning( 0902 this, 0903 tr("Self-signed certificate"), 0904 tr("<qt>The signature is made by an unknown user, and the certificate is self-signed.<br>\n" 0905 "<br>\n" 0906 "<nobr>Common Name: %1</nobr><br>\n" 0907 "<nobr>SHA1 Fingerprint: %2</nobr><br>\n" 0908 "<br>\n" 0909 "Trust the certificate?</qt>") 0910 .arg(cert.commonName(), get_fingerprint(cert)), 0911 QMessageBox::Yes | QMessageBox::No, 0912 QMessageBox::No); 0913 0914 if (ret == QMessageBox::Yes) { 0915 self_signed_verify_cert = cert; 0916 do_verify(); 0917 return; 0918 } 0919 } 0920 } 0921 0922 setEnabled(true); 0923 0924 QMessageBox::information(this, tr("Error"), msg); 0925 } 0926 }; 0927 0928 int main(int argc, char **argv) 0929 { 0930 QCA::Initializer qcaInit; 0931 QApplication qapp(argc, argv); 0932 0933 qapp.setApplicationName(MainWin::tr("CMS Signer")); 0934 0935 if (!QCA::isSupported("cert,crl,cms")) { 0936 QMessageBox::critical( 0937 0, 0938 qapp.applicationName() + ": " + MainWin::tr("Error"), 0939 MainWin::tr( 0940 "No support for CMS is available. Please install an appropriate QCA plugin, such as qca-ossl.")); 0941 return 1; 0942 } 0943 0944 QCA::KeyStoreManager::start(); 0945 0946 MainWin mainWin; 0947 mainWin.show(); 0948 return qapp.exec(); 0949 } 0950 0951 #include "main.moc"