QCA

cmssigner/main.cpp
1/*
2 Copyright (C) 2007 Justin Karneges <justin@affinix.com>
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
40class Icons
41{
42public:
43 QPixmap cert, crl, keybundle, pgppub, pgpsec;
44};
45
46Icons *g_icons = 0;
47
48//----------------------------------------------------------------------------
49// Operation
50//----------------------------------------------------------------------------
51class Operation : public QObject
52{
54public:
55 Operation(QObject *parent = 0)
57 {
58 }
59
61 void error(const QString &str);
62};
63
64static QString validityToString(QCA::Validity v)
65{
66 QString s;
67 switch (v) {
69 s = Operation::tr("Validated");
70 break;
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;
90 s = Operation::tr("Certificate has been revoked");
91 break;
93 s = Operation::tr("Maximum certificate chain length exceeded");
94 break;
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
109static 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
148static 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
170class SignOperation : public Operation
171{
173private:
174 QByteArray in;
175 CertItemStore *store;
176 int id;
177 QCA::CMS *cms;
178 CertItemPrivateLoader *loader;
180 int pending;
181
182public:
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
197 void loadError();
198 void finished(const QString &sig);
199
200private 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
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
264class VerifyOperation : public Operation
265{
267private:
268 QByteArray in, sig;
269 QCA::CMS *cms;
271 int pending;
272
273public:
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
294 void finished();
295
296private 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//----------------------------------------------------------------------------
342static 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
354class MainWin : public QMainWindow
355{
357private:
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
366public:
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
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
489private 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);
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 {
573 if (!Pkcs11ConfigDlg::isSupported()) {
575 this, tr("Error"), tr("No provider available supporting standard PKCS#11 configuration."));
576 return;
577 }
578
579 Pkcs11ConfigDlg *w = new Pkcs11ConfigDlg(this);
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);
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);
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());
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
928int 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"),
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"
Cryptographic Message Syntax messaging system.
void setTrustedCertificates(const CertificateCollection &trusted)
Set the trusted certificates to use for the messages built using this CMS object.
A chain of related Certificates.
Definition qca_cert.h:1226
const Certificate & primary() const
Return the primary (end-user) Certificate.
Definition qca_cert.h:1249
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
Bundle of Certificates and CRLs.
Definition qca_cert.h:1929
void addCertificate(const Certificate &cert)
Append a Certificate to this collection.
Public Key (X.509) certificate.
Definition qca_cert.h:857
QString commonName() const
The common name of the subject of the certificate.
bool isSelfSigned() const
Test if the Certificate is self-signed.
static Certificate fromPEMFile(const QString &fileName, ConvertResult *result=nullptr, const QString &provider=QString())
Import the certificate from a file.
bool isNull() const
Test if the certificate is empty (null)
QByteArray toDER() const
Export the Certificate into a DER format.
General class for hashing algorithms.
Definition qca_basic.h:209
QString hashToString(const MemoryRegion &array)
Hash a byte array, returning it as a printable string
Convenience method for initialising and cleaning up QCA.
Definition qca_core.h:660
Single entry in a KeyStore.
static void start()
Initialize all key store providers.
bool isNull() const
Test if the key is null (empty)
Generic private key.
Algorithm provider.
Definition qca_core.h:765
virtual QString credit() const
Optional credit text for the provider.
Key for SecureMessage system.
void setX509PrivateKey(const PrivateKey &k)
Set the private key part of this X.509 key.
bool isNull() const
Returns true for null object.
CertificateChain x509CertificateChain() const
The X.509 certificate chain (public part) for this key.
void setX509CertificateChain(const CertificateChain &c)
Set the public key part of this X.509 key.
SecureMessage signature.
IdentityResult identityResult() const
get the results of the identity check on this signature
@ InvalidSignature
valid key provided, but signature failed
@ Valid
indentity is verified, matches signature
@ InvalidKey
invalid key provided
SecureMessageKey key() const
get the key associated with this signature
Validity keyValidity() const
get the results of the key validation check on this signature
Class representing a secure message.
bool success() const
Indicates whether or not the operation was successful or failed.
QByteArray signature() const
The signature for the message.
void setFormat(Format f)
Set the Format used for messages.
void startSign(SignMode m=Message)
SecureMessageSignature signer() const
Information on the signer for the message.
void setSigner(const SecureMessageKey &key)
Set the signer for a signed message.
void startVerify(const QByteArray &detachedSig=QByteArray())
Start a verification operation.
Error
Errors for secure messages.
@ ErrorSignerExpired
signing key is expired
@ ErrorEncryptExpired
encrypting key is expired
@ ErrorSignerInvalid
signing key is invalid in some way
@ ErrorEncryptUntrusted
encrypting key is untrusted
@ ErrorEncryptInvalid
encrypting key is invalid in some way
@ ErrorCertKeyMismatch
certificate and private key don't match
@ ErrorFormat
input format was bad
@ ErrorPassphrase
passphrase was either wrong or not provided
@ ErrorNeedCard
pgp card is missing
void end()
Complete an operation.
@ Detached
the signature is detached
@ Ascii
PEM/ascii-armored.
Error errorCode() const
Returns the failure code.
void update(const QByteArray &in)
Process a message (or the next part of a message) in the current operation.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
Validity
The validity (or otherwise) of a certificate.
Definition qca_cert.h:497
@ ErrorValidityUnknown
Validity is unknown.
Definition qca_cert.h:510
@ ErrorRevoked
The certificate has been revoked.
Definition qca_cert.h:505
@ ErrorUntrusted
The certificate is not trusted.
Definition qca_cert.h:500
@ 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
@ ErrorSignatureFailed
The signature does not match.
Definition qca_cert.h:501
@ ErrorInvalidPurpose
The purpose does not match the intended usage.
Definition qca_cert.h:503
@ ErrorExpiredCA
The Certificate Authority has expired.
Definition qca_cert.h:509
@ ErrorSelfSigned
The certificate is self-signed, and is not found in the list of trusted certificates.
Definition qca_cert.h:504
@ ErrorInvalidCA
The Certificate Authority is invalid.
Definition qca_cert.h:502
@ ValidityGood
The certificate is valid.
Definition qca_cert.h:498
@ ErrorRejected
The root CA rejected the certificate purpose.
Definition qca_cert.h:499
QCA_EXPORT bool isSupported(const char *features, const QString &provider=QString())
Test if a capability (algorithm) is available.
QCA_EXPORT ProviderList providers()
Return a list of the current providers.
QCA_EXPORT CertificateCollection systemStore()
Get system-wide root Certificate Authority (CA) certificates.
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
bool isEmpty() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
qsizetype size() const const
QCA_EXPORT int qcaVersion()
The current version of QCA.
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QModelIndexList indexes() const const
qsizetype count() const const
T value(qsizetype i) const const
void about(QWidget *parent, const QString &title, const QString &text)
StandardButton critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
StandardButton information(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
int row() const const
Q_OBJECTQ_OBJECT
Q_SIGNALSQ_SIGNALS
Q_SLOTSQ_SLOTS
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
QObject * sender() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool isNull() const const
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
CustomContextMenu
WA_DeleteOnClose
WindowModal
QTextStream & hex(QTextStream &stream)
bool close()
void customContextMenuRequested(const QPoint &pos)
void setEnabled(bool)
void setAttribute(Qt::WidgetAttribute attribute, bool on)
void show()
void setWindowModality(Qt::WindowModality windowModality)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:26 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.