diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/asn1/der_enc.cpp')
-rw-r--r-- | comm/third_party/botan/src/lib/asn1/der_enc.cpp | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/asn1/der_enc.cpp b/comm/third_party/botan/src/lib/asn1/der_enc.cpp new file mode 100644 index 0000000000..056766f435 --- /dev/null +++ b/comm/third_party/botan/src/lib/asn1/der_enc.cpp @@ -0,0 +1,405 @@ +/* +* DER Encoder +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/der_enc.h> +#include <botan/asn1_obj.h> +#include <botan/bigint.h> +#include <botan/loadstor.h> +#include <botan/internal/bit_ops.h> +#include <algorithm> + +namespace Botan { + +namespace { + +/* +* DER encode an ASN.1 type 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)); + + if(type_tag <= 30) + { + encoded_tag.push_back(static_cast<uint8_t>(type_tag | class_tag)); + } + else + { + size_t blocks = high_bit(static_cast<uint32_t>(type_tag)) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + 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); + } + } + +/* +* DER encode an ASN.1 length field +*/ +void encode_length(std::vector<uint8_t>& encoded_length, size_t length) + { + if(length <= 127) + { + encoded_length.push_back(static_cast<uint8_t>(length)); + } + else + { + const size_t bytes_needed = significant_bytes(length); + + encoded_length.push_back(static_cast<uint8_t>(0x80 | bytes_needed)); + + for(size_t i = sizeof(length) - bytes_needed; i < sizeof(length); ++i) + encoded_length.push_back(get_byte(i, length)); + } + } + +} + +DER_Encoder::DER_Encoder(secure_vector<uint8_t>& vec) + { + m_append_output = [&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 = [&vec](const uint8_t b[], size_t l) + { + vec.insert(vec.end(), b, b + l); + }; + } + +/* +* Push the encoded SEQUENCE/SET to the encoder stream +*/ +void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der) + { + const ASN1_Tag real_class_tag = ASN1_Tag(m_class_tag | CONSTRUCTED); + + if(m_type_tag == SET) + { + std::sort(m_set_contents.begin(), m_set_contents.end()); + for(size_t i = 0; i != m_set_contents.size(); ++i) + m_contents += m_set_contents[i]; + m_set_contents.clear(); + } + + der.add_object(m_type_tag, real_class_tag, m_contents.data(), m_contents.size()); + m_contents.clear(); + } + +/* +* Add an encoded value to the SEQUENCE/SET +*/ +void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length) + { + if(m_type_tag == SET) + m_set_contents.push_back(secure_vector<uint8_t>(data, data + length)); + else + 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 +*/ +ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const + { + return ASN1_Tag(m_type_tag | m_class_tag); + } + +/* +* DER_Sequence Constructor +*/ +DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) : + m_type_tag(t1), m_class_tag(t2) + { + } + +/* +* Return the encoded contents +*/ +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) + throw Invalid_State("DER_Encoder Cannot get contents when using output vector"); + + secure_vector<uint8_t> output; + std::swap(output, m_default_outbuf); + 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"); + + if(m_append_output) + 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; + } + +/* +* Start a new ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + m_subsequences.push_back(DER_Sequence(type_tag, class_tag)); + return (*this); + } + +/* +* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::end_cons() + { + if(m_subsequences.empty()) + throw Invalid_State("DER_Encoder::end_cons: No such sequence"); + + DER_Sequence last_seq = std::move(m_subsequences[m_subsequences.size()-1]); + m_subsequences.pop_back(); + last_seq.push_contents(*this); + + return (*this); + } + +/* +* Start a new ASN.1 EXPLICIT encoding +*/ +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) not supported"); + + return start_cons(type_tag, CONTEXT_SPECIFIC); + } + +/* +* Finish the current ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::end_explicit() + { + return end_cons(); + } + +/* +* Write raw bytes into the stream +*/ +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 if(m_append_output) + { + m_append_output(bytes, length); + } + else + { + 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) + { + m_append_output(hdr.data(), hdr.size()); + m_append_output(rep, length); + } + else + { + m_default_outbuf += hdr; + m_default_outbuf += std::make_pair(rep, length); + } + + return (*this); + } + +/* +* Encode a NULL object +*/ +DER_Encoder& DER_Encoder::encode_null() + { + return add_object(NULL_TAG, UNIVERSAL, nullptr, 0); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true) + { + return encode(is_true, BOOLEAN, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n) + { + return encode(BigInt(n), INTEGER, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n) + { + return encode(n, INTEGER, UNIVERSAL); + } + +/* +* Encode this object +*/ +DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, + ASN1_Tag real_type) + { + return encode(bytes, length, real_type, real_type, UNIVERSAL); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + uint8_t val = is_true ? 0xFF : 0x00; + return add_object(type_tag, class_tag, &val, 1); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(BigInt(n), type_tag, class_tag); + } + +/* +* DER encode an INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(n == 0) + return add_object(type_tag, class_tag, 0); + + const size_t extra_zero = (n.bits() % 8 == 0) ? 1 : 0; + secure_vector<uint8_t> contents(extra_zero + n.bytes()); + n.binary_encode(&contents[extra_zero]); + if(n < 0) + { + for(size_t i = 0; i != contents.size(); ++i) + contents[i] = ~contents[i]; + for(size_t i = contents.size(); i > 0; --i) + if(++contents[i-1]) + break; + } + + return add_object(type_tag, class_tag, contents); + } + +/* +* 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) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string"); + + if(real_type == BIT_STRING) + { + secure_vector<uint8_t> encoded; + encoded.push_back(0); + encoded += std::make_pair(bytes, length); + return add_object(type_tag, class_tag, encoded); + } + else + return add_object(type_tag, class_tag, bytes, length); + } + +DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj) + { + obj.encode_into(*this); + 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()); + const size_t rep_len = rep_str.size(); + return add_object(type_tag, class_tag, rep, rep_len); + } + +/* +* Write the encoding of the byte +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, + ASN1_Tag class_tag, uint8_t rep) + { + return add_object(type_tag, class_tag, &rep, 1); + } + +} |