diff options
author | Jack Lloyd <[email protected]> | 2018-05-22 11:04:15 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-05-22 11:04:15 -0400 |
commit | 3789138906cecbcc5e33bb0d5784e6b576171080 (patch) | |
tree | 147c442020bec8ad6effe62727fdb6b300d0f7f7 /src/lib/asn1 | |
parent | cd0bcd90817ece3e4fcba32e06a372580bbe3008 (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.cpp | 17 | ||||
-rw-r--r-- | src/lib/asn1/asn1_obj.h | 9 | ||||
-rw-r--r-- | src/lib/asn1/asn1_print.cpp | 5 | ||||
-rw-r--r-- | src/lib/asn1/der_enc.cpp | 85 | ||||
-rw-r--r-- | src/lib/asn1/der_enc.h | 23 |
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; }; |