summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/asn1
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/asn1')
-rw-r--r--comm/third_party/botan/src/lib/asn1/alg_id.cpp109
-rw-r--r--comm/third_party/botan/src/lib/asn1/alg_id.h14
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_obj.cpp238
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_obj.h475
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_oid.cpp216
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_oid.h14
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_print.cpp327
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_print.h125
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_str.cpp153
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_str.h14
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_time.cpp290
-rw-r--r--comm/third_party/botan/src/lib/asn1/asn1_time.h14
-rw-r--r--comm/third_party/botan/src/lib/asn1/ber_dec.cpp549
-rw-r--r--comm/third_party/botan/src/lib/asn1/ber_dec.h418
-rw-r--r--comm/third_party/botan/src/lib/asn1/der_enc.cpp405
-rw-r--r--comm/third_party/botan/src/lib/asn1/der_enc.h227
-rw-r--r--comm/third_party/botan/src/lib/asn1/info.txt7
-rw-r--r--comm/third_party/botan/src/lib/asn1/oid_maps.cpp510
-rw-r--r--comm/third_party/botan/src/lib/asn1/oids.cpp134
-rw-r--r--comm/third_party/botan/src/lib/asn1/oids.h98
20 files changed, 4337 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/asn1/alg_id.cpp b/comm/third_party/botan/src/lib/asn1/alg_id.cpp
new file mode 100644
index 0000000000..1e82f29955
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/alg_id.cpp
@@ -0,0 +1,109 @@
+/*
+* Algorithm Identifier
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/asn1_obj.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/oids.h>
+
+namespace Botan {
+
+/*
+* Create an AlgorithmIdentifier
+*/
+AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id,
+ const std::vector<uint8_t>& param) :
+ oid(alg_id),
+ parameters(param)
+ {}
+
+/*
+* Create an AlgorithmIdentifier
+*/
+AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id,
+ const std::vector<uint8_t>& param) :
+ AlgorithmIdentifier(OID::from_string(alg_id), param)
+ {}
+
+/*
+* Create an AlgorithmIdentifier
+*/
+AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id,
+ Encoding_Option option) :
+ oid(alg_id),
+ parameters()
+ {
+ const uint8_t DER_NULL[] = { 0x05, 0x00 };
+
+ if(option == USE_NULL_PARAM)
+ parameters.assign(DER_NULL, DER_NULL + 2);
+ }
+
+/*
+* Create an AlgorithmIdentifier
+*/
+AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id,
+ Encoding_Option option) :
+ oid(OID::from_string(alg_id)),
+ parameters()
+ {
+ const uint8_t DER_NULL[] = { 0x05, 0x00 };
+
+ if(option == USE_NULL_PARAM)
+ parameters.assign(DER_NULL, DER_NULL + 2);
+ }
+
+bool AlgorithmIdentifier::parameters_are_null() const
+ {
+ return (parameters.size() == 2 && (parameters[0] == 0x05) && (parameters[1] == 0x00));
+ }
+
+bool operator==(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2)
+ {
+ if(a1.get_oid() != a2.get_oid())
+ return false;
+
+ /*
+ * Treat NULL and empty as equivalent
+ */
+ if(a1.parameters_are_null_or_empty() &&
+ a2.parameters_are_null_or_empty())
+ {
+ return true;
+ }
+
+ return (a1.get_parameters() == a2.get_parameters());
+ }
+
+bool operator!=(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2)
+ {
+ return !(a1 == a2);
+ }
+
+/*
+* DER encode an AlgorithmIdentifier
+*/
+void AlgorithmIdentifier::encode_into(DER_Encoder& codec) const
+ {
+ codec.start_cons(SEQUENCE)
+ .encode(get_oid())
+ .raw_bytes(get_parameters())
+ .end_cons();
+ }
+
+/*
+* Decode a BER encoded AlgorithmIdentifier
+*/
+void AlgorithmIdentifier::decode_from(BER_Decoder& codec)
+ {
+ codec.start_cons(SEQUENCE)
+ .decode(oid)
+ .raw_bytes(parameters)
+ .end_cons();
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/alg_id.h b/comm/third_party/botan/src/lib/asn1/alg_id.h
new file mode 100644
index 0000000000..88e54466d3
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/alg_id.h
@@ -0,0 +1,14 @@
+/*
+* Algorithm Identifier
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ALGORITHM_IDENTIFIER_H_
+#define BOTAN_ALGORITHM_IDENTIFIER_H_
+
+#include <botan/asn1_obj.h>
+BOTAN_DEPRECATED_HEADER(alg_id.h)
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_obj.cpp b/comm/third_party/botan/src/lib/asn1/asn1_obj.cpp
new file mode 100644
index 0000000000..8243552648
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_obj.cpp
@@ -0,0 +1,238 @@
+/*
+* ASN.1 Internals
+* (C) 1999-2007,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/asn1_obj.h>
+#include <botan/der_enc.h>
+#include <botan/data_src.h>
+#include <botan/internal/stl_util.h>
+#include <sstream>
+
+namespace Botan {
+
+std::vector<uint8_t> ASN1_Object::BER_encode() const
+ {
+ std::vector<uint8_t> output;
+ DER_Encoder der(output);
+ this->encode_into(der);
+ return output;
+ }
+
+/*
+* Check a type invariant on BER data
+*/
+void BER_Object::assert_is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_,
+ const std::string& descr) const
+ {
+ if(this->is_a(type_tag_, class_tag_) == false)
+ {
+ std::stringstream msg;
+
+ msg << "Tag mismatch when decoding " << descr << " got ";
+
+ if(class_tag == NO_OBJECT && type_tag == NO_OBJECT)
+ {
+ msg << "EOF";
+ }
+ else
+ {
+ if(class_tag == UNIVERSAL || class_tag == CONSTRUCTED)
+ {
+ msg << asn1_tag_to_string(type_tag);
+ }
+ else
+ {
+ msg << std::to_string(type_tag);
+ }
+
+ msg << "/" << asn1_class_to_string(class_tag);
+ }
+
+ msg << " expected ";
+
+ if(class_tag_ == UNIVERSAL || class_tag_ == CONSTRUCTED)
+ {
+ msg << asn1_tag_to_string(type_tag_);
+ }
+ else
+ {
+ msg << std::to_string(type_tag_);
+ }
+
+ msg << "/" << asn1_class_to_string(class_tag_);
+
+ throw BER_Decoding_Error(msg.str());
+ }
+ }
+
+bool BER_Object::is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_) const
+ {
+ return (type_tag == type_tag_ && class_tag == class_tag_);
+ }
+
+bool BER_Object::is_a(int type_tag_, ASN1_Tag class_tag_) const
+ {
+ return is_a(ASN1_Tag(type_tag_), class_tag_);
+ }
+
+void BER_Object::set_tagging(ASN1_Tag t, ASN1_Tag c)
+ {
+ type_tag = t;
+ class_tag = c;
+ }
+
+std::string asn1_class_to_string(ASN1_Tag type)
+ {
+ switch(type)
+ {
+ case UNIVERSAL:
+ return "UNIVERSAL";
+ case CONSTRUCTED:
+ return "CONSTRUCTED";
+ case CONTEXT_SPECIFIC:
+ return "CONTEXT_SPECIFIC";
+ case APPLICATION:
+ return "APPLICATION";
+ case CONSTRUCTED | CONTEXT_SPECIFIC:
+ return "PRIVATE";
+ case Botan::NO_OBJECT:
+ return "NO_OBJECT";
+ default:
+ return "CLASS(" + std::to_string(static_cast<size_t>(type)) + ")";
+ }
+ }
+
+std::string asn1_tag_to_string(ASN1_Tag type)
+ {
+ switch(type)
+ {
+ case Botan::SEQUENCE:
+ return "SEQUENCE";
+
+ case Botan::SET:
+ return "SET";
+
+ case Botan::PRINTABLE_STRING:
+ return "PRINTABLE STRING";
+
+ case Botan::NUMERIC_STRING:
+ return "NUMERIC STRING";
+
+ case Botan::IA5_STRING:
+ return "IA5 STRING";
+
+ case Botan::T61_STRING:
+ return "T61 STRING";
+
+ case Botan::UTF8_STRING:
+ return "UTF8 STRING";
+
+ case Botan::VISIBLE_STRING:
+ return "VISIBLE STRING";
+
+ case Botan::BMP_STRING:
+ return "BMP STRING";
+
+ case Botan::UNIVERSAL_STRING:
+ return "UNIVERSAL STRING";
+
+ case Botan::UTC_TIME:
+ return "UTC TIME";
+
+ case Botan::GENERALIZED_TIME:
+ return "GENERALIZED TIME";
+
+ case Botan::OCTET_STRING:
+ return "OCTET STRING";
+
+ case Botan::BIT_STRING:
+ return "BIT STRING";
+
+ case Botan::ENUMERATED:
+ return "ENUMERATED";
+
+ case Botan::INTEGER:
+ return "INTEGER";
+
+ case Botan::NULL_TAG:
+ return "NULL";
+
+ case Botan::OBJECT_ID:
+ return "OBJECT";
+
+ case Botan::BOOLEAN:
+ return "BOOLEAN";
+
+ case Botan::NO_OBJECT:
+ return "NO_OBJECT";
+
+ default:
+ return "TAG(" + std::to_string(static_cast<size_t>(type)) + ")";
+ }
+ }
+
+/*
+* BER Decoding Exceptions
+*/
+BER_Decoding_Error::BER_Decoding_Error(const std::string& str) :
+ Decoding_Error("BER: " + str) {}
+
+BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) :
+ BER_Decoding_Error(str + ": " + std::to_string(tag)) {}
+
+BER_Bad_Tag::BER_Bad_Tag(const std::string& str,
+ ASN1_Tag tag1, ASN1_Tag tag2) :
+ BER_Decoding_Error(str + ": " + std::to_string(tag1) + "/" + std::to_string(tag2)) {}
+
+namespace ASN1 {
+
+/*
+* Put some arbitrary bytes into a SEQUENCE
+*/
+std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& contents)
+ {
+ return ASN1::put_in_sequence(contents.data(), contents.size());
+ }
+
+std::vector<uint8_t> put_in_sequence(const uint8_t bits[], size_t len)
+ {
+ std::vector<uint8_t> output;
+ DER_Encoder(output)
+ .start_cons(SEQUENCE)
+ .raw_bytes(bits, len)
+ .end_cons();
+ return output;
+ }
+
+/*
+* Convert a BER object into a string object
+*/
+std::string to_string(const BER_Object& obj)
+ {
+ return std::string(cast_uint8_ptr_to_char(obj.bits()),
+ obj.length());
+ }
+
+/*
+* Do heuristic tests for BER data
+*/
+bool maybe_BER(DataSource& source)
+ {
+ uint8_t first_u8;
+ if(!source.peek_byte(first_u8))
+ {
+ BOTAN_ASSERT_EQUAL(source.read_byte(first_u8), 0, "Expected EOF");
+ throw Stream_IO_Error("ASN1::maybe_BER: Source was empty");
+ }
+
+ if(first_u8 == (SEQUENCE | CONSTRUCTED))
+ return true;
+ return false;
+ }
+
+}
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_obj.h b/comm/third_party/botan/src/lib/asn1/asn1_obj.h
new file mode 100644
index 0000000000..0ce4437712
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_obj.h
@@ -0,0 +1,475 @@
+/*
+* (C) 1999-2007,2018,2020 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ASN1_OBJECT_TYPES_H_
+#define BOTAN_ASN1_OBJECT_TYPES_H_
+
+#include <botan/secmem.h>
+#include <botan/exceptn.h>
+#include <vector>
+#include <string>
+#include <chrono>
+
+namespace Botan {
+
+class BER_Decoder;
+class DER_Encoder;
+
+/**
+* ASN.1 Type and Class Tags
+* This will become an enum class in a future major release
+*/
+enum ASN1_Tag : uint32_t {
+ UNIVERSAL = 0x00,
+ APPLICATION = 0x40,
+ CONTEXT_SPECIFIC = 0x80,
+
+ CONSTRUCTED = 0x20,
+
+ PRIVATE = CONSTRUCTED | CONTEXT_SPECIFIC,
+
+ EOC = 0x00,
+ BOOLEAN = 0x01,
+ INTEGER = 0x02,
+ BIT_STRING = 0x03,
+ OCTET_STRING = 0x04,
+ NULL_TAG = 0x05,
+ OBJECT_ID = 0x06,
+ ENUMERATED = 0x0A,
+ SEQUENCE = 0x10,
+ SET = 0x11,
+
+ UTF8_STRING = 0x0C,
+ NUMERIC_STRING = 0x12,
+ PRINTABLE_STRING = 0x13,
+ T61_STRING = 0x14,
+ IA5_STRING = 0x16,
+ VISIBLE_STRING = 0x1A,
+ UNIVERSAL_STRING = 0x1C,
+ BMP_STRING = 0x1E,
+
+ UTC_TIME = 0x17,
+ GENERALIZED_TIME = 0x18,
+ UTC_OR_GENERALIZED_TIME = 0x19,
+
+ NO_OBJECT = 0xFF00,
+ DIRECTORY_STRING = 0xFF01
+};
+
+std::string BOTAN_UNSTABLE_API asn1_tag_to_string(ASN1_Tag type);
+std::string BOTAN_UNSTABLE_API asn1_class_to_string(ASN1_Tag type);
+
+/**
+* Basic ASN.1 Object Interface
+*/
+class BOTAN_PUBLIC_API(2,0) ASN1_Object
+ {
+ public:
+ /**
+ * Encode whatever this object is into to
+ * @param to the DER_Encoder that will be written to
+ */
+ virtual void encode_into(DER_Encoder& to) const = 0;
+
+ /**
+ * Decode whatever this object is from from
+ * @param from the BER_Decoder that will be read from
+ */
+ virtual void decode_from(BER_Decoder& from) = 0;
+
+ /**
+ * Return the encoding of this object. This is a convenience
+ * method when just one object needs to be serialized. Use
+ * DER_Encoder for complicated encodings.
+ */
+ std::vector<uint8_t> BER_encode() const;
+
+ ASN1_Object() = default;
+ ASN1_Object(const ASN1_Object&) = default;
+ ASN1_Object & operator=(const ASN1_Object&) = default;
+ virtual ~ASN1_Object() = default;
+ };
+
+/**
+* BER Encoded Object
+*/
+class BOTAN_PUBLIC_API(2,0) BER_Object final
+ {
+ public:
+ BER_Object() : type_tag(NO_OBJECT), class_tag(UNIVERSAL) {}
+
+ BER_Object(const BER_Object& other) = default;
+
+ BER_Object& operator=(const BER_Object& other) = default;
+
+ BER_Object(BER_Object&& other) = default;
+
+ BER_Object& operator=(BER_Object&& other) = default;
+
+ bool is_set() const { return type_tag != NO_OBJECT; }
+
+ ASN1_Tag tagging() const { return ASN1_Tag(type() | get_class()); }
+
+ ASN1_Tag type() const { return type_tag; }
+ ASN1_Tag get_class() const { return class_tag; }
+
+ const uint8_t* bits() const { return value.data(); }
+
+ size_t length() const { return value.size(); }
+
+ void assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const std::string& descr = "object") const;
+
+ bool is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const;
+
+ bool is_a(int type_tag, ASN1_Tag class_tag) const;
+
+ BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES:
+ /*
+ * The following member variables are public for historical reasons, but
+ * will be made private in a future major release. Use the accessor
+ * functions above.
+ */
+ ASN1_Tag type_tag, class_tag;
+ secure_vector<uint8_t> value;
+
+ private:
+
+ friend class BER_Decoder;
+
+ void set_tagging(ASN1_Tag type_tag, ASN1_Tag class_tag);
+
+ uint8_t* mutable_bits(size_t length)
+ {
+ value.resize(length);
+ return value.data();
+ }
+ };
+
+/*
+* ASN.1 Utility Functions
+*/
+class DataSource;
+
+namespace ASN1 {
+
+std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& val);
+std::vector<uint8_t> put_in_sequence(const uint8_t bits[], size_t len);
+std::string to_string(const BER_Object& obj);
+
+/**
+* Heuristics tests; is this object possibly BER?
+* @param src a data source that will be peeked at but not modified
+*/
+bool maybe_BER(DataSource& src);
+
+}
+
+/**
+* General BER Decoding Error Exception
+*/
+class BOTAN_PUBLIC_API(2,0) BER_Decoding_Error : public Decoding_Error
+ {
+ public:
+ explicit BER_Decoding_Error(const std::string&);
+ };
+
+/**
+* Exception For Incorrect BER Taggings
+*/
+class BOTAN_PUBLIC_API(2,0) BER_Bad_Tag final : public BER_Decoding_Error
+ {
+ public:
+ BER_Bad_Tag(const std::string& msg, ASN1_Tag tag);
+ BER_Bad_Tag(const std::string& msg, ASN1_Tag tag1, ASN1_Tag tag2);
+ };
+
+/**
+* This class represents ASN.1 object identifiers.
+*/
+class BOTAN_PUBLIC_API(2,0) OID final : public ASN1_Object
+ {
+ public:
+
+ /**
+ * Create an uninitialied OID object
+ */
+ explicit OID() {}
+
+ /**
+ * Construct an OID from a string.
+ * @param str a string in the form "a.b.c" etc., where a,b,c are numbers
+ */
+ explicit OID(const std::string& str);
+
+ /**
+ * Initialize an OID from a sequence of integer values
+ */
+ explicit OID(std::initializer_list<uint32_t> init) : m_id(init) {}
+
+ /**
+ * Initialize an OID from a vector of integer values
+ */
+ explicit OID(std::vector<uint32_t>&& init) : m_id(init) {}
+
+ /**
+ * Construct an OID from a string.
+ * @param str a string in the form "a.b.c" etc., where a,b,c are numbers
+ * or any known OID name (for example "RSA" or "X509v3.SubjectKeyIdentifier")
+ */
+ static OID from_string(const std::string& str);
+
+ void encode_into(class DER_Encoder&) const override;
+ void decode_from(class BER_Decoder&) override;
+
+ /**
+ * Find out whether this OID is empty
+ * @return true is no OID value is set
+ */
+ bool empty() const { return m_id.empty(); }
+
+ /**
+ * Find out whether this OID has a value
+ * @return true is this OID has a value
+ */
+ bool has_value() const { return (m_id.empty() == false); }
+
+ /**
+ * Get this OID as list (vector) of its components.
+ * @return vector representing this OID
+ */
+ const std::vector<uint32_t>& get_components() const { return m_id; }
+
+ const std::vector<uint32_t>& get_id() const { return get_components(); }
+
+ /**
+ * Get this OID as a string
+ * @return string representing this OID
+ */
+ std::string BOTAN_DEPRECATED("Use OID::to_string") as_string() const
+ {
+ return this->to_string();
+ }
+
+ /**
+ * Get this OID as a dotted-decimal string
+ * @return string representing this OID
+ */
+ std::string to_string() const;
+
+ /**
+ * If there is a known name associated with this OID, return that.
+ * Otherwise return the result of to_string
+ */
+ std::string to_formatted_string() const;
+
+ /**
+ * Compare two OIDs.
+ * @return true if they are equal, false otherwise
+ */
+ bool operator==(const OID& other) const
+ {
+ return m_id == other.m_id;
+ }
+
+ /**
+ * Reset this instance to an empty OID.
+ */
+ void BOTAN_DEPRECATED("Avoid mutation of OIDs") clear() { m_id.clear(); }
+
+ /**
+ * Add a component to this OID.
+ * @param new_comp the new component to add to the end of this OID
+ * @return reference to *this
+ */
+ BOTAN_DEPRECATED("Avoid mutation of OIDs") OID& operator+=(uint32_t new_comp)
+ {
+ m_id.push_back(new_comp);
+ return (*this);
+ }
+
+ private:
+ std::vector<uint32_t> m_id;
+ };
+
+/**
+* Append another component onto the OID.
+* @param oid the OID to add the new component to
+* @param new_comp the new component to add
+*/
+OID BOTAN_PUBLIC_API(2,0) operator+(const OID& oid, uint32_t new_comp);
+
+/**
+* Compare two OIDs.
+* @param a the first OID
+* @param b the second OID
+* @return true if a is not equal to b
+*/
+inline bool operator!=(const OID& a, const OID& b)
+ {
+ return !(a == b);
+ }
+
+/**
+* Compare two OIDs.
+* @param a the first OID
+* @param b the second OID
+* @return true if a is lexicographically smaller than b
+*/
+bool BOTAN_PUBLIC_API(2,0) operator<(const OID& a, const OID& b);
+
+/**
+* Time (GeneralizedTime/UniversalTime)
+*/
+class BOTAN_PUBLIC_API(2,0) ASN1_Time final : public ASN1_Object
+ {
+ public:
+ /// DER encode a ASN1_Time
+ void encode_into(DER_Encoder&) const override;
+
+ // Decode a BER encoded ASN1_Time
+ void decode_from(BER_Decoder&) override;
+
+ /// Return an internal string representation of the time
+ std::string to_string() const;
+
+ /// Returns a human friendly string replesentation of no particular formatting
+ std::string readable_string() const;
+
+ /// Return if the time has been set somehow
+ bool time_is_set() const;
+
+ /// Compare this time against another
+ int32_t cmp(const ASN1_Time& other) const;
+
+ /// Create an invalid ASN1_Time
+ ASN1_Time() = default;
+
+ /// Create a ASN1_Time from a time point
+ explicit ASN1_Time(const std::chrono::system_clock::time_point& time);
+
+ /// Create an ASN1_Time from string
+ ASN1_Time(const std::string& t_spec, ASN1_Tag tag);
+
+ /// Returns a STL timepoint object
+ std::chrono::system_clock::time_point to_std_timepoint() const;
+
+ /// Return time since epoch
+ uint64_t time_since_epoch() const;
+
+ private:
+ void set_to(const std::string& t_spec, ASN1_Tag);
+ bool passes_sanity_check() const;
+
+ uint32_t m_year = 0;
+ uint32_t m_month = 0;
+ uint32_t m_day = 0;
+ uint32_t m_hour = 0;
+ uint32_t m_minute = 0;
+ uint32_t m_second = 0;
+ ASN1_Tag m_tag = NO_OBJECT;
+ };
+
+/*
+* Comparison Operations
+*/
+bool BOTAN_PUBLIC_API(2,0) operator==(const ASN1_Time&, const ASN1_Time&);
+bool BOTAN_PUBLIC_API(2,0) operator!=(const ASN1_Time&, const ASN1_Time&);
+bool BOTAN_PUBLIC_API(2,0) operator<=(const ASN1_Time&, const ASN1_Time&);
+bool BOTAN_PUBLIC_API(2,0) operator>=(const ASN1_Time&, const ASN1_Time&);
+bool BOTAN_PUBLIC_API(2,0) operator<(const ASN1_Time&, const ASN1_Time&);
+bool BOTAN_PUBLIC_API(2,0) operator>(const ASN1_Time&, const ASN1_Time&);
+
+typedef ASN1_Time X509_Time;
+
+/**
+* ASN.1 string type
+* This class normalizes all inputs to a UTF-8 std::string
+*/
+class BOTAN_PUBLIC_API(2,0) ASN1_String final : public ASN1_Object
+ {
+ public:
+ void encode_into(class DER_Encoder&) const override;
+ void decode_from(class BER_Decoder&) override;
+
+ ASN1_Tag tagging() const { return m_tag; }
+
+ const std::string& value() const { return m_utf8_str; }
+
+ size_t size() const { return value().size(); }
+
+ bool empty() const { return m_utf8_str.empty(); }
+
+ std::string BOTAN_DEPRECATED("Use value() to get UTF-8 string instead")
+ iso_8859() const;
+
+ /**
+ * Return true iff this is a tag for a known string type we can handle.
+ * This ignores string types that are not supported, eg teletexString
+ */
+ static bool is_string_type(ASN1_Tag tag);
+
+ bool operator==(const ASN1_String& other) const
+ { return value() == other.value(); }
+
+ explicit ASN1_String(const std::string& utf8 = "");
+ ASN1_String(const std::string& utf8, ASN1_Tag tag);
+ private:
+ std::vector<uint8_t> m_data;
+ std::string m_utf8_str;
+ ASN1_Tag m_tag;
+ };
+
+/**
+* Algorithm Identifier
+*/
+class BOTAN_PUBLIC_API(2,0) AlgorithmIdentifier final : public ASN1_Object
+ {
+ public:
+ enum Encoding_Option { USE_NULL_PARAM, USE_EMPTY_PARAM };
+
+ void encode_into(class DER_Encoder&) const override;
+ void decode_from(class BER_Decoder&) override;
+
+ AlgorithmIdentifier() = default;
+
+ AlgorithmIdentifier(const OID& oid, Encoding_Option enc);
+ AlgorithmIdentifier(const std::string& oid_name, Encoding_Option enc);
+
+ AlgorithmIdentifier(const OID& oid, const std::vector<uint8_t>& params);
+ AlgorithmIdentifier(const std::string& oid_name, const std::vector<uint8_t>& params);
+
+ const OID& get_oid() const { return oid; }
+ const std::vector<uint8_t>& get_parameters() const { return parameters; }
+
+ bool parameters_are_null() const;
+ bool parameters_are_empty() const { return parameters.empty(); }
+
+ bool parameters_are_null_or_empty() const
+ {
+ return parameters_are_empty() || parameters_are_null();
+ }
+
+ 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;
+ };
+
+/*
+* Comparison Operations
+*/
+bool BOTAN_PUBLIC_API(2,0) operator==(const AlgorithmIdentifier&,
+ const AlgorithmIdentifier&);
+bool BOTAN_PUBLIC_API(2,0) operator!=(const AlgorithmIdentifier&,
+ const AlgorithmIdentifier&);
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_oid.cpp b/comm/third_party/botan/src/lib/asn1/asn1_oid.cpp
new file mode 100644
index 0000000000..cbbe3a4cbb
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_oid.cpp
@@ -0,0 +1,216 @@
+/*
+* ASN.1 OID
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/asn1_obj.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/internal/bit_ops.h>
+#include <botan/parsing.h>
+#include <botan/oids.h>
+#include <algorithm>
+#include <sstream>
+
+namespace Botan {
+
+namespace {
+
+// returns empty on invalid
+std::vector<uint32_t> parse_oid_str(const std::string& oid)
+ {
+ try
+ {
+ std::string elem;
+ std::vector<uint32_t> oid_elems;
+
+ for(char c : oid)
+ {
+ if(c == '.')
+ {
+ if(elem.empty())
+ return std::vector<uint32_t>();
+ oid_elems.push_back(to_u32bit(elem));
+ elem.clear();
+ }
+ else
+ {
+ elem += c;
+ }
+ }
+
+ if(elem.empty())
+ return std::vector<uint32_t>();
+ oid_elems.push_back(to_u32bit(elem));
+
+ if(oid_elems.size() < 2)
+ return std::vector<uint32_t>();
+
+ return oid_elems;
+ }
+ catch(Invalid_Argument&) // thrown by to_u32bit
+ {
+ return std::vector<uint32_t>();
+ }
+ }
+
+}
+
+//static
+OID OID::from_string(const std::string& str)
+ {
+ if(str.empty())
+ throw Invalid_Argument("OID::from_string argument must be non-empty");
+
+ const OID o = OIDS::str2oid_or_empty(str);
+ if(o.has_value())
+ return o;
+
+ std::vector<uint32_t> raw = parse_oid_str(str);
+
+ if(raw.size() > 0)
+ return OID(std::move(raw));
+
+ throw Lookup_Error("No OID associated with name " + str);
+ }
+
+/*
+* ASN.1 OID Constructor
+*/
+OID::OID(const std::string& oid_str)
+ {
+ if(!oid_str.empty())
+ {
+ m_id = parse_oid_str(oid_str);
+
+ if(m_id.size() < 2 || m_id[0] > 2)
+ throw Invalid_OID(oid_str);
+ if((m_id[0] == 0 || m_id[0] == 1) && m_id[1] > 39)
+ throw Invalid_OID(oid_str);
+ }
+ }
+
+/*
+* Return this OID as a string
+*/
+std::string OID::to_string() const
+ {
+ std::ostringstream oss;
+ oss.imbue(std::locale("C"));
+ for(size_t i = 0; i != m_id.size(); ++i)
+ {
+ oss << m_id[i];
+ if(i != m_id.size() - 1)
+ oss << ".";
+ }
+ return oss.str();
+ }
+
+std::string OID::to_formatted_string() const
+ {
+ const std::string s = OIDS::oid2str_or_empty(*this);
+ if(!s.empty())
+ return s;
+ return this->to_string();
+ }
+
+/*
+* Append another component to the OID
+*/
+OID operator+(const OID& oid, uint32_t new_component)
+ {
+ std::vector<uint32_t> val = oid.get_components();
+ val.push_back(new_component);
+ return OID(std::move(val));
+ }
+
+/*
+* Compare two OIDs
+*/
+bool operator<(const OID& a, const OID& b)
+ {
+ const std::vector<uint32_t>& oid1 = a.get_components();
+ const std::vector<uint32_t>& oid2 = b.get_components();
+
+ return std::lexicographical_compare(oid1.begin(), oid1.end(),
+ oid2.begin(), oid2.end());
+ }
+
+/*
+* DER encode an OBJECT IDENTIFIER
+*/
+void OID::encode_into(DER_Encoder& der) const
+ {
+ if(m_id.size() < 2)
+ throw Invalid_Argument("OID::encode_into: OID is invalid");
+
+ std::vector<uint8_t> encoding;
+
+ if(m_id[0] > 2 || m_id[1] >= 40)
+ throw Encoding_Error("Invalid OID prefix, cannot encode");
+
+ encoding.push_back(static_cast<uint8_t>(40 * m_id[0] + m_id[1]));
+
+ for(size_t i = 2; i != m_id.size(); ++i)
+ {
+ if(m_id[i] == 0)
+ encoding.push_back(0);
+ else
+ {
+ size_t blocks = high_bit(m_id[i]) + 6;
+ blocks = (blocks - (blocks % 7)) / 7;
+
+ BOTAN_ASSERT(blocks > 0, "Math works");
+
+ for(size_t j = 0; j != blocks - 1; ++j)
+ encoding.push_back(0x80 | ((m_id[i] >> 7*(blocks-j-1)) & 0x7F));
+ encoding.push_back(m_id[i] & 0x7F);
+ }
+ }
+ der.add_object(OBJECT_ID, UNIVERSAL, encoding);
+ }
+
+/*
+* Decode a BER encoded OBJECT IDENTIFIER
+*/
+void OID::decode_from(BER_Decoder& decoder)
+ {
+ BER_Object obj = decoder.get_next_object();
+ if(obj.tagging() != OBJECT_ID)
+ throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging());
+
+ const size_t length = obj.length();
+ const uint8_t* bits = obj.bits();
+
+ if(length < 2 && !(length == 1 && bits[0] == 0))
+ {
+ throw BER_Decoding_Error("OID encoding is too short");
+ }
+
+ m_id.clear();
+ m_id.push_back(bits[0] / 40);
+ m_id.push_back(bits[0] % 40);
+
+ size_t i = 0;
+ while(i != length - 1)
+ {
+ uint32_t component = 0;
+ while(i != length - 1)
+ {
+ ++i;
+
+ if(component >> (32-7))
+ throw Decoding_Error("OID component overflow");
+
+ component = (component << 7) + (bits[i] & 0x7F);
+
+ if(!(bits[i] & 0x80))
+ break;
+ }
+ m_id.push_back(component);
+ }
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_oid.h b/comm/third_party/botan/src/lib/asn1/asn1_oid.h
new file mode 100644
index 0000000000..91c5da9d8d
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_oid.h
@@ -0,0 +1,14 @@
+/*
+* ASN.1 OID
+* (C) 1999-2007,2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ASN1_OID_H_
+#define BOTAN_ASN1_OID_H_
+
+#include <botan/asn1_obj.h>
+BOTAN_DEPRECATED_HEADER(asn1_oid.h)
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_print.cpp b/comm/third_party/botan/src/lib/asn1/asn1_print.cpp
new file mode 100644
index 0000000000..faadad02b6
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_print.cpp
@@ -0,0 +1,327 @@
+/*
+* (C) 2014,2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/asn1_print.h>
+#include <botan/bigint.h>
+#include <botan/hex.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/oids.h>
+#include <iomanip>
+#include <sstream>
+#include <cctype>
+
+namespace Botan {
+
+namespace {
+
+bool all_printable_chars(const uint8_t bits[], size_t bits_len)
+ {
+ for(size_t i = 0; i != bits_len; ++i)
+ {
+ int c = bits[i];
+ if(c > 127)
+ return false;
+
+ if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false)
+ return false;
+ }
+ return true;
+ }
+
+/*
+* Special hack to handle GeneralName [2] and [6] (DNS name and URI)
+*/
+bool possibly_a_general_name(const uint8_t bits[], size_t bits_len)
+ {
+ if(bits_len <= 2)
+ return false;
+
+ if(bits[0] != 0x82 && bits[0] != 0x86)
+ return false;
+
+ if(bits[1] != bits_len - 2)
+ return false;
+
+ if(all_printable_chars(bits + 2, bits_len - 2) == false)
+ return false;
+
+ return true;
+ }
+
+}
+
+std::string ASN1_Formatter::print(const uint8_t in[], size_t len) const
+ {
+ std::ostringstream output;
+ print_to_stream(output, in, len);
+ return output.str();
+ }
+
+void ASN1_Formatter::print_to_stream(std::ostream& output,
+ const uint8_t in[],
+ size_t len) const
+ {
+ BER_Decoder dec(in, len);
+ decode(output, dec, 0);
+ }
+
+void ASN1_Formatter::decode(std::ostream& output,
+ BER_Decoder& decoder,
+ size_t level) const
+ {
+ BER_Object obj = decoder.get_next_object();
+
+ const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth);
+
+ while(obj.is_set())
+ {
+ const ASN1_Tag type_tag = obj.type();
+ const ASN1_Tag class_tag = obj.get_class();
+ const size_t length = obj.length();
+
+ /* hack to insert the tag+length back in front of the stuff now
+ that we've gotten the type info */
+ std::vector<uint8_t> bits;
+ DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length());
+
+ BER_Decoder data(bits);
+
+ if(class_tag & CONSTRUCTED)
+ {
+ BER_Decoder cons_info(obj.bits(), obj.length());
+
+ if(recurse_deeper)
+ {
+ output << format(type_tag, class_tag, level, length, "");
+ decode(output, cons_info, level + 1); // recurse
+ }
+ else
+ {
+ output << format(type_tag, class_tag, level, length,
+ format_bin(type_tag, class_tag, bits));
+ }
+ }
+ else if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC))
+ {
+ bool success_parsing_cs = false;
+
+ if(m_print_context_specific)
+ {
+ try
+ {
+ if(possibly_a_general_name(bits.data(), bits.size()))
+ {
+ output << format(type_tag, class_tag, level, level,
+ std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2));
+ success_parsing_cs = true;
+ }
+ else if(recurse_deeper)
+ {
+ std::vector<uint8_t> inner_bits;
+ data.decode(inner_bits, type_tag);
+
+ BER_Decoder inner(inner_bits);
+ std::ostringstream inner_data;
+ decode(inner_data, inner, level + 1); // recurse
+ output << inner_data.str();
+ success_parsing_cs = true;
+ }
+ }
+ catch(...)
+ {
+ }
+ }
+
+ if(success_parsing_cs == false)
+ {
+ output << format(type_tag, class_tag, level, length,
+ format_bin(type_tag, class_tag, bits));
+ }
+ }
+ else if(type_tag == OBJECT_ID)
+ {
+ OID oid;
+ data.decode(oid);
+
+ std::string out = OIDS::oid2str_or_empty(oid);
+ if(out.empty())
+ {
+ out = oid.to_string();
+ }
+ else
+ {
+ out += " [" + oid.to_string() + "]";
+ }
+
+ output << format(type_tag, class_tag, level, length, out);
+ }
+ else if(type_tag == INTEGER || type_tag == ENUMERATED)
+ {
+ BigInt number;
+
+ if(type_tag == INTEGER)
+ {
+ data.decode(number);
+ }
+ else if(type_tag == ENUMERATED)
+ {
+ data.decode(number, ENUMERATED, class_tag);
+ }
+
+ std::vector<uint8_t> rep = BigInt::encode(number);
+ if(rep.empty()) // if zero
+ rep.resize(1);
+
+ output << format(type_tag, class_tag, level, length, hex_encode(rep));
+ }
+ else if(type_tag == BOOLEAN)
+ {
+ bool boolean;
+ data.decode(boolean);
+ output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false"));
+ }
+ else if(type_tag == NULL_TAG)
+ {
+ output << format(type_tag, class_tag, level, length, "");
+ }
+ else if(type_tag == OCTET_STRING || type_tag == BIT_STRING)
+ {
+ std::vector<uint8_t> decoded_bits;
+ data.decode(decoded_bits, type_tag);
+ bool printing_octet_string_worked = false;
+
+ if(recurse_deeper)
+ {
+ try
+ {
+ BER_Decoder inner(decoded_bits);
+
+ std::ostringstream inner_data;
+ decode(inner_data, inner, level + 1); // recurse
+
+ output << format(type_tag, class_tag, level, length, "");
+ output << inner_data.str();
+ printing_octet_string_worked = true;
+ }
+ catch(...)
+ {
+ }
+ }
+
+ if(!printing_octet_string_worked)
+ {
+ output << format(type_tag, class_tag, level, length,
+ format_bin(type_tag, class_tag, decoded_bits));
+ }
+ }
+ else if(ASN1_String::is_string_type(type_tag))
+ {
+ ASN1_String str;
+ data.decode(str);
+ output << format(type_tag, class_tag, level, length, str.value());
+ }
+ else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME)
+ {
+ ASN1_Time time;
+ data.decode(time);
+ output << format(type_tag, class_tag, level, length, time.readable_string());
+ }
+ else
+ {
+ output << "Unknown ASN.1 tag class=" << static_cast<int>(class_tag)
+ << " type=" << static_cast<int>(type_tag) << "\n";
+ }
+
+ obj = decoder.get_next_object();
+ }
+ }
+
+namespace {
+
+std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ if(class_tag == UNIVERSAL)
+ return asn1_tag_to_string(type_tag);
+
+ if(class_tag == CONSTRUCTED && (type_tag == SEQUENCE || type_tag == SET))
+ return asn1_tag_to_string(type_tag);
+
+ std::string name;
+
+ if(class_tag & CONSTRUCTED)
+ name += "cons ";
+
+ name += "[" + std::to_string(type_tag) + "]";
+
+ if(class_tag & APPLICATION)
+ {
+ name += " appl";
+ }
+ if(class_tag & CONTEXT_SPECIFIC)
+ {
+ name += " context";
+ }
+
+ return name;
+ }
+
+}
+
+std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ size_t level,
+ size_t length,
+ const std::string& value) const
+ {
+ bool should_skip = false;
+
+ if(value.length() > m_print_limit)
+ {
+ should_skip = true;
+ }
+
+ if((type_tag == OCTET_STRING || type_tag == BIT_STRING) &&
+ value.length() > m_print_binary_limit)
+ {
+ should_skip = true;
+ }
+
+ level += m_initial_level;
+
+ std::ostringstream oss;
+
+ oss << " d=" << std::setw(2) << level
+ << ", l=" << std::setw(4) << length << ":"
+ << std::string(level + 1, ' ') << format_type(type_tag, class_tag);
+
+ if(value != "" && !should_skip)
+ {
+ const size_t current_pos = static_cast<size_t>(oss.tellp());
+ const size_t spaces_to_align =
+ (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos);
+
+ oss << std::string(spaces_to_align, ' ') << value;
+ }
+
+ oss << "\n";
+
+ return oss.str();
+ }
+
+std::string ASN1_Pretty_Printer::format_bin(ASN1_Tag /*type_tag*/,
+ ASN1_Tag /*class_tag*/,
+ const std::vector<uint8_t>& vec) const
+ {
+ if(all_printable_chars(vec.data(), vec.size()))
+ {
+ return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size());
+ }
+ else
+ return hex_encode(vec);
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_print.h b/comm/third_party/botan/src/lib/asn1/asn1_print.h
new file mode 100644
index 0000000000..a6bc6b15f2
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_print.h
@@ -0,0 +1,125 @@
+/*
+* (C) 2014,2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ASN1_PRINT_H_
+#define BOTAN_ASN1_PRINT_H_
+
+#include <botan/asn1_obj.h>
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+namespace Botan {
+
+class BER_Decoder;
+
+/**
+* Format ASN.1 data and call a virtual to format
+*/
+class BOTAN_PUBLIC_API(2,4) ASN1_Formatter
+ {
+ public:
+ virtual ~ASN1_Formatter() = default;
+
+ /**
+ * @param print_context_specific if true, try to parse nested context specific data.
+ * @param max_depth do not recurse more than this many times. If zero, recursion
+ * is unbounded.
+ */
+ ASN1_Formatter(bool print_context_specific, size_t max_depth) :
+ m_print_context_specific(print_context_specific),
+ m_max_depth(max_depth)
+ {}
+
+ void print_to_stream(std::ostream& out,
+ const uint8_t in[],
+ size_t len) const;
+
+ std::string print(const uint8_t in[], size_t len) const;
+
+ template<typename Alloc>
+ std::string print(const std::vector<uint8_t, Alloc>& vec) const
+ {
+ return print(vec.data(), vec.size());
+ }
+
+ protected:
+ /**
+ * This is called for each element
+ */
+ virtual std::string format(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ size_t level,
+ size_t length,
+ const std::string& value) const = 0;
+
+ /**
+ * This is called to format binary elements that we don't know how to
+ * convert to a string The result will be passed as value to format; the
+ * tags are included as a hint to aid decoding.
+ */
+ virtual std::string format_bin(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ const std::vector<uint8_t>& vec) const = 0;
+
+ private:
+ void decode(std::ostream& output,
+ BER_Decoder& decoder,
+ size_t level) const;
+
+ const bool m_print_context_specific;
+ const size_t m_max_depth;
+ };
+
+/**
+* Format ASN.1 data into human readable output. The exact form of the output for
+* any particular input is not guaranteed and may change from release to release.
+*/
+class BOTAN_PUBLIC_API(2,4) ASN1_Pretty_Printer final : public ASN1_Formatter
+ {
+ public:
+ /**
+ * @param print_limit strings larger than this are not printed
+ * @param print_binary_limit binary strings larger than this are not printed
+ * @param print_context_specific if true, try to parse nested context specific data.
+ * @param initial_level the initial depth (0 or 1 are the only reasonable values)
+ * @param value_column ASN.1 values are lined up at this column in output
+ * @param max_depth do not recurse more than this many times. If zero, recursion
+ * is unbounded.
+ */
+ ASN1_Pretty_Printer(size_t print_limit = 4096,
+ size_t print_binary_limit = 2048,
+ bool print_context_specific = true,
+ size_t initial_level = 0,
+ size_t value_column = 60,
+ size_t max_depth = 64) :
+ ASN1_Formatter(print_context_specific, max_depth),
+ m_print_limit(print_limit),
+ m_print_binary_limit(print_binary_limit),
+ m_initial_level(initial_level),
+ m_value_column(value_column)
+ {}
+
+ private:
+ std::string format(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ size_t level,
+ size_t length,
+ const std::string& value) const override;
+
+ std::string format_bin(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ const std::vector<uint8_t>& vec) const override;
+
+ const size_t m_print_limit;
+ const size_t m_print_binary_limit;
+ const size_t m_initial_level;
+ const size_t m_value_column;
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_str.cpp b/comm/third_party/botan/src/lib/asn1/asn1_str.cpp
new file mode 100644
index 0000000000..6a31c5bb2f
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_str.cpp
@@ -0,0 +1,153 @@
+/*
+* Simple ASN.1 String Types
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/asn1_obj.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/charset.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* Choose an encoding for the string
+*/
+ASN1_Tag choose_encoding(const std::string& str)
+ {
+ static const uint8_t IS_PRINTABLE[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+ for(size_t i = 0; i != str.size(); ++i)
+ {
+ if(!IS_PRINTABLE[static_cast<uint8_t>(str[i])])
+ {
+ return UTF8_STRING;
+ }
+ }
+ return PRINTABLE_STRING;
+ }
+
+void assert_is_string_type(ASN1_Tag tag)
+ {
+ if(!ASN1_String::is_string_type(tag))
+ {
+ throw Invalid_Argument("ASN1_String: Unknown string type " +
+ std::to_string(tag));
+ }
+ }
+
+}
+
+//static
+bool ASN1_String::is_string_type(ASN1_Tag tag)
+ {
+ return (tag == NUMERIC_STRING ||
+ tag == PRINTABLE_STRING ||
+ tag == VISIBLE_STRING ||
+ tag == T61_STRING ||
+ tag == IA5_STRING ||
+ tag == UTF8_STRING ||
+ tag == BMP_STRING ||
+ tag == UNIVERSAL_STRING);
+ }
+
+
+/*
+* Create an ASN1_String
+*/
+ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : m_utf8_str(str), m_tag(t)
+ {
+ if(m_tag == DIRECTORY_STRING)
+ {
+ m_tag = choose_encoding(m_utf8_str);
+ }
+
+ assert_is_string_type(m_tag);
+ }
+
+/*
+* Create an ASN1_String
+*/
+ASN1_String::ASN1_String(const std::string& str) :
+ m_utf8_str(str),
+ m_tag(choose_encoding(m_utf8_str))
+ {}
+
+/*
+* Return this string in ISO 8859-1 encoding
+*/
+std::string ASN1_String::iso_8859() const
+ {
+ return utf8_to_latin1(m_utf8_str);
+ }
+
+/*
+* DER encode an ASN1_String
+*/
+void ASN1_String::encode_into(DER_Encoder& encoder) const
+ {
+ if(m_data.empty())
+ {
+ encoder.add_object(tagging(), UNIVERSAL, m_utf8_str);
+ }
+ else
+ {
+ // If this string was decoded, reserialize using original encoding
+ encoder.add_object(tagging(), UNIVERSAL, m_data.data(), m_data.size());
+ }
+ }
+
+/*
+* Decode a BER encoded ASN1_String
+*/
+void ASN1_String::decode_from(BER_Decoder& source)
+ {
+ BER_Object obj = source.get_next_object();
+
+ assert_is_string_type(obj.type());
+
+ m_tag = obj.type();
+ m_data.assign(obj.bits(), obj.bits() + obj.length());
+
+ if(m_tag == BMP_STRING)
+ {
+ m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size());
+ }
+ else if(m_tag == UNIVERSAL_STRING)
+ {
+ m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size());
+ }
+ else
+ {
+ // All other supported string types are UTF-8 or some subset thereof
+ m_utf8_str = ASN1::to_string(obj);
+ }
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_str.h b/comm/third_party/botan/src/lib/asn1/asn1_str.h
new file mode 100644
index 0000000000..fed4950cc3
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_str.h
@@ -0,0 +1,14 @@
+/*
+* ASN.1 string type
+* (C) 1999-2010 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ASN1_STRING_H_
+#define BOTAN_ASN1_STRING_H_
+
+#include <botan/asn1_obj.h>
+BOTAN_DEPRECATED_HEADER(asn1_str.h)
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_time.cpp b/comm/third_party/botan/src/lib/asn1/asn1_time.cpp
new file mode 100644
index 0000000000..004be27b97
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_time.cpp
@@ -0,0 +1,290 @@
+/*
+* X.509 Time Types
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/asn1_obj.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/exceptn.h>
+#include <botan/parsing.h>
+#include <botan/calendar.h>
+#include <sstream>
+#include <iomanip>
+
+namespace Botan {
+
+ASN1_Time::ASN1_Time(const std::chrono::system_clock::time_point& time)
+ {
+ calendar_point cal = calendar_value(time);
+
+ m_year = cal.get_year();
+ m_month = cal.get_month();
+ m_day = cal.get_day();
+ m_hour = cal.get_hour();
+ m_minute = cal.get_minutes();
+ m_second = cal.get_seconds();
+
+ m_tag = (m_year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
+ }
+
+ASN1_Time::ASN1_Time(const std::string& t_spec, ASN1_Tag tag)
+ {
+ set_to(t_spec, tag);
+ }
+
+void ASN1_Time::encode_into(DER_Encoder& der) const
+ {
+ BOTAN_ARG_CHECK(m_tag == UTC_TIME || m_tag == GENERALIZED_TIME,
+ "ASN1_Time: Bad encoding tag");
+
+ der.add_object(m_tag, UNIVERSAL, to_string());
+ }
+
+void ASN1_Time::decode_from(BER_Decoder& source)
+ {
+ BER_Object ber_time = source.get_next_object();
+
+ set_to(ASN1::to_string(ber_time), ber_time.type());
+ }
+
+std::string ASN1_Time::to_string() const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("ASN1_Time::to_string: No time set");
+
+ uint32_t full_year = m_year;
+
+ if(m_tag == UTC_TIME)
+ {
+ if(m_year < 1950 || m_year >= 2050)
+ throw Encoding_Error("ASN1_Time: The time " + readable_string() +
+ " cannot be encoded as a UTCTime");
+
+ full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900);
+ }
+
+ const uint64_t YEAR_FACTOR = 10000000000ULL;
+ const uint64_t MON_FACTOR = 100000000;
+ const uint64_t DAY_FACTOR = 1000000;
+ const uint64_t HOUR_FACTOR = 10000;
+ const uint64_t MIN_FACTOR = 100;
+
+ const uint64_t int_repr =
+ YEAR_FACTOR * full_year +
+ MON_FACTOR * m_month +
+ DAY_FACTOR * m_day +
+ HOUR_FACTOR * m_hour +
+ MIN_FACTOR * m_minute +
+ m_second;
+
+ std::string repr = std::to_string(int_repr) + "Z";
+
+ uint32_t desired_size = (m_tag == UTC_TIME) ? 13 : 15;
+
+ while(repr.size() < desired_size)
+ repr = "0" + repr;
+
+ return repr;
+ }
+
+std::string ASN1_Time::readable_string() const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("ASN1_Time::readable_string: No time set");
+
+ // desired format: "%04d/%02d/%02d %02d:%02d:%02d UTC"
+ std::stringstream output;
+ output << std::setfill('0')
+ << std::setw(4) << m_year << "/"
+ << std::setw(2) << m_month << "/"
+ << std::setw(2) << m_day
+ << " "
+ << std::setw(2) << m_hour << ":"
+ << std::setw(2) << m_minute << ":"
+ << std::setw(2) << m_second
+ << " UTC";
+
+ return output.str();
+ }
+
+bool ASN1_Time::time_is_set() const
+ {
+ return (m_year != 0);
+ }
+
+int32_t ASN1_Time::cmp(const ASN1_Time& other) const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("ASN1_Time::cmp: No time set");
+
+ const int32_t EARLIER = -1, LATER = 1, SAME_TIME = 0;
+
+ if(m_year < other.m_year) return EARLIER;
+ if(m_year > other.m_year) return LATER;
+ if(m_month < other.m_month) return EARLIER;
+ if(m_month > other.m_month) return LATER;
+ if(m_day < other.m_day) return EARLIER;
+ if(m_day > other.m_day) return LATER;
+ if(m_hour < other.m_hour) return EARLIER;
+ if(m_hour > other.m_hour) return LATER;
+ if(m_minute < other.m_minute) return EARLIER;
+ if(m_minute > other.m_minute) return LATER;
+ if(m_second < other.m_second) return EARLIER;
+ if(m_second > other.m_second) return LATER;
+
+ return SAME_TIME;
+ }
+
+void ASN1_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
+ {
+ if(spec_tag == UTC_OR_GENERALIZED_TIME)
+ {
+ try
+ {
+ set_to(t_spec, GENERALIZED_TIME);
+ return;
+ }
+ catch(Invalid_Argument&) {} // Not a generalized time. Continue
+
+ try
+ {
+ set_to(t_spec, UTC_TIME);
+ return;
+ }
+ catch(Invalid_Argument&) {} // Not a UTC time. Continue
+
+ throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime.");
+ }
+
+ BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag.");
+
+ BOTAN_ARG_CHECK(t_spec.size() > 0, "Time string must not be empty.");
+
+ BOTAN_ARG_CHECK(t_spec.back() == 'Z', "Botan does not support times with timezones other than Z");
+
+ if(spec_tag == GENERALIZED_TIME)
+ {
+ BOTAN_ARG_CHECK(t_spec.size() == 15, "Invalid GeneralizedTime string");
+ }
+ else if(spec_tag == UTC_TIME)
+ {
+ BOTAN_ARG_CHECK(t_spec.size() == 13, "Invalid UTCTime string");
+ }
+
+ const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;
+
+ std::vector<std::string> params;
+ std::string current;
+
+ for(size_t j = 0; j != YEAR_SIZE; ++j)
+ current += t_spec[j];
+ params.push_back(current);
+ current.clear();
+
+ for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
+ {
+ current += t_spec[j];
+ if(current.size() == 2)
+ {
+ params.push_back(current);
+ current.clear();
+ }
+ }
+
+ m_year = to_u32bit(params[0]);
+ m_month = to_u32bit(params[1]);
+ m_day = to_u32bit(params[2]);
+ m_hour = to_u32bit(params[3]);
+ m_minute = to_u32bit(params[4]);
+ m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
+ m_tag = spec_tag;
+
+ if(spec_tag == UTC_TIME)
+ {
+ if(m_year >= 50) m_year += 1900;
+ else m_year += 2000;
+ }
+
+ if(!passes_sanity_check())
+ throw Invalid_Argument("Time " + t_spec + " does not seem to be valid");
+ }
+
+/*
+* Do a general sanity check on the time
+*/
+bool ASN1_Time::passes_sanity_check() const
+ {
+ // AppVeyor's trust store includes a cert with expiration date in 3016 ...
+ if(m_year < 1950 || m_year > 3100)
+ return false;
+ if(m_month == 0 || m_month > 12)
+ return false;
+
+ const uint32_t days_in_month[12] = { 31, 28+1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+ if(m_day == 0 || m_day > days_in_month[m_month-1])
+ return false;
+
+ if(m_month == 2 && m_day == 29)
+ {
+ if(m_year % 4 != 0)
+ return false; // not a leap year
+
+ if(m_year % 100 == 0 && m_year % 400 != 0)
+ return false;
+ }
+
+ if(m_hour >= 24 || m_minute >= 60 || m_second > 60)
+ return false;
+
+ if (m_tag == UTC_TIME)
+ {
+ /*
+ UTCTime limits the value of components such that leap seconds
+ are not covered. See "UNIVERSAL 23" in "Information technology
+ Abstract Syntax Notation One (ASN.1): Specification of basic notation"
+
+ http://www.itu.int/ITU-T/studygroups/com17/languages/
+ */
+ if(m_second > 59)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+std::chrono::system_clock::time_point ASN1_Time::to_std_timepoint() const
+ {
+ return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint();
+ }
+
+uint64_t ASN1_Time::time_since_epoch() const
+ {
+ auto tp = this->to_std_timepoint();
+ return std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count();
+ }
+
+/*
+* Compare two ASN1_Times for in various ways
+*/
+bool operator==(const ASN1_Time& t1, const ASN1_Time& t2)
+ { return (t1.cmp(t2) == 0); }
+bool operator!=(const ASN1_Time& t1, const ASN1_Time& t2)
+ { return (t1.cmp(t2) != 0); }
+
+bool operator<=(const ASN1_Time& t1, const ASN1_Time& t2)
+ { return (t1.cmp(t2) <= 0); }
+bool operator>=(const ASN1_Time& t1, const ASN1_Time& t2)
+ { return (t1.cmp(t2) >= 0); }
+
+bool operator<(const ASN1_Time& t1, const ASN1_Time& t2)
+ { return (t1.cmp(t2) < 0); }
+bool operator>(const ASN1_Time& t1, const ASN1_Time& t2)
+ { return (t1.cmp(t2) > 0); }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/asn1_time.h b/comm/third_party/botan/src/lib/asn1/asn1_time.h
new file mode 100644
index 0000000000..55ef82e052
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/asn1_time.h
@@ -0,0 +1,14 @@
+/*
+* ASN.1 Time Representation
+* (C) 1999-2007,2012 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ASN1_TIME_H_
+#define BOTAN_ASN1_TIME_H_
+
+#include <botan/asn1_obj.h>
+BOTAN_DEPRECATED_HEADER(asn1_time.h)
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/ber_dec.cpp b/comm/third_party/botan/src/lib/asn1/ber_dec.cpp
new file mode 100644
index 0000000000..c5af2f9338
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/ber_dec.cpp
@@ -0,0 +1,549 @@
+/*
+* BER Decoder
+* (C) 1999-2008,2015,2017,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ber_dec.h>
+#include <botan/bigint.h>
+#include <botan/loadstor.h>
+#include <botan/internal/safeint.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* This value is somewhat arbitrary. OpenSSL allows up to 128 nested
+* indefinite length sequences. If you increase this, also increase the
+* limit in the test in test_asn1.cpp
+*/
+const size_t ALLOWED_EOC_NESTINGS = 16;
+
+/*
+* BER decode an ASN.1 type tag
+*/
+size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag)
+ {
+ uint8_t b;
+ if(!ber->read_byte(b))
+ {
+ class_tag = type_tag = NO_OBJECT;
+ return 0;
+ }
+
+ if((b & 0x1F) != 0x1F)
+ {
+ type_tag = ASN1_Tag(b & 0x1F);
+ class_tag = ASN1_Tag(b & 0xE0);
+ return 1;
+ }
+
+ size_t tag_bytes = 1;
+ class_tag = ASN1_Tag(b & 0xE0);
+
+ size_t tag_buf = 0;
+ while(true)
+ {
+ if(!ber->read_byte(b))
+ throw BER_Decoding_Error("Long-form tag truncated");
+ if(tag_buf & 0xFF000000)
+ throw BER_Decoding_Error("Long-form tag overflowed 32 bits");
+ ++tag_bytes;
+ tag_buf = (tag_buf << 7) | (b & 0x7F);
+ if((b & 0x80) == 0) break;
+ }
+ type_tag = ASN1_Tag(tag_buf);
+ return tag_bytes;
+ }
+
+/*
+* Find the EOC marker
+*/
+size_t find_eoc(DataSource* src, size_t allow_indef);
+
+/*
+* BER decode an ASN.1 length field
+*/
+size_t decode_length(DataSource* ber, size_t& field_size, size_t allow_indef)
+ {
+ uint8_t b;
+ if(!ber->read_byte(b))
+ throw BER_Decoding_Error("Length field not found");
+ field_size = 1;
+ if((b & 0x80) == 0)
+ return b;
+
+ field_size += (b & 0x7F);
+ if(field_size > 5)
+ throw BER_Decoding_Error("Length field is too large");
+
+ if(field_size == 1)
+ {
+ if(allow_indef == 0)
+ {
+ throw BER_Decoding_Error("Nested EOC markers too deep, rejecting to avoid stack exhaustion");
+ }
+ else
+ {
+ return find_eoc(ber, allow_indef - 1);
+ }
+ }
+
+ size_t length = 0;
+
+ for(size_t i = 0; i != field_size - 1; ++i)
+ {
+ if(get_byte(0, length) != 0)
+ throw BER_Decoding_Error("Field length overflow");
+ if(!ber->read_byte(b))
+ throw BER_Decoding_Error("Corrupted length field");
+ length = (length << 8) | b;
+ }
+ return length;
+ }
+
+/*
+* Find the EOC marker
+*/
+size_t find_eoc(DataSource* ber, size_t allow_indef)
+ {
+ secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE), data;
+
+ while(true)
+ {
+ const size_t got = ber->peek(buffer.data(), buffer.size(), data.size());
+ if(got == 0)
+ break;
+
+ data += std::make_pair(buffer.data(), got);
+ }
+
+ DataSource_Memory source(data);
+ data.clear();
+
+ size_t length = 0;
+ while(true)
+ {
+ ASN1_Tag type_tag, class_tag;
+ size_t tag_size = decode_tag(&source, type_tag, class_tag);
+ if(type_tag == NO_OBJECT)
+ break;
+
+ size_t length_size = 0;
+ size_t item_size = decode_length(&source, length_size, allow_indef);
+ source.discard_next(item_size);
+
+ length = BOTAN_CHECKED_ADD(length, item_size);
+ length = BOTAN_CHECKED_ADD(length, tag_size);
+ length = BOTAN_CHECKED_ADD(length, length_size);
+
+ if(type_tag == EOC && class_tag == UNIVERSAL)
+ break;
+ }
+ return length;
+ }
+
+class DataSource_BERObject final : public DataSource
+ {
+ public:
+ size_t read(uint8_t out[], size_t length) override
+ {
+ BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length());
+ const size_t got = std::min<size_t>(m_obj.length() - m_offset, length);
+ copy_mem(out, m_obj.bits() + m_offset, got);
+ m_offset += got;
+ return got;
+ }
+
+ size_t peek(uint8_t out[], size_t length, size_t peek_offset) const override
+ {
+ BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length());
+ const size_t bytes_left = m_obj.length() - m_offset;
+
+ if(peek_offset >= bytes_left)
+ return 0;
+
+ const size_t got = std::min(bytes_left - peek_offset, length);
+ copy_mem(out, m_obj.bits() + peek_offset, got);
+ return got;
+ }
+
+ bool check_available(size_t n) override
+ {
+ BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length());
+ return (n <= (m_obj.length() - m_offset));
+ }
+
+ bool end_of_data() const override
+ {
+ return get_bytes_read() == m_obj.length();
+ }
+
+ size_t get_bytes_read() const override { return m_offset; }
+
+ explicit DataSource_BERObject(BER_Object&& obj) : m_obj(std::move(obj)), m_offset(0) {}
+
+ private:
+ BER_Object m_obj;
+ size_t m_offset;
+ };
+
+}
+
+/*
+* Check if more objects are there
+*/
+bool BER_Decoder::more_items() const
+ {
+ if(m_source->end_of_data() && !m_pushed.is_set())
+ return false;
+ return true;
+ }
+
+/*
+* Verify that no bytes remain in the source
+*/
+BER_Decoder& BER_Decoder::verify_end()
+ {
+ return verify_end("BER_Decoder::verify_end called, but data remains");
+ }
+
+/*
+* Verify that no bytes remain in the source
+*/
+BER_Decoder& BER_Decoder::verify_end(const std::string& err)
+ {
+ if(!m_source->end_of_data() || m_pushed.is_set())
+ throw Decoding_Error(err);
+ return (*this);
+ }
+
+/*
+* Discard all the bytes remaining in the source
+*/
+BER_Decoder& BER_Decoder::discard_remaining()
+ {
+ uint8_t buf;
+ while(m_source->read_byte(buf))
+ {}
+ return (*this);
+ }
+
+/*
+* Return the BER encoding of the next object
+*/
+BER_Object BER_Decoder::get_next_object()
+ {
+ BER_Object next;
+
+ if(m_pushed.is_set())
+ {
+ std::swap(next, m_pushed);
+ return next;
+ }
+
+ for(;;)
+ {
+ ASN1_Tag type_tag, class_tag;
+ decode_tag(m_source, type_tag, class_tag);
+ next.set_tagging(type_tag, class_tag);
+ if(next.is_set() == false) // no more objects
+ return next;
+
+ size_t field_size;
+ const size_t length = decode_length(m_source, field_size, ALLOWED_EOC_NESTINGS);
+ if(!m_source->check_available(length))
+ throw BER_Decoding_Error("Value truncated");
+
+ uint8_t* out = next.mutable_bits(length);
+ if(m_source->read(out, length) != length)
+ throw BER_Decoding_Error("Value truncated");
+
+ if(next.tagging() == EOC)
+ continue;
+ else
+ break;
+ }
+
+ return next;
+ }
+
+/*
+* Push a object back into the stream
+*/
+void BER_Decoder::push_back(const BER_Object& obj)
+ {
+ if(m_pushed.is_set())
+ throw Invalid_State("BER_Decoder: Only one push back is allowed");
+ m_pushed = obj;
+ }
+
+void BER_Decoder::push_back(BER_Object&& obj)
+ {
+ if(m_pushed.is_set())
+ throw Invalid_State("BER_Decoder: Only one push back is allowed");
+ m_pushed = std::move(obj);
+ }
+
+BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ BER_Object obj = get_next_object();
+ obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED));
+ return BER_Decoder(std::move(obj), this);
+ }
+
+/*
+* Finish decoding a CONSTRUCTED type
+*/
+BER_Decoder& BER_Decoder::end_cons()
+ {
+ if(!m_parent)
+ throw Invalid_State("BER_Decoder::end_cons called with null parent");
+ if(!m_source->end_of_data())
+ throw Decoding_Error("BER_Decoder::end_cons called with data left");
+ return (*m_parent);
+ }
+
+BER_Decoder::BER_Decoder(BER_Object&& obj, BER_Decoder* parent)
+ {
+ m_data_src.reset(new DataSource_BERObject(std::move(obj)));
+ m_source = m_data_src.get();
+ m_parent = parent;
+ }
+
+/*
+* BER_Decoder Constructor
+*/
+BER_Decoder::BER_Decoder(DataSource& src)
+ {
+ m_source = &src;
+ }
+
+/*
+* BER_Decoder Constructor
+ */
+BER_Decoder::BER_Decoder(const uint8_t data[], size_t length)
+ {
+ m_data_src.reset(new DataSource_Memory(data, length));
+ m_source = m_data_src.get();
+ }
+
+/*
+* BER_Decoder Constructor
+*/
+BER_Decoder::BER_Decoder(const secure_vector<uint8_t>& data)
+ {
+ m_data_src.reset(new DataSource_Memory(data));
+ m_source = m_data_src.get();
+ }
+
+/*
+* BER_Decoder Constructor
+*/
+BER_Decoder::BER_Decoder(const std::vector<uint8_t>& data)
+ {
+ m_data_src.reset(new DataSource_Memory(data.data(), data.size()));
+ m_source = m_data_src.get();
+ }
+
+/*
+* BER_Decoder Copy Constructor
+*/
+BER_Decoder::BER_Decoder(const BER_Decoder& other)
+ {
+ m_source = other.m_source;
+
+ // take ownership
+ std::swap(m_data_src, other.m_data_src);
+ m_parent = other.m_parent;
+ }
+
+/*
+* Request for an object to decode itself
+*/
+BER_Decoder& BER_Decoder::decode(ASN1_Object& obj,
+ ASN1_Tag, ASN1_Tag)
+ {
+ obj.decode_from(*this);
+ return (*this);
+ }
+
+/*
+* Decode a BER encoded NULL
+*/
+BER_Decoder& BER_Decoder::decode_null()
+ {
+ BER_Object obj = get_next_object();
+ obj.assert_is_a(NULL_TAG, UNIVERSAL);
+ if(obj.length() > 0)
+ throw BER_Decoding_Error("NULL object had nonzero size");
+ return (*this);
+ }
+
+BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out)
+ {
+ secure_vector<uint8_t> out_vec;
+ decode(out_vec, OCTET_STRING);
+ out = BigInt::decode(out_vec.data(), out_vec.size());
+ return (*this);
+ }
+
+/*
+* Decode a BER encoded BOOLEAN
+*/
+BER_Decoder& BER_Decoder::decode(bool& out,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ BER_Object obj = get_next_object();
+ obj.assert_is_a(type_tag, class_tag);
+
+ if(obj.length() != 1)
+ throw BER_Decoding_Error("BER boolean value had invalid size");
+
+ out = (obj.bits()[0]) ? true : false;
+ return (*this);
+ }
+
+/*
+* Decode a small BER encoded INTEGER
+*/
+BER_Decoder& BER_Decoder::decode(size_t& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag)
+ {
+ BigInt integer;
+ decode(integer, type_tag, class_tag);
+
+ if(integer.is_negative())
+ throw BER_Decoding_Error("Decoded small integer value was negative");
+
+ if(integer.bits() > 32)
+ throw BER_Decoding_Error("Decoded integer value larger than expected");
+
+ out = 0;
+ for(size_t i = 0; i != 4; ++i)
+ out = (out << 8) | integer.byte_at(3-i);
+
+ return (*this);
+ }
+
+/*
+* Decode a small BER encoded INTEGER
+*/
+uint64_t BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ size_t T_bytes)
+ {
+ if(T_bytes > 8)
+ throw BER_Decoding_Error("Can't decode small integer over 8 bytes");
+
+ BigInt integer;
+ decode(integer, type_tag, class_tag);
+
+ if(integer.bits() > 8*T_bytes)
+ throw BER_Decoding_Error("Decoded integer value larger than expected");
+
+ uint64_t out = 0;
+ for(size_t i = 0; i != 8; ++i)
+ out = (out << 8) | integer.byte_at(7-i);
+
+ return out;
+ }
+
+/*
+* Decode a BER encoded INTEGER
+*/
+BER_Decoder& BER_Decoder::decode(BigInt& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag)
+ {
+ BER_Object obj = get_next_object();
+ obj.assert_is_a(type_tag, class_tag);
+
+ if(obj.length() == 0)
+ {
+ out = 0;
+ }
+ else
+ {
+ const bool negative = (obj.bits()[0] & 0x80) ? true : false;
+
+ if(negative)
+ {
+ secure_vector<uint8_t> vec(obj.bits(), obj.bits() + obj.length());
+ for(size_t i = obj.length(); i > 0; --i)
+ if(vec[i-1]--)
+ break;
+ for(size_t i = 0; i != obj.length(); ++i)
+ vec[i] = ~vec[i];
+ out = BigInt(vec.data(), vec.size());
+ out.flip_sign();
+ }
+ else
+ {
+ out = BigInt(obj.bits(), obj.length());
+ }
+ }
+
+ return (*this);
+ }
+
+namespace {
+
+template<typename Alloc>
+void asn1_decode_binary_string(std::vector<uint8_t, Alloc>& buffer,
+ const BER_Object& obj,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag)
+ {
+ obj.assert_is_a(type_tag, class_tag);
+
+ if(real_type == OCTET_STRING)
+ {
+ buffer.assign(obj.bits(), obj.bits() + obj.length());
+ }
+ else
+ {
+ if(obj.length() == 0)
+ throw BER_Decoding_Error("Invalid BIT STRING");
+ if(obj.bits()[0] >= 8)
+ throw BER_Decoding_Error("Bad number of unused bits in BIT STRING");
+
+ buffer.resize(obj.length() - 1);
+
+ if(obj.length() > 1)
+ copy_mem(buffer.data(), obj.bits() + 1, obj.length() - 1);
+ }
+ }
+
+}
+
+/*
+* BER decode a BIT STRING or OCTET STRING
+*/
+BER_Decoder& BER_Decoder::decode(secure_vector<uint8_t>& buffer,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ if(real_type != OCTET_STRING && real_type != BIT_STRING)
+ throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type);
+
+ asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag);
+ return (*this);
+ }
+
+BER_Decoder& BER_Decoder::decode(std::vector<uint8_t>& buffer,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ if(real_type != OCTET_STRING && real_type != BIT_STRING)
+ throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type);
+
+ asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag);
+ return (*this);
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/ber_dec.h b/comm/third_party/botan/src/lib/asn1/ber_dec.h
new file mode 100644
index 0000000000..1fb8c4a9da
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/ber_dec.h
@@ -0,0 +1,418 @@
+/*
+* BER Decoder
+* (C) 1999-2010,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_BER_DECODER_H_
+#define BOTAN_BER_DECODER_H_
+
+#include <botan/asn1_obj.h>
+#include <botan/data_src.h>
+
+namespace Botan {
+
+class BigInt;
+
+/**
+* BER Decoding Object
+*/
+class BOTAN_PUBLIC_API(2,0) BER_Decoder final
+ {
+ public:
+ /**
+ * Set up to BER decode the data in buf of length len
+ */
+ BER_Decoder(const uint8_t buf[], size_t len);
+
+ /**
+ * Set up to BER decode the data in vec
+ */
+ explicit BER_Decoder(const secure_vector<uint8_t>& vec);
+
+ /**
+ * Set up to BER decode the data in vec
+ */
+ explicit BER_Decoder(const std::vector<uint8_t>& vec);
+
+ /**
+ * Set up to BER decode the data in src
+ */
+ explicit BER_Decoder(DataSource& src);
+
+ /**
+ * Set up to BER decode the data in obj
+ */
+ BER_Decoder(const BER_Object& obj) :
+ BER_Decoder(obj.bits(), obj.length()) {}
+
+ /**
+ * Set up to BER decode the data in obj
+ */
+ BER_Decoder(BER_Object&& obj) :
+ BER_Decoder(std::move(obj), nullptr) {}
+
+ BER_Decoder(const BER_Decoder& other);
+
+ BER_Decoder& operator=(const BER_Decoder&) = delete;
+
+ /**
+ * Get the next object in the data stream.
+ * If EOF, returns an object with type NO_OBJECT.
+ */
+ BER_Object get_next_object();
+
+ BER_Decoder& get_next(BER_Object& ber)
+ {
+ ber = get_next_object();
+ return (*this);
+ }
+
+ /**
+ * Push an object back onto the stream. Throws if another
+ * object was previously pushed and has not been subsequently
+ * read out.
+ */
+ void push_back(const BER_Object& obj);
+
+ /**
+ * Push an object back onto the stream. Throws if another
+ * object was previously pushed and has not been subsequently
+ * read out.
+ */
+ void push_back(BER_Object&& obj);
+
+ /**
+ * Return true if there is at least one more item remaining
+ */
+ bool more_items() const;
+
+ /**
+ * Verify the stream is concluded, throws otherwise.
+ * Returns (*this)
+ */
+ BER_Decoder& verify_end();
+
+ /**
+ * Verify the stream is concluded, throws otherwise.
+ * Returns (*this)
+ */
+ BER_Decoder& verify_end(const std::string& err_msg);
+
+ /**
+ * Discard any data that remains unread
+ * Returns (*this)
+ */
+ BER_Decoder& discard_remaining();
+
+ /**
+ * Start decoding a constructed data (sequence or set)
+ */
+ BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = UNIVERSAL);
+
+ /**
+ * Finish decoding a constructed data, throws if any data remains.
+ * Returns the parent of *this (ie the object on which start_cons was called).
+ */
+ BER_Decoder& end_cons();
+
+ /**
+ * Get next object and copy value to POD type
+ * Asserts value length is equal to POD type sizeof.
+ * Asserts Type tag and optional Class tag according to parameters.
+ * Copy value to POD type (struct, union, C-style array, std::array, etc.).
+ * @param out POD type reference where to copy object value
+ * @param type_tag ASN1_Tag enum to assert type on object read
+ * @param class_tag ASN1_Tag enum to assert class on object read (default: CONTEXT_SPECIFIC)
+ * @return this reference
+ */
+ template <typename T>
+ BER_Decoder& get_next_value(T &out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC)
+ {
+ static_assert(std::is_standard_layout<T>::value && std::is_trivial<T>::value, "Type must be POD");
+
+ BER_Object obj = get_next_object();
+ obj.assert_is_a(type_tag, class_tag);
+
+ if (obj.length() != sizeof(T))
+ throw BER_Decoding_Error(
+ "Size mismatch. Object value size is " +
+ std::to_string(obj.length()) +
+ "; Output type size is " +
+ std::to_string(sizeof(T)));
+
+ copy_mem(reinterpret_cast<uint8_t*>(&out), obj.bits(), obj.length());
+
+ return (*this);
+ }
+
+ /*
+ * Save all the bytes remaining in the source
+ */
+ template<typename Alloc>
+ BER_Decoder& raw_bytes(std::vector<uint8_t, Alloc>& out)
+ {
+ out.clear();
+ uint8_t buf;
+ while(m_source->read_byte(buf))
+ out.push_back(buf);
+ return (*this);
+ }
+
+ BER_Decoder& decode_null();
+
+ /**
+ * Decode a BER encoded BOOLEAN
+ */
+ BER_Decoder& decode(bool& out)
+ {
+ return decode(out, BOOLEAN, UNIVERSAL);
+ }
+
+ /*
+ * Decode a small BER encoded INTEGER
+ */
+ BER_Decoder& decode(size_t& out)
+ {
+ return decode(out, INTEGER, UNIVERSAL);
+ }
+
+ /*
+ * Decode a BER encoded INTEGER
+ */
+ BER_Decoder& decode(BigInt& out)
+ {
+ return decode(out, INTEGER, UNIVERSAL);
+ }
+
+ std::vector<uint8_t> get_next_octet_string()
+ {
+ std::vector<uint8_t> out_vec;
+ decode(out_vec, OCTET_STRING);
+ return out_vec;
+ }
+
+ /*
+ * BER decode a BIT STRING or OCTET STRING
+ */
+ template<typename Alloc>
+ BER_Decoder& decode(std::vector<uint8_t, Alloc>& out, ASN1_Tag real_type)
+ {
+ return decode(out, real_type, real_type, UNIVERSAL);
+ }
+
+ BER_Decoder& decode(bool& v,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ BER_Decoder& decode(size_t& v,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ BER_Decoder& decode(BigInt& v,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ BER_Decoder& decode(std::vector<uint8_t>& v,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ BER_Decoder& decode(secure_vector<uint8_t>& v,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ BER_Decoder& decode(class ASN1_Object& obj,
+ ASN1_Tag type_tag = NO_OBJECT,
+ ASN1_Tag class_tag = NO_OBJECT);
+
+ /**
+ * Decode an integer value which is typed as an octet string
+ */
+ BER_Decoder& decode_octet_string_bigint(BigInt& b);
+
+ uint64_t decode_constrained_integer(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ size_t T_bytes);
+
+ template<typename T> BER_Decoder& decode_integer_type(T& out)
+ {
+ return decode_integer_type<T>(out, INTEGER, UNIVERSAL);
+ }
+
+ template<typename T>
+ BER_Decoder& decode_integer_type(T& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC)
+ {
+ out = static_cast<T>(decode_constrained_integer(type_tag, class_tag, sizeof(out)));
+ return (*this);
+ }
+
+ template<typename T>
+ BER_Decoder& decode_optional(T& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ const T& default_value = T());
+
+ template<typename T>
+ BER_Decoder& decode_optional_implicit(
+ T& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ ASN1_Tag real_type,
+ ASN1_Tag real_class,
+ const T& default_value = T());
+
+ template<typename T>
+ BER_Decoder& decode_list(std::vector<T>& out,
+ ASN1_Tag type_tag = SEQUENCE,
+ ASN1_Tag class_tag = UNIVERSAL);
+
+ template<typename T>
+ BER_Decoder& decode_and_check(const T& expected,
+ const std::string& error_msg)
+ {
+ T actual;
+ decode(actual);
+
+ if(actual != expected)
+ throw Decoding_Error(error_msg);
+
+ return (*this);
+ }
+
+ /*
+ * Decode an OPTIONAL string type
+ */
+ template<typename Alloc>
+ BER_Decoder& decode_optional_string(std::vector<uint8_t, Alloc>& out,
+ ASN1_Tag real_type,
+ uint16_t type_no,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC)
+ {
+ BER_Object obj = get_next_object();
+
+ ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no);
+
+ if(obj.is_a(type_tag, class_tag))
+ {
+ if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC))
+ {
+ BER_Decoder(std::move(obj)).decode(out, real_type).verify_end();
+ }
+ else
+ {
+ push_back(std::move(obj));
+ decode(out, real_type, type_tag, class_tag);
+ }
+ }
+ else
+ {
+ out.clear();
+ push_back(std::move(obj));
+ }
+
+ return (*this);
+ }
+
+ private:
+ BER_Decoder(BER_Object&& obj, BER_Decoder* parent);
+
+ BER_Decoder* m_parent = nullptr;
+ BER_Object m_pushed;
+ // either m_data_src.get() or an unowned pointer
+ DataSource* m_source;
+ mutable std::unique_ptr<DataSource> m_data_src;
+ };
+
+/*
+* Decode an OPTIONAL or DEFAULT element
+*/
+template<typename T>
+BER_Decoder& BER_Decoder::decode_optional(T& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ const T& default_value)
+ {
+ BER_Object obj = get_next_object();
+
+ if(obj.is_a(type_tag, class_tag))
+ {
+ if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC))
+ {
+ BER_Decoder(std::move(obj)).decode(out).verify_end();
+ }
+ else
+ {
+ push_back(std::move(obj));
+ decode(out, type_tag, class_tag);
+ }
+ }
+ else
+ {
+ out = default_value;
+ push_back(std::move(obj));
+ }
+
+ return (*this);
+ }
+
+/*
+* Decode an OPTIONAL or DEFAULT element
+*/
+template<typename T>
+BER_Decoder& BER_Decoder::decode_optional_implicit(
+ T& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ ASN1_Tag real_type,
+ ASN1_Tag real_class,
+ const T& default_value)
+ {
+ BER_Object obj = get_next_object();
+
+ if(obj.is_a(type_tag, class_tag))
+ {
+ obj.set_tagging(real_type, real_class);
+ push_back(std::move(obj));
+ decode(out, real_type, real_class);
+ }
+ else
+ {
+ // Not what we wanted, push it back on the stream
+ out = default_value;
+ push_back(std::move(obj));
+ }
+
+ return (*this);
+ }
+/*
+* Decode a list of homogenously typed values
+*/
+template<typename T>
+BER_Decoder& BER_Decoder::decode_list(std::vector<T>& vec,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag)
+ {
+ BER_Decoder list = start_cons(type_tag, class_tag);
+
+ while(list.more_items())
+ {
+ T value;
+ list.decode(value);
+ vec.push_back(std::move(value));
+ }
+
+ list.end_cons();
+
+ return (*this);
+ }
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/der_enc.cpp b/comm/third_party/botan/src/lib/asn1/der_enc.cpp
new file mode 100644
index 0000000000..056766f435
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/der_enc.cpp
@@ -0,0 +1,405 @@
+/*
+* DER Encoder
+* (C) 1999-2007,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/der_enc.h>
+#include <botan/asn1_obj.h>
+#include <botan/bigint.h>
+#include <botan/loadstor.h>
+#include <botan/internal/bit_ops.h>
+#include <algorithm>
+
+namespace Botan {
+
+namespace {
+
+/*
+* DER encode an ASN.1 type tag
+*/
+void encode_tag(std::vector<uint8_t>& encoded_tag,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ if((class_tag | 0xE0) != 0xE0)
+ throw Encoding_Error("DER_Encoder: Invalid class tag " +
+ std::to_string(class_tag));
+
+ if(type_tag <= 30)
+ {
+ encoded_tag.push_back(static_cast<uint8_t>(type_tag | class_tag));
+ }
+ else
+ {
+ size_t blocks = high_bit(static_cast<uint32_t>(type_tag)) + 6;
+ blocks = (blocks - (blocks % 7)) / 7;
+
+ BOTAN_ASSERT_NOMSG(blocks > 0);
+
+ encoded_tag.push_back(static_cast<uint8_t>(class_tag | 0x1F));
+ for(size_t i = 0; i != blocks - 1; ++i)
+ encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F));
+ encoded_tag.push_back(type_tag & 0x7F);
+ }
+ }
+
+/*
+* DER encode an ASN.1 length field
+*/
+void encode_length(std::vector<uint8_t>& encoded_length, size_t length)
+ {
+ if(length <= 127)
+ {
+ encoded_length.push_back(static_cast<uint8_t>(length));
+ }
+ else
+ {
+ const size_t bytes_needed = significant_bytes(length);
+
+ encoded_length.push_back(static_cast<uint8_t>(0x80 | bytes_needed));
+
+ for(size_t i = sizeof(length) - bytes_needed; i < sizeof(length); ++i)
+ encoded_length.push_back(get_byte(i, length));
+ }
+ }
+
+}
+
+DER_Encoder::DER_Encoder(secure_vector<uint8_t>& vec)
+ {
+ m_append_output = [&vec](const uint8_t b[], size_t l)
+ {
+ vec.insert(vec.end(), b, b + l);
+ };
+ }
+
+DER_Encoder::DER_Encoder(std::vector<uint8_t>& vec)
+ {
+ m_append_output = [&vec](const uint8_t b[], size_t l)
+ {
+ vec.insert(vec.end(), b, b + l);
+ };
+ }
+
+/*
+* Push the encoded SEQUENCE/SET to the encoder stream
+*/
+void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der)
+ {
+ const ASN1_Tag real_class_tag = ASN1_Tag(m_class_tag | CONSTRUCTED);
+
+ if(m_type_tag == SET)
+ {
+ std::sort(m_set_contents.begin(), m_set_contents.end());
+ for(size_t i = 0; i != m_set_contents.size(); ++i)
+ m_contents += m_set_contents[i];
+ m_set_contents.clear();
+ }
+
+ der.add_object(m_type_tag, real_class_tag, m_contents.data(), m_contents.size());
+ m_contents.clear();
+ }
+
+/*
+* Add an encoded value to the SEQUENCE/SET
+*/
+void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length)
+ {
+ if(m_type_tag == SET)
+ m_set_contents.push_back(secure_vector<uint8_t>(data, data + length));
+ else
+ m_contents += std::make_pair(data, length);
+ }
+
+void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len,
+ const uint8_t val[], size_t val_len)
+ {
+ if(m_type_tag == SET)
+ {
+ secure_vector<uint8_t> m;
+ m.reserve(hdr_len + val_len);
+ m += std::make_pair(hdr, hdr_len);
+ m += std::make_pair(val, val_len);
+ m_set_contents.push_back(std::move(m));
+ }
+ else
+ {
+ m_contents += std::make_pair(hdr, hdr_len);
+ m_contents += std::make_pair(val, val_len);
+ }
+ }
+
+/*
+* Return the type and class taggings
+*/
+ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const
+ {
+ return ASN1_Tag(m_type_tag | m_class_tag);
+ }
+
+/*
+* DER_Sequence Constructor
+*/
+DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) :
+ m_type_tag(t1), m_class_tag(t2)
+ {
+ }
+
+/*
+* Return the encoded contents
+*/
+secure_vector<uint8_t> DER_Encoder::get_contents()
+ {
+ if(m_subsequences.size() != 0)
+ throw Invalid_State("DER_Encoder: Sequence hasn't been marked done");
+
+ if(m_append_output)
+ throw Invalid_State("DER_Encoder Cannot get contents when using output vector");
+
+ secure_vector<uint8_t> output;
+ std::swap(output, m_default_outbuf);
+ return output;
+ }
+
+std::vector<uint8_t> DER_Encoder::get_contents_unlocked()
+ {
+ if(m_subsequences.size() != 0)
+ throw Invalid_State("DER_Encoder: Sequence hasn't been marked done");
+
+ if(m_append_output)
+ throw Invalid_State("DER_Encoder Cannot get contents when using output vector");
+
+ std::vector<uint8_t> output(m_default_outbuf.begin(), m_default_outbuf.end());
+ m_default_outbuf.clear();
+ return output;
+ }
+
+/*
+* Start a new ASN.1 SEQUENCE/SET/EXPLICIT
+*/
+DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag,
+ ASN1_Tag class_tag)
+ {
+ m_subsequences.push_back(DER_Sequence(type_tag, class_tag));
+ return (*this);
+ }
+
+/*
+* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT
+*/
+DER_Encoder& DER_Encoder::end_cons()
+ {
+ if(m_subsequences.empty())
+ throw Invalid_State("DER_Encoder::end_cons: No such sequence");
+
+ DER_Sequence last_seq = std::move(m_subsequences[m_subsequences.size()-1]);
+ m_subsequences.pop_back();
+ last_seq.push_contents(*this);
+
+ return (*this);
+ }
+
+/*
+* Start a new ASN.1 EXPLICIT encoding
+*/
+DER_Encoder& DER_Encoder::start_explicit(uint16_t type_no)
+ {
+ ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no);
+
+ // This would confuse DER_Sequence
+ if(type_tag == SET)
+ throw Internal_Error("DER_Encoder.start_explicit(SET) not supported");
+
+ return start_cons(type_tag, CONTEXT_SPECIFIC);
+ }
+
+/*
+* Finish the current ASN.1 EXPLICIT encoding
+*/
+DER_Encoder& DER_Encoder::end_explicit()
+ {
+ return end_cons();
+ }
+
+/*
+* Write raw bytes into the stream
+*/
+DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length)
+ {
+ if(m_subsequences.size())
+ {
+ m_subsequences[m_subsequences.size()-1].add_bytes(bytes, length);
+ }
+ else if(m_append_output)
+ {
+ m_append_output(bytes, length);
+ }
+ else
+ {
+ m_default_outbuf += std::make_pair(bytes, length);
+ }
+
+ return (*this);
+ }
+
+/*
+* Write the encoding of the byte(s)
+*/
+DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const uint8_t rep[], size_t length)
+ {
+ std::vector<uint8_t> hdr;
+ encode_tag(hdr, type_tag, class_tag);
+ encode_length(hdr, length);
+
+ if(m_subsequences.size())
+ {
+ m_subsequences[m_subsequences.size()-1].add_bytes(hdr.data(), hdr.size(), rep, length);
+ }
+ else if(m_append_output)
+ {
+ m_append_output(hdr.data(), hdr.size());
+ m_append_output(rep, length);
+ }
+ else
+ {
+ m_default_outbuf += hdr;
+ m_default_outbuf += std::make_pair(rep, length);
+ }
+
+ return (*this);
+ }
+
+/*
+* Encode a NULL object
+*/
+DER_Encoder& DER_Encoder::encode_null()
+ {
+ return add_object(NULL_TAG, UNIVERSAL, nullptr, 0);
+ }
+
+/*
+* DER encode a BOOLEAN
+*/
+DER_Encoder& DER_Encoder::encode(bool is_true)
+ {
+ return encode(is_true, BOOLEAN, UNIVERSAL);
+ }
+
+/*
+* DER encode a small INTEGER
+*/
+DER_Encoder& DER_Encoder::encode(size_t n)
+ {
+ return encode(BigInt(n), INTEGER, UNIVERSAL);
+ }
+
+/*
+* DER encode a small INTEGER
+*/
+DER_Encoder& DER_Encoder::encode(const BigInt& n)
+ {
+ return encode(n, INTEGER, UNIVERSAL);
+ }
+
+/*
+* Encode this object
+*/
+DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length,
+ ASN1_Tag real_type)
+ {
+ return encode(bytes, length, real_type, real_type, UNIVERSAL);
+ }
+
+/*
+* DER encode a BOOLEAN
+*/
+DER_Encoder& DER_Encoder::encode(bool is_true,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ uint8_t val = is_true ? 0xFF : 0x00;
+ return add_object(type_tag, class_tag, &val, 1);
+ }
+
+/*
+* DER encode a small INTEGER
+*/
+DER_Encoder& DER_Encoder::encode(size_t n,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ return encode(BigInt(n), type_tag, class_tag);
+ }
+
+/*
+* DER encode an INTEGER
+*/
+DER_Encoder& DER_Encoder::encode(const BigInt& n,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ if(n == 0)
+ return add_object(type_tag, class_tag, 0);
+
+ const size_t extra_zero = (n.bits() % 8 == 0) ? 1 : 0;
+ secure_vector<uint8_t> contents(extra_zero + n.bytes());
+ n.binary_encode(&contents[extra_zero]);
+ if(n < 0)
+ {
+ for(size_t i = 0; i != contents.size(); ++i)
+ contents[i] = ~contents[i];
+ for(size_t i = contents.size(); i > 0; --i)
+ if(++contents[i-1])
+ break;
+ }
+
+ return add_object(type_tag, class_tag, contents);
+ }
+
+/*
+* DER encode an OCTET STRING or BIT STRING
+*/
+DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ if(real_type != OCTET_STRING && real_type != BIT_STRING)
+ throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string");
+
+ if(real_type == BIT_STRING)
+ {
+ secure_vector<uint8_t> encoded;
+ encoded.push_back(0);
+ encoded += std::make_pair(bytes, length);
+ return add_object(type_tag, class_tag, encoded);
+ }
+ else
+ return add_object(type_tag, class_tag, bytes, length);
+ }
+
+DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
+ {
+ obj.encode_into(*this);
+ return (*this);
+ }
+
+/*
+* Write the encoding of the byte(s)
+*/
+DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const std::string& rep_str)
+ {
+ const uint8_t* rep = cast_char_ptr_to_uint8(rep_str.data());
+ const size_t rep_len = rep_str.size();
+ return add_object(type_tag, class_tag, rep, rep_len);
+ }
+
+/*
+* Write the encoding of the byte
+*/
+DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag,
+ ASN1_Tag class_tag, uint8_t rep)
+ {
+ return add_object(type_tag, class_tag, &rep, 1);
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/der_enc.h b/comm/third_party/botan/src/lib/asn1/der_enc.h
new file mode 100644
index 0000000000..93d53f4b91
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/der_enc.h
@@ -0,0 +1,227 @@
+/*
+* DER Encoder
+* (C) 1999-2007,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_DER_ENCODER_H_
+#define BOTAN_DER_ENCODER_H_
+
+#include <botan/asn1_obj.h>
+#include <vector>
+#include <functional>
+
+namespace Botan {
+
+class BigInt;
+
+/**
+* General DER Encoding Object
+*/
+class BOTAN_PUBLIC_API(2,0) DER_Encoder final
+ {
+ public:
+ typedef std::function<void (const uint8_t[], size_t)> append_fn;
+
+ /**
+ * DER encode, writing to an internal buffer
+ * Use get_contents or get_contents_unlocked to read the results
+ * after all encoding is completed.
+ */
+ DER_Encoder() = default;
+
+ /**
+ * DER encode, writing to @param vec
+ * If this constructor is used, get_contents* may not be called.
+ */
+ DER_Encoder(secure_vector<uint8_t>& vec);
+
+ /**
+ * DER encode, writing to @param vec
+ * If this constructor is used, get_contents* may not be called.
+ */
+ DER_Encoder(std::vector<uint8_t>& vec);
+
+ /**
+ * DER encode, calling append to write output
+ * If this constructor is used, get_contents* may not be called.
+ */
+ DER_Encoder(append_fn append) : m_append_output(append) {}
+
+ secure_vector<uint8_t> get_contents();
+
+ /**
+ * Return the encoded contents as a std::vector
+ *
+ * If using this function, instead pass a std::vector to the
+ * contructor of DER_Encoder where the output will be placed. This
+ * avoids several unecessary copies.
+ */
+ std::vector<uint8_t> BOTAN_DEPRECATED("Use DER_Encoder(vector) instead") get_contents_unlocked();
+
+ DER_Encoder& start_cons(ASN1_Tag type_tag,
+ ASN1_Tag class_tag = UNIVERSAL);
+ DER_Encoder& end_cons();
+
+ DER_Encoder& start_explicit(uint16_t type_tag);
+ DER_Encoder& end_explicit();
+
+ /**
+ * Insert raw bytes directly into the output stream
+ */
+ DER_Encoder& raw_bytes(const uint8_t val[], size_t len);
+
+ template<typename Alloc>
+ DER_Encoder& raw_bytes(const std::vector<uint8_t, Alloc>& val)
+ {
+ return raw_bytes(val.data(), val.size());
+ }
+
+ DER_Encoder& encode_null();
+ DER_Encoder& encode(bool b);
+ DER_Encoder& encode(size_t s);
+ DER_Encoder& encode(const BigInt& n);
+ DER_Encoder& encode(const uint8_t val[], size_t len, ASN1_Tag real_type);
+
+ template<typename Alloc>
+ DER_Encoder& encode(const std::vector<uint8_t, Alloc>& vec, ASN1_Tag real_type)
+ {
+ return encode(vec.data(), vec.size(), real_type);
+ }
+
+ DER_Encoder& encode(bool b,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ DER_Encoder& encode(size_t s,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ DER_Encoder& encode(const BigInt& n,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ DER_Encoder& encode(const uint8_t v[], size_t len,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ template<typename Alloc>
+ DER_Encoder& encode(const std::vector<uint8_t, Alloc>& bytes,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ return encode(bytes.data(), bytes.size(),
+ real_type, type_tag, class_tag);
+ }
+
+ template<typename T>
+ DER_Encoder& encode_optional(const T& value, const T& default_value)
+ {
+ if(value != default_value)
+ encode(value);
+ return (*this);
+ }
+
+ template<typename T>
+ DER_Encoder& encode_list(const std::vector<T>& values)
+ {
+ for(size_t i = 0; i != values.size(); ++i)
+ encode(values[i]);
+ return (*this);
+ }
+
+ /*
+ * Request for an object to encode itself to this stream
+ */
+ DER_Encoder& encode(const ASN1_Object& obj);
+
+ /*
+ * Conditionally write some values to the stream
+ */
+ DER_Encoder& encode_if(bool pred, DER_Encoder& enc)
+ {
+ if(pred)
+ return raw_bytes(enc.get_contents());
+ return (*this);
+ }
+
+ DER_Encoder& encode_if(bool pred, const ASN1_Object& obj)
+ {
+ if(pred)
+ encode(obj);
+ return (*this);
+ }
+
+ DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const uint8_t rep[], size_t length);
+
+ DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const std::vector<uint8_t>& rep)
+ {
+ return add_object(type_tag, class_tag, rep.data(), rep.size());
+ }
+
+ DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const secure_vector<uint8_t>& rep)
+ {
+ return add_object(type_tag, class_tag, rep.data(), rep.size());
+ }
+
+ DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ const std::string& str);
+
+ DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
+ uint8_t val);
+
+ private:
+ class DER_Sequence final
+ {
+ public:
+ ASN1_Tag tag_of() const;
+
+ void push_contents(DER_Encoder& der);
+
+ void add_bytes(const uint8_t val[], size_t len);
+
+ void add_bytes(const uint8_t hdr[], size_t hdr_len,
+ const uint8_t val[], size_t val_len);
+
+ DER_Sequence(ASN1_Tag, ASN1_Tag);
+
+ DER_Sequence(DER_Sequence&& seq)
+ {
+ std::swap(m_type_tag, seq.m_type_tag);
+ std::swap(m_class_tag, seq.m_class_tag);
+ std::swap(m_contents, seq.m_contents);
+ std::swap(m_set_contents, seq.m_set_contents);
+ }
+
+ DER_Sequence& operator=(DER_Sequence&& seq)
+ {
+ std::swap(m_type_tag, seq.m_type_tag);
+ std::swap(m_class_tag, seq.m_class_tag);
+ std::swap(m_contents, seq.m_contents);
+ std::swap(m_set_contents, seq.m_set_contents);
+ return (*this);
+ }
+
+ DER_Sequence(const DER_Sequence& seq) = default;
+
+ DER_Sequence& operator=(const DER_Sequence& seq) = default;
+
+ private:
+ ASN1_Tag m_type_tag, m_class_tag;
+ secure_vector<uint8_t> m_contents;
+ std::vector< secure_vector<uint8_t> > m_set_contents;
+ };
+
+ append_fn m_append_output;
+ secure_vector<uint8_t> m_default_outbuf;
+ std::vector<DER_Sequence> m_subsequences;
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/asn1/info.txt b/comm/third_party/botan/src/lib/asn1/info.txt
new file mode 100644
index 0000000000..4772e1ca70
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/info.txt
@@ -0,0 +1,7 @@
+<defines>
+ASN1 -> 20171109
+</defines>
+
+<requires>
+bigint
+</requires>
diff --git a/comm/third_party/botan/src/lib/asn1/oid_maps.cpp b/comm/third_party/botan/src/lib/asn1/oid_maps.cpp
new file mode 100644
index 0000000000..d385dfd840
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/oid_maps.cpp
@@ -0,0 +1,510 @@
+/*
+* OID maps
+*
+* This file was automatically generated by ./src/scripts/oids.py on 2019-10-21
+*
+* All manual edits to this file will be lost. Edit the script
+* then regenerate this source file.
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/oids.h>
+#include <unordered_map>
+
+namespace Botan {
+
+std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
+ {
+ return std::unordered_map<std::string,std::string>{
+ { "0.3.4401.5.3.1.9.26", "Camellia-192/GCM" },
+ { "0.3.4401.5.3.1.9.46", "Camellia-256/GCM" },
+ { "0.3.4401.5.3.1.9.6", "Camellia-128/GCM" },
+ { "0.4.0.127.0.15.1.1.13.0", "XMSS" },
+ { "1.0.14888.3.0.5", "ECKCDSA" },
+ { "1.2.156.10197.1.104.100", "SM4/OCB" },
+ { "1.2.156.10197.1.104.2", "SM4/CBC" },
+ { "1.2.156.10197.1.104.8", "SM4/GCM" },
+ { "1.2.156.10197.1.301", "sm2p256v1" },
+ { "1.2.156.10197.1.301.1", "SM2" },
+ { "1.2.156.10197.1.301.2", "SM2_Kex" },
+ { "1.2.156.10197.1.301.3", "SM2_Enc" },
+ { "1.2.156.10197.1.401", "SM3" },
+ { "1.2.156.10197.1.501", "SM2_Sig/SM3" },
+ { "1.2.156.10197.1.504", "RSA/EMSA3(SM3)" },
+ { "1.2.250.1.223.101.256.1", "frp256v1" },
+ { "1.2.392.200011.61.1.1.1.2", "Camellia-128/CBC" },
+ { "1.2.392.200011.61.1.1.1.3", "Camellia-192/CBC" },
+ { "1.2.392.200011.61.1.1.1.4", "Camellia-256/CBC" },
+ { "1.2.410.200004.1.100.4.3", "ECKCDSA/EMSA1(SHA-1)" },
+ { "1.2.410.200004.1.100.4.4", "ECKCDSA/EMSA1(SHA-224)" },
+ { "1.2.410.200004.1.100.4.5", "ECKCDSA/EMSA1(SHA-256)" },
+ { "1.2.410.200004.1.4", "SEED/CBC" },
+ { "1.2.643.100.1", "GOST.OGRN" },
+ { "1.2.643.100.111", "GOST.SubjectSigningTool" },
+ { "1.2.643.100.112", "GOST.IssuerSigningTool" },
+ { "1.2.643.2.2.19", "GOST-34.10" },
+ { "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)" },
+ { "1.2.643.2.2.35.1", "gost_256A" },
+ { "1.2.643.2.2.36.0", "gost_256A" },
+ { "1.2.643.3.131.1.1", "GOST.INN" },
+ { "1.2.643.7.1.1.1.1", "GOST-34.10-2012-256" },
+ { "1.2.643.7.1.1.1.2", "GOST-34.10-2012-512" },
+ { "1.2.643.7.1.1.2.2", "Streebog-256" },
+ { "1.2.643.7.1.1.2.3", "Streebog-512" },
+ { "1.2.643.7.1.1.3.2", "GOST-34.10-2012-256/EMSA1(Streebog-256)" },
+ { "1.2.643.7.1.1.3.3", "GOST-34.10-2012-512/EMSA1(Streebog-512)" },
+ { "1.2.643.7.1.2.1.1.1", "gost_256A" },
+ { "1.2.643.7.1.2.1.1.2", "gost_256B" },
+ { "1.2.643.7.1.2.1.2.1", "gost_512A" },
+ { "1.2.643.7.1.2.1.2.2", "gost_512B" },
+ { "1.2.840.10040.4.1", "DSA" },
+ { "1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)" },
+ { "1.2.840.10045.2.1", "ECDSA" },
+ { "1.2.840.10045.3.1.1", "secp192r1" },
+ { "1.2.840.10045.3.1.2", "x962_p192v2" },
+ { "1.2.840.10045.3.1.3", "x962_p192v3" },
+ { "1.2.840.10045.3.1.4", "x962_p239v1" },
+ { "1.2.840.10045.3.1.5", "x962_p239v2" },
+ { "1.2.840.10045.3.1.6", "x962_p239v3" },
+ { "1.2.840.10045.3.1.7", "secp256r1" },
+ { "1.2.840.10045.4.1", "ECDSA/EMSA1(SHA-160)" },
+ { "1.2.840.10045.4.3.1", "ECDSA/EMSA1(SHA-224)" },
+ { "1.2.840.10045.4.3.2", "ECDSA/EMSA1(SHA-256)" },
+ { "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)" },
+ { "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)" },
+ { "1.2.840.10046.2.1", "DH" },
+ { "1.2.840.113533.7.66.10", "CAST-128/CBC" },
+ { "1.2.840.113533.7.66.15", "KeyWrap.CAST-128" },
+ { "1.2.840.113549.1.1.1", "RSA" },
+ { "1.2.840.113549.1.1.10", "RSA/EMSA4" },
+ { "1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)" },
+ { "1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)" },
+ { "1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)" },
+ { "1.2.840.113549.1.1.14", "RSA/EMSA3(SHA-224)" },
+ { "1.2.840.113549.1.1.16", "RSA/EMSA3(SHA-512-256)" },
+ { "1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)" },
+ { "1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)" },
+ { "1.2.840.113549.1.1.7", "RSA/OAEP" },
+ { "1.2.840.113549.1.1.8", "MGF1" },
+ { "1.2.840.113549.1.5.12", "PKCS5.PBKDF2" },
+ { "1.2.840.113549.1.5.13", "PBE-PKCS5v20" },
+ { "1.2.840.113549.1.9.1", "PKCS9.EmailAddress" },
+ { "1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest" },
+ { "1.2.840.113549.1.9.16.3.18", "ChaCha20Poly1305" },
+ { "1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES" },
+ { "1.2.840.113549.1.9.16.3.8", "Compression.Zlib" },
+ { "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName" },
+ { "1.2.840.113549.1.9.3", "PKCS9.ContentType" },
+ { "1.2.840.113549.1.9.4", "PKCS9.MessageDigest" },
+ { "1.2.840.113549.1.9.7", "PKCS9.ChallengePassword" },
+ { "1.2.840.113549.2.10", "HMAC(SHA-384)" },
+ { "1.2.840.113549.2.11", "HMAC(SHA-512)" },
+ { "1.2.840.113549.2.13", "HMAC(SHA-512-256)" },
+ { "1.2.840.113549.2.5", "MD5" },
+ { "1.2.840.113549.2.7", "HMAC(SHA-160)" },
+ { "1.2.840.113549.2.8", "HMAC(SHA-224)" },
+ { "1.2.840.113549.2.9", "HMAC(SHA-256)" },
+ { "1.2.840.113549.3.7", "TripleDES/CBC" },
+ { "1.3.101.110", "Curve25519" },
+ { "1.3.101.112", "Ed25519" },
+ { "1.3.132.0.10", "secp256k1" },
+ { "1.3.132.0.30", "secp160r2" },
+ { "1.3.132.0.31", "secp192k1" },
+ { "1.3.132.0.32", "secp224k1" },
+ { "1.3.132.0.33", "secp224r1" },
+ { "1.3.132.0.34", "secp384r1" },
+ { "1.3.132.0.35", "secp521r1" },
+ { "1.3.132.0.8", "secp160r1" },
+ { "1.3.132.0.9", "secp160k1" },
+ { "1.3.132.1.12", "ECDH" },
+ { "1.3.14.3.2.26", "SHA-160" },
+ { "1.3.14.3.2.7", "DES/CBC" },
+ { "1.3.36.3.2.1", "RIPEMD-160" },
+ { "1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)" },
+ { "1.3.36.3.3.2.5.2.1", "ECGDSA" },
+ { "1.3.36.3.3.2.5.4.1", "ECGDSA/EMSA1(RIPEMD-160)" },
+ { "1.3.36.3.3.2.5.4.2", "ECGDSA/EMSA1(SHA-160)" },
+ { "1.3.36.3.3.2.5.4.3", "ECGDSA/EMSA1(SHA-224)" },
+ { "1.3.36.3.3.2.5.4.4", "ECGDSA/EMSA1(SHA-256)" },
+ { "1.3.36.3.3.2.5.4.5", "ECGDSA/EMSA1(SHA-384)" },
+ { "1.3.36.3.3.2.5.4.6", "ECGDSA/EMSA1(SHA-512)" },
+ { "1.3.36.3.3.2.8.1.1.1", "brainpool160r1" },
+ { "1.3.36.3.3.2.8.1.1.11", "brainpool384r1" },
+ { "1.3.36.3.3.2.8.1.1.13", "brainpool512r1" },
+ { "1.3.36.3.3.2.8.1.1.3", "brainpool192r1" },
+ { "1.3.36.3.3.2.8.1.1.5", "brainpool224r1" },
+ { "1.3.36.3.3.2.8.1.1.7", "brainpool256r1" },
+ { "1.3.36.3.3.2.8.1.1.9", "brainpool320r1" },
+ { "1.3.6.1.4.1.11591.12.2", "Tiger(24,3)" },
+ { "1.3.6.1.4.1.11591.15.1", "OpenPGP.Ed25519" },
+ { "1.3.6.1.4.1.11591.4.11", "Scrypt" },
+ { "1.3.6.1.4.1.25258.1.3", "McEliece" },
+ { "1.3.6.1.4.1.25258.1.5", "XMSS-draft6" },
+ { "1.3.6.1.4.1.25258.1.6.1", "GOST-34.10-2012-256/EMSA1(SHA-256)" },
+ { "1.3.6.1.4.1.25258.1.8", "XMSS-draft12" },
+ { "1.3.6.1.4.1.25258.3.1", "Serpent/CBC" },
+ { "1.3.6.1.4.1.25258.3.101", "Serpent/GCM" },
+ { "1.3.6.1.4.1.25258.3.102", "Twofish/GCM" },
+ { "1.3.6.1.4.1.25258.3.2", "Threefish-512/CBC" },
+ { "1.3.6.1.4.1.25258.3.2.1", "AES-128/OCB" },
+ { "1.3.6.1.4.1.25258.3.2.2", "AES-192/OCB" },
+ { "1.3.6.1.4.1.25258.3.2.3", "AES-256/OCB" },
+ { "1.3.6.1.4.1.25258.3.2.4", "Serpent/OCB" },
+ { "1.3.6.1.4.1.25258.3.2.5", "Twofish/OCB" },
+ { "1.3.6.1.4.1.25258.3.2.6", "Camellia-128/OCB" },
+ { "1.3.6.1.4.1.25258.3.2.7", "Camellia-192/OCB" },
+ { "1.3.6.1.4.1.25258.3.2.8", "Camellia-256/OCB" },
+ { "1.3.6.1.4.1.25258.3.3", "Twofish/CBC" },
+ { "1.3.6.1.4.1.25258.3.4.1", "AES-128/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.2", "AES-192/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.3", "AES-256/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.4", "Serpent/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.5", "Twofish/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.6", "Camellia-128/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.7", "Camellia-192/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.8", "Camellia-256/SIV" },
+ { "1.3.6.1.4.1.25258.3.4.9", "SM4/SIV" },
+ { "1.3.6.1.4.1.3029.1.2.1", "ElGamal" },
+ { "1.3.6.1.4.1.3029.1.5.1", "OpenPGP.Curve25519" },
+ { "1.3.6.1.4.1.311.20.2.2", "Microsoft SmartcardLogon" },
+ { "1.3.6.1.4.1.311.20.2.3", "Microsoft UPN" },
+ { "1.3.6.1.4.1.8301.3.1.2.9.0.38", "secp521r1" },
+ { "1.3.6.1.5.5.7.1.1", "PKIX.AuthorityInformationAccess" },
+ { "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth" },
+ { "1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth" },
+ { "1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning" },
+ { "1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection" },
+ { "1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem" },
+ { "1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel" },
+ { "1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser" },
+ { "1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping" },
+ { "1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning" },
+ { "1.3.6.1.5.5.7.48.1", "PKIX.OCSP" },
+ { "1.3.6.1.5.5.7.48.1.1", "PKIX.OCSP.BasicResponse" },
+ { "1.3.6.1.5.5.7.48.2", "PKIX.CertificateAuthorityIssuers" },
+ { "1.3.6.1.5.5.7.8.5", "PKIX.XMPPAddr" },
+ { "2.16.840.1.101.3.4.1.2", "AES-128/CBC" },
+ { "2.16.840.1.101.3.4.1.22", "AES-192/CBC" },
+ { "2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192" },
+ { "2.16.840.1.101.3.4.1.26", "AES-192/GCM" },
+ { "2.16.840.1.101.3.4.1.27", "AES-192/CCM" },
+ { "2.16.840.1.101.3.4.1.42", "AES-256/CBC" },
+ { "2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256" },
+ { "2.16.840.1.101.3.4.1.46", "AES-256/GCM" },
+ { "2.16.840.1.101.3.4.1.47", "AES-256/CCM" },
+ { "2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128" },
+ { "2.16.840.1.101.3.4.1.6", "AES-128/GCM" },
+ { "2.16.840.1.101.3.4.1.7", "AES-128/CCM" },
+ { "2.16.840.1.101.3.4.2.1", "SHA-256" },
+ { "2.16.840.1.101.3.4.2.10", "SHA-3(512)" },
+ { "2.16.840.1.101.3.4.2.11", "SHAKE-128" },
+ { "2.16.840.1.101.3.4.2.12", "SHAKE-256" },
+ { "2.16.840.1.101.3.4.2.2", "SHA-384" },
+ { "2.16.840.1.101.3.4.2.3", "SHA-512" },
+ { "2.16.840.1.101.3.4.2.4", "SHA-224" },
+ { "2.16.840.1.101.3.4.2.6", "SHA-512-256" },
+ { "2.16.840.1.101.3.4.2.7", "SHA-3(224)" },
+ { "2.16.840.1.101.3.4.2.8", "SHA-3(256)" },
+ { "2.16.840.1.101.3.4.2.9", "SHA-3(384)" },
+ { "2.16.840.1.101.3.4.3.1", "DSA/EMSA1(SHA-224)" },
+ { "2.16.840.1.101.3.4.3.10", "ECDSA/EMSA1(SHA-3(256))" },
+ { "2.16.840.1.101.3.4.3.11", "ECDSA/EMSA1(SHA-3(384))" },
+ { "2.16.840.1.101.3.4.3.12", "ECDSA/EMSA1(SHA-3(512))" },
+ { "2.16.840.1.101.3.4.3.13", "RSA/EMSA3(SHA-3(224))" },
+ { "2.16.840.1.101.3.4.3.14", "RSA/EMSA3(SHA-3(256))" },
+ { "2.16.840.1.101.3.4.3.15", "RSA/EMSA3(SHA-3(384))" },
+ { "2.16.840.1.101.3.4.3.16", "RSA/EMSA3(SHA-3(512))" },
+ { "2.16.840.1.101.3.4.3.2", "DSA/EMSA1(SHA-256)" },
+ { "2.16.840.1.101.3.4.3.3", "DSA/EMSA1(SHA-384)" },
+ { "2.16.840.1.101.3.4.3.4", "DSA/EMSA1(SHA-512)" },
+ { "2.16.840.1.101.3.4.3.5", "DSA/EMSA1(SHA-3(224))" },
+ { "2.16.840.1.101.3.4.3.6", "DSA/EMSA1(SHA-3(256))" },
+ { "2.16.840.1.101.3.4.3.7", "DSA/EMSA1(SHA-3(384))" },
+ { "2.16.840.1.101.3.4.3.8", "DSA/EMSA1(SHA-3(512))" },
+ { "2.16.840.1.101.3.4.3.9", "ECDSA/EMSA1(SHA-3(224))" },
+ { "2.16.840.1.113730.1.13", "Certificate Comment" },
+ { "2.5.29.14", "X509v3.SubjectKeyIdentifier" },
+ { "2.5.29.15", "X509v3.KeyUsage" },
+ { "2.5.29.16", "X509v3.PrivateKeyUsagePeriod" },
+ { "2.5.29.17", "X509v3.SubjectAlternativeName" },
+ { "2.5.29.18", "X509v3.IssuerAlternativeName" },
+ { "2.5.29.19", "X509v3.BasicConstraints" },
+ { "2.5.29.20", "X509v3.CRLNumber" },
+ { "2.5.29.21", "X509v3.ReasonCode" },
+ { "2.5.29.23", "X509v3.HoldInstructionCode" },
+ { "2.5.29.24", "X509v3.InvalidityDate" },
+ { "2.5.29.28", "X509v3.CRLIssuingDistributionPoint" },
+ { "2.5.29.30", "X509v3.NameConstraints" },
+ { "2.5.29.31", "X509v3.CRLDistributionPoints" },
+ { "2.5.29.32", "X509v3.CertificatePolicies" },
+ { "2.5.29.32.0", "X509v3.AnyPolicy" },
+ { "2.5.29.35", "X509v3.AuthorityKeyIdentifier" },
+ { "2.5.29.36", "X509v3.PolicyConstraints" },
+ { "2.5.29.37", "X509v3.ExtendedKeyUsage" },
+ { "2.5.4.10", "X520.Organization" },
+ { "2.5.4.11", "X520.OrganizationalUnit" },
+ { "2.5.4.12", "X520.Title" },
+ { "2.5.4.3", "X520.CommonName" },
+ { "2.5.4.4", "X520.Surname" },
+ { "2.5.4.42", "X520.GivenName" },
+ { "2.5.4.43", "X520.Initials" },
+ { "2.5.4.44", "X520.GenerationalQualifier" },
+ { "2.5.4.46", "X520.DNQualifier" },
+ { "2.5.4.5", "X520.SerialNumber" },
+ { "2.5.4.6", "X520.Country" },
+ { "2.5.4.65", "X520.Pseudonym" },
+ { "2.5.4.7", "X520.Locality" },
+ { "2.5.4.8", "X520.State" },
+ { "2.5.4.9", "X520.StreetAddress" },
+ { "2.5.8.1.1", "RSA" }
+ };
+ }
+
+std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
+ {
+ return std::unordered_map<std::string,OID>{
+ { "AES-128/CBC", OID({2,16,840,1,101,3,4,1,2}) },
+ { "AES-128/CCM", OID({2,16,840,1,101,3,4,1,7}) },
+ { "AES-128/GCM", OID({2,16,840,1,101,3,4,1,6}) },
+ { "AES-128/OCB", OID({1,3,6,1,4,1,25258,3,2,1}) },
+ { "AES-128/SIV", OID({1,3,6,1,4,1,25258,3,4,1}) },
+ { "AES-192/CBC", OID({2,16,840,1,101,3,4,1,22}) },
+ { "AES-192/CCM", OID({2,16,840,1,101,3,4,1,27}) },
+ { "AES-192/GCM", OID({2,16,840,1,101,3,4,1,26}) },
+ { "AES-192/OCB", OID({1,3,6,1,4,1,25258,3,2,2}) },
+ { "AES-192/SIV", OID({1,3,6,1,4,1,25258,3,4,2}) },
+ { "AES-256/CBC", OID({2,16,840,1,101,3,4,1,42}) },
+ { "AES-256/CCM", OID({2,16,840,1,101,3,4,1,47}) },
+ { "AES-256/GCM", OID({2,16,840,1,101,3,4,1,46}) },
+ { "AES-256/OCB", OID({1,3,6,1,4,1,25258,3,2,3}) },
+ { "AES-256/SIV", OID({1,3,6,1,4,1,25258,3,4,3}) },
+ { "CAST-128/CBC", OID({1,2,840,113533,7,66,10}) },
+ { "Camellia-128/CBC", OID({1,2,392,200011,61,1,1,1,2}) },
+ { "Camellia-128/GCM", OID({0,3,4401,5,3,1,9,6}) },
+ { "Camellia-128/OCB", OID({1,3,6,1,4,1,25258,3,2,6}) },
+ { "Camellia-128/SIV", OID({1,3,6,1,4,1,25258,3,4,6}) },
+ { "Camellia-192/CBC", OID({1,2,392,200011,61,1,1,1,3}) },
+ { "Camellia-192/GCM", OID({0,3,4401,5,3,1,9,26}) },
+ { "Camellia-192/OCB", OID({1,3,6,1,4,1,25258,3,2,7}) },
+ { "Camellia-192/SIV", OID({1,3,6,1,4,1,25258,3,4,7}) },
+ { "Camellia-256/CBC", OID({1,2,392,200011,61,1,1,1,4}) },
+ { "Camellia-256/GCM", OID({0,3,4401,5,3,1,9,46}) },
+ { "Camellia-256/OCB", OID({1,3,6,1,4,1,25258,3,2,8}) },
+ { "Camellia-256/SIV", OID({1,3,6,1,4,1,25258,3,4,8}) },
+ { "Certificate Comment", OID({2,16,840,1,113730,1,13}) },
+ { "ChaCha20Poly1305", OID({1,2,840,113549,1,9,16,3,18}) },
+ { "Compression.Zlib", OID({1,2,840,113549,1,9,16,3,8}) },
+ { "Curve25519", OID({1,3,101,110}) },
+ { "DES/CBC", OID({1,3,14,3,2,7}) },
+ { "DH", OID({1,2,840,10046,2,1}) },
+ { "DSA", OID({1,2,840,10040,4,1}) },
+ { "DSA/EMSA1(SHA-160)", OID({1,2,840,10040,4,3}) },
+ { "DSA/EMSA1(SHA-224)", OID({2,16,840,1,101,3,4,3,1}) },
+ { "DSA/EMSA1(SHA-256)", OID({2,16,840,1,101,3,4,3,2}) },
+ { "DSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,5}) },
+ { "DSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,6}) },
+ { "DSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,7}) },
+ { "DSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,8}) },
+ { "DSA/EMSA1(SHA-384)", OID({2,16,840,1,101,3,4,3,3}) },
+ { "DSA/EMSA1(SHA-512)", OID({2,16,840,1,101,3,4,3,4}) },
+ { "ECDH", OID({1,3,132,1,12}) },
+ { "ECDSA", OID({1,2,840,10045,2,1}) },
+ { "ECDSA/EMSA1(SHA-160)", OID({1,2,840,10045,4,1}) },
+ { "ECDSA/EMSA1(SHA-224)", OID({1,2,840,10045,4,3,1}) },
+ { "ECDSA/EMSA1(SHA-256)", OID({1,2,840,10045,4,3,2}) },
+ { "ECDSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,9}) },
+ { "ECDSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,10}) },
+ { "ECDSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,11}) },
+ { "ECDSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,12}) },
+ { "ECDSA/EMSA1(SHA-384)", OID({1,2,840,10045,4,3,3}) },
+ { "ECDSA/EMSA1(SHA-512)", OID({1,2,840,10045,4,3,4}) },
+ { "ECGDSA", OID({1,3,36,3,3,2,5,2,1}) },
+ { "ECGDSA/EMSA1(RIPEMD-160)", OID({1,3,36,3,3,2,5,4,1}) },
+ { "ECGDSA/EMSA1(SHA-160)", OID({1,3,36,3,3,2,5,4,2}) },
+ { "ECGDSA/EMSA1(SHA-224)", OID({1,3,36,3,3,2,5,4,3}) },
+ { "ECGDSA/EMSA1(SHA-256)", OID({1,3,36,3,3,2,5,4,4}) },
+ { "ECGDSA/EMSA1(SHA-384)", OID({1,3,36,3,3,2,5,4,5}) },
+ { "ECGDSA/EMSA1(SHA-512)", OID({1,3,36,3,3,2,5,4,6}) },
+ { "ECKCDSA", OID({1,0,14888,3,0,5}) },
+ { "ECKCDSA/EMSA1(SHA-1)", OID({1,2,410,200004,1,100,4,3}) },
+ { "ECKCDSA/EMSA1(SHA-224)", OID({1,2,410,200004,1,100,4,4}) },
+ { "ECKCDSA/EMSA1(SHA-256)", OID({1,2,410,200004,1,100,4,5}) },
+ { "Ed25519", OID({1,3,101,112}) },
+ { "ElGamal", OID({1,3,6,1,4,1,3029,1,2,1}) },
+ { "GOST-34.10", OID({1,2,643,2,2,19}) },
+ { "GOST-34.10-2012-256", OID({1,2,643,7,1,1,1,1}) },
+ { "GOST-34.10-2012-256/EMSA1(SHA-256)", OID({1,3,6,1,4,1,25258,1,6,1}) },
+ { "GOST-34.10-2012-256/EMSA1(Streebog-256)", OID({1,2,643,7,1,1,3,2}) },
+ { "GOST-34.10-2012-512", OID({1,2,643,7,1,1,1,2}) },
+ { "GOST-34.10-2012-512/EMSA1(Streebog-512)", OID({1,2,643,7,1,1,3,3}) },
+ { "GOST-34.10/EMSA1(GOST-R-34.11-94)", OID({1,2,643,2,2,3}) },
+ { "GOST.INN", OID({1,2,643,3,131,1,1}) },
+ { "GOST.IssuerSigningTool", OID({1,2,643,100,112}) },
+ { "GOST.OGRN", OID({1,2,643,100,1}) },
+ { "GOST.SubjectSigningTool", OID({1,2,643,100,111}) },
+ { "HMAC(SHA-160)", OID({1,2,840,113549,2,7}) },
+ { "HMAC(SHA-224)", OID({1,2,840,113549,2,8}) },
+ { "HMAC(SHA-256)", OID({1,2,840,113549,2,9}) },
+ { "HMAC(SHA-384)", OID({1,2,840,113549,2,10}) },
+ { "HMAC(SHA-512)", OID({1,2,840,113549,2,11}) },
+ { "HMAC(SHA-512-256)", OID({1,2,840,113549,2,13}) },
+ { "KeyWrap.AES-128", OID({2,16,840,1,101,3,4,1,5}) },
+ { "KeyWrap.AES-192", OID({2,16,840,1,101,3,4,1,25}) },
+ { "KeyWrap.AES-256", OID({2,16,840,1,101,3,4,1,45}) },
+ { "KeyWrap.CAST-128", OID({1,2,840,113533,7,66,15}) },
+ { "KeyWrap.TripleDES", OID({1,2,840,113549,1,9,16,3,6}) },
+ { "MD5", OID({1,2,840,113549,2,5}) },
+ { "MGF1", OID({1,2,840,113549,1,1,8}) },
+ { "McEliece", OID({1,3,6,1,4,1,25258,1,3}) },
+ { "Microsoft SmartcardLogon", OID({1,3,6,1,4,1,311,20,2,2}) },
+ { "Microsoft UPN", OID({1,3,6,1,4,1,311,20,2,3}) },
+ { "OpenPGP.Curve25519", OID({1,3,6,1,4,1,3029,1,5,1}) },
+ { "OpenPGP.Ed25519", OID({1,3,6,1,4,1,11591,15,1}) },
+ { "PBE-PKCS5v20", OID({1,2,840,113549,1,5,13}) },
+ { "PBES2", OID({1,2,840,113549,1,5,13}) },
+ { "PKCS5.PBKDF2", OID({1,2,840,113549,1,5,12}) },
+ { "PKCS9.ChallengePassword", OID({1,2,840,113549,1,9,7}) },
+ { "PKCS9.ContentType", OID({1,2,840,113549,1,9,3}) },
+ { "PKCS9.EmailAddress", OID({1,2,840,113549,1,9,1}) },
+ { "PKCS9.ExtensionRequest", OID({1,2,840,113549,1,9,14}) },
+ { "PKCS9.MessageDigest", OID({1,2,840,113549,1,9,4}) },
+ { "PKCS9.UnstructuredName", OID({1,2,840,113549,1,9,2}) },
+ { "PKIX.AuthorityInformationAccess", OID({1,3,6,1,5,5,7,1,1}) },
+ { "PKIX.CertificateAuthorityIssuers", OID({1,3,6,1,5,5,7,48,2}) },
+ { "PKIX.ClientAuth", OID({1,3,6,1,5,5,7,3,2}) },
+ { "PKIX.CodeSigning", OID({1,3,6,1,5,5,7,3,3}) },
+ { "PKIX.EmailProtection", OID({1,3,6,1,5,5,7,3,4}) },
+ { "PKIX.IPsecEndSystem", OID({1,3,6,1,5,5,7,3,5}) },
+ { "PKIX.IPsecTunnel", OID({1,3,6,1,5,5,7,3,6}) },
+ { "PKIX.IPsecUser", OID({1,3,6,1,5,5,7,3,7}) },
+ { "PKIX.OCSP", OID({1,3,6,1,5,5,7,48,1}) },
+ { "PKIX.OCSP.BasicResponse", OID({1,3,6,1,5,5,7,48,1,1}) },
+ { "PKIX.OCSPSigning", OID({1,3,6,1,5,5,7,3,9}) },
+ { "PKIX.ServerAuth", OID({1,3,6,1,5,5,7,3,1}) },
+ { "PKIX.TimeStamping", OID({1,3,6,1,5,5,7,3,8}) },
+ { "PKIX.XMPPAddr", OID({1,3,6,1,5,5,7,8,5}) },
+ { "RIPEMD-160", OID({1,3,36,3,2,1}) },
+ { "RSA", OID({1,2,840,113549,1,1,1}) },
+ { "RSA/EMSA3(MD5)", OID({1,2,840,113549,1,1,4}) },
+ { "RSA/EMSA3(RIPEMD-160)", OID({1,3,36,3,3,1,2}) },
+ { "RSA/EMSA3(SHA-160)", OID({1,2,840,113549,1,1,5}) },
+ { "RSA/EMSA3(SHA-224)", OID({1,2,840,113549,1,1,14}) },
+ { "RSA/EMSA3(SHA-256)", OID({1,2,840,113549,1,1,11}) },
+ { "RSA/EMSA3(SHA-3(224))", OID({2,16,840,1,101,3,4,3,13}) },
+ { "RSA/EMSA3(SHA-3(256))", OID({2,16,840,1,101,3,4,3,14}) },
+ { "RSA/EMSA3(SHA-3(384))", OID({2,16,840,1,101,3,4,3,15}) },
+ { "RSA/EMSA3(SHA-3(512))", OID({2,16,840,1,101,3,4,3,16}) },
+ { "RSA/EMSA3(SHA-384)", OID({1,2,840,113549,1,1,12}) },
+ { "RSA/EMSA3(SHA-512)", OID({1,2,840,113549,1,1,13}) },
+ { "RSA/EMSA3(SHA-512-256)", OID({1,2,840,113549,1,1,16}) },
+ { "RSA/EMSA3(SM3)", OID({1,2,156,10197,1,504}) },
+ { "RSA/EMSA4", OID({1,2,840,113549,1,1,10}) },
+ { "RSA/OAEP", OID({1,2,840,113549,1,1,7}) },
+ { "SEED/CBC", OID({1,2,410,200004,1,4}) },
+ { "SHA-160", OID({1,3,14,3,2,26}) },
+ { "SHA-224", OID({2,16,840,1,101,3,4,2,4}) },
+ { "SHA-256", OID({2,16,840,1,101,3,4,2,1}) },
+ { "SHA-3(224)", OID({2,16,840,1,101,3,4,2,7}) },
+ { "SHA-3(256)", OID({2,16,840,1,101,3,4,2,8}) },
+ { "SHA-3(384)", OID({2,16,840,1,101,3,4,2,9}) },
+ { "SHA-3(512)", OID({2,16,840,1,101,3,4,2,10}) },
+ { "SHA-384", OID({2,16,840,1,101,3,4,2,2}) },
+ { "SHA-512", OID({2,16,840,1,101,3,4,2,3}) },
+ { "SHA-512-256", OID({2,16,840,1,101,3,4,2,6}) },
+ { "SHAKE-128", OID({2,16,840,1,101,3,4,2,11}) },
+ { "SHAKE-256", OID({2,16,840,1,101,3,4,2,12}) },
+ { "SM2", OID({1,2,156,10197,1,301,1}) },
+ { "SM2_Enc", OID({1,2,156,10197,1,301,3}) },
+ { "SM2_Kex", OID({1,2,156,10197,1,301,2}) },
+ { "SM2_Sig", OID({1,2,156,10197,1,301,1}) },
+ { "SM2_Sig/SM3", OID({1,2,156,10197,1,501}) },
+ { "SM3", OID({1,2,156,10197,1,401}) },
+ { "SM4/CBC", OID({1,2,156,10197,1,104,2}) },
+ { "SM4/GCM", OID({1,2,156,10197,1,104,8}) },
+ { "SM4/OCB", OID({1,2,156,10197,1,104,100}) },
+ { "SM4/SIV", OID({1,3,6,1,4,1,25258,3,4,9}) },
+ { "Scrypt", OID({1,3,6,1,4,1,11591,4,11}) },
+ { "Serpent/CBC", OID({1,3,6,1,4,1,25258,3,1}) },
+ { "Serpent/GCM", OID({1,3,6,1,4,1,25258,3,101}) },
+ { "Serpent/OCB", OID({1,3,6,1,4,1,25258,3,2,4}) },
+ { "Serpent/SIV", OID({1,3,6,1,4,1,25258,3,4,4}) },
+ { "Streebog-256", OID({1,2,643,7,1,1,2,2}) },
+ { "Streebog-512", OID({1,2,643,7,1,1,2,3}) },
+ { "Threefish-512/CBC", OID({1,3,6,1,4,1,25258,3,2}) },
+ { "Tiger(24,3)", OID({1,3,6,1,4,1,11591,12,2}) },
+ { "TripleDES/CBC", OID({1,2,840,113549,3,7}) },
+ { "Twofish/CBC", OID({1,3,6,1,4,1,25258,3,3}) },
+ { "Twofish/GCM", OID({1,3,6,1,4,1,25258,3,102}) },
+ { "Twofish/OCB", OID({1,3,6,1,4,1,25258,3,2,5}) },
+ { "Twofish/SIV", OID({1,3,6,1,4,1,25258,3,4,5}) },
+ { "X509v3.AnyPolicy", OID({2,5,29,32,0}) },
+ { "X509v3.AuthorityKeyIdentifier", OID({2,5,29,35}) },
+ { "X509v3.BasicConstraints", OID({2,5,29,19}) },
+ { "X509v3.CRLDistributionPoints", OID({2,5,29,31}) },
+ { "X509v3.CRLIssuingDistributionPoint", OID({2,5,29,28}) },
+ { "X509v3.CRLNumber", OID({2,5,29,20}) },
+ { "X509v3.CertificatePolicies", OID({2,5,29,32}) },
+ { "X509v3.ExtendedKeyUsage", OID({2,5,29,37}) },
+ { "X509v3.HoldInstructionCode", OID({2,5,29,23}) },
+ { "X509v3.InvalidityDate", OID({2,5,29,24}) },
+ { "X509v3.IssuerAlternativeName", OID({2,5,29,18}) },
+ { "X509v3.KeyUsage", OID({2,5,29,15}) },
+ { "X509v3.NameConstraints", OID({2,5,29,30}) },
+ { "X509v3.PolicyConstraints", OID({2,5,29,36}) },
+ { "X509v3.PrivateKeyUsagePeriod", OID({2,5,29,16}) },
+ { "X509v3.ReasonCode", OID({2,5,29,21}) },
+ { "X509v3.SubjectAlternativeName", OID({2,5,29,17}) },
+ { "X509v3.SubjectKeyIdentifier", OID({2,5,29,14}) },
+ { "X520.CommonName", OID({2,5,4,3}) },
+ { "X520.Country", OID({2,5,4,6}) },
+ { "X520.DNQualifier", OID({2,5,4,46}) },
+ { "X520.GenerationalQualifier", OID({2,5,4,44}) },
+ { "X520.GivenName", OID({2,5,4,42}) },
+ { "X520.Initials", OID({2,5,4,43}) },
+ { "X520.Locality", OID({2,5,4,7}) },
+ { "X520.Organization", OID({2,5,4,10}) },
+ { "X520.OrganizationalUnit", OID({2,5,4,11}) },
+ { "X520.Pseudonym", OID({2,5,4,65}) },
+ { "X520.SerialNumber", OID({2,5,4,5}) },
+ { "X520.State", OID({2,5,4,8}) },
+ { "X520.StreetAddress", OID({2,5,4,9}) },
+ { "X520.Surname", OID({2,5,4,4}) },
+ { "X520.Title", OID({2,5,4,12}) },
+ { "XMSS", OID({0,4,0,127,0,15,1,1,13,0}) },
+ { "XMSS-draft12", OID({1,3,6,1,4,1,25258,1,8}) },
+ { "XMSS-draft6", OID({1,3,6,1,4,1,25258,1,5}) },
+ { "brainpool160r1", OID({1,3,36,3,3,2,8,1,1,1}) },
+ { "brainpool192r1", OID({1,3,36,3,3,2,8,1,1,3}) },
+ { "brainpool224r1", OID({1,3,36,3,3,2,8,1,1,5}) },
+ { "brainpool256r1", OID({1,3,36,3,3,2,8,1,1,7}) },
+ { "brainpool320r1", OID({1,3,36,3,3,2,8,1,1,9}) },
+ { "brainpool384r1", OID({1,3,36,3,3,2,8,1,1,11}) },
+ { "brainpool512r1", OID({1,3,36,3,3,2,8,1,1,13}) },
+ { "frp256v1", OID({1,2,250,1,223,101,256,1}) },
+ { "gost_256A", OID({1,2,643,7,1,2,1,1,1}) },
+ { "gost_256B", OID({1,2,643,7,1,2,1,1,2}) },
+ { "gost_512A", OID({1,2,643,7,1,2,1,2,1}) },
+ { "gost_512B", OID({1,2,643,7,1,2,1,2,2}) },
+ { "secp160k1", OID({1,3,132,0,9}) },
+ { "secp160r1", OID({1,3,132,0,8}) },
+ { "secp160r2", OID({1,3,132,0,30}) },
+ { "secp192k1", OID({1,3,132,0,31}) },
+ { "secp192r1", OID({1,2,840,10045,3,1,1}) },
+ { "secp224k1", OID({1,3,132,0,32}) },
+ { "secp224r1", OID({1,3,132,0,33}) },
+ { "secp256k1", OID({1,3,132,0,10}) },
+ { "secp256r1", OID({1,2,840,10045,3,1,7}) },
+ { "secp384r1", OID({1,3,132,0,34}) },
+ { "secp521r1", OID({1,3,132,0,35}) },
+ { "sm2p256v1", OID({1,2,156,10197,1,301}) },
+ { "x962_p192v2", OID({1,2,840,10045,3,1,2}) },
+ { "x962_p192v3", OID({1,2,840,10045,3,1,3}) },
+ { "x962_p239v1", OID({1,2,840,10045,3,1,4}) },
+ { "x962_p239v2", OID({1,2,840,10045,3,1,5}) },
+ { "x962_p239v3", OID({1,2,840,10045,3,1,6}) }
+ };
+ }
+
+}
+
diff --git a/comm/third_party/botan/src/lib/asn1/oids.cpp b/comm/third_party/botan/src/lib/asn1/oids.cpp
new file mode 100644
index 0000000000..bece7a9b47
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/oids.cpp
@@ -0,0 +1,134 @@
+/*
+* OID Registry
+* (C) 1999-2008,2013 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/oids.h>
+#include <botan/mutex.h>
+
+namespace Botan {
+
+namespace {
+
+class OID_Map final
+ {
+ public:
+ void add_oid(const OID& oid, const std::string& str)
+ {
+ add_str2oid(oid, str);
+ add_oid2str(oid, str);
+ }
+
+ void add_str2oid(const OID& oid, const std::string& str)
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ auto i = m_str2oid.find(str);
+ if(i == m_str2oid.end())
+ m_str2oid.insert(std::make_pair(str, oid));
+ }
+
+ void add_oid2str(const OID& oid, const std::string& str)
+ {
+ const std::string oid_str = oid.to_string();
+ lock_guard_type<mutex_type> lock(m_mutex);
+ auto i = m_oid2str.find(oid_str);
+ if(i == m_oid2str.end())
+ m_oid2str.insert(std::make_pair(oid_str, str));
+ }
+
+ std::string oid2str(const OID& oid)
+ {
+ const std::string oid_str = oid.to_string();
+
+ lock_guard_type<mutex_type> lock(m_mutex);
+
+ auto i = m_oid2str.find(oid_str);
+ if(i != m_oid2str.end())
+ return i->second;
+
+ return "";
+ }
+
+ OID str2oid(const std::string& str)
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ auto i = m_str2oid.find(str);
+ if(i != m_str2oid.end())
+ return i->second;
+
+ return OID();
+ }
+
+ bool have_oid(const std::string& str)
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ return m_str2oid.find(str) != m_str2oid.end();
+ }
+
+ static OID_Map& global_registry()
+ {
+ static OID_Map g_map;
+ return g_map;
+ }
+
+ private:
+
+ OID_Map()
+ {
+ m_str2oid = OIDS::load_str2oid_map();
+ m_oid2str = OIDS::load_oid2str_map();
+ }
+
+ mutex_type m_mutex;
+ std::unordered_map<std::string, OID> m_str2oid;
+ std::unordered_map<std::string, std::string> m_oid2str;
+ };
+
+}
+
+void OIDS::add_oid(const OID& oid, const std::string& name)
+ {
+ OID_Map::global_registry().add_oid(oid, name);
+ }
+
+void OIDS::add_oidstr(const char* oidstr, const char* name)
+ {
+ add_oid(OID(oidstr), name);
+ }
+
+void OIDS::add_oid2str(const OID& oid, const std::string& name)
+ {
+ OID_Map::global_registry().add_oid2str(oid, name);
+ }
+
+void OIDS::add_str2oid(const OID& oid, const std::string& name)
+ {
+ OID_Map::global_registry().add_str2oid(oid, name);
+ }
+
+std::string OIDS::oid2str_or_empty(const OID& oid)
+ {
+ return OID_Map::global_registry().oid2str(oid);
+ }
+
+OID OIDS::str2oid_or_empty(const std::string& name)
+ {
+ return OID_Map::global_registry().str2oid(name);
+ }
+
+std::string OIDS::oid2str_or_throw(const OID& oid)
+ {
+ const std::string s = OIDS::oid2str_or_empty(oid);
+ if(s.empty())
+ throw Lookup_Error("No name associated with OID " + oid.to_string());
+ return s;
+ }
+
+bool OIDS::have_oid(const std::string& name)
+ {
+ return OID_Map::global_registry().have_oid(name);
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/asn1/oids.h b/comm/third_party/botan/src/lib/asn1/oids.h
new file mode 100644
index 0000000000..9af451fe41
--- /dev/null
+++ b/comm/third_party/botan/src/lib/asn1/oids.h
@@ -0,0 +1,98 @@
+/*
+* OID Registry
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_OIDS_H_
+#define BOTAN_OIDS_H_
+
+#include <botan/asn1_obj.h>
+#include <unordered_map>
+
+namespace Botan {
+
+namespace OIDS {
+
+/**
+* Register an OID to string mapping.
+* @param oid the oid to register
+* @param name the name to be associated with the oid
+*/
+BOTAN_UNSTABLE_API void add_oid(const OID& oid, const std::string& name);
+
+BOTAN_UNSTABLE_API void add_oid2str(const OID& oid, const std::string& name);
+BOTAN_UNSTABLE_API void add_str2oid(const OID& oid, const std::string& name);
+
+BOTAN_UNSTABLE_API void add_oidstr(const char* oidstr, const char* name);
+
+std::unordered_map<std::string, std::string> load_oid2str_map();
+std::unordered_map<std::string, OID> load_str2oid_map();
+
+/**
+* Resolve an OID
+* @param oid the OID to look up
+* @return name associated with this OID, or an empty string
+*/
+BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID& oid);
+
+/**
+* Find the OID to a name. The lookup will be performed in the
+* general OID section of the configuration.
+* @param name the name to resolve
+* @return OID associated with the specified name
+*/
+BOTAN_UNSTABLE_API OID str2oid_or_empty(const std::string& name);
+
+BOTAN_UNSTABLE_API std::string oid2str_or_throw(const OID& oid);
+
+/**
+* See if an OID exists in the internal table.
+* @param oid the oid to check for
+* @return true if the oid is registered
+*/
+BOTAN_UNSTABLE_API bool BOTAN_DEPRECATED("Just lookup the value instead") have_oid(const std::string& oid);
+
+/**
+* Tests whether the specified OID stands for the specified name.
+* @param oid the OID to check
+* @param name the name to check
+* @return true if the specified OID stands for the specified name
+*/
+inline bool BOTAN_DEPRECATED("Use oid == OID::from_string(name)") name_of(const OID& oid, const std::string& name)
+ {
+ return (oid == str2oid_or_empty(name));
+ }
+
+/**
+* Prefer oid2str_or_empty
+*/
+inline std::string lookup(const OID& oid)
+ {
+ return oid2str_or_empty(oid);
+ }
+
+/**
+* Prefer str2oid_or_empty
+*/
+inline OID lookup(const std::string& name)
+ {
+ return str2oid_or_empty(name);
+ }
+
+inline std::string BOTAN_DEPRECATED("Use oid2str_or_empty") oid2str(const OID& oid)
+ {
+ return oid2str_or_empty(oid);
+ }
+
+inline OID BOTAN_DEPRECATED("Use str2oid_or_empty") str2oid(const std::string& name)
+ {
+ return str2oid_or_empty(name);
+ }
+
+}
+
+}
+
+#endif