aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorubbo <ubbo@34ebc366-c3a9-4b3c-9f84-69acf7962910>2012-08-05 23:26:56 +0000
committerubbo <ubbo@34ebc366-c3a9-4b3c-9f84-69acf7962910>2012-08-05 23:26:56 +0000
commit4db2fdfca8c9c5e226ff1589f8c8a88ebf879eca (patch)
treed6340ee2b354096b435e4fd41c2ff3926dab1e45
parentsigning text works (diff)
downloadgpg4usb-4db2fdfca8c9c5e226ff1589f8c8a88ebf879eca.tar.gz
gpg4usb-4db2fdfca8c9c5e226ff1589f8c8a88ebf879eca.zip
some work on verify
git-svn-id: http://cpunk.de/svn/src/gpg4usb/branches/0.3.2-mac@943 34ebc366-c3a9-4b3c-9f84-69acf7962910
-rw-r--r--TODO.kgpgport1
-rw-r--r--gpg4usb.pro9
-rw-r--r--kgpg/transactions/kgpgverify.cpp204
-rw-r--r--kgpg/transactions/kgpgverify.h90
-rw-r--r--mainwindow.cpp16
-rw-r--r--verifynotification.cpp160
-rw-r--r--verifynotification.h5
7 files changed, 466 insertions, 19 deletions
diff --git a/TODO.kgpgport b/TODO.kgpgport
index b19fed3..1267f3f 100644
--- a/TODO.kgpgport
+++ b/TODO.kgpgport
@@ -3,3 +3,4 @@ TODO:
-reactivate keyimportdetaildialog
- sign should work for more than one secret keyid
- why is listkeys called so often (twice?)
+- signverify on one button like kgpg?
diff --git a/gpg4usb.pro b/gpg4usb.pro
index 5801afd..2953f79 100644
--- a/gpg4usb.pro
+++ b/gpg4usb.pro
@@ -71,7 +71,10 @@ HEADERS += attachments.h \
kgpg/transactions/kgpgimport.h \
kgpg/transactions/kgpgdelkey.h \
kgpg/transactions/kgpggeneratekey.h \
- kgpg/transactions/kgpgsigntext.h
+ kgpg/transactions/kgpgsigntext.h \
+ kgpg/transactions/kgpgverify.h \
+ #kgpg/model/kgpgitemmodel.h \
+ #kgpg/model/kgpgitemnode.h
SOURCES += attachments.cpp \
@@ -126,7 +129,9 @@ SOURCES += attachments.cpp \
kgpg/transactions/kgpgimport.cpp \
kgpg/transactions/kgpgdelkey.cpp \
kgpg/transactions/kgpggeneratekey.cpp \
- kgpg/transactions/kgpgsigntext.cpp
+ kgpg/transactions/kgpgsigntext.cpp \
+ kgpg/transactions/kgpgverify.cpp \
+ #kgpg/model/kgpgitemmodel.cpp
RC_FILE = gpg4usb.rc
diff --git a/kgpg/transactions/kgpgverify.cpp b/kgpg/transactions/kgpgverify.cpp
new file mode 100644
index 0000000..e9dbb36
--- /dev/null
+++ b/kgpg/transactions/kgpgverify.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2012 Rolf Eike Beer <[email protected]>
+ */
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kgpgverify.h"
+
+#include "../gpgproc.h"
+#include "../core/KGpgKeyNode.h"
+//#include "../model/kgpgitemmodel.h"
+
+//#include <KGlobal>
+//#include <KLocale>
+
+KGpgVerify::KGpgVerify(QObject *parent, const QString &text)
+ : KGpgTextOrFileTransaction(parent, text),
+ m_fileIndex(-1)
+{
+}
+
+KGpgVerify::KGpgVerify(QObject *parent, const QList<QUrl> &files)
+ : KGpgTextOrFileTransaction(parent, files),
+ m_fileIndex(0)
+{
+}
+
+KGpgVerify::~KGpgVerify()
+{
+}
+
+QStringList
+KGpgVerify::command() const
+{
+ QStringList ret(QLatin1String("--verify"));
+
+ return ret;
+}
+
+bool
+KGpgVerify::nextLine(const QString &line)
+{
+ if (line.startsWith(QLatin1String("[GNUPG:] NO_PUBKEY "))) {
+ setSuccess(TS_MISSING_KEY);
+ m_missingId = line.mid(19).simplified();
+ return false;
+ }
+
+ if (line.startsWith(QLatin1String("[GNUPG:] ")) &&
+ line.contains(QLatin1String("SIG"))) {
+ if (line.startsWith(QLatin1String("[GNUPG:] BADSIG")))
+ setSuccess(KGpgVerify::TS_BAD_SIGNATURE);
+ else
+ setSuccess(KGpgTransaction::TS_OK);
+ }
+
+ return KGpgTextOrFileTransaction::nextLine(line);
+}
+
+void
+KGpgVerify::finish()
+{
+ // GnuPG will return error code 2 if it wasn't able to verify the file.
+ // If it complained about a missing signature before that is fine.
+ if (((getProcess()->exitCode() == 2) && (getSuccess() == TS_MISSING_KEY)) ||
+ ((getProcess()->exitCode() == 1) && (getSuccess() == TS_BAD_SIGNATURE)))
+ return;
+
+ KGpgTextOrFileTransaction::finish();
+}
+
+static QString
+sigTimeMessage(const QString &sigtime)
+{
+ QDateTime stamp;
+ if (sigtime.contains(QLatin1Char('T'))) {
+ stamp = QDateTime::fromString(sigtime, Qt::ISODate);
+ } else {
+ bool ok;
+ qint64 secs = sigtime.toLongLong(&ok);
+ if (ok)
+ stamp = QDateTime::fromMSecsSinceEpoch(secs * 1000);
+ }
+
+ if (!stamp.isValid())
+ return QString();
+
+/* return tr("first argument is formatted date, second argument is formatted time",
+ "The signature was created at %1 %2",
+ KGlobal::locale()->formatDate(stamp.date(), KLocale::LongDate),
+ KGlobal::locale()->formatTime(stamp.time(), KLocale::LongDate)) +
+ QLatin1String("<br/>");*/
+ return "todo";
+}
+
+/*
+QString
+KGpgVerify::getReport(const QStringList &log, const KGpgItemModel *model)
+{
+ QString result;
+ // newer versions of GnuPG emit both VALIDSIG and GOODSIG
+ // for a good signature. Since VALIDSIG has more information
+ // we use that.
+ const QRegExp validsig(QLatin1String("^\\[GNUPG:\\] VALIDSIG([ ]+[^ ]+){10,}.*$"));
+ const bool useGoodSig = (model != NULL) && (log.indexOf(validsig) == -1);
+ QString sigtime; // timestamp of signature creation
+
+ foreach (const QString &line, log) {
+ if (!line.startsWith(QLatin1String("[GNUPG:] ")))
+ continue;
+
+ const QString msg = line.mid(9);
+
+ if (msg.startsWith(QLatin1String("VALIDSIG ")) && !useGoodSig) {
+ // from GnuPG source, doc/DETAILS:
+ // VALIDSIG <fingerprint in hex> <sig_creation_date> <sig-timestamp>
+ // <expire-timestamp> <sig-version> <reserved> <pubkey-algo>
+ // <hash-algo> <sig-class> <primary-key-fpr>
+ const QStringList vsig = msg.mid(9).split(QLatin1Char(' '), QString::SkipEmptyParts);
+ Q_ASSERT(vsig.count() >= 10);
+
+ const KGpgKeyNode *node = model->findKeyNode(vsig[9]);
+
+ if (node != NULL) {
+ // ignore for now if this is signed with the primary id (vsig[0] == vsig[9]) or not
+ if (node->getEmail().isEmpty())
+ result += tr("<qt>Good signature from:<br /><b>%1</b><br />Key ID: %2<br /></qt>")
+ .arg(node->getName()).arg(vsig[9]);
+ else
+ result += tr("Good signature from: NAME <EMAIL>, Key ID: HEXID",
+ "<qt>Good signature from:<br /><b>%1 &lt;%2&gt;</b><br />Key ID: %3<br /></qt>")
+ .arg(node->getName()).arg(node->getEmail()).arg(vsig[9]);
+
+ result += sigTimeMessage(vsig[2]);
+ } else {
+ // this should normally never happen, but one could delete
+ // the key just after the verification. Brute force solution:
+ // do the whole report generation again, but this time make
+ // sure GOODSIG is used.
+ return getReport(log, NULL);
+ }
+ } else if (msg.startsWith(QLatin1String("UNEXPECTED")) ||
+ msg.startsWith(QLatin1String("NODATA"))) {
+ result += tr("No signature found.") + QLatin1Char('\n');
+ } else if (useGoodSig && msg.startsWith(QLatin1String("GOODSIG "))) {
+ int sigpos = msg.indexOf( ' ' , 8);
+ const QString keyid = msg.mid(8, sigpos - 8);
+
+ // split the name/email pair to give translators more power to handle this
+ QString email;
+ QString name = msg.mid(sigpos + 1);
+
+ int oPos = name.indexOf(QLatin1Char('<'));
+ int cPos = name.indexOf(QLatin1Char('>'));
+ if ((oPos >= 0) && (cPos >= 0)) {
+ email = name.mid(oPos + 1, cPos - oPos - 1);
+ name = name.left(oPos).simplified();
+ }
+
+ if (email.isEmpty())
+ result += tr("<qt>Good signature from:<br /><b>%1</b><br />Key ID: %2<br /></qt>")
+ .arg(name).arg(keyid);
+ else
+ result += tr("Good signature from: NAME <EMAIL>, Key ID: HEXID",
+ "<qt>Good signature from:<br /><b>%1 &lt;%2&gt;</b><br />Key ID: %3<br /></qt>")
+ .arg(name).arg(email).arg(keyid);
+ if (!sigtime.isEmpty()) {
+ result += sigTimeMessage(sigtime);
+ sigtime.clear();
+ }
+ } else if (msg.startsWith(QLatin1String("SIG_ID "))) {
+ const QStringList parts = msg.simplified().split(QLatin1Char(' '));
+ if (parts.count() > 2)
+ sigtime = parts[2];
+ } else if (msg.startsWith(QLatin1String("BADSIG"))) {
+ int sigpos = msg.indexOf( ' ', 7);
+ result += tr("<qt><b>BAD signature</b> from:<br /> %1<br />Key id: %2<br /><br /><b>The file is corrupted</b><br /></qt>")
+ .arg(msg.mid(sigpos + 1).replace(QLatin1Char('<'), QLatin1String("&lt;")))
+ .arg(msg.mid(7, sigpos - 7));
+ } else if (msg.startsWith(QLatin1String("TRUST_UNDEFINED"))) {
+ result += tr("<qt>The signature is valid, but the key is untrusted<br /></qt>");
+ } else if (msg.startsWith(QLatin1String("TRUST_ULTIMATE"))) {
+ result += tr("<qt>The signature is valid, and the key is ultimately trusted<br /></qt>");
+ }
+ }
+
+ return result;
+}
+*/
+
+QString
+KGpgVerify::missingId() const
+{
+ return m_missingId;
+}
+
+//#include "kgpgverify.moc"
diff --git a/kgpg/transactions/kgpgverify.h b/kgpg/transactions/kgpgverify.h
new file mode 100644
index 0000000..beba12f
--- /dev/null
+++ b/kgpg/transactions/kgpgverify.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 Rolf Eike Beer <[email protected]>
+ */
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KGPGVERIFY_H
+#define KGPGVERIFY_H
+
+#include "kgpgtextorfiletransaction.h"
+
+#include <QObject>
+#include <QString>
+#include <QStringList>
+
+#include <QUrl>
+
+//class KGpgItemModel;
+class QProcess;
+
+/**
+ * @brief verify the signature of the given text or files
+ */
+class KGpgVerify: public KGpgTextOrFileTransaction {
+ Q_OBJECT
+
+ Q_DISABLE_COPY(KGpgVerify)
+ KGpgVerify(); // = delete C++0x
+public:
+ enum ts_verify {
+ TS_MISSING_KEY = KGpgTransaction::TS_COMMON_END + 1, ///< signing key not in keyring
+ TS_BAD_SIGNATURE = TS_MISSING_KEY + 1 ///< the file is signed, but the signature is invalid
+ };
+
+ /**
+ * @brief verify signature of given text
+ * @param parent parent object
+ * @param text text to verify
+ */
+ explicit KGpgVerify(QObject *parent, const QString &text = QString());
+
+ /**
+ * @brief verify signatures of file(s)
+ * @param parent parent object
+ * @param files list of file locations to verify
+ */
+ KGpgVerify(QObject *parent, const QList<QUrl> &files);
+
+ /**
+ * @brief destructor
+ */
+ virtual ~KGpgVerify();
+
+ /**
+ * @brief get verification report
+ * @param log the log lines to scan
+ * @param model key model to use for key lookups
+ * @return verification report of GnuPG
+ */
+ //static QString getReport(const QStringList &log, const KGpgItemModel *model = NULL);
+
+ /**
+ * @brief get the missing key id
+ * @return key id that signed the message
+ *
+ * This is only valid if the transaction returned with result
+ * TS_MISSING_KEY.
+ */
+ QString missingId() const;
+
+protected:
+ virtual QStringList command() const;
+ virtual bool nextLine(const QString &line);
+ virtual void finish();
+
+private:
+ int m_fileIndex;
+ QString m_currentFile;
+ QStringList m_report;
+ QString m_missingId;
+};
+
+#endif // KGPGVERIFY_H
diff --git a/mainwindow.cpp b/mainwindow.cpp
index d8e6588..bda6a96 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -918,24 +918,10 @@ void MainWindow::slotSignDone(int result)
//return;
qDebug() << "Signing not possible: bad passphrase or missing key";
return;
- } else {
- edit->fillTextEditWithText(signt->signedText().join(QLatin1String("\n")) + QLatin1String("\n"));
- }
-
- //signt->deleteLater();
- //const QString content = signt->signedText().join(QLatin1String("\n")) + QLatin1String("\n");
- //setPlainText(content);
- //emit resetEncoding(false);
- /*sender()->deleteLater();
-
- if (text.isEmpty())
- {
- qDebug() << "Signing not possible: bad passphrase or missing key";
- return;
}
edit->fillTextEditWithText(signt->signedText().join(QLatin1String("\n")) + QLatin1String("\n"));
- */
+
}
void MainWindow::decrypt()
diff --git a/verifynotification.cpp b/verifynotification.cpp
index 3e056b9..9d9a0d9 100644
--- a/verifynotification.cpp
+++ b/verifynotification.cpp
@@ -98,8 +98,14 @@ bool VerifyNotification::refresh()
mCtx->preventNoDataErr(&text);
int textIsSigned = mCtx->textIsSigned(text);
- gpgme_signature_t sign = mCtx->verify(text);
+ //gpgme_signature_t sign = mCtx->verify(text);
+ //KGpgVerify *verify = new KGpgVerify(this, message.mid(posstart, posend - posstart));
+ KGpgVerify *verify = new KGpgVerify(this, text);
+ connect(verify, SIGNAL(done(int)), SLOT(slotVerifyDone(int)));
+ verify->start();
+
+ /*
if (sign == NULL) {
return false;
}
@@ -178,6 +184,156 @@ bool VerifyNotification::refresh()
verifyLabelText.remove(verifyLabelText.length()-1,1);
this->setVerifyLabel(verifyLabelText,verifyStatus);
-
+ */
return true;
}
+
+void VerifyNotification::slotVerifyDone(int result)
+{
+ const KGpgVerify * const verify = qobject_cast<KGpgVerify *>(sender());
+ sender()->deleteLater();
+ Q_ASSERT(verify != NULL);
+
+ if (result == KGpgVerify::TS_MISSING_KEY) {
+ qDebug() << "missing keys" << verify->missingId();
+ this->keysNotInList->append(verify->missingId());
+ this->showImportAction(true);
+ }
+
+ const QStringList messages = verify->getMessages();
+ foreach(QString mess, messages) {
+ qDebug() << "vm: " << mess;
+ }
+
+ getReport(messages);
+ /*emit verifyFinished();
+
+ if (result == KGpgVerify::TS_MISSING_KEY) {
+ verifyKeyNeeded(verify->missingId());
+ return;
+ }
+
+ const QStringList messages = verify->getMessages();
+
+ if (messages.isEmpty())
+ return;
+
+ QStringList msglist;
+ foreach (QString rawmsg, messages)
+ msglist << rawmsg.replace(QLatin1Char('<'), QLatin1String("&lt;"));
+
+ (void) new KgpgDetailedInfo(this, KGpgVerify::getReport(messages, m_model),
+ msglist.join(QLatin1String("<br/>")),
+ QStringList(), i18nc("Caption of message box", "Verification Finished"));
+ */
+}
+
+QString VerifyNotification::getReport(const QStringList &log)
+{
+ QString verifyLabelText;
+ verify_label_status verifyStatus=VERIFY_ERROR_OK;
+
+ QString result;
+ // newer versions of GnuPG emit both VALIDSIG and GOODSIG
+ // for a good signature. Since VALIDSIG has more information
+ // we use that.
+ const QRegExp validsig(QLatin1String("^\\[GNUPG:\\] VALIDSIG([ ]+[^ ]+){10,}.*$"));
+
+
+// const bool useGoodSig = (model != NULL) && (log.indexOf(validsig) == -1);
+ const bool useGoodSig = false;
+
+ QString sigtime; // timestamp of signature creation
+
+ foreach (const QString &line, log) {
+ if (!line.startsWith(QLatin1String("[GNUPG:] ")))
+ continue;
+
+ const QString msg = line.mid(9);
+
+ if (msg.startsWith(QLatin1String("VALIDSIG ")) && !useGoodSig) {
+ // from GnuPG source, doc/DETAILS:
+ // VALIDSIG <fingerprint in hex> <sig_creation_date> <sig-timestamp>
+ // <expire-timestamp> <sig-version> <reserved> <pubkey-algo>
+ // <hash-algo> <sig-class> <primary-key-fpr>
+ const QStringList vsig = msg.mid(9).split(QLatin1Char(' '), QString::SkipEmptyParts);
+ Q_ASSERT(vsig.count() >= 10);
+
+ qDebug() << "sig: " << vsig[9];
+
+ verifyStatus=VERIFY_ERROR_WARN;
+ verifyLabelText.append(tr("Error for key with fingerprint ")+mCtx->beautifyFingerprint(QString(vsig[9])));
+
+
+ }
+ }
+
+ this->setVerifyLabel(verifyLabelText,verifyStatus);
+ /*const KGpgKeyNode *node = model->findKeyNode(vsig[9]);
+
+ if (node != NULL) {
+ // ignore for now if this is signed with the primary id (vsig[0] == vsig[9]) or not
+ if (node->getEmail().isEmpty())
+ result += tr("<qt>Good signature from:<br /><b>%1</b><br />Key ID: %2<br /></qt>")
+ .arg(node->getName()).arg(vsig[9]);
+ else
+ result += tr("Good signature from: NAME <EMAIL>, Key ID: HEXID",
+ "<qt>Good signature from:<br /><b>%1 &lt;%2&gt;</b><br />Key ID: %3<br /></qt>")
+ .arg(node->getName()).arg(node->getEmail()).arg(vsig[9]);
+
+ result += sigTimeMessage(vsig[2]);
+ } else {
+ // this should normally never happen, but one could delete
+ // the key just after the verification. Brute force solution:
+ // do the whole report generation again, but this time make
+ // sure GOODSIG is used.
+ return getReport(log, NULL);
+ }
+ } else if (msg.startsWith(QLatin1String("UNEXPECTED")) ||
+ msg.startsWith(QLatin1String("NODATA"))) {
+ result += tr("No signature found.") + QLatin1Char('\n');
+ } else if (useGoodSig && msg.startsWith(QLatin1String("GOODSIG "))) {
+ int sigpos = msg.indexOf( ' ' , 8);
+ const QString keyid = msg.mid(8, sigpos - 8);
+
+ // split the name/email pair to give translators more power to handle this
+ QString email;
+ QString name = msg.mid(sigpos + 1);
+
+ int oPos = name.indexOf(QLatin1Char('<'));
+ int cPos = name.indexOf(QLatin1Char('>'));
+ if ((oPos >= 0) && (cPos >= 0)) {
+ email = name.mid(oPos + 1, cPos - oPos - 1);
+ name = name.left(oPos).simplified();
+ }
+
+ if (email.isEmpty())
+ result += tr("<qt>Good signature from:<br /><b>%1</b><br />Key ID: %2<br /></qt>")
+ .arg(name).arg(keyid);
+ else
+ result += tr("Good signature from: NAME <EMAIL>, Key ID: HEXID",
+ "<qt>Good signature from:<br /><b>%1 &lt;%2&gt;</b><br />Key ID: %3<br /></qt>")
+ .arg(name).arg(email).arg(keyid);
+ if (!sigtime.isEmpty()) {
+ result += sigTimeMessage(sigtime);
+ sigtime.clear();
+ }
+ } else if (msg.startsWith(QLatin1String("SIG_ID "))) {
+ const QStringList parts = msg.simplified().split(QLatin1Char(' '));
+ if (parts.count() > 2)
+ sigtime = parts[2];
+ } else if (msg.startsWith(QLatin1String("BADSIG"))) {
+ int sigpos = msg.indexOf( ' ', 7);
+ result += tr("<qt><b>BAD signature</b> from:<br /> %1<br />Key id: %2<br /><br /><b>The file is corrupted</b><br /></qt>")
+ .arg(msg.mid(sigpos + 1).replace(QLatin1Char('<'), QLatin1String("&lt;")))
+ .arg(msg.mid(7, sigpos - 7));
+ } else if (msg.startsWith(QLatin1String("TRUST_UNDEFINED"))) {
+ result += tr("<qt>The signature is valid, but the key is untrusted<br /></qt>");
+ } else if (msg.startsWith(QLatin1String("TRUST_ULTIMATE"))) {
+ result += tr("<qt>The signature is valid, and the key is ultimately trusted<br /></qt>");
+ }
+ }
+ */
+ return result;
+}
+
diff --git a/verifynotification.h b/verifynotification.h
index e1b4f1b..6f34f47 100644
--- a/verifynotification.h
+++ b/verifynotification.h
@@ -24,6 +24,7 @@
#include "editorpage.h"
#include "verifydetailsdialog.h"
+#include "kgpg/transactions/kgpgverify.h"
#include <gpgme.h>
#include <QWidget>
@@ -75,6 +76,8 @@ public:
QStringList *keysNotInList; /** List with keys, which are in signature but not in keylist */
+ QString getReport(const QStringList &log);
+
public slots:
/**
@@ -93,6 +96,8 @@ public slots:
*/
bool refresh();
+ void slotVerifyDone(int result);
+
private:
QMenu *detailMenu; /** Menu for te Button in verfiyNotification */
QAction *importFromKeyserverAct; /** Action for importing keys from keyserver which are notin keylist */