aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2025-04-11 18:51:02 +0000
committersaturneric <[email protected]>2025-04-11 18:51:13 +0000
commitc5f1c389e0fb66e932f1eb221068db175e4bbd96 (patch)
treed7cd8bbd7fbcca9e2848862110999cc32eceeef1 /src
parentchore: not possible to build a universal version without support from homebrew (diff)
downloadGpgFrontend-c5f1c389e0fb66e932f1eb221068db175e4bbd96.tar.gz
GpgFrontend-c5f1c389e0fb66e932f1eb221068db175e4bbd96.zip
feat: support adsk
Diffstat (limited to 'src')
-rw-r--r--src/core/function/gpg/GpgKeyOpera.cpp38
-rw-r--r--src/core/function/gpg/GpgKeyOpera.h19
-rw-r--r--src/core/model/GpgKey.h175
-rw-r--r--src/core/model/GpgSubKey.cpp5
-rw-r--r--src/core/model/GpgSubKey.h75
-rw-r--r--src/test/core/GpgCoreTestKeyOpera.cpp117
6 files changed, 314 insertions, 115 deletions
diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp
index 9511b347..931eae72 100644
--- a/src/core/function/gpg/GpgKeyOpera.cpp
+++ b/src/core/function/gpg/GpgKeyOpera.cpp
@@ -364,4 +364,42 @@ void GpgKeyOpera::DeleteKey(const KeyId& key_id) {
keys.push_back(key_id);
DeleteKeys(keys);
}
+
+auto AddADSKImpl(GpgContext& ctx, const GpgKey& key, const GpgSubKey& adsk,
+ const DataObjectPtr& data_object) -> GpgError {
+ auto algo = adsk.GetFingerprint();
+ unsigned int flags = GPGME_CREATE_ADSK;
+
+ LOG_D() << "add adsk args: " << key.GetId() << algo;
+
+ auto err =
+ gpgme_op_createsubkey(ctx.DefaultContext(), static_cast<gpgme_key_t>(key),
+ algo.toLatin1(), 0, 0, flags);
+ if (CheckGpgError(err) != GPG_ERR_NO_ERROR) {
+ data_object->Swap({GpgGenerateKeyResult{}});
+ return err;
+ }
+
+ data_object->Swap(
+ {GpgGenerateKeyResult{gpgme_op_genkey_result(ctx.DefaultContext())}});
+ return CheckGpgError(err);
+}
+
+void GpgKeyOpera::AddADSK(const GpgKey& key, const GpgSubKey& adsk,
+ const GpgOperationCallback& callback) {
+ RunGpgOperaAsync(
+ [=](const DataObjectPtr& data_object) -> GpgError {
+ return AddADSKImpl(ctx_, key, adsk, data_object);
+ },
+ callback, "gpgme_op_createsubkey", "2.4.1");
+}
+
+auto GpgKeyOpera::AddADSKSync(const GpgKey& key, const GpgSubKey& adsk)
+ -> std::tuple<GpgError, DataObjectPtr> {
+ return RunGpgOperaSync(
+ [=](const DataObjectPtr& data_object) -> GpgError {
+ return AddADSKImpl(ctx_, key, adsk, data_object);
+ },
+ "gpgme_op_createsubkey", "2.4.1");
+}
} // namespace GpgFrontend
diff --git a/src/core/function/gpg/GpgKeyOpera.h b/src/core/function/gpg/GpgKeyOpera.h
index f6b7143e..4728992d 100644
--- a/src/core/function/gpg/GpgKeyOpera.h
+++ b/src/core/function/gpg/GpgKeyOpera.h
@@ -170,6 +170,25 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera
const QSharedPointer<KeyGenerateInfo>& s_params)
-> std::tuple<GpgError, DataObjectPtr>;
+ /**
+ * @brief
+ *
+ * @param key
+ * @param adsk
+ */
+ void AddADSK(const GpgKey& key, const GpgSubKey& adsk,
+ const GpgOperationCallback&);
+
+ /**
+ * @brief
+ *
+ * @param key
+ * @param adsk
+ * @return GpgError
+ */
+ auto AddADSKSync(const GpgKey& key, const GpgSubKey& adsk)
+ -> std::tuple<GpgError, DataObjectPtr>;
+
private:
GpgContext& ctx_ =
GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); ///<
diff --git a/src/core/model/GpgKey.h b/src/core/model/GpgKey.h
index 26423dae..a3fe8396 100644
--- a/src/core/model/GpgKey.h
+++ b/src/core/model/GpgKey.h
@@ -41,6 +41,96 @@ class GPGFRONTEND_CORE_EXPORT GpgKey {
Q_DECLARE_TR_FUNCTIONS(GpgKey)
public:
/**
+ * @brief Construct a new Gpg Key object
+ *
+ */
+ GpgKey() = default;
+
+ /**
+ * @brief Construct a new Gpg Key object
+ *
+ * @param key
+ */
+ explicit GpgKey(gpgme_key_t&& key);
+
+ /**
+ * @brief Destroy the Gpg Key objects
+ *
+ */
+ ~GpgKey() = default;
+
+ /**
+ * @brief Construct a new Gpg Key object
+ *
+ * @param key
+ */
+ GpgKey(const gpgme_key_t& key) = delete;
+
+ /**
+ * @brief Construct a new Gpg Key object
+ *
+ * @param k
+ */
+ GpgKey(GpgKey&&) noexcept;
+
+ /**
+ * @brief
+ *
+ * @param k
+ * @return GpgKey&
+ */
+ auto operator=(GpgKey&&) noexcept -> GpgKey&;
+
+ /**
+ * @brief Construct a new Gpg Key object
+ *
+ * @param k
+ */
+ GpgKey(const GpgKey&);
+
+ /**
+ * @brief
+ *
+ * @param k
+ * @return GpgKey&
+ */
+ auto operator=(const GpgKey&) -> GpgKey&;
+
+ /**
+ * @brief
+ *
+ * @param key
+ * @return GpgKey&
+ */
+ auto operator=(const gpgme_key_t&) -> GpgKey& = delete;
+
+ /**
+ * @brief
+ *
+ * @param o
+ * @return true
+ * @return false
+ */
+ auto operator==(const GpgKey&) const -> bool;
+
+ /**
+ * @brief
+ *
+ * @param o
+ * @return true
+ * @return false
+ */
+ auto operator<=(const GpgKey&) const -> bool;
+
+ /**
+ * @brief
+ *
+ * @return gpgme_key_t
+ */
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator gpgme_key_t() const;
+
+ /**
* @brief
*
* @return true
@@ -274,91 +364,6 @@ class GPGFRONTEND_CORE_EXPORT GpgKey {
*/
[[nodiscard]] auto GetUIDs() const -> std::unique_ptr<QContainer<GpgUID>>;
- /**
- * @brief Construct a new Gpg Key object
- *
- */
- GpgKey() = default;
-
- /**
- * @brief Construct a new Gpg Key object
- *
- * @param key
- */
- explicit GpgKey(gpgme_key_t&& key);
-
- /**
- * @brief Destroy the Gpg Key objects
- *
- */
- ~GpgKey() = default;
-
- /**
- * @brief Construct a new Gpg Key object
- *
- * @param key
- */
- GpgKey(const gpgme_key_t& key) = delete;
-
- /**
- * @brief Construct a new Gpg Key object
- *
- * @param k
- */
- GpgKey(GpgKey&&) noexcept;
-
- /**
- * @brief
- *
- * @param k
- * @return GpgKey&
- */
- auto operator=(GpgKey&&) noexcept -> GpgKey&;
-
- /**
- * @brief Construct a new Gpg Key object
- *
- * @param k
- */
- GpgKey(const GpgKey&);
-
- /**
- * @brief
- *
- * @param k
- * @return GpgKey&
- */
- auto operator=(const GpgKey&) -> GpgKey&;
-
- /**
- * @brief
- *
- * @param key
- * @return GpgKey&
- */
- auto operator=(const gpgme_key_t&) -> GpgKey& = delete;
-
- /**
- * @brief
- *
- * @param o
- * @return true
- * @return false
- */
- auto operator==(const GpgKey&) const -> bool;
-
- /**
- * @brief
- *
- * @param o
- * @return true
- * @return false
- */
- auto operator<=(const GpgKey&) const -> bool;
-
- // NOLINTNEXTLINE(google-explicit-constructor)
- operator gpgme_key_t() const;
-
private:
/**
* @brief
diff --git a/src/core/model/GpgSubKey.cpp b/src/core/model/GpgSubKey.cpp
index 98b87706..42fc476a 100644
--- a/src/core/model/GpgSubKey.cpp
+++ b/src/core/model/GpgSubKey.cpp
@@ -94,4 +94,9 @@ auto GpgSubKey::GetExpireTime() const -> QDateTime {
return QDateTime::fromSecsSinceEpoch(subkey_ref_->expires);
}
+auto GpgSubKey::IsADSK() const -> bool { return subkey_ref_->can_renc; }
+
+auto GpgSubKey::SmartCardSerialNumber() -> QString {
+ return subkey_ref_->card_number;
+}
} // namespace GpgFrontend
diff --git a/src/core/model/GpgSubKey.h b/src/core/model/GpgSubKey.h
index f7d6afd9..e5a8a21b 100644
--- a/src/core/model/GpgSubKey.h
+++ b/src/core/model/GpgSubKey.h
@@ -41,6 +41,41 @@ namespace GpgFrontend {
class GPGFRONTEND_CORE_EXPORT GpgSubKey {
public:
/**
+ * @brief Construct a new Gpg Sub Key object
+ *
+ */
+ GpgSubKey();
+
+ /**
+ * @brief Construct a new Gpg Sub Key object
+ *
+ * @param subkey
+ */
+ explicit GpgSubKey(gpgme_subkey_t subkey);
+
+ /**
+ * @brief Construct a new Gpg Sub Key object
+ *
+ */
+ GpgSubKey(const GpgSubKey&);
+
+ /**
+ * @brief
+ *
+ * @return GpgSubKey&
+ */
+ auto operator=(const GpgSubKey&) -> GpgSubKey&;
+
+ /**
+ * @brief
+ *
+ * @param o
+ * @return true
+ * @return false
+ */
+ auto operator==(const GpgSubKey& o) const -> bool;
+
+ /**
* @brief
*
* @return QString
@@ -167,42 +202,22 @@ class GPGFRONTEND_CORE_EXPORT GpgSubKey {
*
* @return QDateTime
*/
- [[nodiscard]] QDateTime GetExpireTime() const;
-
- /**
- * @brief Construct a new Gpg Sub Key object
- *
- */
- GpgSubKey();
-
- /**
- * @brief Construct a new Gpg Sub Key object
- *
- * @param subkey
- */
- explicit GpgSubKey(gpgme_subkey_t subkey);
-
- /**
- * @brief Construct a new Gpg Sub Key object
- *
- */
- GpgSubKey(const GpgSubKey&);
+ [[nodiscard]] auto GetExpireTime() const -> QDateTime;
/**
- * @brief
- *
- * @return GpgSubKey&
+ * @brief
+ *
+ * @return true
+ * @return false
*/
- auto operator=(const GpgSubKey&) -> GpgSubKey&;
+ [[nodiscard]] auto IsADSK() const -> bool;
/**
- * @brief
- *
- * @param o
- * @return true
- * @return false
+ * @brief
+ *
+ * @return QString
*/
- auto operator==(const GpgSubKey& o) const -> bool;
+ [[nodiscard]] auto SmartCardSerialNumber() -> QString;
private:
gpgme_subkey_t subkey_ref_ = nullptr; ///<
diff --git a/src/test/core/GpgCoreTestKeyOpera.cpp b/src/test/core/GpgCoreTestKeyOpera.cpp
new file mode 100644
index 00000000..6f1f41d5
--- /dev/null
+++ b/src/test/core/GpgCoreTestKeyOpera.cpp
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2021-2024 Saturneric <[email protected]>
+ *
+ * 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 "GpgCoreTest.h"
+#include "core/GpgConstants.h"
+#include "core/function/gpg/GpgKeyOpera.h"
+#include "core/model/GpgGenerateKeyResult.h"
+#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "core/model/GpgImportInformation.h"
+#include "core/utils/GpgUtils.h"
+
+namespace GpgFrontend::Test {
+
+static const char *test_private_key_data = R"(
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lQOYBGf5Yb0BCADY9VaMNtAKVt4Woy45PbBmTtSgr8gUZ32zOCypKv/Cnoc0o2xR
+nyHSelh/GMImHPt7BFAFplK68+b7pRpWuWC+ljUi+MJliGDTJX2FFJpFTlhqROHO
+6982f2OnTyDaCG+XCDtKktK6U29eK3Y+e08WN8o52fYNzYOQc7pfn428gt4Nx9s9
+CJDUvdeZFbLj7UfN/0tCe+loiOHF13ZVpyIWiIFi06ANsBPut6CZRxlVJTgNNPZf
+PJ813m83PId4w3ExvJ+ndeRDWE5MXqi8NmoRJGNtcS0/D2bnTkgqT89rWSfEkEuz
+jOLUR3tzerh6xohwe0U86QuPRsiJFhL0NmMRABEBAAEAB/wMkk7FCioM51KwIh18
+EKCHlRrKAtWHpSWJ/H/N/6FZUCFKggu1QRDPJuq41qDtX3GNA8d1RFl33sksHLmF
+e/FoqcCDecGd64Scx4fZ7cMwr+T8p2gkOtOwzznhiHrBV4rLyBzTaeWPCWWjIcaU
+wUVoZqwvpPsWeqmcdbA/eTnXyewsU48Bpd2mFGhtPl6ZrHtoj4gW7h4/sU1GwACn
+GXzyeVzWU/HJJRLVSysnxOyU2wUX9NJSoFhz3j73hw+5dqovOph/IA7FEgDh5s+i
+7MbvF9f7m+3o4FsNk964PS+6L8/5vfR6gHYNP8Kfy14Iab5UcLj0jjLTaZxQr/hB
+yNqfBADlHg9+Bq7aJ9he5MCr1Hjj90bkuO4XVgGl4vzIFmNf9YXVoOGG7EY38Av0
+XO9iKFFLG+uLDA9iWAps1GhefWM9Cfy1SRbZrPQAcWiX4cv8BLukYYDUucp1Gb0a
+k1CUR3MSdZ5znv28lH5jZyX5jGhJjuXDea4Y9ZHEiTfHavre+wQA8moPCNTQEgX6
+gPxo/gYuCgrEWy5L+t6vNjhQl5bs7XG3YjKKLHjS2zHe16/74C1K+t1n3vmbhQ0a
+1mobf+AUwkTAgcvp0U/KzvUJccbfMsSHR3Wl4xnDAtzooEkKWzy82XEx8FFv3cQp
+xbvF+isFYRSt6tcj7yemIsDaFeRd+GMEAOvpX8lwyVjGk2U4O2OFvbsJmyQ5MNN3
+hZn3e9qUoeVvYvWEwszpqz1p8yHu/Y9SmMU/srZpFq1FARyAYZ0Y+HEPsY6qIzex
+NZ4lL0Y/ADK2mOAnvd0EHU2jzizWmANzwnl2D5O1n2SbPRzPYQXb3OPjhFONSdUI
+RqrieywWW5hYT8a0HEFEU0tUZXN0KCk8dGVzdGVyQGJrdHVzLmNvbT6JAVEEEwEI
+ADsWIQRQlfHaU+FFX6pRe11cTYBUbrblLwUCZ/lhvQIbLwULCQgHAgIiAgYVCgkI
+CwIEFgIDAQIeBwIXgAAKCRBcTYBUbrblLwvDCADY43HmTA4UwypSj6lOkC+5tOp9
+wll4ph9qAO3lbuWeqLX1uV6XFH4NMvFO6uDQvNaRQFFja8HM3s3uzo0d0ltDNkNx
+WroWeUTb1lyX3cPHoApo6jKbQ8jSJkk4+5Jd1/tL34teYJRgZqitTpdOWVc348/a
+H3nzsWNgb6fyq2nvkBERV+Er2I2ZG33JKuAw5Qr0eO4CpktKqHGzXpR7R07LdZwF
+uWQdeF3NPBl1KgBLJgZYUy2GmDMShaBL4sw1f4z8A21/7W8ld3Ma1eQSNStoQOxI
+P8/Isa2Lcw9z0Xec1INfEmYQpGfTnRgJhfNlNHQZYgjIK20sETGvTTjJyPX3
+=vR4I
+-----END PGP PRIVATE KEY BLOCK-----
+)";
+
+TEST_F(GpgCoreTest, CoreAddADSKTestA) {
+ auto info = GpgKeyImportExporter::GetInstance().ImportKey(
+ GFBuffer(QString::fromLatin1(test_private_key_data)));
+ ASSERT_EQ(info->not_imported, 0);
+ ASSERT_EQ(info->imported, 1);
+
+ auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel)
+ .GetKey("5C4D80546EB6E52F");
+ ASSERT_TRUE(key.IsGood());
+ ASSERT_TRUE(key.IsPrivateKey());
+ ASSERT_TRUE(key.IsHasMasterKey());
+
+ auto key_b = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel)
+ .GetKey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ASSERT_TRUE(key_b.IsGood());
+ ASSERT_TRUE(key_b.IsPrivateKey());
+ ASSERT_TRUE(key_b.IsHasMasterKey());
+
+ auto key_b_subkeys = key_b.GetSubKeys();
+ ASSERT_EQ(key_b_subkeys->size(), 2);
+
+ auto [err, data_object] = GpgKeyOpera::GetInstance().AddADSKSync(key, key_b_subkeys->last());
+
+ ASSERT_EQ(CheckGpgError(err), GPG_ERR_NO_ERROR);
+ ASSERT_EQ(data_object->GetObjectSize(), 1);
+ ASSERT_TRUE(data_object->Check<GpgGenerateKeyResult>());
+
+ auto result = ExtractParams<GpgGenerateKeyResult>(data_object, 0);
+ ASSERT_TRUE(result.IsGood());
+
+ GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).FlushKeyCache();
+ key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel)
+ .GetKey("5C4D80546EB6E52F");
+ ASSERT_TRUE(key.IsGood());
+ ASSERT_TRUE(key.IsPrivateKey());
+ ASSERT_TRUE(key.IsHasMasterKey());
+
+ auto key_subkeys = key.GetSubKeys();
+ ASSERT_EQ(key_subkeys->size(), 2);
+ ASSERT_EQ(key_subkeys->last().GetID(), "F89C95A05088CC93");
+ ASSERT_EQ(key_subkeys->last().IsADSK(), true);
+
+ GpgKeyOpera::GetInstance().DeleteKey(key.GetId());
+}
+}; \ No newline at end of file