aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/asn1/ber_dec.h
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-06-08 05:47:56 -0400
committerJack Lloyd <[email protected]>2018-06-08 05:50:10 -0400
commit2559c80b098cec1bfcb30be1ca976f595aaf1fd6 (patch)
tree198a9c49cc5fa70f9d4fc38246e23a2ef04a6146 /src/lib/asn1/ber_dec.h
parentd507c1fa99f881ff7f21a289f4efa2b64f4f9c4b (diff)
Reduce copying/allocations when BER decoding
We are constrained in how far we can go because BER_Object must mandatorily copy its value (due to the public member variable exposting the bytes). But this reduces the number of allocations when parsing a sample X.509 certificate by about 15%
Diffstat (limited to 'src/lib/asn1/ber_dec.h')
-rw-r--r--src/lib/asn1/ber_dec.h164
1 files changed, 132 insertions, 32 deletions
diff --git a/src/lib/asn1/ber_dec.h b/src/lib/asn1/ber_dec.h
index d454c45d6..2086eacd3 100644
--- a/src/lib/asn1/ber_dec.h
+++ b/src/lib/asn1/ber_dec.h
@@ -1,6 +1,6 @@
/*
* BER Decoder
-* (C) 1999-2010 Jack Lloyd
+* (C) 1999-2010,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -13,28 +13,103 @@
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()) {}
+
+ 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();
- std::vector<uint8_t> get_next_octet_string();
+ 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();
- BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = UNIVERSAL);
- BER_Decoder& end_cons();
+ /**
+ * Start decoding a constructed data (sequence or set)
+ */
+ BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = UNIVERSAL);
- BER_Decoder& get_next(BER_Object& ber);
+ /**
+ * 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
@@ -82,9 +157,37 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
}
BER_Decoder& decode_null();
- BER_Decoder& decode(bool& v);
- BER_Decoder& decode(size_t& v);
- BER_Decoder& decode(class BigInt& v);
+
+ /**
+ * 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
@@ -103,7 +206,7 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
ASN1_Tag type_tag,
ASN1_Tag class_tag = CONTEXT_SPECIFIC);
- BER_Decoder& decode(class BigInt& v,
+ BER_Decoder& decode(BigInt& v,
ASN1_Tag type_tag,
ASN1_Tag class_tag = CONTEXT_SPECIFIC);
@@ -121,11 +224,14 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
ASN1_Tag type_tag = NO_OBJECT,
ASN1_Tag class_tag = NO_OBJECT);
- BER_Decoder& decode_octet_string_bigint(class BigInt& b);
+ /**
+ * 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);
+ ASN1_Tag class_tag,
+ size_t T_bytes);
template<typename T> BER_Decoder& decode_integer_type(T& out)
{
@@ -190,36 +296,27 @@ class BOTAN_PUBLIC_API(2,0) BER_Decoder final
if(obj.is_a(type_tag, class_tag))
{
if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC))
+ {
BER_Decoder(obj).decode(out, real_type).verify_end();
+ }
else
{
- push_back(obj);
+ push_back(std::move(obj));
decode(out, real_type, type_tag, class_tag);
}
}
else
{
out.clear();
- push_back(obj);
+ push_back(std::move(obj));
}
return (*this);
}
- BER_Decoder& operator=(const BER_Decoder&) = delete;
-
- explicit BER_Decoder(DataSource&);
-
- 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(BER_Object&& obj, BER_Decoder* parent);
+
BER_Decoder* m_parent = nullptr;
BER_Object m_pushed;
// either m_data_src.get() or an unowned pointer
@@ -241,17 +338,19 @@ BER_Decoder& BER_Decoder::decode_optional(T& out,
if(obj.is_a(type_tag, class_tag))
{
if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC))
+ {
BER_Decoder(obj).decode(out).verify_end();
+ }
else
{
- push_back(obj);
+ push_back(std::move(obj));
decode(out, type_tag, class_tag);
}
}
else
{
out = default_value;
- push_back(obj);
+ push_back(std::move(obj));
}
return (*this);
@@ -274,13 +373,14 @@ BER_Decoder& BER_Decoder::decode_optional_implicit(
if(obj.is_a(type_tag, class_tag))
{
obj.set_tagging(real_type, real_class);
- push_back(obj);
+ 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(obj);
+ push_back(std::move(obj));
}
return (*this);
@@ -299,7 +399,7 @@ BER_Decoder& BER_Decoder::decode_list(std::vector<T>& vec,
{
T value;
list.decode(value);
- vec.push_back(value);
+ vec.push_back(std::move(value));
}
list.end_cons();