Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

asn1_print.cpp
Go to the documentation of this file.
1 /*
2 * (C) 2014,2015,2017 Jack Lloyd
3 *
4 * Botan is released under the Simplified BSD License (see license.txt)
5 */
6
7 #include <botan/asn1_print.h>
8 #include <botan/bigint.h>
9 #include <botan/hex.h>
10 #include <botan/der_enc.h>
11 #include <botan/ber_dec.h>
12 #include <botan/asn1_time.h>
13 #include <botan/asn1_str.h>
14 #include <botan/oids.h>
15 #include <iomanip>
16 #include <sstream>
17 #include <cctype>
18
19 namespace Botan {
20
21 namespace {
22
23 bool all_printable_chars(const uint8_t bits[], size_t bits_len)
24 {
25 for(size_t i = 0; i != bits_len; ++i)
26 {
27 int c = bits[i];
28 if(c > 127)
29 return false;
30
31 if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false)
32 return false;
33 }
34 return true;
35 }
36
37 /*
38 * Special hack to handle GeneralName [2] and [6] (DNS name and URI)
39 */
40 bool possibly_a_general_name(const uint8_t bits[], size_t bits_len)
41 {
42 if(bits_len <= 2)
43 return false;
44
45 if(bits[0] != 0x82 && bits[0] != 0x86)
46 return false;
47
48 if(bits[1] != bits_len - 2)
49 return false;
50
51 if(all_printable_chars(bits + 2, bits_len - 2) == false)
52 return false;
53
54 return true;
55 }
56
57 }
58
59 std::string ASN1_Formatter::print(const uint8_t in[], size_t len) const
60 {
61 std::ostringstream output;
62 print_to_stream(output, in, len);
63 return output.str();
64 }
65
66 void ASN1_Formatter::print_to_stream(std::ostream& output,
67 const uint8_t in[],
68 size_t len) const
69 {
70 BER_Decoder dec(in, len);
71 decode(output, dec, 0);
72 }
73
74 void ASN1_Formatter::decode(std::ostream& output,
75 BER_Decoder& decoder,
76 size_t level) const
77 {
78 BER_Object obj = decoder.get_next_object();
79
80 const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth);
81
82 while(obj.is_set())
83 {
84 const ASN1_Tag type_tag = obj.type();
85 const ASN1_Tag class_tag = obj.get_class();
86 const size_t length = obj.length();
87
88 /* hack to insert the tag+length back in front of the stuff now
89 that we've gotten the type info */
90 std::vector<uint8_t> bits;
91 DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length());
92
93 BER_Decoder data(bits);
94
95 if(class_tag & CONSTRUCTED)
96 {
97 BER_Decoder cons_info(obj.bits(), obj.length());
98
99 if(recurse_deeper)
100 {
101 output << format(type_tag, class_tag, level, length, "");
102 decode(output, cons_info, level + 1); // recurse
103 }
104 else
105 {
106 output << format(type_tag, class_tag, level, length,
107 format_bin(type_tag, class_tag, bits));
108 }
109 }
110 else if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC))
111 {
112 bool success_parsing_cs = false;
113
114 if(m_print_context_specific)
115 {
116 try
117 {
118 if(possibly_a_general_name(bits.data(), bits.size()))
119 {
120 output << format(type_tag, class_tag, level, level,
121 std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2));
122 success_parsing_cs = true;
123 }
124 else if(recurse_deeper)
125 {
126 std::vector<uint8_t> inner_bits;
127 data.decode(inner_bits, type_tag);
128
129 BER_Decoder inner(inner_bits);
130 std::ostringstream inner_data;
131 decode(inner_data, inner, level + 1); // recurse
132 output << inner_data.str();
133 success_parsing_cs = true;
134 }
135 }
136 catch(...)
137 {
138 }
139 }
140
141 if(success_parsing_cs == false)
142 {
143 output << format(type_tag, class_tag, level, length,
144 format_bin(type_tag, class_tag, bits));
145 }
146 }
147 else if(type_tag == OBJECT_ID)
148 {
149 OID oid;
150 data.decode(oid);
151
152 std::string out = OIDS::oid2str_or_empty(oid);
153 if(out.empty())
154 {
155 out = oid.to_string();
156 }
157 else
158 {
159 out += " [" + oid.to_string() + "]";
160 }
161
162 output << format(type_tag, class_tag, level, length, out);
163 }
164 else if(type_tag == INTEGER || type_tag == ENUMERATED)
165 {
166 BigInt number;
167
168 if(type_tag == INTEGER)
169 {
170 data.decode(number);
171 }
172 else if(type_tag == ENUMERATED)
173 {
174 data.decode(number, ENUMERATED, class_tag);
175 }
176
177 std::vector<uint8_t> rep = BigInt::encode(number);
178 if(rep.empty()) // if zero
179 rep.resize(1);
180
181 output << format(type_tag, class_tag, level, length, hex_encode(rep));
182 }
183 else if(type_tag == BOOLEAN)
184 {
185 bool boolean;
186 data.decode(boolean);
187 output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false"));
188 }
189 else if(type_tag == NULL_TAG)
190 {
191 output << format(type_tag, class_tag, level, length, "");
192 }
193 else if(type_tag == OCTET_STRING || type_tag == BIT_STRING)
194 {
195 std::vector<uint8_t> decoded_bits;
196 data.decode(decoded_bits, type_tag);
197 bool printing_octet_string_worked = false;
198
199 if(recurse_deeper)
200 {
201 try
202 {
203 BER_Decoder inner(decoded_bits);
204
205 std::ostringstream inner_data;
206 decode(inner_data, inner, level + 1); // recurse
207
208 output << format(type_tag, class_tag, level, length, "");
209 output << inner_data.str();
210 printing_octet_string_worked = true;
211 }
212 catch(...)
213 {
214 }
215 }
216
217 if(!printing_octet_string_worked)
218 {
219 output << format(type_tag, class_tag, level, length,
220 format_bin(type_tag, class_tag, decoded_bits));
221 }
222 }
223 else if(ASN1_String::is_string_type(type_tag))
224 {
225 ASN1_String str;
226 data.decode(str);
227 output << format(type_tag, class_tag, level, length, str.value());
228 }
229 else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME)
230 {
231 X509_Time time;
232 data.decode(time);
233 output << format(type_tag, class_tag, level, length, time.readable_string());
234 }
235 else
236 {
237 output << "Unknown ASN.1 tag class=" << static_cast<int>(class_tag)
238 << " type=" << static_cast<int>(type_tag) << "\n";
239 }
240
241 obj = decoder.get_next_object();
242 }
243 }
244
245 namespace {
246
247 std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag)
248 {
249 if(class_tag == UNIVERSAL)
250 return asn1_tag_to_string(type_tag);
251
252 if(class_tag == CONSTRUCTED && (type_tag == SEQUENCE || type_tag == SET))
253 return asn1_tag_to_string(type_tag);
254
255 std::string name;
256
257 if(class_tag & CONSTRUCTED)
258 name += "cons ";
259
260 name += "[" + std::to_string(type_tag) + "]";
261
262 if(class_tag & APPLICATION)
263 {
264 name += " appl";
265 }
266 if(class_tag & CONTEXT_SPECIFIC)
267 {
268 name += " context";
269 }
270
271 return name;
272 }
273
274 }
275
276 std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag,
277 ASN1_Tag class_tag,
278 size_t level,
279 size_t length,
280 const std::string& value) const
281 {
282 bool should_skip = false;
283
284 if(value.length() > m_print_limit)
285 {
286 should_skip = true;
287 }
288
289 if((type_tag == OCTET_STRING || type_tag == BIT_STRING) &&
290 value.length() > m_print_binary_limit)
291 {
292 should_skip = true;
293 }
294
295 level += m_initial_level;
296
297 std::ostringstream oss;
298
299 oss << " d=" << std::setw(2) << level
300 << ", l=" << std::setw(4) << length << ":"
301 << std::string(level + 1, ' ') << format_type(type_tag, class_tag);
302
303 if(value != "" && !should_skip)
304 {
305 const size_t current_pos = static_cast<size_t>(oss.tellp());
306 const size_t spaces_to_align =
307 (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos);
308
309 oss << std::string(spaces_to_align, ' ') << value;
310 }
311
312 oss << "\n";
313
314 return oss.str();
315 }
316
317 std::string ASN1_Pretty_Printer::format_bin(ASN1_Tag /*type_tag*/,
318 ASN1_Tag /*class_tag*/,
319 const std::vector<uint8_t>& vec) const
320 {
321 if(all_printable_chars(vec.data(), vec.size()))
322 {
323 return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size());
324 }
325 else
326 return hex_encode(vec);
327 }
328
329 }
Botan::asn1_tag_to_string
std::string asn1_tag_to_string(ASN1_Tag type)
Definition: asn1_obj.cpp:108
Botan::hex_encode
void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase)
Definition: hex.cpp:14
Botan::DER_Encoder::add_object
DER_Encoder & add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, const uint8_t rep[], size_t length)
Definition: der_enc.cpp:249
Botan::BER_Object::type
ASN1_Tag type() const
Definition: asn1_obj.h:114
Botan::ASN1_String::is_string_type
static bool is_string_type(ASN1_Tag tag)
Definition: asn1_str.cpp:68
Botan::BER_Object::length
size_t length() const
Definition: asn1_obj.h:119
Botan::BigInt::encode
static std::vector< uint8_t > encode(const BigInt &n)
Definition: bigint.h:763
Botan::OIDS::oid2str_or_empty
BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID &oid)
Definition: oids.cpp:111
Botan::INTEGER
Definition: asn1_obj.h:34
Botan::BOOLEAN
Definition: asn1_obj.h:33
Botan::CONSTRUCTED
Definition: asn1_obj.h:28
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan::ASN1_Tag
ASN1_Tag
Definition: asn1_obj.h:23
Botan::ENUMERATED
Definition: asn1_obj.h:39
Botan::BER_Object::bits
const uint8_t * bits() const
Definition: asn1_obj.h:117
Botan::SEQUENCE
Definition: asn1_obj.h:40
Botan::DER_Encoder
Definition: der_enc.h:23
name
std::string name
Definition: commoncrypto_hash.cpp:23
Botan::BER_Object::get_class
ASN1_Tag get_class() const
Definition: asn1_obj.h:115
Botan::UNIVERSAL
Definition: asn1_obj.h:24
Botan::SET
Definition: asn1_obj.h:41
Botan::OBJECT_ID
Definition: asn1_obj.h:38
Botan::GENERALIZED_TIME
Definition: asn1_obj.h:53
Botan
Definition: alg_id.cpp:13
Botan::OCTET_STRING
Definition: asn1_obj.h:36
Botan::NULL_TAG
Definition: asn1_obj.h:37
Botan::BER_Decoder::get_next_object
BER_Object get_next_object()
Definition: ber_dec.cpp:237
Botan::ASN1_Formatter::print_to_stream
void print_to_stream(std::ostream &out, const uint8_t in[], size_t len) const
Definition: asn1_print.cpp:66
Botan::BER_Object::is_set
bool is_set() const
Definition: asn1_obj.h:110
Botan::APPLICATION
Definition: asn1_obj.h:25
Botan::ASN1_Formatter::format
virtual std::string format(ASN1_Tag type_tag, ASN1_Tag class_tag, size_t level, size_t length, const std::string &value) const =0
Botan::cast_uint8_ptr_to_char
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition: mem_ops.h:194
Botan::BIT_STRING
Definition: asn1_obj.h:35
Botan::ASN1_Formatter::format_bin
virtual std::string format_bin(ASN1_Tag type_tag, ASN1_Tag class_tag, const std::vector< uint8_t > &vec) const =0
Botan::ASN1_Formatter::print
std::string print(const uint8_t in[], size_t len) const
Definition: asn1_print.cpp:59
Botan::CONTEXT_SPECIFIC
Definition: asn1_obj.h:26
Botan::BER_Decoder
Definition: ber_dec.h:21
Botan::BER_Object
Definition: asn1_obj.h:97
Botan::UTC_TIME
Definition: asn1_obj.h:52