From 915e840bd0f77d8c2cd526a5d26a88621708f6ca Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Thu, 18 Jan 2018 15:21:47 -0500 Subject: Prepare for making BER_Object members private Now there are usable accessors that allow the library to avoid using BER_Object members directly. --- doc/manual/deprecated.rst | 2 +- src/lib/asn1/asn1_obj.cpp | 42 +++++++++++++++- src/lib/asn1/asn1_obj.h | 42 ++++++++++++++-- src/lib/asn1/asn1_oid.cpp | 24 ++++----- src/lib/asn1/asn1_print.cpp | 12 ++--- src/lib/asn1/asn1_str.cpp | 6 +-- src/lib/asn1/asn1_time.cpp | 2 +- src/lib/asn1/ber_dec.cpp | 95 ++++++++++++++++-------------------- src/lib/asn1/ber_dec.h | 23 ++++----- src/lib/pubkey/ec_group/ec_group.cpp | 6 +-- src/lib/x509/asn1_alt_name.cpp | 48 +++++++++--------- src/lib/x509/name_constraint.cpp | 51 ++++++++----------- src/lib/x509/ocsp.cpp | 6 +-- src/lib/x509/ocsp_types.cpp | 2 +- src/lib/x509/pkcs10.cpp | 17 +++---- src/lib/x509/x509_crl.cpp | 11 ++--- src/lib/x509/x509_ext.cpp | 31 +++++++----- src/lib/x509/x509cert.cpp | 24 ++++----- src/lib/x509/x509cert.h | 7 +++ src/tests/data/x509/bsi/expected.txt | 4 +- 20 files changed, 258 insertions(+), 197 deletions(-) diff --git a/doc/manual/deprecated.rst b/doc/manual/deprecated.rst index cb2a76d01..29a7b35fe 100644 --- a/doc/manual/deprecated.rst +++ b/doc/manual/deprecated.rst @@ -10,7 +10,7 @@ This is in addition to specific API calls marked with BOTAN_DEPRECATED in the source. - Directly accessing the member variables of types calendar_point, ASN1_Attribute, - and AlgorithmIdentifier + AlgorithmIdentifier, and BER_Object - The headers ``botan.h``, ``init.h``, ``lookup.h`` diff --git a/src/lib/asn1/asn1_obj.cpp b/src/lib/asn1/asn1_obj.cpp index c83875ae5..bbe469f5c 100644 --- a/src/lib/asn1/asn1_obj.cpp +++ b/src/lib/asn1/asn1_obj.cpp @@ -12,6 +12,38 @@ namespace Botan { +/* +* 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) + { + throw BER_Decoding_Error("Tag mismatch when decoding " + descr + " got " + + std::to_string(type_tag) + "/" + + std::to_string(class_tag) + " expected " + + std::to_string(type_tag_) + "/" + + std::to_string(class_tag_)); + } + } + +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_tag_to_string(ASN1_Tag type) { switch(type) @@ -94,10 +126,15 @@ namespace ASN1 { * Put some arbitrary bytes into a SEQUENCE */ std::vector put_in_sequence(const std::vector& contents) + { + return ASN1::put_in_sequence(contents.data(), contents.size()); + } + +std::vector put_in_sequence(const uint8_t bits[], size_t len) { return DER_Encoder() .start_cons(SEQUENCE) - .raw_bytes(contents) + .raw_bytes(bits, len) .end_cons() .get_contents_unlocked(); } @@ -107,7 +144,8 @@ std::vector put_in_sequence(const std::vector& contents) */ std::string to_string(const BER_Object& obj) { - return to_string(obj.value); + return std::string(cast_uint8_ptr_to_char(obj.bits()), + obj.length()); } /* diff --git a/src/lib/asn1/asn1_obj.h b/src/lib/asn1/asn1_obj.h index 0b9a1493e..814b8f4f2 100644 --- a/src/lib/asn1/asn1_obj.h +++ b/src/lib/asn1/asn1_obj.h @@ -88,13 +88,46 @@ class BOTAN_PUBLIC_API(2,0) ASN1_Object class BOTAN_PUBLIC_API(2,0) BER_Object final { public: - void assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const; + BER_Object() : type_tag(NO_OBJECT), class_tag(UNIVERSAL) {} - // public member variable: - ASN1_Tag type_tag, class_tag; + 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; - // public member variable: + public: + /* + * 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 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(); + } }; /* @@ -105,6 +138,7 @@ class DataSource; namespace ASN1 { std::vector put_in_sequence(const std::vector& val); +std::vector put_in_sequence(const uint8_t bits[], size_t len); std::string to_string(const BER_Object& obj); /** diff --git a/src/lib/asn1/asn1_oid.cpp b/src/lib/asn1/asn1_oid.cpp index 7c7161f47..2aa453c2b 100644 --- a/src/lib/asn1/asn1_oid.cpp +++ b/src/lib/asn1/asn1_oid.cpp @@ -161,31 +161,33 @@ void OID::encode_into(DER_Encoder& der) const void OID::decode_from(BER_Decoder& decoder) { BER_Object obj = decoder.get_next_object(); - if(obj.type_tag != OBJECT_ID || obj.class_tag != UNIVERSAL) - throw BER_Bad_Tag("Error decoding OID, unknown tag", - obj.type_tag, obj.class_tag); - if(obj.value.size() < 2) - throw BER_Decoding_Error("OID encoding is too short"); + 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) + throw BER_Decoding_Error("OID encoding is too short"); clear(); - m_id.push_back(obj.value[0] / 40); - m_id.push_back(obj.value[0] % 40); + m_id.push_back(bits[0] / 40); + m_id.push_back(bits[0] % 40); size_t i = 0; - while(i != obj.value.size() - 1) + while(i != length - 1) { uint32_t component = 0; - while(i != obj.value.size() - 1) + while(i != length - 1) { ++i; if(component >> (32-7)) throw Decoding_Error("OID component overflow"); - component = (component << 7) + (obj.value[i] & 0x7F); + component = (component << 7) + (bits[i] & 0x7F); - if(!(obj.value[i] & 0x80)) + if(!(bits[i] & 0x80)) break; } m_id.push_back(component); diff --git a/src/lib/asn1/asn1_print.cpp b/src/lib/asn1/asn1_print.cpp index f0d994dbd..13ae6d387 100644 --- a/src/lib/asn1/asn1_print.cpp +++ b/src/lib/asn1/asn1_print.cpp @@ -79,23 +79,23 @@ void ASN1_Formatter::decode(std::ostream& output, const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth); - while(obj.type_tag != NO_OBJECT) + while(obj.is_set()) { - const ASN1_Tag type_tag = obj.type_tag; - const ASN1_Tag class_tag = obj.class_tag; - const size_t length = obj.value.size(); + 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 */ DER_Encoder encoder; - encoder.add_object(type_tag, class_tag, obj.value); + encoder.add_object(type_tag, class_tag, obj.bits(), obj.length()); const std::vector bits = encoder.get_contents_unlocked(); BER_Decoder data(bits); if(class_tag & CONSTRUCTED) { - BER_Decoder cons_info(obj.value); + BER_Decoder cons_info(obj.bits(), obj.length()); if(recurse_deeper) { diff --git a/src/lib/asn1/asn1_str.cpp b/src/lib/asn1/asn1_str.cpp index 8b9524de2..416e4f0ac 100644 --- a/src/lib/asn1/asn1_str.cpp +++ b/src/lib/asn1/asn1_str.cpp @@ -130,10 +130,10 @@ void ASN1_String::decode_from(BER_Decoder& source) { BER_Object obj = source.get_next_object(); - assert_is_string_type(obj.type_tag); + assert_is_string_type(obj.type()); - m_tag = obj.type_tag; - m_data.assign(obj.value.begin(), obj.value.end()); + m_tag = obj.type(); + m_data.assign(obj.bits(), obj.bits() + obj.length()); if(m_tag == BMP_STRING) { diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp index aca7fdca0..e64fd57c7 100644 --- a/src/lib/asn1/asn1_time.cpp +++ b/src/lib/asn1/asn1_time.cpp @@ -47,7 +47,7 @@ void X509_Time::decode_from(BER_Decoder& source) { BER_Object ber_time = source.get_next_object(); - set_to(ASN1::to_string(ber_time), ber_time.type_tag); + set_to(ASN1::to_string(ber_time), ber_time.type()); } std::string X509_Time::to_string() const diff --git a/src/lib/asn1/ber_dec.cpp b/src/lib/asn1/ber_dec.cpp index 225197224..ca0056937 100644 --- a/src/lib/asn1/ber_dec.cpp +++ b/src/lib/asn1/ber_dec.cpp @@ -147,25 +147,12 @@ size_t find_eoc(DataSource* ber, size_t allow_indef) } -/* -* Check a type invariant on BER data -*/ -void BER_Object::assert_is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_) const - { - if(type_tag != type_tag_ || class_tag != class_tag_) - throw BER_Decoding_Error("Tag mismatch when decoding got " + - std::to_string(type_tag) + "/" + - std::to_string(class_tag) + " expected " + - std::to_string(type_tag_) + "/" + - std::to_string(class_tag_)); - } - /* * Check if more objects are there */ bool BER_Decoder::more_items() const { - if(m_source->end_of_data() && (m_pushed.type_tag == NO_OBJECT)) + if(m_source->end_of_data() && !m_pushed.is_set()) return false; return true; } @@ -175,7 +162,7 @@ bool BER_Decoder::more_items() const */ BER_Decoder& BER_Decoder::verify_end() { - if(!m_source->end_of_data() || (m_pushed.type_tag != NO_OBJECT)) + if(!m_source->end_of_data() || m_pushed.is_set()) throw Invalid_State("BER_Decoder::verify_end called, but data remains"); return (*this); } @@ -198,17 +185,18 @@ BER_Object BER_Decoder::get_next_object() { BER_Object next; - if(m_pushed.type_tag != NO_OBJECT) + if(m_pushed.is_set()) { - next = m_pushed; - m_pushed.class_tag = m_pushed.type_tag = NO_OBJECT; + std::swap(next, m_pushed); return next; } for(;;) { - decode_tag(m_source, next.type_tag, next.class_tag); - if(next.type_tag == NO_OBJECT) + 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; @@ -216,11 +204,11 @@ BER_Object BER_Decoder::get_next_object() if(!m_source->check_available(length)) throw BER_Decoding_Error("Value truncated"); - next.value.resize(length); - if(m_source->read(next.value.data(), length) != length) + uint8_t* out = next.mutable_bits(length); + if(m_source->read(out, length) != length) throw BER_Decoding_Error("Value truncated"); - if(next.type_tag == EOC && next.class_tag == UNIVERSAL) + if(next.tagging() == EOC) continue; else break; @@ -240,7 +228,7 @@ BER_Decoder& BER_Decoder::get_next(BER_Object& ber) */ void BER_Decoder::push_back(const BER_Object& obj) { - if(m_pushed.type_tag != NO_OBJECT) + if(m_pushed.is_set()) throw Invalid_State("BER_Decoder: Only one push back is allowed"); m_pushed = obj; } @@ -254,7 +242,7 @@ BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, BER_Object obj = get_next_object(); obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); - BER_Decoder result(obj.value.data(), obj.value.size()); + BER_Decoder result(obj.bits(), obj.length()); result.m_parent = this; return result; } @@ -271,14 +259,16 @@ BER_Decoder& BER_Decoder::end_cons() return (*m_parent); } +BER_Decoder::BER_Decoder(const BER_Object& obj) : BER_Decoder(obj.bits(), obj.length()) + { + } + /* * BER_Decoder Constructor */ BER_Decoder::BER_Decoder(DataSource& src) { m_source = &src; - m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT; - m_parent = nullptr; } /* @@ -288,8 +278,6 @@ 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(); - m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT; - m_parent = nullptr; } /* @@ -299,8 +287,6 @@ BER_Decoder::BER_Decoder(const secure_vector& data) { m_data_src.reset(new DataSource_Memory(data)); m_source = m_data_src.get(); - m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT; - m_parent = nullptr; } /* @@ -310,8 +296,6 @@ BER_Decoder::BER_Decoder(const std::vector& data) { m_data_src.reset(new DataSource_Memory(data.data(), data.size())); m_source = m_data_src.get(); - m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT; - m_parent = nullptr; } /* @@ -323,7 +307,6 @@ BER_Decoder::BER_Decoder(const BER_Decoder& other) // take ownership std::swap(m_data_src, other.m_data_src); - m_pushed.type_tag = m_pushed.class_tag = NO_OBJECT; m_parent = other.m_parent; } @@ -344,7 +327,7 @@ BER_Decoder& BER_Decoder::decode_null() { BER_Object obj = get_next_object(); obj.assert_is_a(NULL_TAG, UNIVERSAL); - if(obj.value.size()) + if(obj.length() > 0) throw BER_Decoding_Error("NULL object had nonzero size"); return (*this); } @@ -397,10 +380,10 @@ BER_Decoder& BER_Decoder::decode(bool& out, BER_Object obj = get_next_object(); obj.assert_is_a(type_tag, class_tag); - if(obj.value.size() != 1) + if(obj.length() != 1) throw BER_Decoding_Error("BER boolean value had invalid size"); - out = (obj.value[0]) ? true : false; + out = (obj.bits()[0]) ? true : false; return (*this); } @@ -457,25 +440,29 @@ BER_Decoder& BER_Decoder::decode(BigInt& out, BER_Object obj = get_next_object(); obj.assert_is_a(type_tag, class_tag); - if(obj.value.empty()) + if(obj.length() == 0) + { out = 0; + } else { - const bool negative = (obj.value[0] & 0x80) ? true : false; + const bool negative = (obj.bits()[0] & 0x80) ? true : false; if(negative) { - for(size_t i = obj.value.size(); i > 0; --i) - if(obj.value[i-1]--) + secure_vector 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.value.size(); ++i) - obj.value[i] = ~obj.value[i]; - } - - out = BigInt(&obj.value[0], obj.value.size()); - - if(negative) + 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); @@ -494,19 +481,19 @@ void asn1_decode_binary_string(std::vector& buffer, if(real_type == OCTET_STRING) { - buffer.assign(obj.value.begin(), obj.value.end()); + buffer.assign(obj.bits(), obj.bits() + obj.length()); } else { - if(obj.value.empty()) + if(obj.length() == 0) throw BER_Decoding_Error("Invalid BIT STRING"); - if(obj.value[0] >= 8) + if(obj.bits()[0] >= 8) throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); - buffer.resize(obj.value.size() - 1); + buffer.resize(obj.length() - 1); - if(obj.value.size() > 1) - copy_mem(buffer.data(), &obj.value[1], obj.value.size() - 1); + if(obj.length() > 1) + copy_mem(buffer.data(), obj.bits() + 1, obj.length() - 1); } } diff --git a/src/lib/asn1/ber_dec.h b/src/lib/asn1/ber_dec.h index 637cdc527..ab2516175 100644 --- a/src/lib/asn1/ber_dec.h +++ b/src/lib/asn1/ber_dec.h @@ -54,14 +54,14 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final BER_Object obj = get_next_object(); obj.assert_is_a(type_tag, class_tag); - if (obj.value.size() != sizeof(T)) + if (obj.length() != sizeof(T)) throw BER_Decoding_Error( "Size mismatch. Object value size is " + - std::to_string(obj.value.size()) + + std::to_string(obj.length()) + "; Output type size is " + std::to_string(sizeof(T))); - copy_mem(reinterpret_cast(&out), obj.value.data(), obj.value.size()); + copy_mem(reinterpret_cast(&out), obj.bits(), obj.length()); return (*this); } @@ -185,10 +185,10 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final ASN1_Tag type_tag = static_cast(type_no); - if(obj.type_tag == type_tag && obj.class_tag == class_tag) + if(obj.is_a(type_tag, class_tag)) { if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) - BER_Decoder(obj.value).decode(out, real_type).verify_end(); + BER_Decoder(obj).decode(out, real_type).verify_end(); else { push_back(obj); @@ -210,13 +210,15 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final BER_Decoder(const uint8_t[], size_t); + explicit BER_Decoder(const BER_Object& obj); + explicit BER_Decoder(const secure_vector&); explicit BER_Decoder(const std::vector& vec); BER_Decoder(const BER_Decoder&); private: - BER_Decoder* m_parent; + BER_Decoder* m_parent = nullptr; BER_Object m_pushed; // either m_data_src.get() or an unowned pointer DataSource* m_source; @@ -234,10 +236,10 @@ BER_Decoder& BER_Decoder::decode_optional(T& out, { BER_Object obj = get_next_object(); - if(obj.type_tag == type_tag && obj.class_tag == class_tag) + if(obj.is_a(type_tag, class_tag)) { if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) - BER_Decoder(obj.value).decode(out).verify_end(); + BER_Decoder(obj).decode(out).verify_end(); else { push_back(obj); @@ -267,10 +269,9 @@ BER_Decoder& BER_Decoder::decode_optional_implicit( { BER_Object obj = get_next_object(); - if(obj.type_tag == type_tag && obj.class_tag == class_tag) + if(obj.is_a(type_tag, class_tag)) { - obj.type_tag = real_type; - obj.class_tag = real_class; + obj.set_tagging(real_type, real_class); push_back(obj); decode(out, real_type, real_class); } diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp index 831c41e37..6ae8c16d8 100644 --- a/src/lib/pubkey/ec_group/ec_group.cpp +++ b/src/lib/pubkey/ec_group/ec_group.cpp @@ -52,15 +52,15 @@ EC_Group::EC_Group(const std::vector& ber_data) BER_Decoder ber(ber_data); BER_Object obj = ber.get_next_object(); - if(obj.type_tag == NULL_TAG) + if(obj.type() == NULL_TAG) throw Decoding_Error("Cannot handle ImplicitCA ECDSA parameters"); - else if(obj.type_tag == OBJECT_ID) + else if(obj.type() == OBJECT_ID) { OID dom_par_oid; BER_Decoder(ber_data).decode(dom_par_oid); *this = EC_Group(dom_par_oid); } - else if(obj.type_tag == SEQUENCE) + else if(obj.type() == SEQUENCE) { BigInt p, a, b; std::vector sv_base_point; diff --git a/src/lib/x509/asn1_alt_name.cpp b/src/lib/x509/asn1_alt_name.cpp index c9f7c780b..4e052ca58 100644 --- a/src/lib/x509/asn1_alt_name.cpp +++ b/src/lib/x509/asn1_alt_name.cpp @@ -179,18 +179,15 @@ void AlternativeName::decode_from(BER_Decoder& source) { BER_Decoder names = source.start_cons(SEQUENCE); + // FIXME this is largely a duplication of GeneralName::decode_from + while(names.more_items()) { BER_Object obj = names.get_next_object(); - if((obj.class_tag != CONTEXT_SPECIFIC) && - (obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))) - continue; - - const ASN1_Tag tag = obj.type_tag; - if(tag == 0) + if(obj.is_a(0, CONTEXT_SPECIFIC)) { - BER_Decoder othername(obj.value); + BER_Decoder othername(obj); OID oid; othername.decode(oid); @@ -199,34 +196,35 @@ void AlternativeName::decode_from(BER_Decoder& source) BER_Object othername_value_outer = othername.get_next_object(); othername.verify_end(); - if(othername_value_outer.type_tag != ASN1_Tag(0) || - othername_value_outer.class_tag != - (CONTEXT_SPECIFIC | CONSTRUCTED) - ) + if(othername_value_outer.is_a(0, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) throw Decoding_Error("Invalid tags on otherName value"); - BER_Decoder othername_value_inner(othername_value_outer.value); + BER_Decoder othername_value_inner(othername_value_outer); BER_Object value = othername_value_inner.get_next_object(); othername_value_inner.verify_end(); - const ASN1_Tag value_type = value.type_tag; - - if(ASN1_String::is_string_type(value_type) && value.class_tag == UNIVERSAL) + if(ASN1_String::is_string_type(value.type()) && value.get_class() == UNIVERSAL) { - add_othername(oid, ASN1::to_string(value), value_type); + add_othername(oid, ASN1::to_string(value), value.type()); } } } - else if(tag == 1 || tag == 2 || tag == 6) + if(obj.is_a(1, CONTEXT_SPECIFIC)) + { + add_attribute("RFC822", ASN1::to_string(obj)); + } + else if(obj.is_a(2, CONTEXT_SPECIFIC)) + { + add_attribute("DNS", ASN1::to_string(obj)); + } + else if(obj.is_a(6, CONTEXT_SPECIFIC)) { - if(tag == 1) add_attribute("RFC822", ASN1::to_string(obj)); - if(tag == 2) add_attribute("DNS", ASN1::to_string(obj)); - if(tag == 6) add_attribute("URI", ASN1::to_string(obj)); + add_attribute("URI", ASN1::to_string(obj)); } - else if(tag == 4) + else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) { - BER_Decoder dec(obj.value); + BER_Decoder dec(obj); X509_DN dn; std::stringstream ss; @@ -235,11 +233,11 @@ void AlternativeName::decode_from(BER_Decoder& source) add_attribute("DN", ss.str()); } - else if(tag == 7) + else if(obj.is_a(7, CONTEXT_SPECIFIC)) { - if(obj.value.size() == 4) + if(obj.length() == 4) { - const uint32_t ip = load_be(&obj.value[0], 0); + const uint32_t ip = load_be(obj.bits(), 0); add_attribute("IP", ipv4_to_string(ip)); } } diff --git a/src/lib/x509/name_constraint.cpp b/src/lib/x509/name_constraint.cpp index 21145824b..888291557 100644 --- a/src/lib/x509/name_constraint.cpp +++ b/src/lib/x509/name_constraint.cpp @@ -41,58 +41,49 @@ void GeneralName::encode_into(DER_Encoder&) const void GeneralName::decode_from(class BER_Decoder& ber) { BER_Object obj = ber.get_next_object(); - if((obj.class_tag != CONTEXT_SPECIFIC) && - (obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED))) - throw Decoding_Error("Invalid class tag while decoding GeneralName"); - const ASN1_Tag tag = obj.type_tag; - - if(tag == 1 || tag == 2 || tag == 6) + if(obj.is_a(1, CONTEXT_SPECIFIC)) { + m_type = "RFC822"; m_name = ASN1::to_string(obj); - - if(tag == 1) - { - m_type = "RFC822"; - } - else if(tag == 2) - { - m_type = "DNS"; - } - else if(tag == 6) - { - m_type = "URI"; - } } - else if(tag == 4) + else if(obj.is_a(2, CONTEXT_SPECIFIC)) { + m_type = "DNS"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(6, CONTEXT_SPECIFIC)) + { + m_type = "URI"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) + { + m_type = "DN"; X509_DN dn; - BER_Decoder dec(obj.value); + BER_Decoder dec(obj); std::stringstream ss; dn.decode_from(dec); ss << dn; m_name = ss.str(); - m_type = "DN"; } - else if(tag == 7) + else if(obj.is_a(7, CONTEXT_SPECIFIC)) { - if(obj.value.size() == 8) + if(obj.length() == 8) { - const std::vector ip(obj.value.begin(), obj.value.begin() + 4); - const std::vector net(obj.value.begin() + 4, obj.value.end()); m_type = "IP"; - m_name = ipv4_to_string(load_be(ip.data(), 0)) + "/" + ipv4_to_string(load_be(net.data(), 0)); + m_name = ipv4_to_string(load_be(obj.bits(), 0)) + "/" + + ipv4_to_string(load_be(obj.bits(), 1)); } - else if(obj.value.size() == 32) + else if(obj.length() == 32) { throw Decoding_Error("Unsupported IPv6 name constraint"); } else { - throw Decoding_Error("Invalid IP name constraint size " + - std::to_string(obj.value.size())); + throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length())); } } else diff --git a/src/lib/x509/ocsp.cpp b/src/lib/x509/ocsp.cpp index 5a98b7495..10449b019 100644 --- a/src/lib/x509/ocsp.cpp +++ b/src/lib/x509/ocsp.cpp @@ -32,18 +32,18 @@ void decode_optional_list(BER_Decoder& ber, { BER_Object obj = ber.get_next_object(); - if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED)) + if(obj.is_a(tag, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) { ber.push_back(obj); return; } - BER_Decoder list(obj.value); + BER_Decoder list(obj); while(list.more_items()) { BER_Object certbits = list.get_next_object(); - X509_Certificate cert(unlock(certbits.value)); + X509_Certificate cert(certbits.bits(), certbits.length()); output.push_back(std::move(cert)); } } diff --git a/src/lib/x509/ocsp_types.cpp b/src/lib/x509/ocsp_types.cpp index 353cb100a..3eda5c05b 100644 --- a/src/lib/x509/ocsp_types.cpp +++ b/src/lib/x509/ocsp_types.cpp @@ -97,7 +97,7 @@ void SingleResponse::decode_from(class BER_Decoder& from) ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) .end_cons(); - m_cert_status = cert_status.type_tag; + m_cert_status = cert_status.type(); } } diff --git a/src/lib/x509/pkcs10.cpp b/src/lib/x509/pkcs10.cpp index b1543e398..78fea8dc6 100644 --- a/src/lib/x509/pkcs10.cpp +++ b/src/lib/x509/pkcs10.cpp @@ -72,20 +72,18 @@ std::unique_ptr decode_pkcs10(const std::vector& body) cert_req_info.decode(data->m_subject_dn); BER_Object public_key = cert_req_info.get_next_object(); - if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED) - throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", - public_key.type_tag, public_key.class_tag); + if(public_key.is_a(SEQUENCE, CONSTRUCTED) == false) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", public_key.tagging()); - data->m_public_key_bits = ASN1::put_in_sequence(unlock(public_key.value)); + data->m_public_key_bits = ASN1::put_in_sequence(public_key.bits(), public_key.length()); BER_Object attr_bits = cert_req_info.get_next_object(); std::set pkcs9_email; - if(attr_bits.type_tag == 0 && - attr_bits.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + if(attr_bits.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { - BER_Decoder attributes(attr_bits.value); + BER_Decoder attributes(attr_bits); while(attributes.more_items()) { Attribute attr; @@ -113,9 +111,8 @@ std::unique_ptr decode_pkcs10(const std::vector& body) } attributes.verify_end(); } - else if(attr_bits.type_tag != NO_OBJECT) - throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", - attr_bits.type_tag, attr_bits.class_tag); + else if(attr_bits.is_set()) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging()); cert_req_info.verify_end(); diff --git a/src/lib/x509/x509_crl.cpp b/src/lib/x509/x509_crl.cpp index c6449baf8..da075e009 100644 --- a/src/lib/x509/x509_crl.cpp +++ b/src/lib/x509/x509_crl.cpp @@ -141,9 +141,9 @@ std::unique_ptr decode_crl_body(const std::vector& body, BER_Object next = tbs_crl.get_next_object(); - if(next.type_tag == SEQUENCE && next.class_tag == CONSTRUCTED) + if(next.is_a(SEQUENCE, CONSTRUCTED)) { - BER_Decoder cert_list(next.value); + BER_Decoder cert_list(next); while(cert_list.more_items()) { @@ -154,15 +154,14 @@ std::unique_ptr decode_crl_body(const std::vector& body, next = tbs_crl.get_next_object(); } - if(next.type_tag == 0 && - next.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + if(next.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { - BER_Decoder crl_options(next.value); + BER_Decoder crl_options(next); crl_options.decode(data->m_extensions).verify_end(); next = tbs_crl.get_next_object(); } - if(next.type_tag != NO_OBJECT) + if(next.is_set()) throw X509_CRL::X509_CRL_Error("Unknown tag in CRL"); tbs_crl.verify_end(); diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp index c3b58236a..44c469c48 100644 --- a/src/lib/x509/x509_ext.cpp +++ b/src/lib/x509/x509_ext.cpp @@ -350,22 +350,27 @@ void Key_Usage::decode_inner(const std::vector& in) BER_Object obj = ber.get_next_object(); - if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL) - throw BER_Bad_Tag("Bad tag for usage constraint", - obj.type_tag, obj.class_tag); + obj.assert_is_a(BIT_STRING, UNIVERSAL, "usage constraint"); - if(obj.value.size() != 2 && obj.value.size() != 3) + if(obj.length() != 2 && obj.length() != 3) throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); - if(obj.value[0] >= 8) + uint16_t usage = 0; + + const uint8_t* bits = obj.bits(); + + if(bits[0] >= 8) throw BER_Decoding_Error("Invalid unused bits in usage constraint"); - obj.value[obj.value.size()-1] &= (0xFF << obj.value[0]); + const uint8_t mask = static_cast(0xFF << bits[0]); - uint16_t usage = 0; - for(size_t i = 1; i != obj.value.size(); ++i) + if(obj.length() == 2) + { + usage = make_uint16(bits[1] & mask, 0); + } + else if(obj.length() == 3) { - usage = (obj.value[i] << 8*(sizeof(usage)-i)) | usage; + usage = make_uint16(bits[1], bits[2] & mask); } m_constraints = Key_Constraints(usage); @@ -545,7 +550,7 @@ void Name_Constraints::decode_inner(const std::vector& in) BER_Object per = ext.get_next_object(); ext.push_back(per); - if(per.type_tag == 0 && per.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + if(per.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { ext.decode_list(permit,ASN1_Tag(0),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); if(permit.empty()) @@ -554,7 +559,7 @@ void Name_Constraints::decode_inner(const std::vector& in) BER_Object exc = ext.get_next_object(); ext.push_back(exc); - if(per.type_tag == 1 && per.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + if(per.is_a(1, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { ext.decode_list(exclude,ASN1_Tag(1),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); if(exclude.empty()) @@ -771,7 +776,7 @@ void Authority_Information_Access::decode_inner(const std::vector& in) { BER_Object name = info.get_next_object(); - if(name.type_tag == 6 && name.class_tag == CONTEXT_SPECIFIC) + if(name.is_a(6, CONTEXT_SPECIFIC)) { m_ocsp_responder = ASN1::to_string(name); } @@ -781,7 +786,7 @@ void Authority_Information_Access::decode_inner(const std::vector& in) { BER_Object name = info.get_next_object(); - if(name.type_tag == 6 && name.class_tag == CONTEXT_SPECIFIC) + if(name.is_a(6, CONTEXT_SPECIFIC)) { m_ca_issuers.push_back(ASN1::to_string(name)); } diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp index f298006c0..66921ed66 100644 --- a/src/lib/x509/x509cert.cpp +++ b/src/lib/x509/x509cert.cpp @@ -85,6 +85,12 @@ X509_Certificate::X509_Certificate(const std::vector& vec) load_data(src); } +X509_Certificate::X509_Certificate(const uint8_t data[], size_t len) + { + DataSource_Memory src(data, len); + load_data(src); + } + #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) X509_Certificate::X509_Certificate(const std::string& fsname) { @@ -128,13 +134,11 @@ std::unique_ptr parse_x509_cert_body(const X509_Object& o data->m_issuer_dn_bits = ASN1::put_in_sequence(data->m_issuer_dn.get_bits()); BER_Object public_key = tbs_cert.get_next_object(); - if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED) - throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key", - public_key.type_tag, public_key.class_tag); + public_key.assert_is_a(SEQUENCE, CONSTRUCTED, "X.509 certificate public key"); // validate_public_key_params(public_key.value); AlgorithmIdentifier public_key_alg_id; - BER_Decoder(public_key.value).decode(public_key_alg_id).discard_remaining(); + BER_Decoder(public_key).decode(public_key_alg_id).discard_remaining(); std::vector public_key_info = split_on(OIDS::oid2str(public_key_alg_id.get_oid()), '/'); @@ -180,7 +184,7 @@ std::unique_ptr parse_x509_cert_body(const X509_Object& o } } - data->m_subject_public_key_bits = unlock(public_key.value); + data->m_subject_public_key_bits.assign(public_key.bits(), public_key.bits() + public_key.length()); BER_Decoder(data->m_subject_public_key_bits) .decode(data->m_subject_public_key_algid) @@ -190,14 +194,12 @@ std::unique_ptr parse_x509_cert_body(const X509_Object& o tbs_cert.decode_optional_string(data->m_v2_subject_key_id, BIT_STRING, 2); BER_Object v3_exts_data = tbs_cert.get_next_object(); - if(v3_exts_data.type_tag == 3 && - v3_exts_data.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + if(v3_exts_data.is_a(3, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) { - BER_Decoder(v3_exts_data.value).decode(data->m_v3_extensions).verify_end(); + BER_Decoder(v3_exts_data).decode(data->m_v3_extensions).verify_end(); } - else if(v3_exts_data.type_tag != NO_OBJECT) - throw BER_Bad_Tag("Unknown tag in X.509 cert", - v3_exts_data.type_tag, v3_exts_data.class_tag); + else if(v3_exts_data.is_set()) + throw BER_Bad_Tag("Unknown tag in X.509 cert", v3_exts_data.tagging()); if(tbs_cert.more_items()) throw Decoding_Error("TBSCertificate has extra data after extensions block"); diff --git a/src/lib/x509/x509cert.h b/src/lib/x509/x509cert.h index a1448637d..79d16d37f 100644 --- a/src/lib/x509/x509cert.h +++ b/src/lib/x509/x509cert.h @@ -407,6 +407,13 @@ class BOTAN_PUBLIC_API(2,0) X509_Certificate : public X509_Object */ explicit X509_Certificate(const std::vector& in); + /** + * Create a certificate from a buffer + * @param data the buffer containing the DER-encoded certificate + * @param length length of data in bytes + */ + X509_Certificate(const uint8_t data[], size_t length); + /** * Create an uninitialized certificate object. Any attempts to * access this object will throw an exception. diff --git a/src/tests/data/x509/bsi/expected.txt b/src/tests/data/x509/bsi/expected.txt index 6b609a201..fefb42bc5 100644 --- a/src/tests/data/x509/bsi/expected.txt +++ b/src/tests/data/x509/bsi/expected.txt @@ -28,7 +28,7 @@ cert_path_CRL_10$Certificate is revoked cert_path_CRL_11$Certificate is revoked cert_path_CRL_12$No revocation data cert_path_CRL_13$No CRL with matching distribution point for certificate -cert_path_CRL_14$Invalid argument Decoding error: X509 CRL decoding failed: Invalid argument Decoding error: BER: Tag mismatch when decoding got 65280/65280 expected 3/0 +cert_path_CRL_14$Invalid argument Decoding error: X509 CRL decoding failed: Invalid argument Decoding error: BER: Tag mismatch when decoding object got 65280/65280 expected 3/0 cert_path_CRL_15$No CRL with matching distribution point for certificate cert_path_CRL_16$Certificate is revoked cert_path_crypt_01$Signature error @@ -42,7 +42,7 @@ cert_path_ext_06$CA certificate not allowed to issue certs cert_path_ext_07$CA certificate not allowed to issue certs cert_path_ext_08$Certificate chain too long cert_path_ext_09$Verified -cert_path_ext_10$Invalid argument Decoding error: CERTIFICATE decoding failed: Invalid argument Decoding error: Decoding X.509 extension 2.5.29.15 failed failed with exception Invalid argument Decoding error: BER: Bad tag for usage constraint: 16/32 +cert_path_ext_10$Invalid argument Decoding error: CERTIFICATE decoding failed: Invalid argument Decoding error: Decoding X.509 extension 2.5.29.15 failed failed with exception Invalid argument Decoding error: BER: Tag mismatch when decoding usage constraint got 16/32 expected 3/0 cert_path_ext_11$CA certificate not allowed to issue certs cert_path_ext_12$Certificate contains duplicate policy cert_path_ext_13$Unknown critical extension encountered -- cgit v1.2.3