7#include <botan/asn1_print.h>
9#include <botan/asn1_time.h>
10#include <botan/ber_dec.h>
11#include <botan/bigint.h>
12#include <botan/der_enc.h>
14#include <botan/internal/charset.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/mem_utils.h>
24bool all_printable_chars(
const uint8_t bits[],
size_t bits_len) {
28 for(
size_t i = 0; i != bits_len; ++i) {
29 if(!is_printable_char(bits[i])) {
39bool possibly_a_general_name(
const uint8_t bits[],
size_t bits_len) {
44 if(bits[0] != 0x82 && bits[0] != 0x86) {
48 if(bits[1] != bits_len - 2) {
52 if(!all_printable_chars(bits + 2, bits_len - 2)) {
62 std::ostringstream output;
70 const auto decoder_limits =
72 BER_Decoder dec(std::span<const uint8_t>{in, len}, decoder_limits);
73 decode(output, dec, 0);
76void ASN1_Formatter::decode(std::ostream& output,
BER_Decoder& decoder,
size_t level)
const {
79 const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth);
84 const size_t length = obj.
length();
88 output <<
format(type_tag, class_tag, level, length,
"");
92 decode(output, cons_info, level + 1);
94 std::vector<uint8_t> bits;
95 DER_Encoder(bits).add_object(type_tag, class_tag, obj.
bits(), obj.
length());
96 output <<
format(type_tag, class_tag, level, length,
format_bin(type_tag, class_tag, bits));
105 std::vector<uint8_t> bits;
106 DER_Encoder(bits).add_object(type_tag, class_tag, obj.
bits(), obj.
length());
108 BER_Decoder data(bits, decoder.
limits());
111 bool success_parsing_cs =
false;
113 if(m_print_context_specific) {
115 if(possibly_a_general_name(bits.data(), bits.size())) {
117 success_parsing_cs =
true;
118 }
else if(recurse_deeper) {
119 std::vector<uint8_t> inner_bits;
120 data.decode(inner_bits, type_tag);
122 BER_Decoder inner(inner_bits, decoder.
limits());
123 std::ostringstream inner_data;
124 decode(inner_data, inner, level + 1);
125 output << inner_data.str();
126 success_parsing_cs =
true;
131 if(!success_parsing_cs) {
132 output <<
format(type_tag, class_tag, level, length,
format_bin(type_tag, class_tag, bits));
138 const std::string oid_str = oid.to_string();
140 if(
const auto name = oid.registered_name()) {
141 output <<
format(type_tag, class_tag, level, length,
fmt(
"{} [{}]", *name, oid_str));
143 output <<
format(type_tag, class_tag, level, length, oid_str);
154 output <<
format(type_tag, class_tag, level, length,
format_bn(number));
156 bool boolean =
false;
157 data.decode(
boolean);
158 output <<
format(type_tag, class_tag, level, length, (
boolean ?
"true" :
"false"));
160 output <<
format(type_tag, class_tag, level, length,
"");
162 std::vector<uint8_t> decoded_bits;
163 data.decode(decoded_bits, type_tag);
164 bool printing_octet_string_worked =
false;
168 BER_Decoder inner(decoded_bits, decoder.
limits());
170 std::ostringstream inner_data;
171 decode(inner_data, inner, level + 1);
173 output <<
format(type_tag, class_tag, level, length,
"");
174 output << inner_data.str();
175 printing_octet_string_worked =
true;
179 if(!printing_octet_string_worked) {
180 output <<
format(type_tag, class_tag, level, length,
format_bin(type_tag, class_tag, decoded_bits));
185 output <<
format(type_tag, class_tag, level, length, str.value());
189 output <<
format(type_tag, class_tag, level, length, time.readable_string());
191 output <<
"Unknown ASN.1 tag class=" <<
static_cast<int>(class_tag) <<
" type=" <<
static_cast<int>(type_tag)
210 std::ostringstream oss;
216 oss <<
"[" << std::to_string(
static_cast<uint32_t
>(type_tag)) <<
"]";
230std::string ASN1_Pretty_Printer::format(
231 ASN1_Type type_tag,
ASN1_Class class_tag,
size_t level,
size_t length, std::string_view value)
const {
232 bool should_skip =
false;
234 if(value.length() > m_print_limit) {
239 value.length() > m_print_binary_limit) {
243 level += m_initial_level;
245 std::ostringstream oss;
247 oss <<
" d=" << std::setw(2) << level <<
", l=" << std::setw(4) << length <<
":" << std::string(level + 1,
' ')
248 << format_type(type_tag, class_tag);
250 if(!value.empty() && !should_skip) {
251 const size_t current_pos =
static_cast<size_t>(oss.tellp());
252 const size_t spaces_to_align = (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos);
262std::string ASN1_Pretty_Printer::format_bin(
ASN1_Type ,
264 const std::vector<uint8_t>& vec)
const {
268 if(vec.size() > m_print_binary_limit) {
272 if(all_printable_chars(vec.data(), vec.size())) {
279std::string ASN1_Pretty_Printer::format_bn(
const BigInt& bn)
const {
281 return bn.to_dec_string();
283 return bn.to_hex_string();
static bool is_string_type(ASN1_Type tag)
static Limits BER(size_t max_nested_indef=16)
Limits with_standalone_eoc_allowed() const
BER_Object get_next_object()
const uint8_t * bits() const
ASN1_Class get_class() const
static constexpr CharacterValidityTable alpha_numeric_plus(std::string_view extras)
std::string asn1_tag_to_string(ASN1_Type type)
std::string fmt(std::string_view format, const T &... args)
std::string bytes_to_string(std::span< const uint8_t > bytes)
void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase)
bool intersects(ASN1_Class x, ASN1_Class y)
std::string escape_control_chars(std::string_view utf8)