~ubuntu-branches/debian/sid/botan/sid

« back to all changes in this revision

Viewing changes to doc/examples/asn1.cpp

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2018-03-01 22:23:25 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20180301222325-7p7vc45gu3hta34d
Tags: 2.4.0-2
* Don't remove .doctrees from the manual if it doesn't exist.
* Don't specify parallel to debhelper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
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'
5
 
 
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
10
 
  seem them as-is.
11
 
 
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
17
 
 
18
 
  This file is in the public domain.
19
 
*/
20
 
 
21
 
/*******************************************************************/
22
 
 
23
 
// Set this if your terminal understands UTF-8; otherwise output is in Latin-1
24
 
#define UTF8_TERMINAL 1
25
 
 
26
 
/*
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
29
 
   much sense at all.
30
 
*/
31
 
#define INITIAL_LEVEL 0
32
 
 
33
 
/*******************************************************************/
34
 
 
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;
44
 
 
45
 
#include <stdio.h>
46
 
#include <ctype.h>
47
 
 
48
 
void decode(BER_Decoder&, u32bit);
49
 
void emit(const std::string&, u32bit, u32bit, const std::string& = "");
50
 
std::string type_name(ASN1_Tag);
51
 
 
52
 
int main(int argc, char* argv[])
53
 
   {
54
 
   if(argc != 2)
55
 
      {
56
 
      printf("Usage: %s <file>\n", argv[0]);
57
 
      return 1;
58
 
      }
59
 
 
60
 
   try {
61
 
      LibraryInitializer init;
62
 
 
63
 
      DataSource_Stream in(argv[1]);
64
 
 
65
 
      if(!PEM_Code::matches(in))
66
 
         {
67
 
         BER_Decoder decoder(in);
68
 
         decode(decoder, INITIAL_LEVEL);
69
 
         }
70
 
      else
71
 
         {
72
 
         std::string label; // ignored
73
 
         BER_Decoder decoder(PEM_Code::decode(in, label));
74
 
         decode(decoder, INITIAL_LEVEL);
75
 
         }
76
 
 
77
 
   }
78
 
   catch(std::exception& e)
79
 
      {
80
 
      printf("%s\n", e.what());
81
 
      return 1;
82
 
      }
83
 
   return 0;
84
 
   }
85
 
 
86
 
void decode(BER_Decoder& decoder, u32bit level)
87
 
   {
88
 
   BER_Object obj = decoder.get_next_object();
89
 
 
90
 
   while(obj.type_tag != NO_OBJECT)
91
 
      {
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();
95
 
 
96
 
      /* hack to insert the tag+length back in front of the stuff now
97
 
         that we've gotten the type info */
98
 
      DER_Encoder encoder;
99
 
      encoder.add_object(type_tag, class_tag, obj.value, obj.value.size());
100
 
      SecureVector<byte> bits = encoder.get_contents();
101
 
 
102
 
      BER_Decoder data(bits);
103
 
 
104
 
      if(class_tag & CONSTRUCTED)
105
 
         {
106
 
         BER_Decoder cons_info(obj.value);
107
 
         if(type_tag == SEQUENCE)
108
 
            {
109
 
            emit("SEQUENCE", level, length);
110
 
            decode(cons_info, level+1);
111
 
            }
112
 
         else if(type_tag == SET)
113
 
            {
114
 
            emit("SET", level, length);
115
 
            decode(cons_info, level+1);
116
 
            }
117
 
         else
118
 
            {
119
 
            std::string name;
120
 
 
121
 
            if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC) ||
122
 
               (class_tag & PRIVATE))
123
 
               name = "cons [" + to_string(type_tag) + "]";
124
 
            else
125
 
               name = type_name(type_tag) + " (cons)";
126
 
 
127
 
            emit(name, level, length);
128
 
            decode(cons_info, level+1);
129
 
            }
130
 
         }
131
 
      else if(class_tag == APPLICATION || class_tag == CONTEXT_SPECIFIC ||
132
 
              class_tag == PRIVATE)
133
 
         {
134
 
         bool not_text = false;
135
 
 
136
 
         for(u32bit j = 0; j != bits.size(); j++)
137
 
            if(!isgraph(bits[j]) && !isspace(bits[j]))
138
 
               not_text = true;
139
 
 
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());
144
 
         }
145
 
      else if(type_tag == OBJECT_ID)
146
 
         {
147
 
         OID oid;
148
 
         data.decode(oid);
149
 
         emit(type_name(type_tag), level, length, OIDS::lookup(oid));
150
 
         }
151
 
      else if(type_tag == INTEGER)
152
 
         {
153
 
         BigInt number;
154
 
         data.decode(number);
155
 
 
156
 
         SecureVector<byte> rep;
157
 
 
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);
161
 
         else
162
 
            rep = BigInt::encode(number, BigInt::Hexadecimal);
163
 
 
164
 
         std::string str;
165
 
         for(u32bit j = 0; j != rep.size(); j++)
166
 
            str += (char)rep[j];
167
 
 
168
 
         emit(type_name(type_tag), level, length, str);
169
 
         }
170
 
      else if(type_tag == BOOLEAN)
171
 
         {
172
 
         bool boolean;
173
 
         data.decode(boolean);
174
 
         emit(type_name(type_tag),
175
 
              level, length, (boolean ? "true" : "false"));
176
 
         }
177
 
      else if(type_tag == NULL_TAG)
178
 
         {
179
 
         emit(type_name(type_tag), level, length);
180
 
         }
181
 
      else if(type_tag == OCTET_STRING)
182
 
         {
183
 
         SecureVector<byte> bits;
184
 
         data.decode(bits, type_tag);
185
 
         bool not_text = false;
186
 
 
187
 
         for(u32bit j = 0; j != bits.size(); j++)
188
 
            if(!isgraph(bits[j]) && !isspace(bits[j]))
189
 
               not_text = true;
190
 
 
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());
194
 
         }
195
 
      else if(type_tag == BIT_STRING)
196
 
         {
197
 
         SecureVector<byte> bits;
198
 
         data.decode(bits, type_tag);
199
 
 
200
 
         std::vector<bool> bit_set;
201
 
 
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));
205
 
 
206
 
         std::string bit_str;
207
 
         for(u32bit j = 0; j != bit_set.size(); j++)
208
 
            {
209
 
            bool the_bit = bit_set[bit_set.size()-j-1];
210
 
 
211
 
            if(!the_bit && bit_str.size() == 0)
212
 
               continue;
213
 
            bit_str += (the_bit ? "1" : "0");
214
 
            }
215
 
 
216
 
         emit(type_name(type_tag), level, length, bit_str);
217
 
         }
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)
225
 
         {
226
 
         ASN1_String str;
227
 
         data.decode(str);
228
 
         if(UTF8_TERMINAL)
229
 
            emit(type_name(type_tag), level, length,
230
 
                 Charset::transcode(str.iso_8859(),
231
 
                                    LATIN1_CHARSET, UTF8_CHARSET));
232
 
         else
233
 
            emit(type_name(type_tag), level, length, str.iso_8859());
234
 
         }
235
 
      else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME)
236
 
         {
237
 
         X509_Time time;
238
 
         data.decode(time);
239
 
         emit(type_name(type_tag), level, length, time.readable_string());
240
 
         }
241
 
      else
242
 
         fprintf(stderr, "Unknown tag: class=%02X, type=%02X\n",
243
 
                 class_tag, type_tag);
244
 
 
245
 
      obj = decoder.get_next_object();
246
 
      }
247
 
   }
248
 
 
249
 
void emit(const std::string& type, u32bit level, u32bit length,
250
 
          const std::string& value)
251
 
   {
252
 
   const u32bit LIMIT = 128;
253
 
   const u32bit BIN_LIMIT = 64;
254
 
 
255
 
   int written = 0;
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());
260
 
 
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)
265
 
      should_skip = true;
266
 
 
267
 
   if(value != "" && !should_skip)
268
 
      {
269
 
      if(written % 2 == 0) printf(" ");
270
 
      while(written < 50) written += printf("  ");
271
 
      printf(":%s\n", value.c_str());
272
 
      }
273
 
   else
274
 
      printf("\n");
275
 
   }
276
 
 
277
 
std::string type_name(ASN1_Tag type)
278
 
   {
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";
286
 
 
287
 
   if(type == UTC_TIME)         return "UTC TIME";
288
 
   if(type == GENERALIZED_TIME) return "GENERALIZED TIME";
289
 
 
290
 
   if(type == OCTET_STRING)     return "OCTET STRING";
291
 
   if(type == BIT_STRING)       return "BIT STRING";
292
 
 
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";
297
 
   return "(UNKNOWN)";
298
 
   }