diff --git a/src/openpgp/openpgp.cpp b/src/openpgp/openpgp.cpp index 108990fb..437e0d99 100644 --- a/src/openpgp/openpgp.cpp +++ b/src/openpgp/openpgp.cpp @@ -93,15 +93,9 @@ std::string get_armored_block_contents(const std::string &text, const std::strin } // namespace -public_key_rsa::public_key_rsa(const std::string &armored) - : public_key_rsa(decode(armored)) -{ -} - -public_key_rsa::public_key_rsa(std::tuple params) - : m_expression(std::move(std::get<1>(params))) - , m_bits(std::get<2>(params)) - , m_user_id(std::move(std::get<0>(params))) +public_key_rsa::public_key_rsa(s_expression expression, size_t bits) + : m_expression(std::move(expression)) + , m_bits(bits) { } @@ -115,19 +109,14 @@ size_t public_key_rsa::bits() const return m_bits; } -std::string public_key_rsa::user_id() const +public_key_block::public_key_block(const std::string &armored) + : public_key_block(epee::to_byte_span(epee::to_span(epee::string_encoding::base64_decode( + strip_line_breaks(get_armored_block_contents(armored, "BEGIN PGP PUBLIC KEY BLOCK")))))) { - return m_user_id; } -std::tuple public_key_rsa::decode(const std::string &armored) -{ - const std::string buffer = epee::string_encoding::base64_decode( - strip_line_breaks(get_armored_block_contents(armored, "BEGIN PGP PUBLIC KEY BLOCK"))); - return decode(epee::to_byte_span(epee::to_span(buffer))); -} - -std::tuple public_key_rsa::decode(const epee::span buffer) +// TODO: Public-Key expiration, User ID and Public-Key certification, Subkey binding checks +public_key_block::public_key_block(const epee::span buffer) { packet_stream packets(buffer); @@ -136,38 +125,51 @@ std::tuple public_key_rsa::decode(const epee: { throw std::runtime_error("user id is missing"); } - std::string user_id(data->begin(), data->end()); + m_user_id.assign(data->begin(), data->end()); + + const auto append_public_key = [this](const std::vector &data) { + deserializer> serialized(data); + + const auto version = serialized.read_big_endian(); + if (version != 4) + { + throw std::runtime_error("unsupported public key version"); + } + + /* const auto timestamp = */ serialized.read_big_endian(); + + const auto algorithm = serialized.read_big_endian(); + if (algorithm != algorithm::rsa) + { + throw std::runtime_error("unsupported public key algorithm"); + } + + { + const mpi public_key_n = serialized.read_mpi(); + const mpi public_key_e = serialized.read_mpi(); + + emplace_back( + s_expression("(public-key (rsa (n %m) (e %m)))", public_key_n.get(), public_key_e.get()), + gcry_mpi_get_nbits(public_key_n.get())); + } + }; data = packets.find_first(packet_tag::type::public_key); if (data == nullptr) { throw std::runtime_error("public key is missing"); } + append_public_key(*data); - deserializer> serialized(*data); - - const auto version = serialized.read_big_endian(); - if (version != 4) - { - throw std::runtime_error("unsupported public key version"); - } - - /* const auto timestamp = */ serialized.read_big_endian(); - - const auto algorithm = serialized.read_big_endian(); - if (algorithm != algorithm::rsa) - { - throw std::runtime_error("unsupported public key algorithm"); - } - - const mpi public_key_n = serialized.read_mpi(); - const mpi public_key_e = serialized.read_mpi(); - - s_expression expression("(public-key (rsa (n %m) (e %m)))", public_key_n.get(), public_key_e.get()); - - return {std::move(user_id), std::move(expression), gcry_mpi_get_nbits(public_key_n.get())}; + packets.for_each(packet_tag::type::public_subkey, append_public_key); } +std::string public_key_block::user_id() const +{ + return m_user_id; +} + +// TODO: Signature expiration check signature_rsa::signature_rsa( uint8_t algorithm, std::pair hash_leftmost_bytes, diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h index cef003ed..e876ecca 100644 --- a/src/openpgp/openpgp.h +++ b/src/openpgp/openpgp.h @@ -47,20 +47,25 @@ enum algorithm : uint8_t class public_key_rsa { public: - public_key_rsa(const std::string &armored); - public_key_rsa(std::tuple params); + public_key_rsa(s_expression expression, size_t bits); size_t bits() const; const gcry_sexp_t &get() const; - std::string user_id() const; - -private: - static std::tuple decode(const std::string &armored); - static std::tuple decode(const epee::span buffer); private: s_expression m_expression; size_t m_bits; +}; + +class public_key_block : public std::vector +{ +public: + public_key_block(const std::string &armored); + public_key_block(const epee::span buffer); + + std::string user_id() const; + +private: std::string m_user_id; }; diff --git a/src/openpgp/packet_stream.h b/src/openpgp/packet_stream.h index b93b8747..6a993e92 100644 --- a/src/openpgp/packet_stream.h +++ b/src/openpgp/packet_stream.h @@ -69,6 +69,18 @@ public: return nullptr; } + template + void for_each(packet_tag::type type, Callback &callback) const + { + for (const auto &packet : packets) + { + if (packet.first.packet_type == type) + { + callback(packet.second); + } + } + } + private: std::vector>> packets; }; diff --git a/src/openpgp/serialization.h b/src/openpgp/serialization.h index 33de9216..fb42c1b6 100644 --- a/src/openpgp/serialization.h +++ b/src/openpgp/serialization.h @@ -60,6 +60,7 @@ struct packet_tag signature = 2, public_key = 6, user_id = 13, + public_subkey = 14, }; const type packet_type; diff --git a/src/qt/updater.cpp b/src/qt/updater.cpp index b8afc761..63078640 100644 --- a/src/qt/updater.cpp +++ b/src/qt/updater.cpp @@ -158,9 +158,12 @@ QString Updater::verifySignature(const epee::span data, const ope { for (const auto &maintainer : m_maintainers) { - if (signature.verify(data, maintainer)) + for (const auto &public_key : maintainer) { - return QString::fromStdString(maintainer.user_id()); + if (signature.verify(data, public_key)) + { + return QString::fromStdString(maintainer.user_id()); + } } } diff --git a/src/qt/updater.h b/src/qt/updater.h index 48a59a71..e787e42d 100644 --- a/src/qt/updater.h +++ b/src/qt/updater.h @@ -60,5 +60,5 @@ private: QByteArray parseShasumOutput(const QString &message, const QString &filename) const; private: - std::vector m_maintainers; + std::vector m_maintainers; };