From 7165af6006b74522ee19a84cf1a764f573b52784 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Wed, 24 Jan 2024 16:50:14 +0200 Subject: [PATCH] Refactor pgp_key_search_t and related types to C++. --- include/rekey/rnp_key_store.h | 2 +- src/lib/crypto/mem.h | 22 ++ src/lib/ffi-priv-types.h | 22 +- src/lib/key-provider.cpp | 205 ++++++++++++++++++- src/lib/key-provider.h | 126 ++++++++---- src/lib/pgp-key.cpp | 31 +-- src/lib/pgp-key.h | 9 - src/lib/rnp.cpp | 354 ++++++++------------------------- src/librekey/key_store_g10.cpp | 8 +- src/librekey/rnp_key_store.cpp | 22 +- src/librepgp/stream-parse.cpp | 25 +-- src/tests/support.cpp | 55 ++--- 12 files changed, 453 insertions(+), 428 deletions(-) diff --git a/include/rekey/rnp_key_store.h b/include/rekey/rnp_key_store.h index 07735e93e5..de55ecd7c7 100644 --- a/include/rekey/rnp_key_store.h +++ b/include/rekey/rnp_key_store.h @@ -247,7 +247,7 @@ class KeyStore { */ pgp_key_t *primary_key(const pgp_key_t &subkey); - pgp_key_t *search(const pgp_key_search_t &search, pgp_key_t *after = nullptr); + pgp_key_t *search(const KeySearch &search, pgp_key_t *after = nullptr); }; } // namespace rnp diff --git a/src/lib/crypto/mem.h b/src/lib/crypto/mem.h index a69c0162b8..2e05d7158a 100644 --- a/src/lib/crypto/mem.h +++ b/src/lib/crypto/mem.h @@ -36,6 +36,7 @@ #elif defined(CRYPTO_BACKEND_OPENSSL) #include #endif +#include "str-utils.h" namespace rnp { @@ -159,6 +160,27 @@ bool hex_encode(const uint8_t *buf, HexFormat format = HexFormat::Uppercase); size_t hex_decode(const char *hex, uint8_t *buf, size_t buf_len); +inline std::string +bin_to_hex(const uint8_t *data, size_t len, HexFormat format = rnp::HexFormat::Uppercase) +{ + std::string res(len * 2 + 1, '\0'); + hex_encode(data, len, &res.front(), res.size(), format); + return res; +} + +inline std::vector +hex_to_bin(const std::string &str) +{ + if (str.empty() || !rnp::is_hex(str)) { + return {}; + } + /* 1 extra char for case of non-even input , 1 for terminating zero */ + std::vector res(str.size() / 2 + 2); + size_t len = rnp::hex_decode(str.c_str(), res.data(), res.size()); + res.resize(len); + return res; +} + } // namespace rnp void secure_clear(void *vp, size_t size); diff --git a/src/lib/ffi-priv-types.h b/src/lib/ffi-priv-types.h index 85b6cc5e9b..8164580c8b 100644 --- a/src/lib/ffi-priv-types.h +++ b/src/lib/ffi-priv-types.h @@ -29,6 +29,7 @@ #include #include "utils.h" #include +#include #include #include "sec_profile.hpp" @@ -223,12 +224,25 @@ static_assert(RNP_LOCATOR_MAX_SIZE > MAX_ID_LENGTH, "Locator size mismatch."); struct rnp_identifier_iterator_st { rnp_ffi_t ffi; - pgp_key_search_type_t type; + rnp::KeySearch::Type type; rnp::KeyStore * store; std::list::iterator *keyp; - unsigned uididx; - json_object * tbl; - char buf[RNP_LOCATOR_MAX_SIZE]; + size_t uididx; + std::unordered_set tbl; + std::string item; + + rnp_identifier_iterator_st(rnp_ffi_t affi, rnp::KeySearch::Type atype) + : ffi(affi), type(atype) + { + store = nullptr; + keyp = new std::list::iterator(); + uididx = 0; + } + + ~rnp_identifier_iterator_st() + { + delete keyp; + } }; struct rnp_decryption_kp_param_t { diff --git a/src/lib/key-provider.cpp b/src/lib/key-provider.cpp index dbc49be282..60277cb56d 100644 --- a/src/lib/key-provider.cpp +++ b/src/lib/key-provider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com). + * Copyright (c) 2017-2024 [Ribose Inc](https://www.ribose.com). * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -24,28 +24,221 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include +#include +#include #include "key-provider.h" #include "pgp-key.h" #include "fingerprint.h" #include "types.h" #include "utils.h" +#include "str-utils.h" +#include "crypto/mem.h" #include namespace rnp { + +KeySearch::Type +KeySearch::find_type(const std::string &name) +{ + static const std::map types = { + {"keyid", Type::KeyID}, + {"fingerprint", Type::Fingerprint}, + {"grip", Type::Grip}, + {"userid", Type::UserID}}; + if (types.find(name) == types.end()) { + return Type::Unknown; + } + return types.at(name); +} + +std::unique_ptr +KeySearch::create(const pgp_key_id_t &keyid) +{ + return std::unique_ptr(new KeyIDSearch(keyid)); +} + +std::unique_ptr +KeySearch::create(const pgp_fingerprint_t &fp) +{ + return std::unique_ptr(new KeyFingerprintSearch(fp)); +} + +std::unique_ptr +KeySearch::create(const pgp_key_grip_t &grip) +{ + return std::unique_ptr(new KeyGripSearch(grip)); +} + +std::unique_ptr +KeySearch::create(const std::string &uid) +{ + return std::unique_ptr(new KeyUIDSearch(uid)); +} + +std::unique_ptr +KeySearch::create(const std::string &name, const std::string &value) +{ + auto type = find_type(name); + if (type == Type::Unknown) { + return nullptr; + } + if (type == Type::UserID) { + return create(value); + } + /* All the rest values are hex-encoded */ + auto binval = hex_to_bin(value); + if (binval.empty()) { + return nullptr; + } + switch (type) { + case Type::Fingerprint: + if (!pgp_fingerprint_t::size_valid(binval.size())) { + RNP_LOG("Invalid fingerprint: %s", value.c_str()); + return nullptr; + } + return create(pgp_fingerprint_t(binval)); + case Type::KeyID: + if (binval.size() != PGP_KEY_ID_SIZE) { + RNP_LOG("Invalid keyid: %s", value.c_str()); + return nullptr; + } + pgp_key_id_t keyid; + memcpy(keyid.data(), binval.data(), keyid.size()); + return create(keyid); + case Type::Grip: + if (binval.size() != PGP_KEY_GRIP_SIZE) { + RNP_LOG("Invalid grip: %s", value.c_str()); + return nullptr; + } + pgp_key_grip_t grip; + memcpy(grip.data(), binval.data(), grip.size()); + return create(grip); + default: + return nullptr; + } +} + +bool +KeyIDSearch::matches(const pgp_key_t &key) const +{ + return (key.keyid() == keyid_) || (keyid_ == pgp_key_id_t({})); +} + +const std::string +KeyIDSearch::name() const +{ + return "keyid"; +} + +std::string +KeyIDSearch::value() const +{ + return bin_to_hex(keyid_.data(), keyid_.size()); +} + +bool +KeyIDSearch::hidden() const +{ + return keyid_ == pgp_key_id_t({}); +} + +KeyIDSearch::KeyIDSearch(const pgp_key_id_t &keyid) +{ + type_ = Type::KeyID; + keyid_ = keyid; +} + +bool +KeyFingerprintSearch::matches(const pgp_key_t &key) const +{ + return key.fp() == fp_; +} + +const std::string +KeyFingerprintSearch::name() const +{ + return "fingerprint"; +} + +std::string +KeyFingerprintSearch::value() const +{ + return bin_to_hex(fp_.fingerprint, fp_.length); +} + +KeyFingerprintSearch::KeyFingerprintSearch(const pgp_fingerprint_t &fp) +{ + type_ = Type::Fingerprint; + fp_ = fp; +} + +const pgp_fingerprint_t & +KeyFingerprintSearch::get_fp() const +{ + return fp_; +} + +bool +KeyGripSearch::matches(const pgp_key_t &key) const +{ + return key.grip() == grip_; +} + +const std::string +KeyGripSearch::name() const +{ + return "grip"; +} + +std::string +KeyGripSearch::value() const +{ + return bin_to_hex(grip_.data(), grip_.size()); +} + +KeyGripSearch::KeyGripSearch(const pgp_key_grip_t &grip) +{ + type_ = Type::Grip; + grip_ = grip; +} + +bool +KeyUIDSearch::matches(const pgp_key_t &key) const +{ + return key.has_uid(uid_); +} + +const std::string +KeyUIDSearch::name() const +{ + return "userid"; +} + +std::string +KeyUIDSearch::value() const +{ + return uid_; +} + +KeyUIDSearch::KeyUIDSearch(const std::string &uid) +{ + type_ = Type::UserID; + uid_ = uid; +} + pgp_key_t * -KeyProvider::request_key(const pgp_key_request_ctx_t &ctx) const +KeyProvider::request_key(const KeySearch &search, pgp_op_t op, bool secret) const { pgp_key_t *key = nullptr; if (!callback) { return key; } + pgp_key_request_ctx_t ctx(op, secret, search); if (!(key = callback(&ctx, userdata))) { return nullptr; } // confirm that the key actually matches the search criteria - if (!key->matches(ctx.search) || (key->is_secret() != ctx.secret)) { + if (!search.matches(*key) || (key->is_secret() != secret)) { return nullptr; } return key; @@ -57,7 +250,7 @@ rnp_key_provider_key_ptr_list(const pgp_key_request_ctx_t *ctx, void *userdata) { std::vector *key_list = (std::vector *) userdata; for (auto key : *key_list) { - if (key->matches(ctx->search) && (key->is_secret() == ctx->secret)) { + if (ctx->search.matches(*key) && (key->is_secret() == ctx->secret)) { return key; } } diff --git a/src/lib/key-provider.h b/src/lib/key-provider.h index 3323c10863..5133db0aeb 100644 --- a/src/lib/key-provider.h +++ b/src/lib/key-provider.h @@ -31,42 +31,84 @@ typedef struct pgp_key_t pgp_key_t; -typedef enum { - PGP_KEY_SEARCH_UNKNOWN, - PGP_KEY_SEARCH_KEYID, - PGP_KEY_SEARCH_FINGERPRINT, - PGP_KEY_SEARCH_GRIP, - PGP_KEY_SEARCH_USERID -} pgp_key_search_type_t; - -typedef struct pgp_key_search_t { - pgp_key_search_type_t type; - union { - pgp_key_id_t keyid; - pgp_key_grip_t grip; - pgp_fingerprint_t fingerprint; - char userid[MAX_ID_LENGTH + 1]; - } by; - - pgp_key_search_t(pgp_key_search_type_t atype = PGP_KEY_SEARCH_UNKNOWN) : type(atype){}; -} pgp_key_search_t; +typedef struct pgp_key_request_ctx_t pgp_key_request_ctx_t; -typedef struct pgp_key_request_ctx_t { - pgp_op_t op; - bool secret; - pgp_key_search_t search; - - pgp_key_request_ctx_t(pgp_op_t anop = PGP_OP_UNKNOWN, - bool sec = false, - pgp_key_search_type_t tp = PGP_KEY_SEARCH_UNKNOWN) - : op(anop), secret(sec), search(tp) +typedef pgp_key_t *pgp_key_callback_t(const pgp_key_request_ctx_t *ctx, void *userdata); + +namespace rnp { + +class KeySearch { + public: + enum class Type { Unknown, KeyID, Fingerprint, Grip, UserID }; + static Type find_type(const std::string &name); + + virtual Type + type() const { + return type_; } -} pgp_key_request_ctx_t; + virtual bool matches(const pgp_key_t &key) const = 0; + virtual const std::string name() const = 0; + virtual std::string value() const = 0; + virtual ~KeySearch() = default; -typedef pgp_key_t *pgp_key_callback_t(const pgp_key_request_ctx_t *ctx, void *userdata); + static std::unique_ptr create(const pgp_key_id_t &keyid); + static std::unique_ptr create(const pgp_fingerprint_t &fp); + static std::unique_ptr create(const pgp_key_grip_t &grip); + static std::unique_ptr create(const std::string &uid); + static std::unique_ptr create(const std::string &name, + const std::string &value); + + protected: + Type type_; +}; + +class KeyIDSearch : public KeySearch { + pgp_key_id_t keyid_; + + public: + bool matches(const pgp_key_t &key) const; + const std::string name() const; + std::string value() const; + bool hidden() const; + + KeyIDSearch(const pgp_key_id_t &keyid); +}; + +class KeyFingerprintSearch : public KeySearch { + pgp_fingerprint_t fp_; + + public: + bool matches(const pgp_key_t &key) const; + const std::string name() const; + std::string value() const; + + KeyFingerprintSearch(const pgp_fingerprint_t &fp); + const pgp_fingerprint_t &get_fp() const; +}; + +class KeyGripSearch : public KeySearch { + pgp_key_grip_t grip_; + + public: + bool matches(const pgp_key_t &key) const; + const std::string name() const; + std::string value() const; + + KeyGripSearch(const pgp_key_grip_t &grip); +}; + +class KeyUIDSearch : public KeySearch { + std::string uid_; + + public: + bool matches(const pgp_key_t &key) const; + const std::string name() const; + std::string value() const; + + KeyUIDSearch(const std::string &uid); +}; -namespace rnp { class KeyProvider { public: pgp_key_callback_t *callback; @@ -75,15 +117,29 @@ class KeyProvider { KeyProvider(pgp_key_callback_t *cb = nullptr, void *ud = nullptr) : callback(cb), userdata(ud){}; - /** @brief request public or secret pgp key, according to information stored in ctx - * @param ctx information about the request - which operation requested the key, which - *search criteria should be used and whether secret or public key is needed + /** @brief request public or secret pgp key, according to parameters + * @param search search object + * @param op for which operation key is requested + * @param secret whether secret key is requested * @return a key pointer on success, or nullptr if key was not found otherwise **/ - pgp_key_t *request_key(const pgp_key_request_ctx_t &ctx) const; + pgp_key_t *request_key(const KeySearch &search, + pgp_op_t op = PGP_OP_UNKNOWN, + bool secret = false) const; }; } // namespace rnp +typedef struct pgp_key_request_ctx_t { + pgp_op_t op; + bool secret; + const rnp::KeySearch &search; + + pgp_key_request_ctx_t(pgp_op_t anop, bool sec, const rnp::KeySearch &srch) + : op(anop), secret(sec), search(srch) + { + } +} pgp_key_request_ctx_t; + /** key provider callback that searches a list of pgp_key_t pointers * * @param ctx diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 37759b518e..ceb387a5e6 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -456,10 +456,9 @@ find_suitable_key(pgp_op_t op, pgp_key_t *key, rnp::KeyProvider *key_provider, b return key; } /* Check for the case when we need to look up for a secret key */ - pgp_key_request_ctx_t ctx(op, secret, PGP_KEY_SEARCH_FINGERPRINT); if (!no_primary && secret && key->is_public() && key->usable_for(op, true)) { - ctx.search.by.fingerprint = key->fp(); - pgp_key_t *sec = key_provider->request_key(ctx); + rnp::KeyFingerprintSearch search(key->fp()); + pgp_key_t * sec = key_provider->request_key(search, op, secret); if (sec && sec->usable_for(op)) { return sec; } @@ -467,8 +466,8 @@ find_suitable_key(pgp_op_t op, pgp_key_t *key, rnp::KeyProvider *key_provider, b /* Now look up for subkeys */ pgp_key_t *subkey = NULL; for (auto &fp : key->subkey_fps()) { - ctx.search.by.fingerprint = fp; - pgp_key_t *cur = key_provider->request_key(ctx); + rnp::KeyFingerprintSearch search(fp); + pgp_key_t * cur = key_provider->request_key(search, op, secret); if (!cur || !cur->usable_for(op)) { continue; } @@ -1806,28 +1805,6 @@ pgp_key_t::write_vec() const return dst.to_vector(); } -bool -pgp_key_t::matches(const pgp_key_search_t &search) const -{ - switch (search.type) { - case PGP_KEY_SEARCH_KEYID: - return (keyid() == search.by.keyid) || (search.by.keyid == pgp_key_id_t({})); - case PGP_KEY_SEARCH_FINGERPRINT: - return fp() == search.by.fingerprint; - case PGP_KEY_SEARCH_GRIP: - return grip() == search.by.grip; - case PGP_KEY_SEARCH_USERID: - if (has_uid(search.by.userid)) { - return true; - } - break; - default: - assert(false); - break; - } - return false; -} - /* look only for primary userids */ #define PGP_UID_PRIMARY ((uint32_t) -2) /* look for any uid, except PGP_UID_NONE) */ diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index a88de78bac..62e94e113d 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -355,15 +355,6 @@ struct pgp_key_t { * @brief Write key to vector. */ std::vector write_vec() const; - /** checks if a key matches search criteria - * - * Note that this does not do any check on the type of key (public/secret), - * that is left up to the caller. - * - * @param search the search criteria to check against - * @return true if the key satisfies the search criteria, false otherwise - **/ - bool matches(const pgp_key_search_t &search) const; /** * @brief Get the latest valid self-signature with information about the primary key for * the specified uid (including the special cases). It could be userid certification diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 24c8a00e4a..7e1a1965d6 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -80,11 +80,6 @@ static pgp_key_t *get_key_require_public(rnp_key_handle_t handle); static pgp_key_t *get_key_prefer_public(rnp_key_handle_t handle); static pgp_key_t *get_key_require_secret(rnp_key_handle_t handle); -static bool locator_to_str(const pgp_key_search_t &locator, - const char ** identifier_type, - char * identifier, - size_t identifier_size); - static bool rnp_password_cb_bounce(const pgp_password_ctx_t *ctx, char * password, size_t password_size, @@ -93,27 +88,22 @@ static bool rnp_password_cb_bounce(const pgp_password_ctx_t *ctx, static rnp_result_t rnp_dump_src_to_json(pgp_source_t *src, uint32_t flags, char **result); static bool -call_key_callback(rnp_ffi_t ffi, const pgp_key_search_t &search, bool secret) +call_key_callback(rnp_ffi_t ffi, const rnp::KeySearch &search, bool secret) { if (!ffi->getkeycb) { return false; } - char identifier[RNP_LOCATOR_MAX_SIZE]; - const char *identifier_type = NULL; - if (!locator_to_str(search, &identifier_type, identifier, sizeof(identifier))) { - return false; - } - - ffi->getkeycb(ffi, ffi->getkeycb_ctx, identifier_type, identifier, secret); + ffi->getkeycb( + ffi, ffi->getkeycb_ctx, search.name().c_str(), search.value().c_str(), secret); return true; } static pgp_key_t * -find_key(rnp_ffi_t ffi, - const pgp_key_search_t &search, - bool secret, - bool try_key_provider, - pgp_key_t * after = NULL) +find_key(rnp_ffi_t ffi, + const rnp::KeySearch &search, + bool secret, + bool try_key_provider, + pgp_key_t * after = NULL) { auto ks = secret ? ffi->secring : ffi->pubring; pgp_key_t *key = ks->search(search, after); @@ -250,12 +240,6 @@ static const id_str_pair key_flags_map[] = { {0, NULL}, }; -static const id_str_pair identifier_type_map[] = {{PGP_KEY_SEARCH_USERID, "userid"}, - {PGP_KEY_SEARCH_KEYID, "keyid"}, - {PGP_KEY_SEARCH_FINGERPRINT, "fingerprint"}, - {PGP_KEY_SEARCH_GRIP, "grip"}, - {0, NULL}}; - static const id_str_pair key_server_prefs_map[] = {{PGP_KEY_SERVER_NO_MODIFY, "no-modify"}, {0, NULL}}; @@ -3287,8 +3271,12 @@ ffi_decrypt_key_provider(const pgp_key_request_ctx_t *ctx, void *userdata) rnp_decryption_kp_param_t *kparam = (rnp_decryption_kp_param_t *) userdata; auto ffi = kparam->op->ffi; - bool hidden = ctx->secret && (ctx->search.type == PGP_KEY_SEARCH_KEYID) && - (ctx->search.by.keyid == pgp_key_id_t({})); + bool hidden = false; + if (ctx->secret && (ctx->search.type() == rnp::KeySearch::Type::KeyID)) { + auto ksearch = dynamic_cast(&ctx->search); + assert(ksearch != nullptr); + hidden = ksearch->hidden(); + } /* default to the FFI key provider if not hidden keyid request */ if (!hidden) { return ffi->key_provider.callback(ctx, ffi->key_provider.userdata); @@ -3739,118 +3727,10 @@ try { FFI_GUARD static rnp_result_t -str_to_locator(rnp_ffi_t ffi, - pgp_key_search_t *locator, - const char * identifier_type, - const char * identifier) -{ - // parse the identifier type - locator->type = static_cast( - id_str_pair::lookup(identifier_type_map, identifier_type, PGP_KEY_SEARCH_UNKNOWN)); - if (locator->type == PGP_KEY_SEARCH_UNKNOWN) { - FFI_LOG(ffi, "Invalid identifier type: %s", identifier_type); - return RNP_ERROR_BAD_PARAMETERS; - } - // see what type we have - size_t idlen = strlen(identifier); - switch (locator->type) { - case PGP_KEY_SEARCH_USERID: - if (snprintf(locator->by.userid, sizeof(locator->by.userid), "%s", identifier) >= - (int) sizeof(locator->by.userid)) { - FFI_LOG(ffi, "UserID too long"); - return RNP_ERROR_BAD_PARAMETERS; - } - break; - case PGP_KEY_SEARCH_KEYID: { - if (idlen != (PGP_KEY_ID_SIZE * 2) || - !rnp::hex_decode(identifier, locator->by.keyid.data(), locator->by.keyid.size())) { - FFI_LOG(ffi, "Invalid keyid: %s", identifier); - return RNP_ERROR_BAD_PARAMETERS; - } - } break; - case PGP_KEY_SEARCH_FINGERPRINT: { -#if defined(ENABLE_CRYPTO_REFRESH) - static_assert(PGP_FINGERPRINT_V5_SIZE == PGP_FINGERPRINT_V6_SIZE, "FP size mismatch."); -#endif - // Note: v2/v3 fingerprint are 16 bytes (32 chars) long. - if ((idlen != PGP_FINGERPRINT_V4_SIZE * 2) && (idlen != 32) && - (idlen != PGP_FINGERPRINT_V5_SIZE * 2)) { - FFI_LOG(ffi, "Invalid fingerprint: %s", identifier); - return RNP_ERROR_BAD_PARAMETERS; - } - locator->by.fingerprint.length = rnp::hex_decode( - identifier, locator->by.fingerprint.fingerprint, PGP_MAX_FINGERPRINT_SIZE); - if (!locator->by.fingerprint.length) { - FFI_LOG(ffi, "Invalid fingerprint: %s", identifier); - return RNP_ERROR_BAD_PARAMETERS; - } - } break; - case PGP_KEY_SEARCH_GRIP: { - if (strlen(identifier) != (PGP_KEY_GRIP_SIZE * 2) || - !rnp::hex_decode(identifier, locator->by.grip.data(), locator->by.grip.size())) { - FFI_LOG(ffi, "Invalid grip: %s", identifier); - return RNP_ERROR_BAD_PARAMETERS; - } - } break; - default: - // should never happen - assert(false); - return RNP_ERROR_BAD_STATE; - } - return RNP_SUCCESS; -} - -static bool -locator_to_str(const pgp_key_search_t &locator, - const char ** identifier_type, - char * identifier, - size_t identifier_size) -{ - // find the identifier type string with the map - *identifier_type = id_str_pair::lookup(identifier_type_map, locator.type, NULL); - if (!*identifier_type) { - return false; - } - // fill in the actual identifier - switch (locator.type) { - case PGP_KEY_SEARCH_USERID: - if (snprintf(identifier, identifier_size, "%s", locator.by.userid) >= - (int) identifier_size) { - return false; - } - break; - case PGP_KEY_SEARCH_KEYID: - if (!rnp::hex_encode( - locator.by.keyid.data(), locator.by.keyid.size(), identifier, identifier_size)) { - return false; - } - break; - case PGP_KEY_SEARCH_FINGERPRINT: - if (!rnp::hex_encode(locator.by.fingerprint.fingerprint, - locator.by.fingerprint.length, - identifier, - identifier_size)) { - return false; - } - break; - case PGP_KEY_SEARCH_GRIP: - if (!rnp::hex_encode( - locator.by.grip.data(), locator.by.grip.size(), identifier, identifier_size)) { - return false; - } - break; - default: - assert(false); - return false; - } - return true; -} - -static rnp_result_t -rnp_locate_key_int(rnp_ffi_t ffi, - const pgp_key_search_t &locator, - rnp_key_handle_t * handle, - bool require_secret = false) +rnp_locate_key_int(rnp_ffi_t ffi, + const rnp::KeySearch &locator, + rnp_key_handle_t * handle, + bool require_secret = false) { // search pubring pgp_key_t *pub = ffi->pubring->search(locator); @@ -3863,10 +3743,7 @@ rnp_locate_key_int(rnp_ffi_t ffi, } if (pub || sec) { - *handle = new (std::nothrow) rnp_key_handle_st(ffi, pub, sec); - if (!*handle) { - return RNP_ERROR_OUT_OF_MEMORY; - } + *handle = new rnp_key_handle_st(ffi, pub, sec); } else { *handle = nullptr; } @@ -3885,13 +3762,11 @@ try { } // figure out the identifier type - pgp_key_search_t locator; - rnp_result_t ret = str_to_locator(ffi, &locator, identifier_type, identifier); - if (ret) { - return ret; + auto search = rnp::KeySearch::create(identifier_type, identifier); + if (!search) { + return RNP_ERROR_BAD_PARAMETERS; } - - return rnp_locate_key_int(ffi, locator, handle); + return rnp_locate_key_int(ffi, *search, handle); } FFI_GUARD @@ -5002,14 +4877,13 @@ try { return RNP_ERROR_BAD_STATE; } - pgp_key_search_t locator; - rnp_result_t tmpret = str_to_locator(ffi, &locator, identifier_type, identifier); - if (tmpret) { - return tmpret; + auto search = rnp::KeySearch::create(identifier_type, identifier); + if (!search) { + return RNP_ERROR_BAD_PARAMETERS; } - prim_pub = ffi->pubring->search(locator); - prim_sec = ffi->secring->search(locator); + prim_pub = ffi->pubring->search(*search); + prim_sec = ffi->secring->search(*search); if (!prim_sec || !prim_pub) { return RNP_ERROR_KEY_NOT_FOUND; } @@ -5842,21 +5716,16 @@ static pgp_key_t * get_key_require_public(rnp_key_handle_t handle) { if (!handle->pub && handle->sec) { - pgp_key_request_ctx_t request; - request.secret = false; - // try fingerprint - request.search.type = PGP_KEY_SEARCH_FINGERPRINT; - request.search.by.fingerprint = handle->sec->fp(); - handle->pub = handle->ffi->key_provider.request_key(request); + rnp::KeyFingerprintSearch fpsrch(handle->sec->fp()); + handle->pub = handle->ffi->key_provider.request_key(fpsrch); if (handle->pub) { return handle->pub; } // try keyid - request.search.type = PGP_KEY_SEARCH_KEYID; - request.search.by.keyid = handle->sec->keyid(); - handle->pub = handle->ffi->key_provider.request_key(request); + rnp::KeyIDSearch idsrch(handle->sec->keyid()); + handle->pub = handle->ffi->key_provider.request_key(idsrch); } return handle->pub; } @@ -5872,21 +5741,16 @@ static pgp_key_t * get_key_require_secret(rnp_key_handle_t handle) { if (!handle->sec && handle->pub) { - pgp_key_request_ctx_t request; - request.secret = true; - // try fingerprint - request.search.type = PGP_KEY_SEARCH_FINGERPRINT; - request.search.by.fingerprint = handle->pub->fp(); - handle->sec = handle->ffi->key_provider.request_key(request); + rnp::KeyFingerprintSearch fpsrch(handle->pub->fp()); + handle->sec = handle->ffi->key_provider.request_key(fpsrch, PGP_OP_UNKNOWN, true); if (handle->sec) { return handle->sec; } // try keyid - request.search.type = PGP_KEY_SEARCH_KEYID; - request.search.by.keyid = handle->pub->keyid(); - handle->sec = handle->ffi->key_provider.request_key(request); + rnp::KeyIDSearch idsrch(handle->pub->keyid()); + handle->sec = handle->ffi->key_provider.request_key(idsrch, PGP_OP_UNKNOWN, true); } return handle->sec; } @@ -6834,9 +6698,8 @@ try { if (idx >= key->subkey_count()) { return RNP_ERROR_BAD_PARAMETERS; } - pgp_key_search_t locator(PGP_KEY_SEARCH_FINGERPRINT); - locator.by.fingerprint = key->get_subkey_fp(idx); - return rnp_locate_key_int(handle->ffi, locator, subkey); + rnp::KeyFingerprintSearch search(key->get_subkey_fp(idx)); + return rnp_locate_key_int(handle->ffi, search, subkey); } FFI_GUARD @@ -6886,9 +6749,7 @@ try { return RNP_ERROR_NO_SUITABLE_KEY; } - pgp_key_search_t search(PGP_KEY_SEARCH_FINGERPRINT); - search.by.fingerprint = defkey->fp(); - + rnp::KeyFingerprintSearch search(defkey->fp()); rnp_result_t ret = rnp_locate_key_int(primary_key->ffi, search, default_key, secret); if (!*default_key && !ret) { @@ -7231,9 +7092,8 @@ try { return RNP_ERROR_BAD_PARAMETERS; } - pgp_key_search_t search(PGP_KEY_SEARCH_FINGERPRINT); - search.by.fingerprint = pkey->primary_fp(); - pgp_key_t *prim_sec = find_key(key->ffi, search, true, true); + rnp::KeyFingerprintSearch search(pkey->primary_fp()); + pgp_key_t * prim_sec = find_key(key->ffi, search, true, true); if (!prim_sec) { FFI_LOG(key->ffi, "Primary secret key not found."); return RNP_ERROR_KEY_NOT_FOUND; @@ -8444,11 +8304,11 @@ static bool key_iter_next_item(rnp_identifier_iterator_t it) { switch (it->type) { - case PGP_KEY_SEARCH_KEYID: - case PGP_KEY_SEARCH_FINGERPRINT: - case PGP_KEY_SEARCH_GRIP: + case rnp::KeySearch::Type::KeyID: + case rnp::KeySearch::Type::Fingerprint: + case rnp::KeySearch::Type::Grip: return key_iter_next_key(it); - case PGP_KEY_SEARCH_USERID: + case rnp::KeySearch::Type::UserID: it->uididx++; while (it->uididx >= (*it->keyp)->uid_count()) { if (!key_iter_next_key(it)) { @@ -8484,11 +8344,11 @@ static bool key_iter_first_item(rnp_identifier_iterator_t it) { switch (it->type) { - case PGP_KEY_SEARCH_KEYID: - case PGP_KEY_SEARCH_FINGERPRINT: - case PGP_KEY_SEARCH_GRIP: + case rnp::KeySearch::Type::KeyID: + case rnp::KeySearch::Type::Fingerprint: + case rnp::KeySearch::Type::Grip: return key_iter_first_key(it); - case PGP_KEY_SEARCH_USERID: + case rnp::KeySearch::Type::UserID: if (!key_iter_first_key(it)) { return false; } @@ -8506,42 +8366,26 @@ key_iter_first_item(rnp_identifier_iterator_t it) return true; } -static bool -key_iter_get_item(const rnp_identifier_iterator_t it, char *buf, size_t buf_len) +static std::string +key_iter_get_item(const rnp_identifier_iterator_t it) { - const pgp_key_t *key = &**it->keyp; + auto &key = **it->keyp; switch (it->type) { - case PGP_KEY_SEARCH_KEYID: { - if (!rnp::hex_encode(key->keyid().data(), key->keyid().size(), buf, buf_len)) { - return false; - } - break; - } - case PGP_KEY_SEARCH_FINGERPRINT: - if (!rnp::hex_encode(key->fp().fingerprint, key->fp().length, buf, buf_len)) { - return false; - } - break; - case PGP_KEY_SEARCH_GRIP: - if (!rnp::hex_encode(key->grip().data(), key->grip().size(), buf, buf_len)) { - return false; - } - break; - case PGP_KEY_SEARCH_USERID: { - if (it->uididx >= key->uid_count()) { - return false; - } - const pgp_userid_t &uid = key->get_uid(it->uididx); - if (uid.str.size() >= buf_len) { - return false; - } - memcpy(buf, uid.str.c_str(), uid.str.size() + 1); - } break; + case rnp::KeySearch::Type::KeyID: + return rnp::bin_to_hex(key.keyid().data(), key.keyid().size()); + case rnp::KeySearch::Type::Fingerprint: + return rnp::bin_to_hex(key.fp().fingerprint, key.fp().length); + case rnp::KeySearch::Type::Grip: + return rnp::bin_to_hex(key.grip().data(), key.grip().size()); + case rnp::KeySearch::Type::UserID: + if (it->uididx >= key.uid_count()) { + return ""; + } + return key.get_uid(it->uididx).str; default: assert(false); - break; + return ""; } - return true; } rnp_result_t @@ -8549,51 +8393,25 @@ rnp_identifier_iterator_create(rnp_ffi_t ffi, rnp_identifier_iterator_t *it, const char * identifier_type) try { - rnp_result_t ret = RNP_ERROR_GENERIC; - struct rnp_identifier_iterator_st *obj = NULL; - // checks if (!ffi || !it || !identifier_type) { return RNP_ERROR_NULL_POINTER; } // create iterator - obj = (struct rnp_identifier_iterator_st *) calloc(1, sizeof(*obj)); - if (!obj) { - return RNP_ERROR_OUT_OF_MEMORY; - } - obj->ffi = ffi; - obj->keyp = new std::list::iterator(); - obj->uididx = 0; - // parse identifier type - obj->type = static_cast( - id_str_pair::lookup(identifier_type_map, identifier_type, PGP_KEY_SEARCH_UNKNOWN)); - if (obj->type == PGP_KEY_SEARCH_UNKNOWN) { - ret = RNP_ERROR_BAD_PARAMETERS; - goto done; - } - obj->tbl = json_object_new_object(); - if (!obj->tbl) { - ret = RNP_ERROR_OUT_OF_MEMORY; - goto done; + auto type = rnp::KeySearch::find_type(identifier_type); + if (type == rnp::KeySearch::Type::Unknown) { + return RNP_ERROR_BAD_PARAMETERS; } + *it = new rnp_identifier_iterator_st(ffi, type); // move to first item (if any) - key_iter_first_item(obj); - *it = obj; - - ret = RNP_SUCCESS; -done: - if (ret) { - rnp_identifier_iterator_destroy(obj); - } - return ret; + key_iter_first_item(*it); + return RNP_SUCCESS; } FFI_GUARD rnp_result_t rnp_identifier_iterator_next(rnp_identifier_iterator_t it, const char **identifier) try { - rnp_result_t ret = RNP_ERROR_GENERIC; - // checks if (!it || !identifier) { return RNP_ERROR_NULL_POINTER; @@ -8605,41 +8423,31 @@ try { return RNP_SUCCESS; } // get the item - if (!key_iter_get_item(it, it->buf, sizeof(it->buf))) { + it->item = key_iter_get_item(it); + if (it->item.empty()) { return RNP_ERROR_GENERIC; } bool exists; bool iterator_valid = true; - while ((exists = json_object_object_get_ex(it->tbl, it->buf, NULL))) { + while ((exists = (it->tbl.find(it->item) != it->tbl.end()))) { if (!((iterator_valid = key_iter_next_item(it)))) { break; } - if (!key_iter_get_item(it, it->buf, sizeof(it->buf))) { + it->item = key_iter_get_item(it); + if (it->item.empty()) { return RNP_ERROR_GENERIC; } } // see if we actually found a new entry if (!exists) { - // TODO: Newer json-c has a useful return value for json_object_object_add, - // which doesn't require the json_object_object_get_ex check below. - json_object_object_add(it->tbl, it->buf, NULL); - if (!json_object_object_get_ex(it->tbl, it->buf, NULL)) { - ret = RNP_ERROR_OUT_OF_MEMORY; - goto done; - } - *identifier = it->buf; + it->tbl.insert(it->item); + *identifier = it->item.c_str(); } // prepare for the next one if (iterator_valid) { key_iter_next_item(it); } - ret = RNP_SUCCESS; - -done: - if (ret) { - *identifier = NULL; - } - return ret; + return RNP_SUCCESS; } FFI_GUARD @@ -8647,11 +8455,7 @@ rnp_result_t rnp_identifier_iterator_destroy(rnp_identifier_iterator_t it) try { if (it) { - json_object_put(it->tbl); - if (it->keyp) { - delete it->keyp; - } - free(it); + delete it; } return RNP_SUCCESS; } diff --git a/src/librekey/key_store_g10.cpp b/src/librekey/key_store_g10.cpp index 8a06ba4933..96a882344c 100644 --- a/src/librekey/key_store_g10.cpp +++ b/src/librekey/key_store_g10.cpp @@ -908,12 +908,12 @@ KeyStore::load_g10(pgp_source_t &src, const KeyProvider *key_provider) /* copy public key fields if any */ pgp_key_t key; if (key_provider) { - pgp_key_request_ctx_t req_ctx(PGP_OP_MERGE_INFO, false, PGP_KEY_SEARCH_GRIP); - if (!seckey.material.get_grip(req_ctx.search.by.grip)) { + pgp_key_grip_t grip; + if (!seckey.material.get_grip(grip)) { return false; } - - const pgp_key_t *pubkey = key_provider->request_key(req_ctx); + auto pubkey = + key_provider->request_key(*rnp::KeySearch::create(grip), PGP_OP_MERGE_INFO); if (!pubkey) { return false; } diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index 293f968f3d..8a09357280 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -633,11 +633,13 @@ KeyStore::primary_key(const pgp_key_t &subkey) } pgp_key_t * -KeyStore::search(const pgp_key_search_t &search, pgp_key_t *after) +KeyStore::search(const KeySearch &search, pgp_key_t *after) { // since keys are distinguished by fingerprint then just do map lookup - if (search.type == PGP_KEY_SEARCH_FINGERPRINT) { - pgp_key_t *key = get_key(search.by.fingerprint); + if (search.type() == KeySearch::Type::Fingerprint) { + auto fpsearch = dynamic_cast(&search); + assert(fpsearch != nullptr); + auto key = get_key(fpsearch->get_fp()); if (after && (after != key)) { RNP_LOG("searching with invalid after param"); return nullptr; @@ -658,31 +660,29 @@ KeyStore::search(const pgp_key_search_t &search, pgp_key_t *after) it = std::next(it); } it = std::find_if( - it, keys.end(), [&search](const pgp_key_t &key) { return key.matches(search); }); + it, keys.end(), [&search](const pgp_key_t &key) { return search.matches(key); }); return (it == keys.end()) ? nullptr : &(*it); } pgp_key_t * KeyStore::get_signer(const pgp_signature_t &sig, const KeyProvider *prov) { - pgp_key_request_ctx_t ctx(PGP_OP_VERIFY, false, PGP_KEY_SEARCH_UNKNOWN); /* if we have fingerprint let's check it */ + std::unique_ptr ks; if (sig.has_keyfp()) { - ctx.search.by.fingerprint = sig.keyfp(); - ctx.search.type = PGP_KEY_SEARCH_FINGERPRINT; + ks = KeySearch::create(sig.keyfp()); } else if (sig.has_keyid()) { - ctx.search.by.keyid = sig.keyid(); - ctx.search.type = PGP_KEY_SEARCH_KEYID; + ks = KeySearch::create(sig.keyid()); } else { RNP_LOG("No way to search for the signer."); return nullptr; } - pgp_key_t *key = search(ctx.search); + auto key = search(*ks); if (key || !prov) { return key; } - return prov->request_key(ctx); + return prov->request_key(*ks, PGP_OP_VERIFY); } KeyStore::KeyStore(pgp_key_store_format_t _format, diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 440d1d29fc..60e6b528ff 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -862,25 +862,22 @@ signed_validate_signature(pgp_source_signed_param_t ¶m, pgp_signature_info_t return; } /* Find signing key */ - pgp_key_request_ctx_t keyctx(PGP_OP_VERIFY, false, PGP_KEY_SEARCH_FINGERPRINT); - + std::unique_ptr search; /* Get signer's fp or keyid */ if (sinfo.sig->has_keyfp()) { - keyctx.search.by.fingerprint = sinfo.sig->keyfp(); + search = rnp::KeySearch::create(sinfo.sig->keyfp()); } else if (sinfo.sig->has_keyid()) { - keyctx.search.type = PGP_KEY_SEARCH_KEYID; - keyctx.search.by.keyid = sinfo.sig->keyid(); + search = rnp::KeySearch::create(sinfo.sig->keyid()); } else { RNP_LOG("cannot get signer's key fp or id from signature."); sinfo.unknown = true; return; } /* Get the public key */ - pgp_key_t *key = param.handler->key_provider->request_key(keyctx); + auto key = param.handler->key_provider->request_key(*search, PGP_OP_VERIFY); if (!key) { /* fallback to secret key */ - keyctx.secret = true; - if (!(key = param.handler->key_provider->request_key(keyctx))) { + if (!(key = param.handler->key_provider->request_key(*search, PGP_OP_VERIFY, true))) { RNP_LOG("signer's key not found"); sinfo.no_signer = true; return; @@ -2398,26 +2395,24 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t goto finish; } - pgp_key_request_ctx_t keyctx(PGP_OP_DECRYPT, true, PGP_KEY_SEARCH_KEYID); - size_t pubidx = 0; size_t hidden_tries = 0; errcode = RNP_ERROR_NO_SUITABLE_KEY; while (pubidx < param->pubencs.size()) { - auto &pubenc = param->pubencs[pubidx]; + auto & pubenc = param->pubencs[pubidx]; + std::unique_ptr search; #if defined(ENABLE_CRYPTO_REFRESH) if (pubenc.version == PGP_PKSK_V3) { #endif - keyctx.search.by.keyid = pubenc.key_id; + search = rnp::KeySearch::create(pubenc.key_id); #if defined(ENABLE_CRYPTO_REFRESH) } else { // PGP_PKSK_V6 - keyctx.search.by.fingerprint = pubenc.fp; - keyctx.search.type = PGP_KEY_SEARCH_FINGERPRINT; + search = rnp::KeySearch::create(pubenc.fp); } #endif /* Get the key if any */ - pgp_key_t *seckey = handler->key_provider->request_key(keyctx); + auto seckey = handler->key_provider->request_key(*search, PGP_OP_DECRYPT, true); if (!seckey) { pubidx++; continue; diff --git a/src/tests/support.cpp b/src/tests/support.cpp index ce6843e59d..08c3b41779 100644 --- a/src/tests/support.cpp +++ b/src/tests/support.cpp @@ -362,36 +362,15 @@ clean_temp_dir(const char *path) bool bin_eq_hex(const uint8_t *data, size_t len, const char *val) { - size_t stlen = strlen(val); - if (stlen != len * 2) { - return false; - } - - std::vector dec(len); - rnp::hex_decode(val, dec.data(), len); - return !memcmp(data, dec.data(), len); + auto valbin = rnp::hex_to_bin(val); + return (valbin.size() == len) && !memcmp(data, valbin.data(), len); } bool hex2mpi(pgp_mpi_t *val, const char *hex) { - const size_t hex_len = strlen(hex); - size_t buf_len = hex_len / 2; - bool ok; - - uint8_t *buf = NULL; - - buf = (uint8_t *) malloc(buf_len); - - if (buf == NULL) { - return false; - } - - rnp::hex_decode(hex, buf, buf_len); - - ok = mem2mpi(val, buf, buf_len); - free(buf); - return ok; + auto hexbin = rnp::hex_to_bin(hex); + return mem2mpi(val, hexbin.data(), hexbin.size()); } bool @@ -771,8 +750,7 @@ rnp_tests_get_key_by_id(rnp::KeyStore *keyring, const std::string &keyid, pgp_ke if (binlen > PGP_KEY_ID_SIZE) { return NULL; } - pgp_key_search_t search(PGP_KEY_SEARCH_KEYID); - search.by.keyid = keyid_bin; + rnp::KeyIDSearch search(keyid_bin); return keyring->search(search, after); } @@ -796,24 +774,23 @@ rnp_tests_get_key_by_grip(rnp::KeyStore *keyring, const pgp_key_grip_t &grip) if (!keyring) { return NULL; } - pgp_key_search_t search(PGP_KEY_SEARCH_GRIP); - search.by.grip = grip; - return keyring->search(search); + return keyring->search(rnp::KeyGripSearch(grip)); } pgp_key_t * -rnp_tests_get_key_by_fpr(rnp::KeyStore *keyring, const std::string &keyid) +rnp_tests_get_key_by_fpr(rnp::KeyStore *keyring, const std::string &fpstr) { - if (!keyring || keyid.empty() || !rnp::is_hex(keyid)) { + if (!keyring || fpstr.empty() || !rnp::is_hex(fpstr)) { return NULL; } - std::vector keyid_bin(PGP_MAX_FINGERPRINT_SIZE, 0); - size_t binlen = rnp::hex_decode(keyid.c_str(), keyid_bin.data(), keyid_bin.size()); + std::vector fp_bin(PGP_MAX_FINGERPRINT_SIZE, 0); + size_t binlen = rnp::hex_decode(fpstr.c_str(), fp_bin.data(), fp_bin.size()); if (binlen > PGP_MAX_FINGERPRINT_SIZE) { return NULL; } - pgp_fingerprint_t fp = {{}, static_cast(binlen)}; - memcpy(fp.fingerprint, keyid_bin.data(), binlen); + pgp_fingerprint_t fp; + memcpy(fp.fingerprint, fp_bin.data(), binlen); + fp.length = binlen; return keyring->get_key(fp); } @@ -823,11 +800,7 @@ rnp_tests_key_search(rnp::KeyStore *keyring, const std::string &uid) if (!keyring || uid.empty()) { return NULL; } - - pgp_key_search_t srch_userid(PGP_KEY_SEARCH_USERID); - strncpy(srch_userid.by.userid, uid.c_str(), sizeof(srch_userid.by.userid)); - srch_userid.by.userid[sizeof(srch_userid.by.userid) - 1] = '\0'; - return keyring->search(srch_userid); + return keyring->search(rnp::KeyUIDSearch(uid)); } void