diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/x509/pkix_types.h')
-rw-r--r-- | comm/third_party/botan/src/lib/x509/pkix_types.h | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/x509/pkix_types.h b/comm/third_party/botan/src/lib/x509/pkix_types.h new file mode 100644 index 0000000000..983121955f --- /dev/null +++ b/comm/third_party/botan/src/lib/x509/pkix_types.h @@ -0,0 +1,613 @@ +/* +* (C) 1999-2010,2012,2018,2020 Jack Lloyd +* (C) 2007 Yves Jerschow +* (C) 2015 Kai Michaelis +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PKIX_TYPES_H_ +#define BOTAN_PKIX_TYPES_H_ + +#include <botan/asn1_obj.h> +#include <botan/pkix_enums.h> +#include <vector> +#include <string> +#include <iosfwd> +#include <map> +#include <set> + +namespace Botan { + +class X509_Certificate; +class Data_Store; +class Public_Key; + +/** +* Check that key constraints are permitted for a specific public key. +* @param pub_key the public key on which the constraints shall be enforced on +* @param constraints the constraints that shall be enforced on the key +* @throw Invalid_Argument if the given constraints are not permitted for this key +*/ +BOTAN_PUBLIC_API(2,0) void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, + Key_Constraints constraints); + +std::string BOTAN_PUBLIC_API(2,0) key_constraints_to_string(Key_Constraints); + +/** +* Distinguished Name +*/ +class BOTAN_PUBLIC_API(2,0) X509_DN final : public ASN1_Object + { + public: + X509_DN() = default; + + explicit X509_DN(const std::multimap<OID, std::string>& args) + { + for(auto i : args) + add_attribute(i.first, i.second); + } + + explicit X509_DN(const std::multimap<std::string, std::string>& args) + { + for(auto i : args) + add_attribute(i.first, i.second); + } + + void encode_into(DER_Encoder&) const override; + void decode_from(BER_Decoder&) override; + + bool has_field(const OID& oid) const; + ASN1_String get_first_attribute(const OID& oid) const; + + /* + * Return the BER encoded data, if any + */ + const std::vector<uint8_t>& get_bits() const { return m_dn_bits; } + + bool empty() const { return m_rdn.empty(); } + + std::string to_string() const; + + const std::vector<std::pair<OID,ASN1_String>>& dn_info() const { return m_rdn; } + + std::multimap<OID, std::string> get_attributes() const; + std::multimap<std::string, std::string> contents() const; + + bool has_field(const std::string& attr) const; + std::vector<std::string> get_attribute(const std::string& attr) const; + std::string get_first_attribute(const std::string& attr) const; + + void add_attribute(const std::string& key, const std::string& val); + + void add_attribute(const OID& oid, const std::string& val) + { + add_attribute(oid, ASN1_String(val)); + } + + void add_attribute(const OID& oid, const ASN1_String& val); + + static std::string deref_info_field(const std::string& key); + + /** + * Lookup upper bounds in characters for the length of distinguished name fields + * as given in RFC 5280, Appendix A. + * + * @param oid the oid of the DN to lookup + * @return the upper bound, or zero if no ub is known to Botan + */ + static size_t lookup_ub(const OID& oid); + + private: + std::vector<std::pair<OID,ASN1_String>> m_rdn; + std::vector<uint8_t> m_dn_bits; + }; + +bool BOTAN_PUBLIC_API(2,0) operator==(const X509_DN& dn1, const X509_DN& dn2); +bool BOTAN_PUBLIC_API(2,0) operator!=(const X509_DN& dn1, const X509_DN& dn2); + +/* +The ordering here is arbitrary and may change from release to release. +It is intended for allowing DNs as keys in std::map and similiar containers +*/ +bool BOTAN_PUBLIC_API(2,0) operator<(const X509_DN& dn1, const X509_DN& dn2); + +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& out, const X509_DN& dn); +BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream& in, X509_DN& dn); + +/** +* Alternative Name +*/ +class BOTAN_PUBLIC_API(2,0) AlternativeName final : public ASN1_Object + { + public: + void encode_into(DER_Encoder&) const override; + void decode_from(BER_Decoder&) override; + + std::multimap<std::string, std::string> contents() const; + + bool has_field(const std::string& attr) const; + std::vector<std::string> get_attribute(const std::string& attr) const; + + std::string get_first_attribute(const std::string& attr) const; + + void add_attribute(const std::string& type, const std::string& value); + void add_othername(const OID& oid, const std::string& value, ASN1_Tag type); + + const std::multimap<std::string, std::string>& get_attributes() const + { + return m_alt_info; + } + + const std::multimap<OID, ASN1_String>& get_othernames() const + { + return m_othernames; + } + + X509_DN dn() const; + + bool has_items() const; + + AlternativeName(const std::string& email_addr = "", + const std::string& uri = "", + const std::string& dns = "", + const std::string& ip_address = ""); + private: + std::multimap<std::string, std::string> m_alt_info; + std::multimap<OID, ASN1_String> m_othernames; + }; + +/** +* Attribute +*/ +class BOTAN_PUBLIC_API(2,0) Attribute final : public ASN1_Object + { + public: + void encode_into(DER_Encoder& to) const override; + void decode_from(BER_Decoder& from) override; + + Attribute() = default; + Attribute(const OID&, const std::vector<uint8_t>&); + Attribute(const std::string&, const std::vector<uint8_t>&); + + const OID& get_oid() const { return oid; } + + const std::vector<uint8_t>& get_parameters() const { return parameters; } + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + * These values are public for historical reasons, but in a future release + * they will be made private. Do not access them. + */ + OID oid; + std::vector<uint8_t> parameters; + }; + +/** +* @brief X.509 GeneralName Type +* +* Handles parsing GeneralName types in their BER and canonical string +* encoding. Allows matching GeneralNames against each other using +* the rules laid out in the RFC 5280, sec. 4.2.1.10 (Name Contraints). +*/ +class BOTAN_PUBLIC_API(2,0) GeneralName final : public ASN1_Object + { + public: + enum MatchResult : int + { + All, + Some, + None, + NotFound, + UnknownType, + }; + + /** + * Creates an empty GeneralName. + */ + GeneralName() = default; + + /** + * Creates a new GeneralName for its string format. + * @param str type and name, colon-separated, e.g., "DNS:google.com" + */ + GeneralName(const std::string& str); + + void encode_into(DER_Encoder&) const override; + + void decode_from(BER_Decoder&) override; + + /** + * @return Type of the name. Can be DN, DNS, IP, RFC822 or URI. + */ + const std::string& type() const { return m_type; } + + /** + * @return The name as string. Format depends on type. + */ + const std::string& name() const { return m_name; } + + /** + * Checks whether a given certificate (partially) matches this name. + * @param cert certificate to be matched + * @return the match result + */ + MatchResult matches(const X509_Certificate& cert) const; + + private: + std::string m_type; + std::string m_name; + + bool matches_dns(const std::string&) const; + bool matches_dn(const std::string&) const; + bool matches_ip(const std::string&) const; + }; + +std::ostream& operator<<(std::ostream& os, const GeneralName& gn); + +/** +* @brief A single Name Constraint +* +* The Name Constraint extension adds a minimum and maximum path +* length to a GeneralName to form a constraint. The length limits +* are currently unused. +*/ +class BOTAN_PUBLIC_API(2,0) GeneralSubtree final : public ASN1_Object + { + public: + /** + * Creates an empty name constraint. + */ + GeneralSubtree() : m_base(), m_minimum(0), m_maximum(std::numeric_limits<std::size_t>::max()) + {} + + /*** + * Creates a new name constraint. + * @param base name + * @param min minimum path length + * @param max maximum path length + */ + GeneralSubtree(const GeneralName& base, size_t min, size_t max) + : m_base(base), m_minimum(min), m_maximum(max) + {} + + /** + * Creates a new name constraint for its string format. + * @param str name constraint + */ + GeneralSubtree(const std::string& str); + + void encode_into(DER_Encoder&) const override; + + void decode_from(BER_Decoder&) override; + + /** + * @return name + */ + const GeneralName& base() const { return m_base; } + + /** + * @return minimum path length + */ + size_t minimum() const { return m_minimum; } + + /** + * @return maximum path length + */ + size_t maximum() const { return m_maximum; } + + private: + GeneralName m_base; + size_t m_minimum; + size_t m_maximum; + }; + +std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs); + +/** +* @brief Name Constraints +* +* Wraps the Name Constraints associated with a certificate. +*/ +class BOTAN_PUBLIC_API(2,0) NameConstraints final + { + public: + /** + * Creates an empty name NameConstraints. + */ + NameConstraints() : m_permitted_subtrees(), m_excluded_subtrees() {} + + /** + * Creates NameConstraints from a list of permitted and excluded subtrees. + * @param permitted_subtrees names for which the certificate is permitted + * @param excluded_subtrees names for which the certificate is not permitted + */ + NameConstraints(std::vector<GeneralSubtree>&& permitted_subtrees, + std::vector<GeneralSubtree>&& excluded_subtrees) + : m_permitted_subtrees(permitted_subtrees), m_excluded_subtrees(excluded_subtrees) + {} + + /** + * @return permitted names + */ + const std::vector<GeneralSubtree>& permitted() const { return m_permitted_subtrees; } + + /** + * @return excluded names + */ + const std::vector<GeneralSubtree>& excluded() const { return m_excluded_subtrees; } + + private: + std::vector<GeneralSubtree> m_permitted_subtrees; + std::vector<GeneralSubtree> m_excluded_subtrees; + }; + +/** +* X.509 Certificate Extension +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Extension + { + public: + /** + * @return OID representing this extension + */ + virtual OID oid_of() const = 0; + + /* + * @return specific OID name + * If possible OIDS table should match oid_name to OIDS, ie + * OID::from_string(ext->oid_name()) == ext->oid_of() + * Should return empty string if OID is not known + */ + virtual std::string oid_name() const = 0; + + /** + * Make a copy of this extension + * @return copy of this + */ + virtual Certificate_Extension* copy() const = 0; + + /* + * Add the contents of this extension into the information + * for the subject and/or issuer, as necessary. + * @param subject the subject info + * @param issuer the issuer info + */ + virtual void contents_to(Data_Store& subject, + Data_Store& issuer) const = 0; + + /* + * Callback visited during path validation. + * + * An extension can implement this callback to inspect + * the path during path validation. + * + * If an error occurs during validation of this extension, + * an appropriate status code shall be added to cert_status. + * + * @param subject Subject certificate that contains this extension + * @param issuer Issuer certificate + * @param status Certificate validation status codes for subject certificate + * @param cert_path Certificate path which is currently validated + * @param pos Position of subject certificate in cert_path + */ + virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::vector<std::set<Certificate_Status_Code>>& cert_status, + size_t pos); + + virtual ~Certificate_Extension() = default; + protected: + friend class Extensions; + virtual bool should_encode() const { return true; } + virtual std::vector<uint8_t> encode_inner() const = 0; + virtual void decode_inner(const std::vector<uint8_t>&) = 0; + }; + +/** +* X.509 Certificate Extension List +*/ +class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object + { + public: + /** + * Look up an object in the extensions, based on OID Returns + * nullptr if not set, if the extension was either absent or not + * handled. The pointer returned is owned by the Extensions + * object. + * This would be better with an optional<T> return value + */ + const Certificate_Extension* get_extension_object(const OID& oid) const; + + template<typename T> + const T* get_extension_object_as(const OID& oid = T::static_oid()) const + { + if(const Certificate_Extension* extn = get_extension_object(oid)) + { + // Unknown_Extension oid_name is empty + if(extn->oid_name().empty()) + { + return nullptr; + } + else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) + { + return extn_as_T; + } + else + { + throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); + } + } + + return nullptr; + } + + /** + * Return the set of extensions in the order they appeared in the certificate + * (or as they were added, if constructed) + */ + const std::vector<OID>& get_extension_oids() const + { + return m_extension_oids; + } + + /** + * Return true if an extension was set + */ + bool extension_set(const OID& oid) const; + + /** + * Return true if an extesion was set and marked critical + */ + bool critical_extension_set(const OID& oid) const; + + /** + * Return the raw bytes of the extension + * Will throw if OID was not set as an extension. + */ + std::vector<uint8_t> get_extension_bits(const OID& oid) const; + + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + void contents_to(Data_Store&, Data_Store&) const; + + /** + * Adds a new extension to the list. + * @param extn pointer to the certificate extension (Extensions takes ownership) + * @param critical whether this extension should be marked as critical + * @throw Invalid_Argument if the extension is already present in the list + */ + void add(Certificate_Extension* extn, bool critical = false); + + /** + * Adds a new extension to the list unless it already exists. If the extension + * already exists within the Extensions object, the extn pointer will be deleted. + * + * @param extn pointer to the certificate extension (Extensions takes ownership) + * @param critical whether this extension should be marked as critical + * @return true if the object was added false if the extension was already used + */ + bool add_new(Certificate_Extension* extn, bool critical = false); + + /** + * Adds an extension to the list or replaces it. + * @param extn the certificate extension + * @param critical whether this extension should be marked as critical + */ + void replace(Certificate_Extension* extn, bool critical = false); + + /** + * Remove an extension from the list. Returns true if the + * extension had been set, false otherwise. + */ + bool remove(const OID& oid); + + /** + * Searches for an extension by OID and returns the result. + * Only the known extensions types declared in this header + * are searched for by this function. + * @return Copy of extension with oid, nullptr if not found. + * Can avoid creating a copy by using get_extension_object function + */ + std::unique_ptr<Certificate_Extension> get(const OID& oid) const; + + /** + * Searches for an extension by OID and returns the result decoding + * it to some arbitrary extension type chosen by the application. + * + * Only the unknown extensions, that is, extensions types that + * are not declared in this header, are searched for by this + * function. + * + * @return Pointer to new extension with oid, nullptr if not found. + */ + template<typename T> + std::unique_ptr<T> get_raw(const OID& oid) const + { + auto extn_info = m_extension_info.find(oid); + + if(extn_info != m_extension_info.end()) + { + // Unknown_Extension oid_name is empty + if(extn_info->second.obj().oid_name() == "") + { + std::unique_ptr<T> ext(new T); + ext->decode_inner(extn_info->second.bits()); + return ext; + } + } + return nullptr; + } + + /** + * Returns a copy of the list of extensions together with the corresponding + * criticality flag. All extensions are encoded as some object, falling back + * to Unknown_Extension class which simply allows reading the bytes as well + * as the criticality flag. + */ + std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const; + + /** + * Returns the list of extensions as raw, encoded bytes + * together with the corresponding criticality flag. + * Contains all extensions, including any extensions encoded as Unknown_Extension + */ + std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const; + + Extensions() {} + + Extensions(const Extensions&) = default; + Extensions& operator=(const Extensions&) = default; + + Extensions(Extensions&&) = default; + Extensions& operator=(Extensions&&) = default; + + private: + static std::unique_ptr<Certificate_Extension> + create_extn_obj(const OID& oid, + bool critical, + const std::vector<uint8_t>& body); + + class Extensions_Info + { + public: + Extensions_Info(bool critical, + Certificate_Extension* ext) : + m_obj(ext), + m_bits(m_obj->encode_inner()), + m_critical(critical) + { + } + + Extensions_Info(bool critical, + const std::vector<uint8_t>& encoding, + Certificate_Extension* ext) : + m_obj(ext), + m_bits(encoding), + m_critical(critical) + { + } + + bool is_critical() const { return m_critical; } + const std::vector<uint8_t>& bits() const { return m_bits; } + const Certificate_Extension& obj() const + { + BOTAN_ASSERT_NONNULL(m_obj.get()); + return *m_obj.get(); + } + + private: + std::shared_ptr<Certificate_Extension> m_obj; + std::vector<uint8_t> m_bits; + bool m_critical = false; + }; + + std::vector<OID> m_extension_oids; + std::map<OID, Extensions_Info> m_extension_info; + }; + +} + +#endif |