diff options
Diffstat (limited to 'src/lib/asn1')
-rw-r--r-- | src/lib/asn1/asn1_obj.cpp | 42 | ||||
-rw-r--r-- | src/lib/asn1/asn1_obj.h | 42 | ||||
-rw-r--r-- | src/lib/asn1/asn1_oid.cpp | 24 | ||||
-rw-r--r-- | src/lib/asn1/asn1_print.cpp | 12 | ||||
-rw-r--r-- | src/lib/asn1/asn1_str.cpp | 6 | ||||
-rw-r--r-- | src/lib/asn1/asn1_time.cpp | 2 | ||||
-rw-r--r-- | src/lib/asn1/ber_dec.cpp | 95 | ||||
-rw-r--r-- | src/lib/asn1/ber_dec.h | 23 |
8 files changed, 154 insertions, 92 deletions
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) @@ -95,9 +127,14 @@ namespace ASN1 { */ 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) + { return DER_Encoder() .start_cons(SEQUENCE) - .raw_bytes(contents) + .raw_bytes(bits, len) .end_cons() .get_contents_unlocked(); } @@ -107,7 +144,8 @@ std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& 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<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(); + } }; /* @@ -105,6 +138,7 @@ 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); /** 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<uint8_t> 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 @@ -148,24 +148,11 @@ 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<uint8_t>& 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<uint8_t>& 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<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.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<uint8_t, Alloc>& 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<uint8_t*>(&out), obj.value.data(), obj.value.size()); + copy_mem(reinterpret_cast<uint8_t*>(&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<ASN1_Tag>(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<uint8_t>&); explicit BER_Decoder(const std::vector<uint8_t>& 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); } |