aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/asn1
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-05-22 11:04:15 -0400
committerJack Lloyd <[email protected]>2018-05-22 11:04:15 -0400
commit3789138906cecbcc5e33bb0d5784e6b576171080 (patch)
tree147c442020bec8ad6effe62727fdb6b300d0f7f7 /src/lib/asn1
parentcd0bcd90817ece3e4fcba32e06a372580bbe3008 (diff)
DER improvements
Let DER_Encoder write to a user specified vector instead of only to an internal vector. This allows encoding to a std::vector without having to first write to a locked vector and then copying out the result. Add ASN1_Object::BER_encode convenience method. Replaces X509_Object::BER_encode which had the same logic but was restricted to a subtype. This replaces many cases where DER_Encoder was just used to encode a single object (X509_DN, AlgorithmIdentifier, etc).
Diffstat (limited to 'src/lib/asn1')
-rw-r--r--src/lib/asn1/asn1_obj.cpp17
-rw-r--r--src/lib/asn1/asn1_obj.h9
-rw-r--r--src/lib/asn1/asn1_print.cpp5
-rw-r--r--src/lib/asn1/der_enc.cpp85
-rw-r--r--src/lib/asn1/der_enc.h23
5 files changed, 103 insertions, 36 deletions
diff --git a/src/lib/asn1/asn1_obj.cpp b/src/lib/asn1/asn1_obj.cpp
index bbe469f5c..98f44d407 100644
--- a/src/lib/asn1/asn1_obj.cpp
+++ b/src/lib/asn1/asn1_obj.cpp
@@ -1,6 +1,6 @@
/*
* ASN.1 Internals
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -12,6 +12,14 @@
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
*/
@@ -132,11 +140,12 @@ std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& contents)
std::vector<uint8_t> put_in_sequence(const uint8_t bits[], size_t len)
{
- return DER_Encoder()
+ std::vector<uint8_t> output;
+ DER_Encoder(output)
.start_cons(SEQUENCE)
.raw_bytes(bits, len)
- .end_cons()
- .get_contents_unlocked();
+ .end_cons();
+ return output;
}
/*
diff --git a/src/lib/asn1/asn1_obj.h b/src/lib/asn1/asn1_obj.h
index 2c2a3097a..b9477da09 100644
--- a/src/lib/asn1/asn1_obj.h
+++ b/src/lib/asn1/asn1_obj.h
@@ -1,6 +1,6 @@
/*
* ASN.1 Internals
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -76,6 +76,13 @@ class BOTAN_PUBLIC_API(2,0) ASN1_Object
*/
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;
diff --git a/src/lib/asn1/asn1_print.cpp b/src/lib/asn1/asn1_print.cpp
index cb223e130..1f9178266 100644
--- a/src/lib/asn1/asn1_print.cpp
+++ b/src/lib/asn1/asn1_print.cpp
@@ -87,9 +87,8 @@ void ASN1_Formatter::decode(std::ostream& output,
/* 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.bits(), obj.length());
- const std::vector<uint8_t> bits = encoder.get_contents_unlocked();
+ std::vector<uint8_t> bits;
+ DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length());
BER_Decoder data(bits);
diff --git a/src/lib/asn1/der_enc.cpp b/src/lib/asn1/der_enc.cpp
index 461768180..c1ec010a0 100644
--- a/src/lib/asn1/der_enc.cpp
+++ b/src/lib/asn1/der_enc.cpp
@@ -66,6 +66,22 @@ void encode_length(std::vector<uint8_t>& encoded_length, size_t length)
}
+DER_Encoder::DER_Encoder(secure_vector<uint8_t>& vec)
+ {
+ m_append_output_fn = [&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_fn = [&vec](const uint8_t b[], size_t l)
+ {
+ vec.insert(vec.end(), b, b + l);
+ };
+ }
+
/*
* Push the encoded SEQUENCE/SET to the encoder stream
*/
@@ -138,8 +154,11 @@ 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_fn)
+ throw Invalid_State("DER_Encoder Cannot get contents when using output vector");
+
secure_vector<uint8_t> output;
- std::swap(output, m_contents);
+ std::swap(output, m_default_outbuf);
return output;
}
@@ -148,8 +167,11 @@ 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");
- std::vector<uint8_t> output(m_contents.begin(), m_contents.end());
- m_contents.clear();
+ if(m_append_output_fn)
+ 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;
}
@@ -209,9 +231,41 @@ DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length)
{
m_subsequences[m_subsequences.size()-1].add_bytes(bytes, length);
}
+ else if(m_append_output_fn)
+ {
+ m_append_output_fn(bytes, length);
+ }
else
{
- m_contents += std::make_pair(bytes, length);
+ 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_fn)
+ {
+ m_append_output_fn(hdr.data(), hdr.size());
+ m_append_output_fn(rep, length);
+ }
+ else
+ {
+ m_default_outbuf += hdr;
+ m_default_outbuf += std::make_pair(rep, length);
}
return (*this);
@@ -332,29 +386,6 @@ DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
* 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
- {
- m_contents += hdr;
- m_contents += std::make_pair(rep, 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 std::string& rep_str)
{
const uint8_t* rep = cast_char_ptr_to_uint8(rep_str.data());
diff --git a/src/lib/asn1/der_enc.h b/src/lib/asn1/der_enc.h
index ebca73d33..f351817f9 100644
--- a/src/lib/asn1/der_enc.h
+++ b/src/lib/asn1/der_enc.h
@@ -10,6 +10,7 @@
#include <botan/asn1_obj.h>
#include <vector>
+#include <functional>
namespace Botan {
@@ -22,6 +23,25 @@ class ASN1_Object;
class BOTAN_PUBLIC_API(2,0) DER_Encoder final
{
public:
+ /**
+ * 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);
+
secure_vector<uint8_t> get_contents();
std::vector<uint8_t> get_contents_unlocked();
@@ -183,7 +203,8 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
std::vector< secure_vector<uint8_t> > m_set_contents;
};
- secure_vector<uint8_t> m_contents;
+ std::function<void (const uint8_t[], size_t)> m_append_output_fn;
+ secure_vector<uint8_t> m_default_outbuf;
std::vector<DER_Sequence> m_subsequences;
};