Coverage Report

Created: 2020-11-21 08:34

/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
832
   {
23
2.31k
   for(size_t i = 0; i != bits_len; ++i)
24
1.93k
      {
25
1.93k
      int c = bits[i];
26
1.93k
      if(c > 127)
27
208
         return false;
28
29
1.72k
      if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false)
30
251
         return false;
31
1.72k
      }
32
373
   return true;
33
832
   }
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
3.48k
   {
40
3.48k
   if(bits_len <= 2)
41
2.07k
      return false;
42
43
1.41k
   if(bits[0] != 0x82 && bits[0] != 0x86)
44
495
      return false;
45
46
922
   if(bits[1] != bits_len - 2)
47
90
      return false;
48
49
832
   if(all_printable_chars(bits + 2, bits_len - 2) == false)
50
459
      return false;
51
52
373
   return true;
53
373
   }
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.88k
   {
68
2.88k
   BER_Decoder dec(in, len);
69
2.88k
   decode(output, dec, 0);
70
2.88k
   }
71
72
void ASN1_Formatter::decode(std::ostream& output,
73
                            BER_Decoder& decoder,
74
                            size_t level) const
75
20.4k
   {
76
20.4k
   BER_Object obj = decoder.get_next_object();
77
78
20.4k
   const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth);
79
80
89.2k
   while(obj.is_set())
81
68.7k
      {
82
68.7k
      const ASN1_Tag type_tag = obj.type();
83
68.7k
      const ASN1_Tag class_tag = obj.get_class();
84
68.7k
      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
68.7k
      std::vector<uint8_t> bits;
89
68.7k
      DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length());
90
91
68.7k
      BER_Decoder data(bits);
92
93
68.7k
      if(class_tag & CONSTRUCTED)
94
4.64k
         {
95
4.64k
         BER_Decoder cons_info(obj.bits(), obj.length());
96
97
4.64k
         if(recurse_deeper)
98
4.44k
            {
99
4.44k
            output << format(type_tag, class_tag, level, length, "");
100
4.44k
            decode(output, cons_info, level + 1); // recurse
101
4.44k
            }
102
201
         else
103
201
            {
104
201
            output << format(type_tag, class_tag, level, length,
105
201
                             format_bin(type_tag, class_tag, bits));
106
201
            }
107
4.64k
         }
108
64.1k
      else if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC))
109
3.48k
         {
110
3.48k
         bool success_parsing_cs = false;
111
112
3.48k
         if(m_print_context_specific)
113
3.48k
            {
114
3.48k
            try
115
3.48k
               {
116
3.48k
               if(possibly_a_general_name(bits.data(), bits.size()))
117
373
                  {
118
373
                  output << format(type_tag, class_tag, level, level,
119
373
                                   std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2));
120
373
                  success_parsing_cs = true;
121
373
                  }
122
3.11k
               else if(recurse_deeper)
123
2.89k
                  {
124
2.89k
                  std::vector<uint8_t> inner_bits;
125
2.89k
                  data.decode(inner_bits, type_tag);
126
127
2.89k
                  BER_Decoder inner(inner_bits);
128
2.89k
                  std::ostringstream inner_data;
129
2.89k
                  decode(inner_data, inner, level + 1); // recurse
130
2.89k
                  output << inner_data.str();
131
2.89k
                  success_parsing_cs = true;
132
2.89k
                  }
133
3.48k
               }
134
3.48k
            catch(...)
135
2.89k
               {
136
2.89k
               }
137
3.48k
            }
138
139
3.48k
         if(success_parsing_cs == false)
140
3.11k
            {
141
3.11k
            output << format(type_tag, class_tag, level, length,
142
3.11k
                             format_bin(type_tag, class_tag, bits));
143
3.11k
            }
144
3.48k
         }
145
60.6k
      else if(type_tag == OBJECT_ID)
146
4.26k
         {
147
4.26k
         OID oid;
148
4.26k
         data.decode(oid);
149
150
4.26k
         std::string out = OIDS::oid2str_or_empty(oid);
151
4.26k
         if(out.empty())
152
2.94k
            {
153
2.94k
            out = oid.to_string();
154
2.94k
            }
155
1.32k
         else
156
1.32k
            {
157
1.32k
            out += " [" + oid.to_string() + "]";
158
1.32k
            }
159
160
4.26k
         output << format(type_tag, class_tag, level, length, out);
161
4.26k
         }
162
56.3k
      else if(type_tag == INTEGER || type_tag == ENUMERATED)
163
3.60k
         {
164
3.60k
         BigInt number;
165
166
3.60k
         if(type_tag == INTEGER)
167
2.86k
            {
168
2.86k
            data.decode(number);
169
2.86k
            }
170
741
         else if(type_tag == ENUMERATED)
171
741
            {
172
741
            data.decode(number, ENUMERATED, class_tag);
173
741
            }
174
175
3.60k
         std::vector<uint8_t> rep = BigInt::encode(number);
176
3.60k
         if(rep.empty()) // if zero
177
1.39k
            rep.resize(1);
178
179
3.60k
         output << format(type_tag, class_tag, level, length, hex_encode(rep));
180
3.60k
         }
181
52.7k
      else if(type_tag == BOOLEAN)
182
650
         {
183
650
         bool boolean;
184
650
         data.decode(boolean);
185
384
         output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false"));
186
650
         }
187
52.0k
      else if(type_tag == NULL_TAG)
188
199
         {
189
199
         output << format(type_tag, class_tag, level, length, "");
190
199
         }
191
51.8k
      else if(type_tag == OCTET_STRING || type_tag == BIT_STRING)
192
13.9k
         {
193
13.9k
         std::vector<uint8_t> decoded_bits;
194
13.9k
         data.decode(decoded_bits, type_tag);
195
13.9k
         bool printing_octet_string_worked = false;
196
197
13.9k
         if(recurse_deeper)
198
13.1k
            {
199
13.1k
            try
200
13.1k
               {
201
13.1k
               BER_Decoder inner(decoded_bits);
202
203
13.1k
               std::ostringstream inner_data;
204
13.1k
               decode(inner_data, inner, level + 1); // recurse
205
206
13.1k
               output << format(type_tag, class_tag, level, length, "");
207
13.1k
               output << inner_data.str();
208
13.1k
               printing_octet_string_worked = true;
209
13.1k
               }
210
13.1k
            catch(...)
211
7.84k
               {
212
7.84k
               }
213
13.1k
            }
214
215
13.9k
         if(!printing_octet_string_worked)
216
8.04k
            {
217
8.04k
            output << format(type_tag, class_tag, level, length,
218
8.04k
                             format_bin(type_tag, class_tag, decoded_bits));
219
8.04k
            }
220
13.9k
         }
221
37.9k
      else if(ASN1_String::is_string_type(type_tag))
222
2.93k
         {
223
2.93k
         ASN1_String str;
224
2.93k
         data.decode(str);
225
2.93k
         output << format(type_tag, class_tag, level, length, str.value());
226
2.93k
         }
227
35.0k
      else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME)
228
9.05k
         {
229
9.05k
         ASN1_Time time;
230
9.05k
         data.decode(time);
231
9.05k
         output << format(type_tag, class_tag, level, length, time.readable_string());
232
9.05k
         }
233
25.9k
      else
234
25.9k
         {
235
25.9k
         output << "Unknown ASN.1 tag class=" << static_cast<int>(class_tag)
236
25.9k
                << " type=" << static_cast<int>(type_tag) << "\n";
237
25.9k
         }
238
239
68.7k
      obj = decoder.get_next_object();
240
68.7k
      }
241
20.4k
   }
242
243
namespace {
244
245
std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag)
246
0
   {
247
0
   if(class_tag == UNIVERSAL)
248
0
      return asn1_tag_to_string(type_tag);
249
250
0
   if(class_tag == CONSTRUCTED && (type_tag == SEQUENCE || type_tag == SET))
251
0
      return asn1_tag_to_string(type_tag);
252
253
0
   std::string name;
254
255
0
   if(class_tag & CONSTRUCTED)
256
0
      name += "cons ";
257
258
0
   name += "[" + std::to_string(type_tag) + "]";
259
260
0
   if(class_tag & APPLICATION)
261
0
      {
262
0
      name += " appl";
263
0
      }
264
0
   if(class_tag & CONTEXT_SPECIFIC)
265
0
      {
266
0
      name += " context";
267
0
      }
268
269
0
   return name;
270
0
   }
271
272
}
273
274
std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag,
275
                                        ASN1_Tag class_tag,
276
                                        size_t level,
277
                                        size_t length,
278
                                        const std::string& value) const
279
0
   {
280
0
   bool should_skip = false;
281
282
0
   if(value.length() > m_print_limit)
283
0
      {
284
0
      should_skip = true;
285
0
      }
286
287
0
   if((type_tag == OCTET_STRING || type_tag == BIT_STRING) &&
288
0
      value.length() > m_print_binary_limit)
289
0
      {
290
0
      should_skip = true;
291
0
      }
292
293
0
   level += m_initial_level;
294
295
0
   std::ostringstream oss;
296
297
0
   oss << "  d=" << std::setw(2) << level
298
0
       << ", l=" << std::setw(4) << length << ":"
299
0
       << std::string(level + 1, ' ') << format_type(type_tag, class_tag);
300
301
0
   if(value != "" && !should_skip)
302
0
      {
303
0
      const size_t current_pos = static_cast<size_t>(oss.tellp());
304
0
      const size_t spaces_to_align =
305
0
         (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos);
306
307
0
      oss << std::string(spaces_to_align, ' ') << value;
308
0
      }
309
310
0
   oss << "\n";
311
312
0
   return oss.str();
313
0
   }
314
315
std::string ASN1_Pretty_Printer::format_bin(ASN1_Tag /*type_tag*/,
316
                                            ASN1_Tag /*class_tag*/,
317
                                            const std::vector<uint8_t>& vec) const
318
0
   {
319
0
   if(all_printable_chars(vec.data(), vec.size()))
320
0
      {
321
0
      return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size());
322
0
      }
323
0
   else
324
0
      return hex_encode(vec);
325
0
   }
326
327
}