Coverage Report

Created: 2023-02-13 06:21

/src/botan/src/lib/asn1/asn1_print.cpp
Line
Count
Source (jump to first uncovered line)
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/oids.h>
13
#include <iomanip>
14
#include <sstream>
15
#include <cctype>
16
17
namespace Botan {
18
19
namespace {
20
21
bool all_printable_chars(const uint8_t bits[], size_t bits_len)
22
1.08k
   {
23
7.67k
   for(size_t i = 0; i != bits_len; ++i)
24
7.07k
      {
25
7.07k
      int c = bits[i];
26
7.07k
      if(c > 127)
27
228
         return false;
28
29
6.84k
      if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false)
30
260
         return false;
31
6.84k
      }
32
600
   return true;
33
1.08k
   }
34
35
/*
36
* Special hack to handle GeneralName [2] and [6] (DNS name and URI)
37
*/
38
bool possibly_a_general_name(const uint8_t bits[], size_t bits_len)
39
4.01k
   {
40
4.01k
   if(bits_len <= 2)
41
2.00k
      return false;
42
43
2.00k
   if(bits[0] != 0x82 && bits[0] != 0x86)
44
820
      return false;
45
46
1.18k
   if(bits[1] != bits_len - 2)
47
100
      return false;
48
49
1.08k
   if(all_printable_chars(bits + 2, bits_len - 2) == false)
50
488
      return false;
51
52
600
   return true;
53
1.08k
   }
54
55
}
56
57
std::string ASN1_Formatter::print(const uint8_t in[], size_t len) const
58
0
   {
59
0
   std::ostringstream output;
60
0
   print_to_stream(output, in, len);
61
0
   return output.str();
62
0
   }
63
64
void ASN1_Formatter::print_to_stream(std::ostream& output,
65
                                     const uint8_t in[],
66
                                     size_t len) const
67
2.87k
   {
68
2.87k
   BER_Decoder dec(in, len);
69
2.87k
   decode(output, dec, 0);
70
2.87k
   }
71
72
void ASN1_Formatter::decode(std::ostream& output,
73
                            BER_Decoder& decoder,
74
                            size_t level) const
75
22.2k
   {
76
22.2k
   BER_Object obj = decoder.get_next_object();
77
78
22.2k
   const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth);
79
80
95.8k
   while(obj.is_set())
81
73.5k
      {
82
73.5k
      const ASN1_Type type_tag = obj.type();
83
73.5k
      const ASN1_Class class_tag = obj.get_class();
84
73.5k
      const size_t length = obj.length();
85
86
      /* hack to insert the tag+length back in front of the stuff now
87
         that we've gotten the type info */
88
73.5k
      std::vector<uint8_t> bits;
89
73.5k
      DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length());
90
91
73.5k
      BER_Decoder data(bits);
92
93
73.5k
      if(intersects(class_tag, ASN1_Class::Constructed))
94
5.74k
         {
95
5.74k
         BER_Decoder cons_info(obj.bits(), obj.length());
96
97
5.74k
         if(recurse_deeper)
98
5.54k
            {
99
5.54k
            output << format(type_tag, class_tag, level, length, "");
100
5.54k
            decode(output, cons_info, level + 1); // recurse
101
5.54k
            }
102
198
         else
103
198
            {
104
198
            output << format(type_tag, class_tag, level, length,
105
198
                             format_bin(type_tag, class_tag, bits));
106
198
            }
107
5.74k
         }
108
67.7k
      else if(intersects(class_tag, ASN1_Class::Application) || intersects(class_tag, ASN1_Class::ContextSpecific))
109
4.01k
         {
110
4.01k
         bool success_parsing_cs = false;
111
112
4.01k
         if(m_print_context_specific)
113
4.01k
            {
114
4.01k
            try
115
4.01k
               {
116
4.01k
               if(possibly_a_general_name(bits.data(), bits.size()))
117
600
                  {
118
600
                  output << format(type_tag, class_tag, level, level,
119
600
                                   std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2));
120
600
                  success_parsing_cs = true;
121
600
                  }
122
3.41k
               else if(recurse_deeper)
123
3.21k
                  {
124
3.21k
                  std::vector<uint8_t> inner_bits;
125
3.21k
                  data.decode(inner_bits, type_tag);
126
127
3.21k
                  BER_Decoder inner(inner_bits);
128
3.21k
                  std::ostringstream inner_data;
129
3.21k
                  decode(inner_data, inner, level + 1); // recurse
130
3.21k
                  output << inner_data.str();
131
3.21k
                  success_parsing_cs = true;
132
3.21k
                  }
133
4.01k
               }
134
4.01k
            catch(...)
135
4.01k
               {
136
3.21k
               }
137
4.01k
            }
138
139
4.01k
         if(success_parsing_cs == false)
140
3.41k
            {
141
3.41k
            output << format(type_tag, class_tag, level, length,
142
3.41k
                             format_bin(type_tag, class_tag, bits));
143
3.41k
            }
144
4.01k
         }
145
63.7k
      else if(type_tag == ASN1_Type::ObjectId)
146
3.42k
         {
147
3.42k
         OID oid;
148
3.42k
         data.decode(oid);
149
150
3.42k
         std::string out = OIDS::oid2str_or_empty(oid);
151
3.42k
         if(out.empty())
152
2.30k
            {
153
2.30k
            out = oid.to_string();
154
2.30k
            }
155
1.12k
         else
156
1.12k
            {
157
1.12k
            out += " [" + oid.to_string() + "]";
158
1.12k
            }
159
160
3.42k
         output << format(type_tag, class_tag, level, length, out);
161
3.42k
         }
162
60.3k
      else if(type_tag == ASN1_Type::Integer || type_tag == ASN1_Type::Enumerated)
163
1.77k
         {
164
1.77k
         BigInt number;
165
166
1.77k
         if(type_tag == ASN1_Type::Integer)
167
1.44k
            {
168
1.44k
            data.decode(number);
169
1.44k
            }
170
335
         else if(type_tag == ASN1_Type::Enumerated)
171
335
            {
172
335
            data.decode(number, ASN1_Type::Enumerated, class_tag);
173
335
            }
174
175
1.77k
         output << format(type_tag, class_tag, level, length, format_bn(number));
176
1.77k
         }
177
58.5k
      else if(type_tag == ASN1_Type::Boolean)
178
637
         {
179
637
         bool boolean;
180
637
         data.decode(boolean);
181
637
         output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false"));
182
637
         }
183
57.9k
      else if(type_tag == ASN1_Type::Null)
184
262
         {
185
262
         output << format(type_tag, class_tag, level, length, "");
186
262
         }
187
57.6k
      else if(type_tag == ASN1_Type::OctetString || type_tag == ASN1_Type::BitString)
188
14.7k
         {
189
14.7k
         std::vector<uint8_t> decoded_bits;
190
14.7k
         data.decode(decoded_bits, type_tag);
191
14.7k
         bool printing_octet_string_worked = false;
192
193
14.7k
         if(recurse_deeper)
194
13.8k
            {
195
13.8k
            try
196
13.8k
               {
197
13.8k
               BER_Decoder inner(decoded_bits);
198
199
13.8k
               std::ostringstream inner_data;
200
13.8k
               decode(inner_data, inner, level + 1); // recurse
201
202
13.8k
               output << format(type_tag, class_tag, level, length, "");
203
13.8k
               output << inner_data.str();
204
13.8k
               printing_octet_string_worked = true;
205
13.8k
               }
206
13.8k
            catch(...)
207
13.8k
               {
208
9.57k
               }
209
13.8k
            }
210
211
14.7k
         if(!printing_octet_string_worked)
212
9.76k
            {
213
9.76k
            output << format(type_tag, class_tag, level, length,
214
9.76k
                             format_bin(type_tag, class_tag, decoded_bits));
215
9.76k
            }
216
14.7k
         }
217
42.9k
      else if(ASN1_String::is_string_type(type_tag))
218
4.47k
         {
219
4.47k
         ASN1_String str;
220
4.47k
         data.decode(str);
221
4.47k
         output << format(type_tag, class_tag, level, length, str.value());
222
4.47k
         }
223
38.4k
      else if(type_tag == ASN1_Type::UtcTime || type_tag == ASN1_Type::GeneralizedTime)
224
7.38k
         {
225
7.38k
         ASN1_Time time;
226
7.38k
         data.decode(time);
227
7.38k
         output << format(type_tag, class_tag, level, length, time.readable_string());
228
7.38k
         }
229
31.0k
      else
230
31.0k
         {
231
31.0k
         output << "Unknown ASN.1 tag class=" << static_cast<int>(class_tag)
232
31.0k
                << " type=" << static_cast<int>(type_tag) << "\n";
233
31.0k
         }
234
235
73.5k
      obj = decoder.get_next_object();
236
73.5k
      }
237
22.2k
   }
238
239
namespace {
240
241
std::string format_type(ASN1_Type type_tag, ASN1_Class class_tag)
242
0
   {
243
0
   if(class_tag == ASN1_Class::Universal)
244
0
      return asn1_tag_to_string(type_tag);
245
246
0
   if(class_tag == ASN1_Class::Constructed && (type_tag == ASN1_Type::Sequence || type_tag == ASN1_Type::Set))
247
0
      return asn1_tag_to_string(type_tag);
248
249
0
   std::ostringstream oss;
250
251
0
   if(intersects(class_tag, ASN1_Class::Constructed))
252
0
      oss << "cons ";
253
254
0
   oss << "[" << std::to_string(static_cast<uint32_t>(type_tag)) << "]";
255
256
0
   if(intersects(class_tag, ASN1_Class::Application))
257
0
      {
258
0
      oss << " appl";
259
0
      }
260
0
   if(intersects(class_tag, ASN1_Class::ContextSpecific))
261
0
      {
262
0
      oss << " context";
263
0
      }
264
265
0
   return oss.str();
266
0
   }
267
268
}
269
270
std::string ASN1_Pretty_Printer::format(ASN1_Type type_tag,
271
                                        ASN1_Class class_tag,
272
                                        size_t level,
273
                                        size_t length,
274
                                        const std::string& value) const
275
0
   {
276
0
   bool should_skip = false;
277
278
0
   if(value.length() > m_print_limit)
279
0
      {
280
0
      should_skip = true;
281
0
      }
282
283
0
   if((type_tag == ASN1_Type::OctetString || type_tag == ASN1_Type::BitString) &&
284
0
      value.length() > m_print_binary_limit)
285
0
      {
286
0
      should_skip = true;
287
0
      }
288
289
0
   level += m_initial_level;
290
291
0
   std::ostringstream oss;
292
293
0
   oss << "  d=" << std::setw(2) << level
294
0
       << ", l=" << std::setw(4) << length << ":"
295
0
       << std::string(level + 1, ' ') << format_type(type_tag, class_tag);
296
297
0
   if(!value.empty() && !should_skip)
298
0
      {
299
0
      const size_t current_pos = static_cast<size_t>(oss.tellp());
300
0
      const size_t spaces_to_align =
301
0
         (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos);
302
303
0
      oss << std::string(spaces_to_align, ' ') << value;
304
0
      }
305
306
0
   oss << "\n";
307
308
0
   return oss.str();
309
0
   }
310
311
std::string ASN1_Pretty_Printer::format_bin(ASN1_Type /*type_tag*/,
312
                                            ASN1_Class /*class_tag*/,
313
                                            const std::vector<uint8_t>& vec) const
314
0
   {
315
0
   if(all_printable_chars(vec.data(), vec.size()))
316
0
      {
317
0
      return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size());
318
0
      }
319
0
   else
320
0
      return hex_encode(vec);
321
0
   }
322
323
std::string ASN1_Pretty_Printer::format_bn(const BigInt& bn) const
324
0
   {
325
0
   if(bn.bits() < 16)
326
0
      return bn.to_dec_string();
327
0
   else
328
0
      return bn.to_hex_string();
329
0
   }
330
331
}