8#include <botan/ber_dec.h>
10#include <botan/bigint.h>
11#include <botan/data_src.h>
12#include <botan/internal/int_utils.h>
13#include <botan/internal/loadstor.h>
28 auto b = ber->read_byte();
36 if((*b & 0x1F) != 0x1F) {
51 if((tag_buf >> 24) != 0) {
58 if(tag_bytes == 1 && (*b & 0x7F) == 0) {
62 tag_buf = (tag_buf << 7) | (*b & 0x7F);
63 if((*b & 0x80) == 0) {
87size_t find_eoc(
DataSource* src,
size_t base_offset,
size_t allow_indef);
96class BerDecodedLength final {
98 BerDecodedLength(
size_t content_length,
size_t field_length) :
99 BerDecodedLength(content_length, field_length, false) {}
101 static BerDecodedLength indefinite(
size_t content_length,
size_t field_length) {
102 return BerDecodedLength(content_length, field_length,
true);
105 size_t content_length()
const {
return m_content_length; }
108 size_t total_length()
const {
return m_indefinite ? m_content_length + 2 : m_content_length; }
110 size_t field_length()
const {
return m_field_length; }
112 bool indefinite_length()
const {
return m_indefinite; }
115 BerDecodedLength(
size_t content_length,
size_t field_length,
bool indefinite) :
116 m_content_length(content_length), m_field_length(field_length), m_indefinite(indefinite) {}
118 size_t m_content_length;
119 size_t m_field_length;
126BerDecodedLength decode_length(
DataSource* ber,
size_t allow_indef,
bool der_mode,
bool constructed) {
128 if(ber->read_byte(b) == 0) {
131 if((b & 0x80) == 0) {
132 return BerDecodedLength(b, 1);
135 const size_t num_length_bytes = (b & 0x7F);
136 if(num_length_bytes > 4) {
140 const size_t field_size = 1 + num_length_bytes;
142 if(num_length_bytes == 0) {
145 }
else if(!constructed) {
147 throw BER_Decoding_Error(
"Indefinite-length encoding used with non-constructed type");
148 }
else if(allow_indef == 0) {
149 throw BER_Decoding_Error(
"Nested EOC markers too deep, rejecting to avoid stack exhaustion");
153 const size_t eoc_len = find_eoc(ber, 0, allow_indef - 1);
157 return BerDecodedLength::indefinite(eoc_len - 2, field_size);
163 for(
size_t i = 0; i != num_length_bytes; ++i) {
164 if(ber->read_byte(b) == 0) {
168 length = (length << 8) | b;
176 if(num_length_bytes > 1 && length < (
size_t(1) << ((num_length_bytes - 1) * 8))) {
181 return BerDecodedLength(length, field_size);
190 if(src->peek(&b, 1, offset) == 0) {
196 if((b & 0x1F) != 0x1F) {
203 size_t tag_bytes = 1;
204 uint32_t tag_buf = 0;
207 if(src->peek(&b, 1, offset + tag_bytes) == 0) {
210 if((tag_buf >> 24) != 0) {
217 if(tag_bytes == 1 && (b & 0x7F) == 0) {
221 tag_buf = (tag_buf << 7) | (b & 0x7F);
222 if((b & 0x80) == 0) {
248size_t peek_length(
DataSource* src,
size_t offset,
size_t& field_size,
size_t allow_indef,
bool constructed) {
250 if(src->peek(&b, 1, offset) == 0) {
255 if((b & 0x80) == 0) {
259 const size_t num_length_bytes = (b & 0x7F);
260 field_size += num_length_bytes;
265 if(num_length_bytes == 0) {
268 throw BER_Decoding_Error(
"Indefinite-length encoding used with non-constructed type");
270 if(allow_indef == 0) {
271 throw BER_Decoding_Error(
"Nested EOC markers too deep, rejecting to avoid stack exhaustion");
273 return find_eoc(src, offset + 1, allow_indef - 1);
277 for(
size_t i = 0; i < num_length_bytes; ++i) {
278 if(src->peek(&b, 1, offset + 1 + i) == 0) {
284 length = (length << 8) | b;
293size_t find_eoc(
DataSource* src,
size_t base_offset,
size_t allow_indef) {
294 size_t offset = base_offset;
299 const size_t tag_size = peek_tag(src, offset, type_tag, class_tag);
304 size_t length_size = 0;
305 const size_t item_size = peek_length(src, offset + tag_size, length_size, allow_indef, is_constructed(class_tag));
307 if(
auto new_offset =
checked_add(offset, tag_size, length_size, item_size)) {
308 offset = new_offset.value();
315 if(length_size != 1 || item_size != 0) {
322 return offset - base_offset;
325class DataSource_BERObject final :
public DataSource {
327 size_t read(uint8_t out[],
size_t length)
override {
329 const size_t got = std::min<size_t>(m_obj.length() - m_offset, length);
330 copy_mem(out, m_obj.bits() + m_offset, got);
335 size_t peek(uint8_t out[],
size_t length,
size_t peek_offset)
const override {
337 const size_t bytes_left = m_obj.length() - m_offset;
339 if(peek_offset >= bytes_left) {
343 const size_t got = std::min(bytes_left - peek_offset, length);
344 copy_mem(out, m_obj.bits() + m_offset + peek_offset, got);
348 bool check_available(
size_t n)
override {
350 return (n <= (m_obj.length() - m_offset));
353 bool end_of_data()
const override {
return get_bytes_read() == m_obj.length(); }
355 size_t get_bytes_read()
const override {
return m_offset; }
357 explicit DataSource_BERObject(BER_Object&& obj) : m_obj(std::move(obj)) {}
372 if(m_source->end_of_data() && !m_pushed.is_set()) {
382 return verify_end(
"BER_Decoder::verify_end called, but data remains");
389 if(!m_source->end_of_data() || m_pushed.is_set()) {
401 while(m_source->read_byte(buf) != 0) {}
405std::optional<uint8_t> BER_Decoder::read_next_byte() {
416 if(!m_pushed.is_set()) {
429 if(m_pushed.is_set()) {
430 std::swap(next, m_pushed);
437 decode_tag(m_source, type_tag, class_tag);
438 next.set_tagging(type_tag, class_tag);
439 if(next.
is_set() ==
false) {
443 const size_t allow_indef = m_limits.allow_ber_encoding() ? m_limits.max_nested_indefinite_length() : 0;
444 const bool der_mode = m_limits.require_der_encoding();
445 const auto dl = decode_length(m_source, allow_indef, der_mode, is_constructed(class_tag));
451 (dl.content_length() != 0 || dl.indefinite_length())) {
455 if(!m_source->check_available(dl.total_length())) {
459 uint8_t* out = next.mutable_bits(dl.content_length());
460 if(m_source->read(out, dl.content_length()) != dl.content_length()) {
464 if(dl.indefinite_length()) {
466 uint8_t eoc[2] = {0xFF, 0xFF};
467 if(m_source->read(eoc, 2) != 2 || eoc[0] != 0x00 || eoc[1] != 0x00) {
473 if(m_limits.require_der_encoding()) {
489 if(obj.
length() != sizeofT) {
491 "; Output type size is " + std::to_string(sizeofT));
501 if(m_pushed.is_set()) {
502 throw Invalid_State(
"BER_Decoder: Only one push back is allowed");
508 if(m_pushed.is_set()) {
509 throw Invalid_State(
"BER_Decoder: Only one push back is allowed");
511 m_pushed = std::move(obj);
525 if(m_parent ==
nullptr) {
526 throw Invalid_State(
"BER_Decoder::end_cons called with null parent");
528 if(!m_source->end_of_data() || m_pushed.is_set()) {
529 throw Decoding_Error(
"BER_Decoder::end_cons called with data left");
535 m_limits(parent != nullptr ? parent->limits() :
BER_Decoder::Limits::BER()), m_parent(parent) {
536 m_data_src = std::make_unique<DataSource_BERObject>(std::move(obj));
537 m_source = m_data_src.get();
549 m_data_src = std::make_unique<DataSource_Memory>(buf);
550 m_source = m_data_src.get();
561 obj.decode_from(*
this);
595 const uint8_t val = obj.
bits()[0];
598 if(m_limits.require_der_encoding() && val != 0x00 && val != 0xFF) {
602 out = (val != 0) ?
true :
false;
612 decode(integer, type_tag, class_tag);
614 if(integer.
signum() < 0) {
618 if(integer.
bits() > 32) {
623 for(
size_t i = 0; i != 4; ++i) {
624 out = (out << 8) | integer.
byte_at(3 - i);
639 decode(integer, type_tag, class_tag);
645 if(integer.
bits() > 8 * T_bytes) {
650 for(
size_t i = 0; i != 8; ++i) {
651 out = (out << 8) | integer.
byte_at(7 - i);
665 if(m_limits.require_der_encoding()) {
670 if(obj.
bits()[0] == 0x00 && (obj.
bits()[1] & 0x80) == 0) {
673 if(obj.
bits()[0] == 0xFF && (obj.
bits()[1] & 0x80) != 0) {
682 const uint8_t first = obj.
bits()[0];
683 const bool negative = (first & 0x80) == 0x80;
687 for(
size_t i = obj.
length(); i > 0; --i) {
688 const bool gt0 = (vec[i - 1] > 0);
694 for(
size_t i = 0; i != obj.
length(); ++i) {
713template <
typename Alloc>
714void asn1_decode_binary_string(std::vector<uint8_t, Alloc>& buffer,
715 const BER_Object& obj,
720 obj.assert_is_a(type_tag, class_tag);
723 if(require_der && is_constructed(obj)) {
724 throw BER_Decoding_Error(
"Detected constructed string encoding in DER structure");
728 buffer.assign(obj.bits(), obj.bits() + obj.length());
730 if(obj.length() == 0) {
734 const uint8_t unused_bits = obj.bits()[0];
736 if(unused_bits >= 8) {
741 if(unused_bits > 0 && obj.length() < 2) {
746 if(require_der && unused_bits > 0) {
747 const uint8_t last_byte = obj.bits()[obj.length() - 1];
748 if((last_byte & ((1 << unused_bits) - 1)) != 0) {
749 throw BER_Decoding_Error(
"Detected non-zero padding bits in BIT STRING in DER structure");
753 buffer.resize(obj.length() - 1);
755 if(obj.length() > 1) {
756 copy_mem(buffer.data(), obj.bits() + 1, obj.length() - 1);
771 throw BER_Bad_Tag(
"Bad tag for {BIT,OCTET} STRING",
static_cast<uint32_t
>(real_type));
774 asn1_decode_binary_string(
775 buffer,
get_next_object(), real_type, type_tag, class_tag, m_limits.require_der_encoding());
784 throw BER_Bad_Tag(
"Bad tag for {BIT,OCTET} STRING",
static_cast<uint32_t
>(real_type));
787 asn1_decode_binary_string(
788 buffer,
get_next_object(), real_type, type_tag, class_tag, m_limits.require_der_encoding());
#define BOTAN_ASSERT_NOMSG(expr)
const BER_Object & peek_next_object()
void push_back(const BER_Object &obj)
BER_Object get_next_object()
BER_Decoder & get_next_value(T &out, ASN1_Type type_tag, ASN1_Class class_tag=ASN1_Class::ContextSpecific)
BER_Decoder & decode(bool &out)
uint64_t decode_constrained_integer(ASN1_Type type_tag, ASN1_Class class_tag, size_t T_bytes)
BER_Decoder & verify_end()
BER_Decoder(const uint8_t buf[], size_t len, Limits limits=Limits::BER())
BER_Decoder start_cons(ASN1_Type type_tag, ASN1_Class class_tag)
BER_Decoder & discard_remaining()
BER_Decoder & decode_octet_string_bigint(BigInt &b)
BER_Decoder & decode_null()
BER_Decoder & operator=(const BER_Decoder &)=delete
const uint8_t * bits() const
void assert_is_a(ASN1_Type type_tag, ASN1_Class class_tag, std::string_view descr="object") const
std::span< const uint8_t > data() const
ASN1_Class class_tag() const
static BigInt from_bytes(std::span< const uint8_t > bytes)
uint8_t byte_at(size_t n) const
void _assign_from_bytes(std::span< const uint8_t > bytes)
size_t read_byte(uint8_t &out)
constexpr uint8_t get_byte(T input)
constexpr std::optional< T > checked_add(T a, T b)
constexpr void copy_mem(T *out, const T *in, size_t n)
std::vector< T, secure_allocator< T > > secure_vector