summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS7
-rw-r--r--lang/cpp/src/Makefile.am2
-rw-r--r--lang/cpp/src/global.h7
-rw-r--r--lang/cpp/src/gpgrevokekeyeditinteractor.cpp212
-rw-r--r--lang/cpp/src/gpgrevokekeyeditinteractor.h62
5 files changed, 290 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 36cbb10a..98e6d648 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,13 @@ Noteworthy changes in version 1.17.2 (unreleased)
* cpp, qt: Do not export internal symbols anymore. [T5906]
+ * cpp: Support revocation of own OpenPGP keys. [#5904]
+
+ * Interface changes relative to the 1.17.1 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ cpp: RevocationReason NEW.
+ cpp: GpgRevokeKeyEditInteractor NEW.
+
Noteworthy changes in version 1.17.1 (2022-03-06)
-------------------------------------------------
diff --git a/lang/cpp/src/Makefile.am b/lang/cpp/src/Makefile.am
index 7df21326..fbec70bb 100644
--- a/lang/cpp/src/Makefile.am
+++ b/lang/cpp/src/Makefile.am
@@ -34,6 +34,7 @@ main_sources = \
gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \
gpgadduserideditinteractor.cpp gpggencardkeyinteractor.cpp \
gpgaddexistingsubkeyeditinteractor.cpp \
+ gpgrevokekeyeditinteractor.cpp \
defaultassuantransaction.cpp \
scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \
statusconsumerassuantransaction.cpp \
@@ -49,6 +50,7 @@ gpgmepp_headers = \
gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \
gpggencardkeyinteractor.h \
gpgaddexistingsubkeyeditinteractor.h \
+ gpgrevokekeyeditinteractor.h \
importresult.h keygenerationresult.h key.h keylistresult.h \
notation.h result.h scdgetinfoassuantransaction.h signingresult.h \
statusconsumerassuantransaction.h \
diff --git a/lang/cpp/src/global.h b/lang/cpp/src/global.h
index a25b46ce..9aafea87 100644
--- a/lang/cpp/src/global.h
+++ b/lang/cpp/src/global.h
@@ -72,6 +72,13 @@ enum KeyListMode {
enum SignatureMode { NormalSignatureMode, Detached, Clearsigned };
+enum class RevocationReason {
+ Unspecified = 0,
+ Compromised = 1,
+ Superseded = 2,
+ NoLongerUsed = 3
+};
+
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Protocol proto);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Engine eng);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, KeyListMode mode);
diff --git a/lang/cpp/src/gpgrevokekeyeditinteractor.cpp b/lang/cpp/src/gpgrevokekeyeditinteractor.cpp
new file mode 100644
index 00000000..a90b5934
--- /dev/null
+++ b/lang/cpp/src/gpgrevokekeyeditinteractor.cpp
@@ -0,0 +1,212 @@
+/*
+ gpgrevokekeyeditinteractor.cpp - Edit Interactor to revoke own OpenPGP keys
+ Copyright (c) 2022 g10 Code GmbH
+ Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "gpgrevokekeyeditinteractor.h"
+
+#include "error.h"
+
+#include <gpgme.h>
+
+#include <sstream>
+#include <vector>
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+using namespace GpgME;
+
+class GpgRevokeKeyEditInteractor::Private
+{
+ enum {
+ START = EditInteractor::StartState,
+ COMMAND,
+ CONFIRM_REVOKING_ENTIRE_KEY,
+ REASON_CODE,
+ REASON_TEXT,
+ // all these free slots belong to REASON_TEXT, too; we increase state()
+ // by one for each line of text, so that action() is called
+ REASON_TEXT_DONE = REASON_TEXT + 1000,
+ CONFIRM_REASON,
+ QUIT,
+ CONFIRM_SAVE,
+
+ ERROR = EditInteractor::ErrorState
+ };
+
+ GpgRevokeKeyEditInteractor *const q = nullptr;
+
+public:
+ Private(GpgRevokeKeyEditInteractor *q)
+ : q{q}
+ , reasonCode{"0"}
+ {
+ }
+
+ const char *action(Error &err) const;
+ unsigned int nextState(unsigned int statusCode, const char *args, Error &err);
+
+ std::string reasonCode;
+ std::vector<std::string> reasonLines;
+ int nextLine = -1;
+};
+
+const char *GpgRevokeKeyEditInteractor::Private::action(Error &err) const
+{
+ switch (const auto state = q->state()) {
+ case COMMAND:
+ return "revkey";
+ case CONFIRM_REVOKING_ENTIRE_KEY:
+ return "Y";
+ case REASON_CODE:
+ return reasonCode.c_str();
+ case REASON_TEXT_DONE:
+ return "";
+ case CONFIRM_REASON:
+ return "Y";
+ case QUIT:
+ return "quit";
+ case CONFIRM_SAVE:
+ return "Y";
+ case START:
+ return nullptr;
+ default:
+ if (state >= REASON_TEXT && state < REASON_TEXT_DONE) {
+ return reasonLines[nextLine].c_str();
+ }
+ // fall through
+ case ERROR:
+ err = Error::fromCode(GPG_ERR_GENERAL);
+ return nullptr;
+ }
+}
+
+unsigned int GpgRevokeKeyEditInteractor::Private::nextState(unsigned int status, const char *args, Error &err)
+{
+ using std::strcmp;
+
+ static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
+
+ if (q->needsNoResponse(status)) {
+ return q->state();
+ }
+
+ switch (const auto state = q->state()) {
+ case START:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return COMMAND;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case COMMAND:
+ if (status == GPGME_STATUS_GET_BOOL &&
+ strcmp(args, "keyedit.revoke.subkey.okay") == 0) {
+ return CONFIRM_REVOKING_ENTIRE_KEY;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case CONFIRM_REVOKING_ENTIRE_KEY:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "ask_revocation_reason.code") == 0) {
+ return REASON_CODE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case REASON_CODE:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "ask_revocation_reason.text") == 0) {
+ nextLine++;
+ return nextLine < reasonLines.size() ? REASON_TEXT : REASON_TEXT_DONE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ default:
+ if (state >= REASON_TEXT && state < REASON_TEXT_DONE) {
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "ask_revocation_reason.text") == 0) {
+ nextLine++;
+ return nextLine < reasonLines.size() ? state + 1 : REASON_TEXT_DONE;
+ }
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case REASON_TEXT_DONE:
+ if (status == GPGME_STATUS_GET_BOOL &&
+ strcmp(args, "ask_revocation_reason.okay") == 0) {
+ return CONFIRM_REASON;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case CONFIRM_REASON:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case QUIT:
+ if (status == GPGME_STATUS_GET_BOOL &&
+ strcmp(args, "keyedit.save.okay") == 0) {
+ return CONFIRM_SAVE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case ERROR:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ }
+ err = q->lastError();
+ return ERROR;
+ }
+}
+
+GpgRevokeKeyEditInteractor::GpgRevokeKeyEditInteractor()
+ : EditInteractor{}
+ , d{new Private{this}}
+{
+}
+
+GpgRevokeKeyEditInteractor::~GpgRevokeKeyEditInteractor() = default;
+
+void GpgRevokeKeyEditInteractor::setReason(RevocationReason reason, const std::vector<std::string> &description)
+{
+ d->reasonCode = std::to_string(static_cast<int>(reason));
+ d->reasonLines = description;
+}
+
+const char *GpgRevokeKeyEditInteractor::action(Error &err) const
+{
+ return d->action(err);
+}
+
+unsigned int GpgRevokeKeyEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+ return d->nextState(status, args, err);
+}
diff --git a/lang/cpp/src/gpgrevokekeyeditinteractor.h b/lang/cpp/src/gpgrevokekeyeditinteractor.h
new file mode 100644
index 00000000..c64ca015
--- /dev/null
+++ b/lang/cpp/src/gpgrevokekeyeditinteractor.h
@@ -0,0 +1,62 @@
+/*
+ gpgrevokekeyeditinteractor.h - Edit Interactor to revoke own OpenPGP keys
+ Copyright (c) 2022 g10 Code GmbH
+ Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGREVOKEKEYEDITINTERACTOR_H__
+#define __GPGMEPP_GPGREVOKEKEYEDITINTERACTOR_H__
+
+#include "editinteractor.h"
+#include "global.h"
+
+#include <memory>
+#include <vector>
+
+namespace GpgME
+{
+
+/** Edit interactor to revoke the key a key edit operation is working on.
+ * Supports revocation of own keys only. */
+class GPGMEPP_EXPORT GpgRevokeKeyEditInteractor : public EditInteractor
+{
+public:
+ GpgRevokeKeyEditInteractor();
+ ~GpgRevokeKeyEditInteractor() override;
+
+ /** Sets the reason for the revocation. The reason defaults to \c Unspecified.
+ * \a description can be used for adding a comment for the revocation. The
+ * individual elements of \a description must be non-empty strings and they
+ * must not contain any endline characters.
+ */
+ void setReason(RevocationReason reason, const std::vector<std::string> &description = {});
+
+private:
+ const char *action(Error &err) const override;
+ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const override;
+
+private:
+ class Private;
+ const std::unique_ptr<Private> d;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGREVOKEKEYEDITINTERACTOR_H__