aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/GpgContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/GpgContext.cpp')
-rw-r--r--src/core/GpgContext.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp
new file mode 100644
index 00000000..1897202f
--- /dev/null
+++ b/src/core/GpgContext.cpp
@@ -0,0 +1,224 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * All the source code of GpgFrontend was modified and released by
+ * Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#include "core/GpgContext.h"
+
+#include <gpg-error.h>
+#include <gpgme.h>
+
+#include <functional>
+#include <string>
+#include <utility>
+
+#include "GpgConstants.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+namespace GpgFrontend {
+
+/**
+ * Constructor
+ * Set up gpgme-context, set paths to app-run path
+ */
+GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) {
+ static bool _first = true;
+
+ if (_first) {
+ /* Initialize the locale environment. */
+ LOG(INFO) << "locale" << setlocale(LC_CTYPE, nullptr);
+ info_.GpgMEVersion = gpgme_check_version(nullptr);
+ gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
+#ifdef LC_MESSAGES
+ gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
+#endif
+ _first = false;
+ }
+
+ gpgme_ctx_t _p_ctx;
+ check_gpg_error(gpgme_new(&_p_ctx));
+ _ctx_ref = CtxRefHandler(_p_ctx);
+
+ if (args.gpg_alone) {
+ info_.AppPath = args.gpg_path;
+ auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP,
+ info_.AppPath.c_str(),
+ info_.DatabasePath.c_str());
+ assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
+ }
+
+ auto engine_info = gpgme_ctx_get_engine_info(*this);
+ // Check ENV before running
+ bool check_passed = false, find_openpgp = false, find_gpgconf = false,
+ find_cms = false;
+
+ while (engine_info != nullptr) {
+ if (!strcmp(engine_info->version, "1.0.0")) {
+ engine_info = engine_info->next;
+ continue;
+ }
+
+ DLOG(INFO) << gpgme_get_protocol_name(engine_info->protocol)
+ << std::string(engine_info->file_name == nullptr
+ ? "null"
+ : engine_info->file_name)
+ << std::string(engine_info->home_dir == nullptr
+ ? "null"
+ : engine_info->home_dir);
+
+ switch (engine_info->protocol) {
+ case GPGME_PROTOCOL_OpenPGP:
+ find_openpgp = true;
+ info_.AppPath = engine_info->file_name;
+ info_.GnupgVersion = engine_info->version;
+ break;
+ case GPGME_PROTOCOL_CMS:
+ find_cms = true;
+ info_.CMSPath = engine_info->file_name;
+ break;
+ case GPGME_PROTOCOL_GPGCONF:
+ find_gpgconf = true;
+ info_.GpgConfPath = engine_info->file_name;
+ break;
+ case GPGME_PROTOCOL_ASSUAN:
+ break;
+ case GPGME_PROTOCOL_G13:
+ break;
+ case GPGME_PROTOCOL_UISERVER:
+ break;
+ case GPGME_PROTOCOL_SPAWN:
+ break;
+ case GPGME_PROTOCOL_DEFAULT:
+ break;
+ case GPGME_PROTOCOL_UNKNOWN:
+ break;
+ }
+ engine_info = engine_info->next;
+ }
+
+ // conditional check
+ if ((info_.GnupgVersion >= "2.0.0" && find_gpgconf && find_openpgp &&
+ find_cms) ||
+ (info_.GnupgVersion > "1.0.0" && find_gpgconf))
+ check_passed = true;
+
+ if (!check_passed) {
+ this->good_ = false;
+ LOG(ERROR) << "Env check failed";
+ return;
+ } else {
+ DLOG(INFO) << "gnupg version" << info_.GnupgVersion;
+ init_ctx();
+ good_ = true;
+ }
+}
+
+void GpgContext::init_ctx() {
+ // Set Independent Database
+ if (info_.GnupgVersion <= "2.0.0" && args_.independent_database) {
+ info_.DatabasePath = args_.db_path;
+ DLOG(INFO) << "custom key db path" << info_.DatabasePath;
+ auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP,
+ info_.AppPath.c_str(),
+ info_.DatabasePath.c_str());
+ assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
+ } else {
+ info_.DatabasePath = "default";
+ }
+
+ if (args_.ascii) {
+ /** Setting the output type must be done at the beginning */
+ /** think this means ascii-armor --> ? */
+ gpgme_set_armor(*this, 1);
+ } else {
+ /** Setting the output type must be done at the beginning */
+ /** think this means ascii-armor --> ? */
+ gpgme_set_armor(*this, 0);
+ }
+
+ // Speed up loading process
+ gpgme_set_offline(*this, 1);
+
+ if (info_.GnupgVersion >= "2.0.0") {
+ check_gpg_error(gpgme_set_keylist_mode(
+ *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET |
+ GPGME_KEYLIST_MODE_SIGS | GPGME_KEYLIST_MODE_SIG_NOTATIONS |
+ GPGME_KEYLIST_MODE_WITH_TOFU));
+ } else {
+ check_gpg_error(gpgme_set_keylist_mode(
+ *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS |
+ GPGME_KEYLIST_MODE_SIG_NOTATIONS |
+ GPGME_KEYLIST_MODE_WITH_TOFU));
+ }
+
+ // for unit test
+ if (args_.test_mode) {
+ LOG(INFO) << "test mode";
+ if (info_.GnupgVersion >= "2.1.0") SetPassphraseCb(test_passphrase_cb);
+ gpgme_set_status_cb(*this, test_status_cb, nullptr);
+ }
+}
+
+bool GpgContext::good() const { return good_; }
+
+void GpgContext::SetPassphraseCb(gpgme_passphrase_cb_t cb) const {
+ if (info_.GnupgVersion >= "2.1.0") {
+ if (gpgme_get_pinentry_mode(*this) != GPGME_PINENTRY_MODE_LOOPBACK) {
+ gpgme_set_pinentry_mode(*this, GPGME_PINENTRY_MODE_LOOPBACK);
+ }
+ gpgme_set_passphrase_cb(*this, cb, nullptr);
+ } else {
+ LOG(ERROR) << "Not supported for gnupg version" << info_.GnupgVersion;
+ }
+}
+
+gpgme_error_t GpgContext::test_passphrase_cb(void *opaque, const char *uid_hint,
+ const char *passphrase_info,
+ int last_was_bad, int fd) {
+ size_t res;
+ std::string pass = "abcdefg\n";
+ auto pass_len = pass.size();
+
+ size_t off = 0;
+
+ do {
+ res = gpgme_io_write(fd, &pass[off], pass_len - off);
+ if (res > 0) off += res;
+ } while (res > 0 && off != pass_len);
+
+ return off == pass_len ? 0 : gpgme_error_from_errno(errno);
+}
+
+gpgme_error_t GpgContext::test_status_cb(void *hook, const char *keyword,
+ const char *args) {
+ LOG(INFO) << "keyword" << keyword;
+ return GPG_ERR_NO_ERROR;
+}
+
+} // namespace GpgFrontend \ No newline at end of file