QCA

cmssigner/main.cpp
1 /*
2  Copyright (C) 2007 Justin Karneges <[email protected]>
3 
4  Permission is hereby granted, free of charge, to any person obtaining a copy
5  of this software and associated documentation files (the "Software"), to deal
6  in the Software without restriction, including without limitation the rights
7  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  copies of the Software, and to permit persons to whom the Software is
9  furnished to do so, subject to the following conditions:
10 
11  The above copyright notice and this permission notice shall be included in
12  all copies or substantial portions of the Software.
13 
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21 
22 #include <QFileDialog>
23 #include <QMessageBox>
24 #include <QtCore>
25 #include <QtCrypto>
26 #include <QtGui>
27 
28 #include "certitem.h"
29 #include "certviewdlg.h"
30 #include "keyselectdlg.h"
31 #include "pkcs11configdlg/pkcs11configdlg.h"
32 #include "ui_mainwin.h"
33 
34 #ifdef QT_STATICPLUGIN
35 #include "import_plugins.h"
36 #endif
37 
38 #define VERSION "1.0.0"
39 
40 class Icons
41 {
42 public:
43  QPixmap cert, crl, keybundle, pgppub, pgpsec;
44 };
45 
46 Icons *g_icons = 0;
47 
48 //----------------------------------------------------------------------------
49 // Operation
50 //----------------------------------------------------------------------------
51 class Operation : public QObject
52 {
53  Q_OBJECT
54 public:
55  Operation(QObject *parent = 0)
56  : QObject(parent)
57  {
58  }
59 
60 Q_SIGNALS:
61  void error(const QString &str);
62 };
63 
64 static QString validityToString(QCA::Validity v)
65 {
66  QString s;
67  switch (v) {
68  case QCA::ValidityGood:
69  s = Operation::tr("Validated");
70  break;
71  case QCA::ErrorRejected:
72  s = Operation::tr("Root CA is marked to reject the specified purpose");
73  break;
75  s = Operation::tr("Certificate not trusted for the required purpose");
76  break;
78  s = Operation::tr("Invalid signature");
79  break;
81  s = Operation::tr("Invalid CA certificate");
82  break;
84  s = Operation::tr("Invalid certificate purpose");
85  break;
87  s = Operation::tr("Certificate is self-signed");
88  break;
89  case QCA::ErrorRevoked:
90  s = Operation::tr("Certificate has been revoked");
91  break;
93  s = Operation::tr("Maximum certificate chain length exceeded");
94  break;
95  case QCA::ErrorExpired:
96  s = Operation::tr("Certificate has expired");
97  break;
99  s = Operation::tr("CA has expired");
100  break;
102  default:
103  s = Operation::tr("General certificate validation error");
104  break;
105  }
106  return s;
107 }
108 
109 static QString smErrorToString(QCA::SecureMessage::Error e)
110 {
111  QString s;
112  switch (e) {
114  s = Operation::tr("Invalid passphrase.");
115  break;
117  s = Operation::tr("Bad input format.");
118  break;
120  s = Operation::tr("Signer key is expired.");
121  break;
123  s = Operation::tr("Signer key is invalid.");
124  break;
126  s = Operation::tr("Encrypting key is expired.");
127  break;
129  s = Operation::tr("Encrypting key is untrusted.");
130  break;
132  s = Operation::tr("Encrypting key is invalid.");
133  break;
135  s = Operation::tr("Card was needed but not found.");
136  break;
138  s = Operation::tr("Certificate and private key don't match.");
139  break;
141  default:
142  s = Operation::tr("General error.");
143  break;
144  }
145  return s;
146 }
147 
148 static QString smsIdentityToString(const QCA::SecureMessageSignature &sig)
149 {
150  QString s;
151  switch (sig.identityResult()) {
153  break;
155  s = Operation::tr("Invalid signature");
156  break;
158  s = Operation::tr("Invalid key: %1").arg(validityToString(sig.keyValidity()));
159  break;
161  s = Operation::tr("Key not found");
162  break;
163  default: // this should not really be possible
164  s = Operation::tr("Unknown");
165  break;
166  }
167  return s;
168 }
169 
170 class SignOperation : public Operation
171 {
172  Q_OBJECT
173 private:
174  QByteArray in;
175  CertItemStore *store;
176  int id;
177  QCA::CMS *cms;
178  CertItemPrivateLoader *loader;
179  QCA::SecureMessage *msg;
180  int pending;
181 
182 public:
183  SignOperation(const QByteArray &_in, CertItemStore *_store, int _id, QCA::CMS *_cms, QObject *parent = 0)
184  : Operation(parent)
185  , in(_in)
186  , store(_store)
187  , id(_id)
188  , cms(_cms)
189  , msg(0)
190  {
191  loader = new CertItemPrivateLoader(store, this);
192  connect(loader, SIGNAL(finished()), SLOT(loader_finished()));
193  loader->start(id);
194  }
195 
196 Q_SIGNALS:
197  void loadError();
198  void finished(const QString &sig);
199 
200 private Q_SLOTS:
201  void loader_finished()
202  {
203  QCA::PrivateKey privateKey = loader->privateKey();
204  delete loader;
205  loader = 0;
206 
207  if (privateKey.isNull()) {
208  emit loadError();
209  return;
210  }
211 
212  CertItem item = store->itemFromId(id);
213 
214  QCA::SecureMessageKey signer;
215  signer.setX509CertificateChain(item.certificateChain());
216  signer.setX509PrivateKey(privateKey);
217 
218  msg = new QCA::SecureMessage(cms);
219  connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int)));
220  connect(msg, SIGNAL(finished()), SLOT(msg_finished()));
222  msg->setSigner(signer);
224 
225  pending = 0;
226  update();
227  }
228 
229  void update()
230  {
231  QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks
232  in = in.mid(buf.size());
233  pending += buf.size();
234  msg->update(buf);
235  }
236 
237  void msg_bytesWritten(int x)
238  {
239  pending -= x;
240 
241  if (in.isEmpty() && pending == 0)
242  msg->end();
243  else
244  update();
245  }
246 
247  void msg_finished()
248  {
249  if (!msg->success()) {
250  QString str = smErrorToString(msg->errorCode());
251  delete msg;
252  msg = 0;
253  emit error(tr("Error during sign operation.\nReason: %1").arg(str));
254  return;
255  }
256 
257  QByteArray result = msg->signature();
258  delete msg;
259  msg = 0;
260  emit finished(QString::fromLatin1(result));
261  }
262 };
263 
264 class VerifyOperation : public Operation
265 {
266  Q_OBJECT
267 private:
268  QByteArray in, sig;
269  QCA::CMS *cms;
270  QCA::SecureMessage *msg;
271  int pending;
272 
273 public:
275 
276  VerifyOperation(const QByteArray &_in, const QByteArray &_sig, QCA::CMS *_cms, QObject *parent = 0)
277  : Operation(parent)
278  , in(_in)
279  , sig(_sig)
280  , cms(_cms)
281  , msg(0)
282  {
283  msg = new QCA::SecureMessage(cms);
284  connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int)));
285  connect(msg, SIGNAL(finished()), SLOT(msg_finished()));
287  msg->startVerify(sig);
288 
289  pending = 0;
290  update();
291  }
292 
293 Q_SIGNALS:
294  void finished();
295 
296 private Q_SLOTS:
297  void update()
298  {
299  QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks
300  in = in.mid(buf.size());
301  pending += buf.size();
302  msg->update(buf);
303  }
304 
305  void msg_bytesWritten(int x)
306  {
307  pending -= x;
308 
309  if (in.isEmpty() && pending == 0)
310  msg->end();
311  else
312  update();
313  }
314 
315  void msg_finished()
316  {
317  if (!msg->success()) {
318  QString str = smErrorToString(msg->errorCode());
319  delete msg;
320  msg = 0;
321  emit error(tr("Error during verify operation.\nReason: %1").arg(str));
322  return;
323  }
324 
325  signer = msg->signer();
326  delete msg;
327  msg = 0;
328 
330  QString str = smsIdentityToString(signer);
331  emit error(tr("Verification failed!\nReason: %1").arg(str));
332  return;
333  }
334 
335  emit finished();
336  }
337 };
338 
339 //----------------------------------------------------------------------------
340 // MainWin
341 //----------------------------------------------------------------------------
342 static QString get_fingerprint(const QCA::Certificate &cert)
343 {
344  QString hex = QCA::Hash("sha1").hashToString(cert.toDER());
345  QString out;
346  for (int n = 0; n < hex.count(); ++n) {
347  if (n != 0 && n % 2 == 0)
348  out += ':';
349  out += hex[n];
350  }
351  return out;
352 }
353 
354 class MainWin : public QMainWindow
355 {
356  Q_OBJECT
357 private:
358  Ui_MainWin ui;
359  CertItemStore *users, *roots;
360  QCA::CMS *cms;
361  Operation *op;
362  QAction *actionView, *actionRename, *actionRemove;
363  QCA::Certificate self_signed_verify_cert;
364  int auto_import_req_id;
365 
366 public:
367  MainWin(QWidget *parent = 0)
369  , op(0)
370  , auto_import_req_id(-1)
371  {
372  ui.setupUi(this);
373 
374  g_icons = new Icons;
375  g_icons->cert = QPixmap(":/gfx/icons/cert16.png");
376  g_icons->crl = QPixmap(":/gfx/icons/crl16.png");
377  g_icons->keybundle = QPixmap(":/gfx/icons/keybundle16.png");
378  g_icons->pgppub = QPixmap(":/gfx/icons/publickey16.png");
379  g_icons->pgpsec = QPixmap(":/gfx/icons/keypair16.png");
380  if (g_icons->cert.isNull() || g_icons->crl.isNull() || g_icons->keybundle.isNull() ||
381  g_icons->pgppub.isNull() || g_icons->pgpsec.isNull())
382  printf("Warning: not all icons loaded\n");
383 
384  users = new CertItemStore(this);
385  roots = new CertItemStore(this);
386 
387  setIcons(users);
388  setIcons(roots);
389 
390  connect(users, SIGNAL(addSuccess(int, int)), SLOT(users_addSuccess(int, int)));
391  connect(users, SIGNAL(addFailed(int)), SLOT(users_addFailed(int)));
392 
393  actionView = new QAction(tr("&View"), this);
394  actionRename = new QAction(tr("Re&name"), this);
395  actionRemove = new QAction(tr("Rem&ove"), this);
396 
397  connect(ui.actionLoadIdentityFile, SIGNAL(triggered()), SLOT(load_file()));
398  connect(ui.actionLoadIdentityEntry, SIGNAL(triggered()), SLOT(load_device()));
399  connect(ui.actionLoadAuthority, SIGNAL(triggered()), SLOT(load_root()));
400  connect(ui.actionConfigurePkcs11, SIGNAL(triggered()), SLOT(mod_config()));
401  connect(ui.actionQuit, SIGNAL(triggered()), SLOT(close()));
402  connect(ui.actionAbout, SIGNAL(triggered()), SLOT(about()));
403  connect(ui.pb_sign, SIGNAL(clicked()), SLOT(do_sign()));
404  connect(ui.pb_verify, SIGNAL(clicked()), SLOT(do_verify()));
405 
406  connect(actionView, SIGNAL(triggered()), SLOT(item_view()));
407  connect(actionRename, SIGNAL(triggered()), SLOT(item_rename()));
408  connect(actionRemove, SIGNAL(triggered()), SLOT(item_remove()));
409 
410  ui.pb_sign->setEnabled(false);
411 
412  ui.lv_users->setModel(users);
413  connect(ui.lv_users->selectionModel(),
414  SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
415  SLOT(users_selectionChanged(const QItemSelection &, const QItemSelection &)));
416 
417  ui.lv_users->setContextMenuPolicy(Qt::CustomContextMenu);
418  connect(ui.lv_users,
419  SIGNAL(customContextMenuRequested(const QPoint &)),
420  SLOT(users_customContextMenuRequested(const QPoint &)));
421 
422  ui.lv_authorities->setModel(roots);
423 
424  ui.lv_authorities->setContextMenuPolicy(Qt::CustomContextMenu);
425  connect(ui.lv_authorities,
426  SIGNAL(customContextMenuRequested(const QPoint &)),
427  SLOT(roots_customContextMenuRequested(const QPoint &)));
428 
429  cms = new QCA::CMS(this);
430 
431  QStringList ulist, rlist;
432  {
433  QSettings settings("Affinix", "CMS Signer");
434  ulist = settings.value("users").toStringList();
435  rlist = settings.value("roots").toStringList();
436  }
437 
438  users->load(ulist);
439  roots->load(rlist);
440  }
441 
442  ~MainWin()
443  {
444  QStringList ulist = users->save();
445  QStringList rlist = roots->save();
446 
447  QSettings settings("Affinix", "CMS Signer");
448  settings.setValue("users", ulist);
449  settings.setValue("roots", rlist);
450 
451  delete g_icons;
452  g_icons = 0;
453  }
454 
455  void setIcons(CertItemStore *store)
456  {
457  store->setIcon(CertItemStore::IconCert, g_icons->cert);
458  store->setIcon(CertItemStore::IconCrl, g_icons->crl);
459  store->setIcon(CertItemStore::IconKeyBundle, g_icons->keybundle);
460  store->setIcon(CertItemStore::IconPgpPub, g_icons->pgppub);
461  store->setIcon(CertItemStore::IconPgpSec, g_icons->pgpsec);
462  }
463 
464  QCA::CertificateCollection allCerts()
465  {
467 
468  // system store
469  col += QCA::systemStore();
470 
471  // additional roots configured in application
472  foreach (const CertItem &i, roots->items())
473  col.addCertificate(i.certificateChain().primary());
474 
475  // user chains
476  foreach (const CertItem &i, users->items()) {
477  foreach (const QCA::Certificate &cert, i.certificateChain())
478  col.addCertificate(cert);
479  }
480 
481  return col;
482  }
483 
484  QCA::CertificateChain complete(const QCA::CertificateChain &chain)
485  {
486  return chain.complete(allCerts().certificates());
487  }
488 
489 private Q_SLOTS:
490  void load_file()
491  {
492  QString fileName =
493  QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Identities (*.p12 *.pfx)"));
494  if (fileName.isEmpty())
495  return;
496 
497  setEnabled(false);
498  users->addFromFile(fileName);
499  }
500 
501  void load_device()
502  {
503  KeySelectDlg *w = new KeySelectDlg(this);
504  w->setAttribute(Qt::WA_DeleteOnClose, true);
505  w->setWindowModality(Qt::WindowModal);
506  connect(
507  w, SIGNAL(selected(const QCA::KeyStoreEntry &)), SLOT(load_device_finished(const QCA::KeyStoreEntry &)));
508  connect(w,
509  SIGNAL(viewCertificate(const QCA::CertificateChain &)),
510  SLOT(keyselect_viewCertificate(const QCA::CertificateChain &)));
511  w->setIcon(KeySelectDlg::IconCert, g_icons->cert);
512  w->setIcon(KeySelectDlg::IconCrl, g_icons->crl);
513  w->setIcon(KeySelectDlg::IconKeyBundle, g_icons->keybundle);
514  w->setIcon(KeySelectDlg::IconPgpPub, g_icons->pgppub);
515  w->setIcon(KeySelectDlg::IconPgpSec, g_icons->pgpsec);
516  w->show();
517  }
518 
519  void load_device_finished(const QCA::KeyStoreEntry &entry)
520  {
521  users->addFromKeyStore(entry);
522  }
523 
524  void load_root()
525  {
526  QString fileName =
527  QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Certificates (*.pem *.crt)"));
528  if (fileName.isEmpty())
529  return;
530 
532  if (cert.isNull()) {
533  QMessageBox::information(this, tr("Error"), tr("Error opening certificate file."));
534  return;
535  }
536 
537  roots->addUser(cert);
538  }
539 
540  void users_addSuccess(int req_id, int id)
541  {
542  if (req_id == auto_import_req_id) {
543  auto_import_req_id = -1;
544 
545  CertItem i = users->itemFromId(id);
546 
548  tr("User added"),
549  tr("This signature was made by a previously unknown user, and so the "
550  "user has now been added to the keyring as \"%1\".")
551  .arg(i.name()));
552 
553  verify_next();
554  return;
555  }
556 
557  ui.lv_users->selectionModel()->select(users->index(users->rowFromId(id)),
560 
561  setEnabled(true);
562  }
563 
564  void users_addFailed(int req_id)
565  {
566  Q_UNUSED(req_id);
567 
568  setEnabled(true);
569  }
570 
571  void mod_config()
572  {
575  this, tr("Error"), tr("No provider available supporting standard PKCS#11 configuration."));
576  return;
577  }
578 
579  Pkcs11ConfigDlg *w = new Pkcs11ConfigDlg(this);
580  w->setAttribute(Qt::WA_DeleteOnClose, true);
581  w->setWindowModality(Qt::WindowModal);
582  w->show();
583  }
584 
585  void users_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
586  {
587  Q_UNUSED(deselected);
588 
589  int at = -1;
590  if (!selected.indexes().isEmpty()) {
591  QModelIndex index = selected.indexes().first();
592  at = index.row();
593  }
594 
595  bool usable = false;
596  if (at != -1 && users->itemFromRow(at).isUsable())
597  usable = true;
598 
599  if (usable && !ui.pb_sign->isEnabled())
600  ui.pb_sign->setEnabled(true);
601  else if (!usable && ui.pb_sign->isEnabled())
602  ui.pb_sign->setEnabled(false);
603  }
604 
605  void item_view()
606  {
607  if (ui.lv_users->hasFocus()) {
608  QItemSelection selection = ui.lv_users->selectionModel()->selection();
609  if (selection.indexes().isEmpty())
610  return;
611  QModelIndex index = selection.indexes().first();
612  users_view(index.row());
613  } else // lv_authorities
614  {
615  QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
616  if (selection.indexes().isEmpty())
617  return;
618  QModelIndex index = selection.indexes().first();
619  roots_view(index.row());
620  }
621  }
622 
623  void item_rename()
624  {
625  if (ui.lv_users->hasFocus()) {
626  QItemSelection selection = ui.lv_users->selectionModel()->selection();
627  if (selection.indexes().isEmpty())
628  return;
629  QModelIndex index = selection.indexes().first();
630  users_rename(index.row());
631  } else // lv_authorities
632  {
633  QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
634  if (selection.indexes().isEmpty())
635  return;
636  QModelIndex index = selection.indexes().first();
637  roots_rename(index.row());
638  }
639  }
640 
641  void item_remove()
642  {
643  if (ui.lv_users->hasFocus()) {
644  QItemSelection selection = ui.lv_users->selectionModel()->selection();
645  if (selection.indexes().isEmpty())
646  return;
647  QModelIndex index = selection.indexes().first();
648  users_remove(index.row());
649  } else // lv_authorities
650  {
651  QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
652  if (selection.indexes().isEmpty())
653  return;
654  QModelIndex index = selection.indexes().first();
655  roots_remove(index.row());
656  }
657  }
658 
659  void users_view(int at)
660  {
661  CertItem i = users->itemFromRow(at);
662  CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this);
663  w->setAttribute(Qt::WA_DeleteOnClose, true);
664  w->show();
665  }
666 
667  void users_rename(int at)
668  {
669  QModelIndex index = users->index(at);
670  ui.lv_users->setFocus();
671  ui.lv_users->setCurrentIndex(index);
672  ui.lv_users->selectionModel()->select(
674  ui.lv_users->edit(index);
675  }
676 
677  void users_remove(int at)
678  {
679  users->removeItem(users->idFromRow(at));
680  }
681 
682  void roots_view(int at)
683  {
684  CertItem i = roots->itemFromRow(at);
685  CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this);
686  w->setAttribute(Qt::WA_DeleteOnClose, true);
687  w->show();
688  }
689 
690  void roots_rename(int at)
691  {
692  QModelIndex index = roots->index(at);
693  ui.lv_authorities->setFocus();
694  ui.lv_authorities->setCurrentIndex(index);
695  ui.lv_authorities->selectionModel()->select(
697  ui.lv_authorities->edit(index);
698  }
699 
700  void roots_remove(int at)
701  {
702  roots->removeItem(roots->idFromRow(at));
703  }
704 
705  void keyselect_viewCertificate(const QCA::CertificateChain &chain)
706  {
707  CertViewDlg *w = new CertViewDlg(complete(chain), (QWidget *)sender());
708  w->setAttribute(Qt::WA_DeleteOnClose, true);
709  w->show();
710  }
711 
712  void users_customContextMenuRequested(const QPoint &pos)
713  {
714  QItemSelection selection = ui.lv_users->selectionModel()->selection();
715  if (selection.indexes().isEmpty())
716  return;
717 
718  QMenu menu(this);
719  menu.addAction(actionView);
720  menu.addAction(actionRename);
721  menu.addAction(actionRemove);
722  menu.exec(ui.lv_users->viewport()->mapToGlobal(pos));
723  }
724 
725  void roots_customContextMenuRequested(const QPoint &pos)
726  {
727  QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
728  if (selection.indexes().isEmpty())
729  return;
730 
731  QMenu menu(this);
732  menu.addAction(actionView);
733  menu.addAction(actionRename);
734  menu.addAction(actionRemove);
735  menu.exec(ui.lv_authorities->viewport()->mapToGlobal(pos));
736  }
737 
738  void do_sign()
739  {
740  QItemSelection selection = ui.lv_users->selectionModel()->selection();
741  if (selection.indexes().isEmpty())
742  return;
743  QModelIndex index = selection.indexes().first();
744  int at = index.row();
745 
746  setEnabled(false);
747 
748  op = new SignOperation(ui.te_data->toPlainText().toUtf8(), users, users->idFromRow(at), cms, this);
749  connect(op, SIGNAL(loadError()), SLOT(sign_loadError()));
750  connect(op, SIGNAL(finished(const QString &)), SLOT(sign_finished(const QString &)));
751  connect(op, SIGNAL(error(const QString &)), SLOT(sign_error(const QString &)));
752  }
753 
754  void do_verify()
755  {
756  // prepare root certs
758 
759  // system store
760  col += QCA::systemStore();
761 
762  // additional roots configured in application
763  foreach (const CertItem &i, roots->items())
764  col.addCertificate(i.certificateChain().primary());
765 
766  // consider self-signed users as roots
767  // (it is therefore not possible with this application to
768  // have people in your keyring that you don't trust)
769  foreach (const CertItem &i, users->items()) {
770  QCA::Certificate cert = i.certificateChain().primary();
771  if (cert.isSelfSigned())
772  col.addCertificate(cert);
773  }
774 
775  // the self signed verify cert, if applicable
776  if (!self_signed_verify_cert.isNull()) {
777  col.addCertificate(self_signed_verify_cert);
778  self_signed_verify_cert = QCA::Certificate();
779  }
780 
781  cms->setTrustedCertificates(col);
782 
783  setEnabled(false);
784 
785  op = new VerifyOperation(ui.te_data->toPlainText().toUtf8(), ui.te_sig->toPlainText().toUtf8(), cms, this);
786  connect(op, SIGNAL(finished()), SLOT(verify_finished()));
787  connect(op, SIGNAL(error(const QString &)), SLOT(verify_error(const QString &)));
788  }
789 
790  void about()
791  {
792  int ver = qcaVersion();
793  int maj = (ver >> 16) & 0xff;
794  int min = (ver >> 8) & 0xff;
795  int bug = ver & 0xff;
796  QString verstr;
797  verstr.sprintf("%d.%d.%d", maj, min, bug);
798 
799  QString str;
800  str += tr("CMS Signer version %1 by Justin Karneges").arg(VERSION) + '\n';
801  str += tr("A simple tool for creating and verifying digital signatures.") + '\n';
802  str += '\n';
803  str += tr("Using QCA version %1").arg(verstr) + '\n';
804  str += '\n';
805  str += tr("Icons by Jason Kim") + '\n';
806 
808  foreach (QCA::Provider *p, list) {
809  QString credit = p->credit();
810  if (!credit.isEmpty()) {
811  str += '\n';
812  str += credit;
813  }
814  }
815 
816  QMessageBox::about(this, tr("About CMS Signer"), str);
817  }
818 
819  void sign_loadError()
820  {
821  delete op;
822  op = 0;
823 
824  setEnabled(true);
825  }
826 
827  void sign_finished(const QString &sig)
828  {
829  delete op;
830  op = 0;
831 
832  ui.te_sig->setPlainText(sig);
833 
834  setEnabled(true);
835  }
836 
837  void sign_error(const QString &msg)
838  {
839  delete op;
840  op = 0;
841 
842  setEnabled(true);
843 
844  QMessageBox::information(this, tr("Error"), msg);
845  }
846 
847  void verify_finished()
848  {
849  QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
850  delete op;
851  op = 0;
852 
853  // import the cert?
854  QCA::SecureMessageKey skey = signer.key();
855  if (!skey.isNull()) {
857 
858  int at = -1;
859  QList<CertItem> items = users->items();
860  for (int n = 0; n < items.count(); ++n) {
861  const CertItem &i = items[n];
862  if (i.certificateChain().primary() == chain.primary()) {
863  at = n;
864  break;
865  }
866  }
867 
868  // add
869  if (at == -1) {
870  auto_import_req_id = users->addUser(chain);
871  return;
872  }
873  // update
874  else {
875  users->updateChain(users->idFromRow(at), chain);
876  }
877  }
878 
879  verify_next();
880  }
881 
882  void verify_next()
883  {
884  setEnabled(true);
885 
886  QMessageBox::information(this, tr("Verify"), tr("Signature verified successfully."));
887  }
888 
889  void verify_error(const QString &msg)
890  {
891  QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
892  delete op;
893  op = 0;
894 
895  QCA::SecureMessageKey skey = signer.key();
896  if (signer.keyValidity() == QCA::ErrorSelfSigned && !skey.isNull()) {
898  if (chain.count() == 1 && chain.primary().isSelfSigned()) {
899  QCA::Certificate cert = chain.primary();
900 
901  int ret = QMessageBox::warning(
902  this,
903  tr("Self-signed certificate"),
904  tr("<qt>The signature is made by an unknown user, and the certificate is self-signed.<br>\n"
905  "<br>\n"
906  "<nobr>Common Name: %1</nobr><br>\n"
907  "<nobr>SHA1 Fingerprint: %2</nobr><br>\n"
908  "<br>\n"
909  "Trust the certificate?</qt>")
910  .arg(cert.commonName(), get_fingerprint(cert)),
913 
914  if (ret == QMessageBox::Yes) {
915  self_signed_verify_cert = cert;
916  do_verify();
917  return;
918  }
919  }
920  }
921 
922  setEnabled(true);
923 
924  QMessageBox::information(this, tr("Error"), msg);
925  }
926 };
927 
928 int main(int argc, char **argv)
929 {
930  QCA::Initializer qcaInit;
931  QApplication qapp(argc, argv);
932 
933  qapp.setApplicationName(MainWin::tr("CMS Signer"));
934 
935  if (!QCA::isSupported("cert,crl,cms")) {
937  0,
938  qapp.applicationName() + ": " + MainWin::tr("Error"),
939  MainWin::tr(
940  "No support for CMS is available. Please install an appropriate QCA plugin, such as qca-ossl."));
941  return 1;
942  }
943 
945 
946  MainWin mainWin;
947  mainWin.show();
948  return qapp.exec();
949 }
950 
951 #include "main.moc"
bool success() const
Indicates whether or not the operation was successful or failed.
Q_OBJECTQ_OBJECT
CertificateChain complete(const QList< Certificate > &issuers=QList< Certificate >(), Validity *result=nullptr) const
Complete a certificate chain for the primary certificate, using the rest of the certificates in the c...
Definition: qca_cert.h:1309
@ ErrorExpiredCA
The Certificate Authority has expired.
Definition: qca_cert.h:509
@ ErrorInvalidPurpose
The purpose does not match the intended usage.
Definition: qca_cert.h:503
Error errorCode() const
Returns the failure code.
void end()
Complete an operation.
@ Ascii
PEM/ascii-armored.
QCA_EXPORT CertificateCollection systemStore()
Get system-wide root Certificate Authority (CA) certificates.
Q_SLOTSQ_SLOTS
@ ErrorExpired
The certificate has expired, or is not yet valid (e.g.
Definition: qca_cert.h:507
@ ErrorPathLengthExceeded
The path length from the root CA to this certificate is too long.
Definition: qca_cert.h:506
Error
Errors for secure messages.
void customContextMenuRequested(const QPoint &pos)
int count(const T &value) const const
WindowModal
IdentityResult identityResult() const
get the results of the identity check on this signature
@ ErrorEncryptUntrusted
encrypting key is untrusted
QObject * sender() const const
@ InvalidSignature
valid key provided, but signature failed
CustomContextMenu
QString hashToString(const MemoryRegion &array)
Hash a byte array, returning it as a printable string
@ Valid
indentity is verified, matches signature
static Certificate fromPEMFile(const QString &fileName, ConvertResult *result=nullptr, const QString &provider=QString())
Import the certificate from a file.
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
bool close()
void startVerify(const QByteArray &detachedSig=QByteArray())
Start a verification operation.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
@ ErrorCertKeyMismatch
certificate and private key don't match
void startSign(SignMode m=Message)
@ ErrorSignerInvalid
signing key is invalid in some way
QString commonName() const
The common name of the subject of the certificate.
void setX509CertificateChain(const CertificateChain &c)
Set the public key part of this X.509 key.
void update(const QByteArray &in)
Process a message (or the next part of a message) in the current operation.
@ ErrorFormat
input format was bad
bool isNull() const
Test if the key is null (empty)
SecureMessageKey key() const
get the key associated with this signature
@ ValidityGood
The certificate is valid.
Definition: qca_cert.h:498
bool isNull() const
Returns true for null object.
QModelIndexList indexes() const const
void setSigner(const SecureMessageKey &key)
Set the signer for a signed message.
QString & sprintf(const char *cformat,...)
@ InvalidKey
invalid key provided
void setTrustedCertificates(const CertificateCollection &trusted)
Set the trusted certificates to use for the messages built using this CMS object.
@ ErrorEncryptExpired
encrypting key is expired
QTextStream & hex(QTextStream &stream)
void about(QWidget *parent, const QString &text, const QString &title=QString(), Options options=Notify)
@ ErrorPassphrase
passphrase was either wrong or not provided
QByteArray mid(int pos, int len) const const
QByteArray toDER() const
Export the Certificate into a DER format.
bool isEmpty() const const
@ ErrorRejected
The root CA rejected the certificate purpose.
Definition: qca_cert.h:499
@ ErrorSignerExpired
signing key is expired
@ ErrorNeedCard
pgp card is missing
virtual QString credit() const
Optional credit text for the provider.
@ Detached
the signature is detached
@ ErrorInvalidCA
The Certificate Authority is invalid.
Definition: qca_cert.h:502
bool isNull() const
Test if the certificate is empty (null)
@ ErrorSelfSigned
The certificate is self-signed, and is not found in the list of trusted certificates.
Definition: qca_cert.h:504
void setX509PrivateKey(const PrivateKey &k)
Set the private key part of this X.509 key.
void setEnabled(bool)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
int row() const const
Q_SIGNALSQ_SIGNALS
Validity keyValidity() const
get the results of the key validation check on this signature
CertificateChain x509CertificateChain() const
The X.509 certificate chain (public part) for this key.
const Certificate & primary() const
Return the primary (end-user) Certificate.
Definition: qca_cert.h:1249
bool isEmpty() const const
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QByteArray signature() const
The signature for the message.
@ ErrorUnknown
other error
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
QCA_EXPORT bool isSupported(const char *features, const QString &provider=QString())
Test if a capability (algorithm) is available.
void update(Part *part, const QByteArray &data, qint64 dataSize)
bool isSelfSigned() const
Test if the Certificate is self-signed.
@ ErrorRevoked
The certificate has been revoked.
Definition: qca_cert.h:505
QCA_EXPORT int qcaVersion()
The current version of QCA.
@ ErrorValidityUnknown
Validity is unknown.
Definition: qca_cert.h:510
static void start()
Initialize all key store providers.
@ ErrorEncryptInvalid
encrypting key is invalid in some way
int size() const const
void setFormat(Format f)
Set the Format used for messages.
Validity
The validity (or otherwise) of a certificate.
Definition: qca_cert.h:496
SecureMessageSignature signer() const
Information on the signer for the message.
void about(QWidget *parent, const QString &title, const QString &text)
QMessageBox::StandardButton information(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QString tr(const char *sourceText, const char *disambiguation, int n)
void addCertificate(const Certificate &cert)
Append a Certificate to this collection.
@ ErrorUntrusted
The certificate is not trusted.
Definition: qca_cert.h:500
@ ErrorSignatureFailed
The signature does not match.
Definition: qca_cert.h:501
QMessageBox::StandardButton critical(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QObject * parent() const const
WA_DeleteOnClose
T value(int i) const const
QCA_EXPORT ProviderList providers()
Return a list of the current providers.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Fri Sep 22 2023 03:49:30 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.