diff options
author | saturneric <[email protected]> | 2025-04-11 18:51:02 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2025-04-11 18:51:13 +0000 |
commit | c5f1c389e0fb66e932f1eb221068db175e4bbd96 (patch) | |
tree | d7cd8bbd7fbcca9e2848862110999cc32eceeef1 /src | |
parent | chore: not possible to build a universal version without support from homebrew (diff) | |
download | GpgFrontend-c5f1c389e0fb66e932f1eb221068db175e4bbd96.tar.gz GpgFrontend-c5f1c389e0fb66e932f1eb221068db175e4bbd96.zip |
feat: support adsk
Diffstat (limited to 'src')
-rw-r--r-- | src/core/function/gpg/GpgKeyOpera.cpp | 38 | ||||
-rw-r--r-- | src/core/function/gpg/GpgKeyOpera.h | 19 | ||||
-rw-r--r-- | src/core/model/GpgKey.h | 175 | ||||
-rw-r--r-- | src/core/model/GpgSubKey.cpp | 5 | ||||
-rw-r--r-- | src/core/model/GpgSubKey.h | 75 | ||||
-rw-r--r-- | src/test/core/GpgCoreTestKeyOpera.cpp | 117 |
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 |