29#include "certviewdlg.h"
30#include "keyselectdlg.h"
31#include "pkcs11configdlg/pkcs11configdlg.h"
32#include "ui_mainwin.h"
35#include "import_plugins.h"
38#define VERSION "1.0.0"
43 QPixmap cert, crl, keybundle, pgppub, pgpsec;
61 void error(
const QString &str);
72 s =
Operation::tr(
"Root CA is marked to reject the specified purpose");
75 s =
Operation::tr(
"Certificate not trusted for the required purpose");
93 s =
Operation::tr(
"Maximum certificate chain length exceeded");
138 s =
Operation::tr(
"Certificate and private key don't match.");
170class SignOperation :
public Operation
175 CertItemStore *store;
178 CertItemPrivateLoader *loader;
179 QCA::SecureMessage *msg;
183 SignOperation(
const QByteArray &_in, CertItemStore *_store,
int _id, QCA::CMS *_cms,
QObject *
parent = 0)
191 loader =
new CertItemPrivateLoader(store,
this);
192 connect(loader, SIGNAL(finished()), SLOT(loader_finished()));
198 void finished(
const QString &sig);
201 void loader_finished()
203 QCA::PrivateKey privateKey = loader->privateKey();
207 if (privateKey.
isNull()) {
212 CertItem item = store->itemFromId(
id);
214 QCA::SecureMessageKey signer;
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);
231 QByteArray buf = in.mid(0, 16384 - pending);
232 in = in.mid(buf.
size());
233 pending += buf.
size();
237 void msg_bytesWritten(
int x)
241 if (in.isEmpty() && pending == 0)
249 if (!msg->success()) {
250 QString str = smErrorToString(msg->errorCode());
253 emit error(
tr(
"Error during sign operation.\nReason: %1").arg(str));
257 QByteArray result = msg->signature();
264class VerifyOperation :
public Operation
270 QCA::SecureMessage *msg;
274 QCA::SecureMessageSignature signer;
276 VerifyOperation(
const QByteArray &_in,
const QByteArray &_sig, QCA::CMS *_cms,
QObject *
parent = 0)
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);
299 QByteArray buf = in.
mid(0, 16384 - pending);
301 pending += buf.
size();
305 void msg_bytesWritten(
int x)
309 if (in.isEmpty() && pending == 0)
317 if (!msg->success()) {
318 QString str = smErrorToString(msg->errorCode());
321 emit error(
tr(
"Error during verify operation.\nReason: %1").arg(str));
325 signer = msg->signer();
330 QString str = smsIdentityToString(signer);
331 emit error(
tr(
"Verification failed!\nReason: %1").arg(str));
346 for (
int n = 0; n <
hex.count(); ++n) {
347 if (n != 0 && n % 2 == 0)
359 CertItemStore *users, *roots;
362 QAction *actionView, *actionRename, *actionRemove;
363 QCA::Certificate self_signed_verify_cert;
364 int auto_import_req_id;
370 , auto_import_req_id(-1)
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");
382 printf(
"Warning: not all icons loaded\n");
384 users =
new CertItemStore(
this);
385 roots =
new CertItemStore(
this);
390 connect(users, SIGNAL(addSuccess(
int,
int)), SLOT(users_addSuccess(
int,
int)));
391 connect(users, SIGNAL(addFailed(
int)), SLOT(users_addFailed(
int)));
393 actionView =
new QAction(
tr(
"&View"),
this);
394 actionRename =
new QAction(
tr(
"Re&name"),
this);
395 actionRemove =
new QAction(
tr(
"Rem&ove"),
this);
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()));
406 connect(actionView, SIGNAL(triggered()), SLOT(item_view()));
407 connect(actionRename, SIGNAL(triggered()), SLOT(item_rename()));
408 connect(actionRemove, SIGNAL(triggered()), SLOT(item_remove()));
410 ui.pb_sign->setEnabled(
false);
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 &)));
420 SLOT(users_customContextMenuRequested(
const QPoint &)));
422 ui.lv_authorities->setModel(roots);
427 SLOT(roots_customContextMenuRequested(
const QPoint &)));
429 cms =
new QCA::CMS(
this);
431 QStringList ulist, rlist;
433 QSettings settings(
"Affinix",
"CMS Signer");
434 ulist = settings.
value(
"users").toStringList();
435 rlist = settings.
value(
"roots").toStringList();
444 QStringList ulist = users->save();
445 QStringList rlist = roots->save();
447 QSettings settings(
"Affinix",
"CMS Signer");
448 settings.setValue(
"users", ulist);
449 settings.setValue(
"roots", rlist);
455 void setIcons(CertItemStore *store)
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);
464 QCA::CertificateCollection allCerts()
466 QCA::CertificateCollection col;
472 foreach (
const CertItem &i, roots->items())
476 foreach (
const CertItem &i, users->items()) {
477 foreach (
const QCA::Certificate &cert, i.certificateChain())
484 QCA::CertificateChain complete(
const QCA::CertificateChain &chain)
486 return chain.
complete(allCerts().certificates());
498 users->addFromFile(fileName);
503 KeySelectDlg *w =
new KeySelectDlg(
this);
507 w, SIGNAL(selected(
const QCA::KeyStoreEntry &)), SLOT(load_device_finished(
const QCA::KeyStoreEntry &)));
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);
519 void load_device_finished(
const QCA::KeyStoreEntry &entry)
521 users->addFromKeyStore(entry);
537 roots->addUser(cert);
540 void users_addSuccess(
int req_id,
int id)
542 if (req_id == auto_import_req_id) {
543 auto_import_req_id = -1;
545 CertItem i = users->itemFromId(
id);
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\".")
557 ui.lv_users->selectionModel()->select(users->index(users->rowFromId(
id)),
564 void users_addFailed(
int req_id)
573 if (!Pkcs11ConfigDlg::isSupported()) {
575 this,
tr(
"Error"),
tr(
"No provider available supporting standard PKCS#11 configuration."));
579 Pkcs11ConfigDlg *w =
new Pkcs11ConfigDlg(
this);
585 void users_selectionChanged(
const QItemSelection &selected,
const QItemSelection &deselected)
587 Q_UNUSED(deselected);
590 if (!selected.
indexes().isEmpty()) {
591 QModelIndex index = selected.
indexes().first();
596 if (at != -1 && users->itemFromRow(at).isUsable())
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);
607 if (ui.lv_users->hasFocus()) {
608 QItemSelection selection = ui.lv_users->selectionModel()->selection();
609 if (selection.
indexes().isEmpty())
611 QModelIndex index = selection.
indexes().first();
612 users_view(index.
row());
615 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
616 if (selection.
indexes().isEmpty())
618 QModelIndex index = selection.
indexes().first();
619 roots_view(index.
row());
625 if (ui.lv_users->hasFocus()) {
626 QItemSelection selection = ui.lv_users->selectionModel()->selection();
627 if (selection.
indexes().isEmpty())
629 QModelIndex index = selection.
indexes().first();
630 users_rename(index.
row());
633 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
634 if (selection.
indexes().isEmpty())
636 QModelIndex index = selection.
indexes().first();
637 roots_rename(index.
row());
643 if (ui.lv_users->hasFocus()) {
644 QItemSelection selection = ui.lv_users->selectionModel()->selection();
645 if (selection.
indexes().isEmpty())
647 QModelIndex index = selection.
indexes().first();
648 users_remove(index.
row());
651 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
652 if (selection.
indexes().isEmpty())
654 QModelIndex index = selection.
indexes().first();
655 roots_remove(index.
row());
659 void users_view(
int at)
661 CertItem i = users->itemFromRow(at);
662 CertViewDlg *w =
new CertViewDlg(complete(i.certificateChain()),
this);
667 void users_rename(
int at)
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);
677 void users_remove(
int at)
679 users->removeItem(users->idFromRow(at));
682 void roots_view(
int at)
684 CertItem i = roots->itemFromRow(at);
685 CertViewDlg *w =
new CertViewDlg(complete(i.certificateChain()),
this);
690 void roots_rename(
int at)
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);
700 void roots_remove(
int at)
702 roots->removeItem(roots->idFromRow(at));
705 void keyselect_viewCertificate(
const QCA::CertificateChain &chain)
707 CertViewDlg *w =
new CertViewDlg(complete(chain), (
QWidget *)
sender());
712 void users_customContextMenuRequested(
const QPoint &
pos)
714 QItemSelection selection = ui.lv_users->selectionModel()->selection();
715 if (selection.
indexes().isEmpty())
719 menu.addAction(actionView);
720 menu.addAction(actionRename);
721 menu.addAction(actionRemove);
722 menu.exec(ui.lv_users->viewport()->mapToGlobal(
pos));
725 void roots_customContextMenuRequested(
const QPoint &
pos)
727 QItemSelection selection = ui.lv_authorities->selectionModel()->selection();
728 if (selection.
indexes().isEmpty())
732 menu.addAction(actionView);
733 menu.addAction(actionRename);
734 menu.addAction(actionRemove);
735 menu.exec(ui.lv_authorities->viewport()->mapToGlobal(
pos));
740 QItemSelection selection = ui.lv_users->selectionModel()->selection();
741 if (selection.
indexes().isEmpty())
743 QModelIndex index = selection.
indexes().first();
744 int at = index.
row();
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 &)));
757 QCA::CertificateCollection col;
763 foreach (
const CertItem &i, roots->items())
769 foreach (
const CertItem &i, users->items()) {
770 QCA::Certificate cert = i.certificateChain().
primary();
776 if (!self_signed_verify_cert.isNull()) {
778 self_signed_verify_cert = QCA::Certificate();
781 cms->setTrustedCertificates(col);
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 &)));
793 int maj = (ver >> 16) & 0xff;
794 int min = (ver >> 8) & 0xff;
795 int bug = ver & 0xff;
797 verstr.sprintf(
"%d.%d.%d", maj, min, bug);
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';
803 str +=
tr(
"Using QCA version %1").
arg(verstr) +
'\n';
805 str +=
tr(
"Icons by Jason Kim") +
'\n';
808 foreach (QCA::Provider *p, list) {
809 QString credit = p->
credit();
819 void sign_loadError()
827 void sign_finished(
const QString &sig)
832 ui.te_sig->setPlainText(sig);
837 void sign_error(
const QString &msg)
847 void verify_finished()
849 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
854 QCA::SecureMessageKey skey = signer.
key();
859 QList<CertItem> items = users->items();
860 for (
int n = 0; n < items.
count(); ++n) {
861 const CertItem &i = items[n];
870 auto_import_req_id = users->addUser(chain);
875 users->updateChain(users->idFromRow(at), chain);
889 void verify_error(
const QString &msg)
891 QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer;
895 QCA::SecureMessageKey skey = signer.
key();
899 QCA::Certificate cert = chain.
primary();
903 tr(
"Self-signed certificate"),
904 tr(
"<qt>The signature is made by an unknown user, and the certificate is self-signed.<br>\n"
906 "<nobr>Common Name: %1</nobr><br>\n"
907 "<nobr>SHA1 Fingerprint: %2</nobr><br>\n"
909 "Trust the certificate?</qt>")
910 .arg(cert.
commonName(), get_fingerprint(cert)),
915 self_signed_verify_cert = cert;
928int main(
int argc,
char **argv)
933 qapp.setApplicationName(
MainWin::tr(
"CMS Signer"));
938 qapp.applicationName() +
": " +
MainWin::tr(
"Error"),
940 "No support for CMS is available. Please install an appropriate QCA plugin, such as qca-ossl."));
const Certificate & primary() const
Return the primary (end-user) Certificate.
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...
void addCertificate(const Certificate &cert)
Append a Certificate to this collection.
Public Key (X.509) certificate.
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.
QString hashToString(const MemoryRegion &array)
Hash a byte array, returning it as a printable string
Convenience method for initialising and cleaning up QCA.
static void start()
Initialize all key store providers.
bool isNull() const
Test if the key is null (empty)
virtual QString credit() const
Optional credit text for the provider.
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.
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
Error
Errors for secure messages.
@ ErrorUnknown
other error
@ 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
@ Detached
the signature is detached
@ Ascii
PEM/ascii-armored.
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.
@ ErrorValidityUnknown
Validity is unknown.
@ ErrorRevoked
The certificate has been revoked.
@ ErrorUntrusted
The certificate is not trusted.
@ ErrorExpired
The certificate has expired, or is not yet valid (e.g.
@ ErrorPathLengthExceeded
The path length from the root CA to this certificate is too long.
@ ErrorSignatureFailed
The signature does not match.
@ ErrorInvalidPurpose
The purpose does not match the intended usage.
@ ErrorExpiredCA
The Certificate Authority has expired.
@ ErrorSelfSigned
The certificate is self-signed, and is not found in the list of trusted certificates.
@ ErrorInvalidCA
The Certificate Authority is invalid.
@ ValidityGood
The certificate is valid.
@ ErrorRejected
The root CA rejected the certificate purpose.
QList< Provider * > ProviderList
Convenience representation for the plugin providers.
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.
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
QMainWindow(QWidget *parent, Qt::WindowFlags flags)
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 warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
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
QTextStream & hex(QTextStream &stream)