2
A simple ASN.1 parser, similiar to 'dumpasn1' or 'openssl asn1parse', though
3
without some of the bells and whistles of those. Primarily used for testing
4
the BER decoder. The output format is modeled loosely on 'asn1parse -i'
6
The output is actually less precise than the other decoders named, because
7
the underlying BER_Decoder hides quite a bit from userspace, such as the use
8
of indefinite length encodings (and the EOC markers). At some point it will
9
also hide the constructed string types from the user, but right now you'll
12
Written by Jack Lloyd, November 9-10, 2003
13
- Nov 22: Updated to new BER_Object format (tag -> class_tag/type_tag)
14
- Nov 25: Much improved BIT STRING output
15
Can deal with non-constructed taggings
16
Can produce UTF-8 output
18
This file is in the public domain.
21
/*******************************************************************/
23
// Set this if your terminal understands UTF-8; otherwise output is in Latin-1
24
#define UTF8_TERMINAL 1
27
What level the outermost layer of stuff is at. Probably 0 or 1; asn1parse
28
uses 0 as the outermost, while 1 makes more sense to me. 2+ doesn't make
31
#define INITIAL_LEVEL 0
33
/*******************************************************************/
35
#include <botan/botan.h>
36
#include <botan/bigint.h>
37
#include <botan/der_enc.h>
38
#include <botan/ber_dec.h>
39
#include <botan/asn1_obj.h>
40
#include <botan/oids.h>
41
#include <botan/pem.h>
42
#include <botan/charset.h>
43
using namespace Botan;
48
void decode(BER_Decoder&, u32bit);
49
void emit(const std::string&, u32bit, u32bit, const std::string& = "");
50
std::string type_name(ASN1_Tag);
52
int main(int argc, char* argv[])
56
printf("Usage: %s <file>\n", argv[0]);
61
LibraryInitializer init;
63
DataSource_Stream in(argv[1]);
65
if(!PEM_Code::matches(in))
67
BER_Decoder decoder(in);
68
decode(decoder, INITIAL_LEVEL);
72
std::string label; // ignored
73
BER_Decoder decoder(PEM_Code::decode(in, label));
74
decode(decoder, INITIAL_LEVEL);
78
catch(std::exception& e)
80
printf("%s\n", e.what());
86
void decode(BER_Decoder& decoder, u32bit level)
88
BER_Object obj = decoder.get_next_object();
90
while(obj.type_tag != NO_OBJECT)
92
const ASN1_Tag type_tag = obj.type_tag;
93
const ASN1_Tag class_tag = obj.class_tag;
94
const u32bit length = obj.value.size();
96
/* hack to insert the tag+length back in front of the stuff now
97
that we've gotten the type info */
99
encoder.add_object(type_tag, class_tag, obj.value, obj.value.size());
100
SecureVector<byte> bits = encoder.get_contents();
102
BER_Decoder data(bits);
104
if(class_tag & CONSTRUCTED)
106
BER_Decoder cons_info(obj.value);
107
if(type_tag == SEQUENCE)
109
emit("SEQUENCE", level, length);
110
decode(cons_info, level+1);
112
else if(type_tag == SET)
114
emit("SET", level, length);
115
decode(cons_info, level+1);
121
if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC) ||
122
(class_tag & PRIVATE))
123
name = "cons [" + to_string(type_tag) + "]";
125
name = type_name(type_tag) + " (cons)";
127
emit(name, level, length);
128
decode(cons_info, level+1);
131
else if(class_tag == APPLICATION || class_tag == CONTEXT_SPECIFIC ||
132
class_tag == PRIVATE)
134
bool not_text = false;
136
for(u32bit j = 0; j != bits.size(); j++)
137
if(!isgraph(bits[j]) && !isspace(bits[j]))
140
Pipe pipe(((not_text) ? new Hex_Encoder : 0));
141
pipe.process_msg(bits);
142
emit("[" + to_string(type_tag) + "]", level, length,
143
pipe.read_all_as_string());
145
else if(type_tag == OBJECT_ID)
149
emit(type_name(type_tag), level, length, OIDS::lookup(oid));
151
else if(type_tag == INTEGER)
156
SecureVector<byte> rep;
158
/* If it's small, it's probably a number, not a hash */
159
if(number.bits() <= 16)
160
rep = BigInt::encode(number, BigInt::Decimal);
162
rep = BigInt::encode(number, BigInt::Hexadecimal);
165
for(u32bit j = 0; j != rep.size(); j++)
168
emit(type_name(type_tag), level, length, str);
170
else if(type_tag == BOOLEAN)
173
data.decode(boolean);
174
emit(type_name(type_tag),
175
level, length, (boolean ? "true" : "false"));
177
else if(type_tag == NULL_TAG)
179
emit(type_name(type_tag), level, length);
181
else if(type_tag == OCTET_STRING)
183
SecureVector<byte> bits;
184
data.decode(bits, type_tag);
185
bool not_text = false;
187
for(u32bit j = 0; j != bits.size(); j++)
188
if(!isgraph(bits[j]) && !isspace(bits[j]))
191
Pipe pipe(((not_text) ? new Hex_Encoder : 0));
192
pipe.process_msg(bits);
193
emit(type_name(type_tag), level, length, pipe.read_all_as_string());
195
else if(type_tag == BIT_STRING)
197
SecureVector<byte> bits;
198
data.decode(bits, type_tag);
200
std::vector<bool> bit_set;
202
for(u32bit j = 0; j != bits.size(); j++)
203
for(u32bit k = 0; k != 8; k++)
204
bit_set.push_back((bool)((bits[bits.size()-j-1] >> (7-k)) & 1));
207
for(u32bit j = 0; j != bit_set.size(); j++)
209
bool the_bit = bit_set[bit_set.size()-j-1];
211
if(!the_bit && bit_str.size() == 0)
213
bit_str += (the_bit ? "1" : "0");
216
emit(type_name(type_tag), level, length, bit_str);
218
else if(type_tag == PRINTABLE_STRING ||
219
type_tag == NUMERIC_STRING ||
220
type_tag == IA5_STRING ||
221
type_tag == T61_STRING ||
222
type_tag == VISIBLE_STRING ||
223
type_tag == UTF8_STRING ||
224
type_tag == BMP_STRING)
229
emit(type_name(type_tag), level, length,
230
Charset::transcode(str.iso_8859(),
231
LATIN1_CHARSET, UTF8_CHARSET));
233
emit(type_name(type_tag), level, length, str.iso_8859());
235
else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME)
239
emit(type_name(type_tag), level, length, time.readable_string());
242
fprintf(stderr, "Unknown tag: class=%02X, type=%02X\n",
243
class_tag, type_tag);
245
obj = decoder.get_next_object();
249
void emit(const std::string& type, u32bit level, u32bit length,
250
const std::string& value)
252
const u32bit LIMIT = 128;
253
const u32bit BIN_LIMIT = 64;
256
written += printf(" d=%2d, l=%4d: ", level, length);
257
for(u32bit j = INITIAL_LEVEL; j != level; j++)
258
written += printf(" ");
259
written += printf("%s ", type.c_str());
261
bool should_skip = false;
262
if(value.length() > LIMIT) should_skip = true;
263
if((type == "OCTET STRING" || type == "BIT STRING") &&
264
value.length() > BIN_LIMIT)
267
if(value != "" && !should_skip)
269
if(written % 2 == 0) printf(" ");
270
while(written < 50) written += printf(" ");
271
printf(":%s\n", value.c_str());
277
std::string type_name(ASN1_Tag type)
279
if(type == PRINTABLE_STRING) return "PRINTABLE STRING";
280
if(type == NUMERIC_STRING) return "NUMERIC STRING";
281
if(type == IA5_STRING) return "IA5 STRING";
282
if(type == T61_STRING) return "T61 STRING";
283
if(type == UTF8_STRING) return "UTF8 STRING";
284
if(type == VISIBLE_STRING) return "VISIBLE STRING";
285
if(type == BMP_STRING) return "BMP STRING";
287
if(type == UTC_TIME) return "UTC TIME";
288
if(type == GENERALIZED_TIME) return "GENERALIZED TIME";
290
if(type == OCTET_STRING) return "OCTET STRING";
291
if(type == BIT_STRING) return "BIT STRING";
293
if(type == INTEGER) return "INTEGER";
294
if(type == NULL_TAG) return "NULL";
295
if(type == OBJECT_ID) return "OBJECT";
296
if(type == BOOLEAN) return "BOOLEAN";