aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/asn1
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/asn1')
-rw-r--r--src/lib/asn1/asn1_obj.cpp42
-rw-r--r--src/lib/asn1/asn1_obj.h42
-rw-r--r--src/lib/asn1/asn1_oid.cpp24
-rw-r--r--src/lib/asn1/asn1_print.cpp12
-rw-r--r--src/lib/asn1/asn1_str.cpp6
-rw-r--r--src/lib/asn1/asn1_time.cpp2
-rw-r--r--src/lib/asn1/ber_dec.cpp95
-rw-r--r--src/lib/asn1/ber_dec.h23
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);
}