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)