diff options
Diffstat (limited to 'src/librepgp/stream-sig.h')
-rw-r--r-- | src/librepgp/stream-sig.h | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/src/librepgp/stream-sig.h b/src/librepgp/stream-sig.h new file mode 100644 index 0000000..4f36c38 --- /dev/null +++ b/src/librepgp/stream-sig.h @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2018-2022, [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STREAM_SIG_H_ +#define STREAM_SIG_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <sys/types.h> +#include "rnp.h" +#include "stream-common.h" +#include "stream-packet.h" + +typedef struct pgp_signature_t { + private: + pgp_sig_type_t type_; + std::vector<uint8_t> preferred(pgp_sig_subpacket_type_t type) const; + void set_preferred(const std::vector<uint8_t> &data, pgp_sig_subpacket_type_t type); + rnp_result_t parse_v3(pgp_packet_body_t &pkt); + rnp_result_t parse_v4(pgp_packet_body_t &pkt); + bool parse_subpackets(uint8_t *buf, size_t len, bool hashed); + + public: + pgp_version_t version; + /* common v3 and v4 fields */ + pgp_pubkey_alg_t palg; + pgp_hash_alg_t halg; + uint8_t lbits[2]; + uint8_t * hashed_data; + size_t hashed_len; + uint8_t * material_buf; /* raw signature material */ + size_t material_len; /* raw signature material length */ + + /* v3 - only fields */ + uint32_t creation_time; + pgp_key_id_t signer; + + /* v4 - only fields */ + std::vector<pgp_sig_subpkt_t> subpkts; + + pgp_signature_t() + : type_(PGP_SIG_BINARY), version(PGP_VUNKNOWN), palg(PGP_PKA_NOTHING), + halg(PGP_HASH_UNKNOWN), hashed_data(NULL), hashed_len(0), material_buf(NULL), + material_len(0), creation_time(0){}; + pgp_signature_t(const pgp_signature_t &src); + pgp_signature_t(pgp_signature_t &&src); + pgp_signature_t &operator=(pgp_signature_t &&src); + pgp_signature_t &operator=(const pgp_signature_t &src); + bool operator==(const pgp_signature_t &src) const; + bool operator!=(const pgp_signature_t &src) const; + ~pgp_signature_t(); + + /* @brief Get signature's type */ + pgp_sig_type_t + type() const + { + return type_; + }; + void + set_type(pgp_sig_type_t atype) + { + type_ = atype; + }; + + bool + is_document() const + { + return (type_ == PGP_SIG_BINARY) || (type_ == PGP_SIG_TEXT); + }; + + /** @brief Calculate the unique signature identifier by hashing signature's fields. */ + pgp_sig_id_t get_id() const; + + /** + * @brief Get v4 signature's subpacket of the specified type and hashedness. + * @param stype subpacket type. + * @param hashed If true (default), then will search for subpacket only in hashed (i.e. + * covered by signature) area, otherwise will search in both hashed and non-hashed areas. + * @return pointer to the subpacket, or NULL if subpacket was not found. + */ + pgp_sig_subpkt_t * get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed = true); + const pgp_sig_subpkt_t *get_subpkt(pgp_sig_subpacket_type_t stype, + bool hashed = true) const; + /* @brief Check whether v4 signature has subpacket of the specified type/hashedness */ + bool has_subpkt(pgp_sig_subpacket_type_t stype, bool hashed = true) const; + /* @brief Check whether signature has signing key id (via v3 field, or v4 key id/key fp + * subpacket) */ + bool has_keyid() const; + /** + * @brief Get signer's key id if available. Availability may be checked via has_keyid(). + * @return signer's key id if available, or empty (zero-filled) keyid otherwise. + */ + pgp_key_id_t keyid() const noexcept; + /** @brief Set the signer's key id for the signature being populated. Version should be set + * prior of setting key id. */ + void set_keyid(const pgp_key_id_t &id); + /** + * @brief Check whether signature has valid issuer fingerprint subpacket. + * @return true if there is one, and it can be safely returned via keyfp() method or false + * otherwise. + */ + bool has_keyfp() const; + /** + * @brief Get signing key's fingerprint if it is available. Availability may be checked via + * has_keyfp() method. + * @return fingerprint (or empty zero-size fp in case it is unavailable) + */ + pgp_fingerprint_t keyfp() const noexcept; + + /** @brief Set signing key's fingerprint. Works only for signatures with version 4 and up, + * so version should be set prior to fingerprint. */ + void set_keyfp(const pgp_fingerprint_t &fp); + + /** + * @brief Get signature's creation time + * @return time in seconds since the Jan 1, 1970 UTC. 0 is the default value and returned + * even if creation time is not available + */ + uint32_t creation() const; + + /** + * @brief Set signature's creation time + * @param ctime creation time in seconds since the Jan 1, 1970 UTC. + */ + void set_creation(uint32_t ctime); + + /** + * @brief Get the signature's expiration time + * @return expiration time in seconds since the creation time. 0 if signature never + * expires. + */ + uint32_t expiration() const; + + /** + * @brief Set the signature's expiration time + * @param etime expiration time + */ + void set_expiration(uint32_t etime); + + /** + * @brief Get the key expiration time + * @return expiration time in seconds since the creation time. 0 if key never expires. + */ + uint32_t key_expiration() const; + + /** + * @brief Set the key expiration time + * @param etime expiration time + */ + void set_key_expiration(uint32_t etime); + + /** + * @brief Get the key flags + * @return byte of key flags. If there is no corresponding subpackets then 0 is returned. + */ + uint8_t key_flags() const; + + /** + * @brief Set the key flags + * @param flags byte of key flags + */ + void set_key_flags(uint8_t flags); + + /** + * @brief Get the primary user id flag + * @return true if user id is marked as primary or false otherwise + */ + bool primary_uid() const; + + /** + * @brief Set the primary user id flag + * @param primary true if user id should be marked as primary + */ + void set_primary_uid(bool primary); + + /** @brief Get preferred symmetric algorithms if any. If there are no ones then empty + * vector is returned. */ + std::vector<uint8_t> preferred_symm_algs() const; + + /** @brief Set the preferred symmetric algorithms. If empty vector is passed then + * corresponding subpacket is deleted. */ + void set_preferred_symm_algs(const std::vector<uint8_t> &algs); + + /** @brief Get preferred hash algorithms if any. If there are no ones then empty vector is + * returned.*/ + std::vector<uint8_t> preferred_hash_algs() const; + + /** @brief Set the preferred hash algorithms. If empty vector is passed then corresponding + * subpacket is deleted. */ + void set_preferred_hash_algs(const std::vector<uint8_t> &algs); + + /** @brief Get preferred compression algorithms if any. If there are no ones then empty + * vector is returned.*/ + std::vector<uint8_t> preferred_z_algs() const; + + /** @brief Set the preferred compression algorithms. If empty vector is passed then + * corresponding subpacket is deleted. */ + void set_preferred_z_algs(const std::vector<uint8_t> &algs); + + /** @brief Get key server preferences flags. If subpacket is not available then 0 is + * returned. */ + uint8_t key_server_prefs() const; + + /** @brief Set key server preferences flags. */ + void set_key_server_prefs(uint8_t prefs); + + /** @brief Get preferred key server URI, if available. Otherwise empty string is returned. + */ + std::string key_server() const; + + /** @brief Set preferred key server URI. If it is empty string then subpacket is deleted if + * it is available. */ + void set_key_server(const std::string &uri); + + /** @brief Get trust level, if available. Otherwise will return 0. See RFC 4880, 5.2.3.14. + * for the detailed information on trust level and amount. + */ + uint8_t trust_level() const; + + /** @brief Get trust amount, if available. Otherwise will return 0. See RFC 4880, 5.2.3.14. + * for the detailed information on trust level and amount. + */ + uint8_t trust_amount() const; + + /** @brief Set the trust level and amount. See RFC 4880, 5.2.3.14. + * for the detailed information on trust level and amount. + */ + void set_trust(uint8_t level, uint8_t amount); + + /** @brief check whether signature is revocable. True by default. + */ + bool revocable() const; + + /** @brief Set the signature's revocability status. + */ + void set_revocable(bool status); + + /** @brief Get the key/subkey revocation reason in humand-readable form. If there is no + * revocation reason subpacket, then empty string will be returned. + */ + std::string revocation_reason() const; + + /** @brief Get the key/subkey revocation code. If there is no revocation reason subpacket, + * then PGP_REVOCATION_NO_REASON will be rerturned. See the RFC 4880, 5.2.3.24 for + * the detailed explanation. + */ + pgp_revocation_type_t revocation_code() const; + + /** @brief Set the revocation reason and code for key/subkey revocation signature. See the + * RFC 4880, 5.2.3.24 for the detailed explanation. + */ + void set_revocation_reason(pgp_revocation_type_t code, const std::string &reason); + + /** + * @brief Check whether signer's key supports certain feature(s). Makes sense only for + * self-signature, for more details see the RFC 4880bis, 5.2.3.25. If there is + * no corresponding subpacket then false will be returned. + * @param flags one or more flags, combined via bitwise OR operation. + * @return true if key is claimed to support all of the features listed in flags, or false + * otherwise + */ + bool key_has_features(pgp_key_feature_t flags) const; + + /** + * @brief Set the features supported by the signer's key, makes sense only for + * self-signature. For more details see the RFC 4880bis, 5.2.3.25. + * @param flags one or more flags, combined via bitwise OR operation. + */ + void set_key_features(pgp_key_feature_t flags); + + /** @brief Get signer's user id, if available. Otherwise empty string is returned. See the + * RFC 4880bis, 5.2.3.23 for details. + */ + std::string signer_uid() const; + + /** + * @brief Set the signer's uid, responcible for the signature creation. See the RFC + * 4880bis, 5.2.3.23 for details. + */ + void set_signer_uid(const std::string &uid); + + /** + * @brief Add notation. + */ + void add_notation(const std::string & name, + const std::vector<uint8_t> &value, + bool human = true, + bool critical = false); + + /** + * @brief Add human-readable notation. + */ + void add_notation(const std::string &name, + const std::string &value, + bool critical = false); + + /** + * @brief Set the embedded signature. + * @param esig populated and calculated embedded signature. + */ + void set_embedded_sig(const pgp_signature_t &esig); + + /** + * @brief Add subpacket of the specified type to v4 signature + * @param type type of the subpacket + * @param datalen length of the subpacket body + * @param reuse replace already existing subpacket of the specified type if any + * @return reference to the subpacket structure or throws an exception + */ + pgp_sig_subpkt_t &add_subpkt(pgp_sig_subpacket_type_t type, size_t datalen, bool reuse); + + /** + * @brief Remove signature's subpacket + * @param subpkt subpacket to remove. If not in the subpackets list then no action is + * taken. + */ + void remove_subpkt(pgp_sig_subpkt_t *subpkt); + + /** + * @brief Check whether signature packet matches one-pass signature packet. + * @param onepass reference to the read one-pass signature packet + * @return true if sig corresponds to onepass or false otherwise + */ + bool matches_onepass(const pgp_one_pass_sig_t &onepass) const; + + /** + * @brief Parse signature body (i.e. without checking the packet header). + * + * @param pkt packet body with data. + * @return RNP_SUCCESS or error code if failed. May also throw an exception. + */ + rnp_result_t parse(pgp_packet_body_t &pkt); + + /** + * @brief Parse signature packet from source. + * + * @param src source with data. + * @return RNP_SUCCESS or error code if failed. May also throw an exception. + */ + rnp_result_t parse(pgp_source_t &src); + + /** + * @brief Parse signature material, stored in the signature in raw. + * + * @param material on success parsed material will be stored here. + * @return true on success or false otherwise. May also throw an exception. + */ + bool parse_material(pgp_signature_material_t &material) const; + + /** + * @brief Write signature to the destination. May throw an exception. + */ + void write(pgp_dest_t &dst) const; + + /** + * @brief Write the signature material's raw representation. May throw an exception. + * + * @param material populated signature material. + */ + void write_material(const pgp_signature_material_t &material); + + /** + * @brief Fill signature's hashed data. This includes all the fields from signature which + * are hashed after the previous document or key fields. + */ + void fill_hashed_data(); +} pgp_signature_t; + +typedef std::vector<pgp_signature_t> pgp_signature_list_t; + +/* information about the validated signature */ +typedef struct pgp_signature_info_t { + pgp_signature_t *sig{}; /* signature, or NULL if there were parsing error */ + bool valid{}; /* signature is cryptographically valid (but may be expired) */ + bool unknown{}; /* signature is unknown - parsing error, wrong version, etc */ + bool no_signer{}; /* no signer's public key available */ + bool expired{}; /* signature is expired */ + bool signer_valid{}; /* assume that signing key is valid */ + bool ignore_expiry{}; /* ignore signer's key expiration time */ +} pgp_signature_info_t; + +/** + * @brief Hash key packet. Used in signatures and v4 fingerprint calculation. + * Throws exception on error. + * @param key key packet, must be populated + * @param hash initialized hash context + */ +void signature_hash_key(const pgp_key_pkt_t &key, rnp::Hash &hash); + +void signature_hash_userid(const pgp_userid_pkt_t &uid, rnp::Hash &hash, pgp_version_t sigver); + +std::unique_ptr<rnp::Hash> signature_hash_certification(const pgp_signature_t & sig, + const pgp_key_pkt_t & key, + const pgp_userid_pkt_t &userid); + +std::unique_ptr<rnp::Hash> signature_hash_binding(const pgp_signature_t &sig, + const pgp_key_pkt_t & key, + const pgp_key_pkt_t & subkey); + +std::unique_ptr<rnp::Hash> signature_hash_direct(const pgp_signature_t &sig, + const pgp_key_pkt_t & key); + +/** + * @brief Parse stream with signatures to the signatures list. + * Can handle binary or armored stream with signatures, including stream with multiple + * armored signatures. + * + * @param src signatures stream, cannot be NULL. + * @param sigs on success parsed signature structures will be put here. + * @return RNP_SUCCESS or error code otherwise. + */ +rnp_result_t process_pgp_signatures(pgp_source_t &src, pgp_signature_list_t &sigs); + +#endif |