Coverage Report

Created: 2020-06-30 13:58

/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/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
686
   {
25
1.97k
   for(size_t i = 0; i != bits_len; ++i)
26
1.73k
      {
27
1.73k
      int c = bits[i];
28
1.73k
      if(c > 127)
29
212
         return false;
30
1.52k
31
1.52k
      if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false)
32
237
         return false;
33
1.52k
      }
34
686
   return true;
35
686
   }
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
3.70k
   {
42
3.70k
   if(bits_len <= 2)
43
2.31k
      return false;
44
1.39k
45
1.39k
   if(bits[0] != 0x82 && bits[0] != 0x86)
46
603
      return false;
47
787
48
787
   if(bits[1] != bits_len - 2)
49
101
      return false;
50
686
51
686
   if(all_printable_chars(bits + 2, bits_len - 2) == false)
52
449
      return false;
53
237
54
237
   return true;
55
237
   }
56
57
}
58
59
std::string ASN1_Formatter::print(const uint8_t in[], size_t len) const
60
0
   {
61
0
   std::ostringstream output;
62
0
   print_to_stream(output, in, len);
63
0
   return output.str();
64
0
   }
65
66
void ASN1_Formatter::print_to_stream(std::ostream& output,
67
                                     const uint8_t in[],
68
                                     size_t len) const
69
2.74k
   {
70
2.74k
   BER_Decoder dec(in, len);
71
2.74k
   decode(output, dec, 0);
72
2.74k
   }
73
74
void ASN1_Formatter::decode(std::ostream& output,
75
                            BER_Decoder& decoder,
76
                            size_t level) const
77
20.5k
   {
78
20.5k
   BER_Object obj = decoder.get_next_object();
79
20.5k
80
20.5k
   const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth);
81
20.5k
82
94.3k
   while(obj.is_set())
83
73.8k
      {
84
73.8k
      const ASN1_Tag type_tag = obj.type();
85
73.8k
      const ASN1_Tag class_tag = obj.get_class();
86
73.8k
      const size_t length = obj.length();
87
73.8k
88
73.8k
      /* hack to insert the tag+length back in front of the stuff now
89
73.8k
         that we've gotten the type info */
90
73.8k
      std::vector<uint8_t> bits;
91
73.8k
      DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length());
92
73.8k
93
73.8k
      BER_Decoder data(bits);
94
73.8k
95
73.8k
      if(class_tag & CONSTRUCTED)
96
4.79k
         {
97
4.79k
         BER_Decoder cons_info(obj.bits(), obj.length());
98
4.79k
99
4.79k
         if(recurse_deeper)
100
4.46k
            {
101
4.46k
            output << format(type_tag, class_tag, level, length, "");
102
4.46k
            decode(output, cons_info, level + 1); // recurse
103
4.46k
            }
104
335
         else
105
335
            {
106
335
            output << format(type_tag, class_tag, level, length,
107
335
                             format_bin(type_tag, class_tag, bits));
108
335
            }
109
4.79k
         }
110
69.0k
      else if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC))
111
3.70k
         {
112
3.70k
         bool success_parsing_cs = false;
113
3.70k
114
3.70k
         if(m_print_context_specific)
115
3.70k
            {
116
3.70k
            try
117
3.70k
               {
118
3.70k
               if(possibly_a_general_name(bits.data(), bits.size()))
119
237
                  {
120
237
                  output << format(type_tag, class_tag, level, level,
121
237
                                   std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2));
122
237
                  success_parsing_cs = true;
123
237
                  }
124
3.46k
               else if(recurse_deeper)
125
3.23k
                  {
126
3.23k
                  std::vector<uint8_t> inner_bits;
127
3.23k
                  data.decode(inner_bits, type_tag);
128
3.23k
129
3.23k
                  BER_Decoder inner(inner_bits);
130
3.23k
                  std::ostringstream inner_data;
131
3.23k
                  decode(inner_data, inner, level + 1); // recurse
132
3.23k
                  output << inner_data.str();
133
3.23k
                  success_parsing_cs = true;
134
3.23k
                  }
135
3.70k
               }
136
3.70k
            catch(...)
137
3.70k
               {
138
3.23k
               }
139
3.70k
            }
140
3.70k
141
3.70k
         if(success_parsing_cs == false)
142
3.46k
            {
143
3.46k
            output << format(type_tag, class_tag, level, length,
144
3.46k
                             format_bin(type_tag, class_tag, bits));
145
3.46k
            }
146
3.70k
         }
147
65.3k
      else if(type_tag == OBJECT_ID)
148
4.31k
         {
149
4.31k
         OID oid;
150
4.31k
         data.decode(oid);
151
4.31k
152
4.31k
         std::string out = OIDS::oid2str_or_empty(oid);
153
4.31k
         if(out.empty())
154
3.04k
            {
155
3.04k
            out = oid.to_string();
156
3.04k
            }
157
1.26k
         else
158
1.26k
            {
159
1.26k
            out += " [" + oid.to_string() + "]";
160
1.26k
            }
161
4.31k
162
4.31k
         output << format(type_tag, class_tag, level, length, out);
163
4.31k
         }
164
61.0k
      else if(type_tag == INTEGER || type_tag == ENUMERATED)
165
3.84k
         {
166
3.84k
         BigInt number;
167
3.84k
168
3.84k
         if(type_tag == INTEGER)
169
3.29k
            {
170
3.29k
            data.decode(number);
171
3.29k
            }
172
543
         else if(type_tag == ENUMERATED)
173
543
            {
174
543
            data.decode(number, ENUMERATED, class_tag);
175
543
            }
176
3.84k
177
3.84k
         std::vector<uint8_t> rep = BigInt::encode(number);
178
3.84k
         if(rep.empty()) // if zero
179
1.32k
            rep.resize(1);
180
3.84k
181
3.84k
         output << format(type_tag, class_tag, level, length, hex_encode(rep));
182
3.84k
         }
183
57.1k
      else if(type_tag == BOOLEAN)
184
622
         {
185
622
         bool boolean;
186
622
         data.decode(boolean);
187
622
         output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false"));
188
622
         }
189
56.5k
      else if(type_tag == NULL_TAG)
190
243
         {
191
243
         output << format(type_tag, class_tag, level, length, "");
192
243
         }
193
56.2k
      else if(type_tag == OCTET_STRING || type_tag == BIT_STRING)
194
14.0k
         {
195
14.0k
         std::vector<uint8_t> decoded_bits;
196
14.0k
         data.decode(decoded_bits, type_tag);
197
14.0k
         bool printing_octet_string_worked = false;
198
14.0k
199
14.0k
         if(recurse_deeper)
200
13.2k
            {
201
13.2k
            try
202
13.2k
               {
203
13.2k
               BER_Decoder inner(decoded_bits);
204
13.2k
205
13.2k
               std::ostringstream inner_data;
206
13.2k
               decode(inner_data, inner, level + 1); // recurse
207
13.2k
208
13.2k
               output << format(type_tag, class_tag, level, length, "");
209
13.2k
               output << inner_data.str();
210
13.2k
               printing_octet_string_worked = true;
211
13.2k
               }
212
13.2k
            catch(...)
213
13.2k
               {
214
8.05k
               }
215
13.2k
            }
216
14.0k
217
14.0k
         if(!printing_octet_string_worked)
218
8.26k
            {
219
8.26k
            output << format(type_tag, class_tag, level, length,
220
8.26k
                             format_bin(type_tag, class_tag, decoded_bits));
221
8.26k
            }
222
14.0k
         }
223
42.2k
      else if(ASN1_String::is_string_type(type_tag))
224
2.92k
         {
225
2.92k
         ASN1_String str;
226
2.92k
         data.decode(str);
227
2.92k
         output << format(type_tag, class_tag, level, length, str.value());
228
2.92k
         }
229
39.2k
      else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME)
230
9.33k
         {
231
9.33k
         X509_Time time;
232
9.33k
         data.decode(time);
233
9.33k
         output << format(type_tag, class_tag, level, length, time.readable_string());
234
9.33k
         }
235
29.9k
      else
236
29.9k
         {
237
29.9k
         output << "Unknown ASN.1 tag class=" << static_cast<int>(class_tag)
238
29.9k
                << " type=" << static_cast<int>(type_tag) << "\n";
239
29.9k
         }
240
73.8k
241
73.8k
      obj = decoder.get_next_object();
242
73.8k
      }
243
20.5k
   }
244
245
namespace {
246
247
std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag)
248
0
   {
249
0
   if(class_tag == UNIVERSAL)
250
0
      return asn1_tag_to_string(type_tag);
251
0
252
0
   if(class_tag == CONSTRUCTED && (type_tag == SEQUENCE || type_tag == SET))
253
0
      return asn1_tag_to_string(type_tag);
254
0
255
0
   std::string name;
256
0
257
0
   if(class_tag & CONSTRUCTED)
258
0
      name += "cons ";
259
0
260
0
   name += "[" + std::to_string(type_tag) + "]";
261
0
262
0
   if(class_tag & APPLICATION)
263
0
      {
264
0
      name += " appl";
265
0
      }
266
0
   if(class_tag & CONTEXT_SPECIFIC)
267
0
      {
268
0
      name += " context";
269
0
      }
270
0
271
0
   return name;
272
0
   }
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
0
   {
282
0
   bool should_skip = false;
283
0
284
0
   if(value.length() > m_print_limit)
285
0
      {
286
0
      should_skip = true;
287
0
      }
288
0
289
0
   if((type_tag == OCTET_STRING || type_tag == BIT_STRING) &&
290
0
      value.length() > m_print_binary_limit)
291
0
      {
292
0
      should_skip = true;
293
0
      }
294
0
295
0
   level += m_initial_level;
296
0
297
0
   std::ostringstream oss;
298
0
299
0
   oss << "  d=" << std::setw(2) << level
300
0
       << ", l=" << std::setw(4) << length << ":"
301
0
       << std::string(level + 1, ' ') << format_type(type_tag, class_tag);
302
0
303
0
   if(value != "" && !should_skip)
304
0
      {
305
0
      const size_t current_pos = static_cast<size_t>(oss.tellp());
306
0
      const size_t spaces_to_align =
307
0
         (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos);
308
0
309
0
      oss << std::string(spaces_to_align, ' ') << value;
310
0
      }
311
0
312
0
   oss << "\n";
313
0
314
0
   return oss.str();
315
0
   }
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
0
   {
321
0
   if(all_printable_chars(vec.data(), vec.size()))
322
0
      {
323
0
      return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size());
324
0
      }
325
0
   else
326
0
      return hex_encode(vec);
327
0
   }
328
329
}