aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/asn1
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-05-21 17:54:19 -0400
committerJack Lloyd <[email protected]>2018-05-21 17:54:19 -0400
commit29dcc926932d187e34b2e6994e2d5d329d6a6d93 (patch)
tree9506d725c9bf44988c52258443ec777e66cd04b1 /src/lib/asn1
parentea8c01fddc8197bfdc453d3c4c76e98c9f3149cd (diff)
parent0bdf86a57f2e64610c214f429fe5b21418866bcc (diff)
Merge GH #1571 DER_Encoder optimizations
Diffstat (limited to 'src/lib/asn1')
-rw-r--r--src/lib/asn1/der_enc.cpp130
-rw-r--r--src/lib/asn1/der_enc.h76
2 files changed, 123 insertions, 83 deletions
diff --git a/src/lib/asn1/der_enc.cpp b/src/lib/asn1/der_enc.cpp
index 1ed51d593..461768180 100644
--- a/src/lib/asn1/der_enc.cpp
+++ b/src/lib/asn1/der_enc.cpp
@@ -1,6 +1,6 @@
/*
* DER Encoder
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -19,39 +19,40 @@ namespace {
/*
* DER encode an ASN.1 type tag
*/
-secure_vector<uint8_t> encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag)
+void encode_tag(std::vector<uint8_t>& encoded_tag,
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
{
if((class_tag | 0xE0) != 0xE0)
throw Encoding_Error("DER_Encoder: Invalid class tag " +
std::to_string(class_tag));
- secure_vector<uint8_t> encoded_tag;
if(type_tag <= 30)
+ {
encoded_tag.push_back(static_cast<uint8_t>(type_tag | class_tag));
+ }
else
{
size_t blocks = high_bit(type_tag) + 6;
blocks = (blocks - (blocks % 7)) / 7;
- BOTAN_ASSERT(blocks > 0, "Math works");
+ BOTAN_ASSERT_NOMSG(blocks > 0);
encoded_tag.push_back(static_cast<uint8_t>(class_tag | 0x1F));
for(size_t i = 0; i != blocks - 1; ++i)
encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F));
encoded_tag.push_back(type_tag & 0x7F);
}
-
- return encoded_tag;
}
/*
* DER encode an ASN.1 length field
*/
-secure_vector<uint8_t> encode_length(size_t length)
+void encode_length(std::vector<uint8_t>& encoded_length, size_t length)
{
- secure_vector<uint8_t> encoded_length;
if(length <= 127)
+ {
encoded_length.push_back(static_cast<uint8_t>(length));
+ }
else
{
const size_t bytes_needed = significant_bytes(length);
@@ -61,15 +62,14 @@ secure_vector<uint8_t> encode_length(size_t length)
for(size_t i = sizeof(length) - bytes_needed; i < sizeof(length); ++i)
encoded_length.push_back(get_byte(i, length));
}
- return encoded_length;
}
}
/*
-* Return the encoded SEQUENCE/SET
+* Push the encoded SEQUENCE/SET to the encoder stream
*/
-secure_vector<uint8_t> DER_Encoder::DER_Sequence::get_contents()
+void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der)
{
const ASN1_Tag real_class_tag = ASN1_Tag(m_class_tag | CONSTRUCTED);
@@ -81,13 +81,8 @@ secure_vector<uint8_t> DER_Encoder::DER_Sequence::get_contents()
m_set_contents.clear();
}
- secure_vector<uint8_t> result;
- result += encode_tag(m_type_tag, real_class_tag);
- result += encode_length(m_contents.size());
- result += m_contents;
+ der.add_object(m_type_tag, real_class_tag, m_contents.data(), m_contents.size());
m_contents.clear();
-
- return result;
}
/*
@@ -101,6 +96,24 @@ void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length)
m_contents += std::make_pair(data, length);
}
+void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len,
+ const uint8_t val[], size_t val_len)
+ {
+ if(m_type_tag == SET)
+ {
+ secure_vector<uint8_t> m;
+ m.reserve(hdr_len + val_len);
+ m += std::make_pair(hdr, hdr_len);
+ m += std::make_pair(val, val_len);
+ m_set_contents.push_back(std::move(m));
+ }
+ else
+ {
+ m_contents += std::make_pair(hdr, hdr_len);
+ m_contents += std::make_pair(val, val_len);
+ }
+ }
+
/*
* Return the type and class taggings
*/
@@ -130,6 +143,16 @@ secure_vector<uint8_t> DER_Encoder::get_contents()
return output;
}
+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();
+ return output;
+ }
+
/*
* Start a new ASN.1 SEQUENCE/SET/EXPLICIT
*/
@@ -148,9 +171,10 @@ DER_Encoder& DER_Encoder::end_cons()
if(m_subsequences.empty())
throw Invalid_State("DER_Encoder::end_cons: No such sequence");
- secure_vector<uint8_t> seq = m_subsequences[m_subsequences.size()-1].get_contents();
+ DER_Sequence last_seq = std::move(m_subsequences[m_subsequences.size()-1]);
m_subsequences.pop_back();
- raw_bytes(seq);
+ last_seq.push_contents(*this);
+
return (*this);
}
@@ -161,8 +185,9 @@ DER_Encoder& DER_Encoder::start_explicit(uint16_t type_no)
{
ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no);
+ // This would confuse DER_Sequence
if(type_tag == SET)
- throw Internal_Error("DER_Encoder.start_explicit(SET); cannot perform");
+ throw Internal_Error("DER_Encoder.start_explicit(SET) not supported");
return start_cons(type_tag, CONTEXT_SPECIFIC);
}
@@ -181,9 +206,13 @@ DER_Encoder& DER_Encoder::end_explicit()
DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length)
{
if(m_subsequences.size())
+ {
m_subsequences[m_subsequences.size()-1].add_bytes(bytes, length);
+ }
else
+ {
m_contents += std::make_pair(bytes, length);
+ }
return (*this);
}
@@ -275,28 +304,6 @@ DER_Encoder& DER_Encoder::encode(const BigInt& n,
/*
* DER encode an OCTET STRING or BIT STRING
*/
-DER_Encoder& DER_Encoder::encode(const secure_vector<uint8_t>& bytes,
- ASN1_Tag real_type,
- ASN1_Tag type_tag, ASN1_Tag class_tag)
- {
- return encode(bytes.data(), bytes.size(),
- real_type, type_tag, class_tag);
- }
-
-/*
-* DER encode an OCTET STRING or BIT STRING
-*/
-DER_Encoder& DER_Encoder::encode(const std::vector<uint8_t>& bytes,
- ASN1_Tag real_type,
- ASN1_Tag type_tag, ASN1_Tag class_tag)
- {
- return encode(bytes.data(), bytes.size(),
- real_type, type_tag, class_tag);
- }
-
-/*
-* DER encode an OCTET STRING or BIT STRING
-*/
DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length,
ASN1_Tag real_type,
ASN1_Tag type_tag, ASN1_Tag class_tag)
@@ -315,26 +322,6 @@ DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length,
return add_object(type_tag, class_tag, bytes, length);
}
-/*
-* Conditionally write some values to the stream
-*/
-DER_Encoder& DER_Encoder::encode_if(bool cond, DER_Encoder& codec)
- {
- if(cond)
- return raw_bytes(codec.get_contents());
- return (*this);
- }
-
-DER_Encoder& DER_Encoder::encode_if(bool cond, const ASN1_Object& obj)
- {
- if(cond)
- encode(obj);
- return (*this);
- }
-
-/*
-* Request for an object to encode itself
-*/
DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
{
obj.encode_into(*this);
@@ -347,12 +334,21 @@ DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj)
DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
const uint8_t rep[], size_t length)
{
- secure_vector<uint8_t> buffer;
- buffer += encode_tag(type_tag, class_tag);
- buffer += encode_length(length);
- buffer += std::make_pair(rep, length);
+ std::vector<uint8_t> hdr;
+ encode_tag(hdr, type_tag, class_tag);
+ encode_length(hdr, length);
- return raw_bytes(buffer);
+ 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);
}
/*
diff --git a/src/lib/asn1/der_enc.h b/src/lib/asn1/der_enc.h
index f76391ae5..ebca73d33 100644
--- a/src/lib/asn1/der_enc.h
+++ b/src/lib/asn1/der_enc.h
@@ -1,6 +1,6 @@
/*
* DER Encoder
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -24,8 +24,7 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
public:
secure_vector<uint8_t> get_contents();
- std::vector<uint8_t> get_contents_unlocked()
- { return unlock(get_contents()); }
+ std::vector<uint8_t> get_contents_unlocked();
DER_Encoder& start_cons(ASN1_Tag type_tag,
ASN1_Tag class_tag = UNIVERSAL);
@@ -69,20 +68,19 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
ASN1_Tag type_tag,
ASN1_Tag class_tag = CONTEXT_SPECIFIC);
- DER_Encoder& encode(const std::vector<uint8_t>& v,
- ASN1_Tag real_type,
- ASN1_Tag type_tag,
- ASN1_Tag class_tag = CONTEXT_SPECIFIC);
-
- DER_Encoder& encode(const secure_vector<uint8_t>& v,
+ DER_Encoder& encode(const uint8_t v[], size_t len,
ASN1_Tag real_type,
ASN1_Tag type_tag,
ASN1_Tag class_tag = CONTEXT_SPECIFIC);
- DER_Encoder& encode(const uint8_t v[], size_t len,
+ template<typename Alloc>
+ DER_Encoder& encode(const std::vector<uint8_t, Alloc>& bytes,
ASN1_Tag real_type,
- ASN1_Tag type_tag,
- ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+ ASN1_Tag type_tag, ASN1_Tag class_tag)
+ {
+ return encode(bytes.data(), bytes.size(),
+ real_type, type_tag, class_tag);
+ }
template<typename T>
DER_Encoder& encode_optional(const T& value, const T& default_value)
@@ -100,9 +98,27 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
return (*this);
}
+ /*
+ * Request for an object to encode itself to this stream
+ */
DER_Encoder& encode(const ASN1_Object& obj);
- DER_Encoder& encode_if(bool pred, DER_Encoder& enc);
- DER_Encoder& encode_if(bool pred, const ASN1_Object& obj);
+
+ /*
+ * Conditionally write some values to the stream
+ */
+ DER_Encoder& encode_if(bool pred, DER_Encoder& enc)
+ {
+ if(pred)
+ return raw_bytes(enc.get_contents());
+ return (*this);
+ }
+
+ DER_Encoder& encode_if(bool pred, const ASN1_Object& obj)
+ {
+ if(pred)
+ encode(obj);
+ return (*this);
+ }
DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag,
const uint8_t rep[], size_t length);
@@ -130,9 +146,37 @@ class BOTAN_PUBLIC_API(2,0) DER_Encoder final
{
public:
ASN1_Tag tag_of() const;
- secure_vector<uint8_t> get_contents();
- void add_bytes(const uint8_t[], size_t);
+
+ void push_contents(DER_Encoder& der);
+
+ void add_bytes(const uint8_t val[], size_t len);
+
+ void add_bytes(const uint8_t hdr[], size_t hdr_len,
+ const uint8_t val[], size_t val_len);
+
DER_Sequence(ASN1_Tag, ASN1_Tag);
+
+ DER_Sequence(DER_Sequence&& seq)
+ {
+ std::swap(m_type_tag, seq.m_type_tag);
+ std::swap(m_class_tag, seq.m_class_tag);
+ std::swap(m_contents, seq.m_contents);
+ std::swap(m_set_contents, seq.m_set_contents);
+ }
+
+ DER_Sequence& operator=(DER_Sequence&& seq)
+ {
+ std::swap(m_type_tag, seq.m_type_tag);
+ std::swap(m_class_tag, seq.m_class_tag);
+ std::swap(m_contents, seq.m_contents);
+ std::swap(m_set_contents, seq.m_set_contents);
+ return (*this);
+ }
+
+ DER_Sequence(const DER_Sequence& seq) = default;
+
+ DER_Sequence& operator=(const DER_Sequence& seq) = default;
+
private:
ASN1_Tag m_type_tag, m_class_tag;
secure_vector<uint8_t> m_contents;