Rizin
unix-like reverse engineering framework and cli tools
asn1.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2017-2018 deroad <wargio@libero.it>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_util.h>
5 #include <rz_cons.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 
10 static int ASN1_STD_FORMAT = 1;
11 
12 RZ_API void asn1_setformat(int fmt) {
13  ASN1_STD_FORMAT = fmt;
14 }
15 
17  if (!buffer || length < 3) {
18  return 0;
19  }
20  const ut8 *next = buffer + 2;
21  const ut8 *end = buffer + (length - 3);
22  while (next < end) {
23  if (!next[0] && !next[1]) {
24  break;
25  }
26  if (next[0] == 0x80 && (next[-1] & ASN1_FORM) == FORM_CONSTRUCTED) {
27  next--;
28  int sz = asn1_ber_indefinite(next, end - next);
29  if (sz < 1) {
30  break;
31  }
32  next += sz;
33  }
34  next++;
35  }
36  return (next - buffer) + 2;
37 }
38 
39 static RASN1Object *asn1_parse_header(const ut8 *buffer, ut32 length, const ut8 *start_pointer) {
40  ut8 head, length8, byte;
41  ut64 length64;
42  if (!buffer || length < 2) {
43  return NULL;
44  }
45 
46  RASN1Object *object = RZ_NEW0(RASN1Object);
47  if (!object) {
48  return NULL;
49  }
50  head = buffer[0];
51  object->offset = start_pointer ? (buffer - start_pointer) : 0;
52  object->klass = head & ASN1_CLASS;
53  object->form = head & ASN1_FORM;
54  object->tag = head & ASN1_TAG;
55  length8 = buffer[1];
56  if (length8 & ASN1_LENLONG) {
57  length64 = 0;
58  length8 &= ASN1_LENSHORT;
59  object->sector = buffer + 2;
60  if (length8 && length8 < length - 2) {
61  ut8 i8;
62  // can overflow.
63  for (i8 = 0; i8 < length8; i8++) {
64  byte = buffer[2 + i8];
65  length64 <<= 8;
66  length64 |= byte;
67  if (length64 > length) {
68  goto out_error;
69  }
70  }
71  object->sector += length8;
72  } else {
73  length64 = asn1_ber_indefinite(object->sector, length - 2);
74  }
75  object->length = (ut32)length64;
76  } else {
77  object->length = (ut32)length8;
78  object->sector = buffer + 2;
79  }
80 
81  if (object->tag == TAG_BITSTRING && object->sector[0] == 0) {
82  if (object->length > 0) {
83  object->sector++; // real sector starts + 1
84  object->length--;
85  }
86  }
87  if (object->length > length) {
88  // Malformed object - overflow from data ptr
89  goto out_error;
90  }
91  return object;
92 out_error:
93  free(object);
94  return NULL;
95 }
96 
98  if (!buffer || !length) {
99  return 0;
100  }
101  ut32 counter = 0;
102  RASN1Object *object = NULL;
103  const ut8 *next = buffer;
104  const ut8 *end = buffer + length;
105  while (next >= buffer && next < end) {
106  // i do not care about the offset now.
107  object = asn1_parse_header(next, end - next, 0);
108  if (!object || next == object->sector) {
109  RZ_FREE(object);
110  break;
111  }
112  next = object->sector + object->length;
113  counter++;
114  RZ_FREE(object);
115  }
116  RZ_FREE(object);
117  return counter;
118 }
119 
120 RZ_API RASN1Object *rz_asn1_create_object(const ut8 *buffer, ut32 length, const ut8 *start_pointer) {
121  RASN1Object *object = asn1_parse_header(buffer, length, start_pointer);
122  if (object && (object->form == FORM_CONSTRUCTED || object->tag == TAG_BITSTRING || object->tag == TAG_OCTETSTRING)) {
123  const ut8 *next = object->sector;
124  const ut8 *end = next + object->length;
125  if (end > buffer + length) {
126  free(object);
127  return NULL;
128  }
129  ut32 count = rz_asn1_count_objects(object->sector, object->length);
130  if (count > 0) {
131  object->list.length = count;
132  object->list.objects = RZ_NEWS0(RASN1Object *, count);
133  if (!object->list.objects) {
134  rz_asn1_free_object(object);
135  return NULL;
136  }
137  ut32 i;
138  for (i = 0; next >= buffer && next < end && i < count; i++) {
139  RASN1Object *inner = rz_asn1_create_object(next, end - next, start_pointer);
140  if (!inner || next == inner->sector) {
141  rz_asn1_free_object(inner);
142  break;
143  }
144  next = inner->sector + inner->length;
145  object->list.objects[i] = inner;
146  }
147  }
148  }
149  return object;
150 }
151 
153  if (!buffer || !length) {
154  return NULL;
155  }
156  ut8 *buf = (ut8 *)calloc(sizeof(*buf), length);
157  if (!buf) {
158  return NULL;
159  }
161  if (!bin) {
162  free(buf);
163  return NULL;
164  }
165  memcpy(buf, buffer, length);
166  bin->binary = buf;
167  bin->length = length;
168  return bin;
169 }
170 
171 RZ_API void rz_asn1_print_hex(RASN1Object *object, char *buffer, ut32 size, ut32 depth) {
172  ut32 i;
173  if (!object || !object->sector) {
174  return;
175  }
176  char *p = buffer;
177  char *end = buffer + size;
178  if (depth > 0 && !ASN1_STD_FORMAT) {
179  const char *pad = rz_str_pad(' ', (depth * 2) - 2);
180  snprintf(p, end - p, "%s", pad);
181  p += strlen(pad);
182  }
183  for (i = 0; i < object->length && p < end; i++) {
184  snprintf(p, end - p, "%02x", object->sector[i]);
185  p += 2;
186  }
187  if (p >= end) {
188  p -= 4;
189  snprintf(p, end - p, "...");
190  }
191 }
192 
193 #if !ASN1_STD_FORMAT
194 static void rz_asn1_print_padded(RzStrBuf *sb, RASN1Object *object, int depth, const char *k, const char *v) {
195  const char *pad = rz_str_pad(' ', (depth * 2) - 2);
196  if (object->form && !*v) {
197  return;
198  }
199  switch (object->tag) {
200  case TAG_NULL:
201  case TAG_EOC:
202  break;
203  case TAG_INTEGER:
204  case TAG_REAL:
205  if (*rz_str_trim_head_ro(v)) {
206  rz_strbuf_appendf(sb, "%s%s\n%s%s\n", pad, k, pad, v);
207  }
208  break;
209  case TAG_BITSTRING:
210  default:
211  if (*rz_str_trim_head_ro(v)) {
212  rz_strbuf_appendf(sb, "%s%s\n", pad, v);
213  }
214  break;
215  }
216 }
217 #endif
218 
220  const char *pad;
221  ut32 i, j;
222  char readable[20] = { 0 };
223  if (!object || !object->sector || object->length < 1) {
224  return NULL;
225  }
226  RzStrBuf *sb = rz_strbuf_new("");
227  if (ASN1_STD_FORMAT) {
228  pad = " : ";
229  } else {
230  pad = rz_str_pad(' ', depth * 2);
231  rz_strbuf_appendf(sb, " ");
232  }
233 
234  for (i = 0, j = 0; i < object->length; i++, j++) {
235  ut8 c = object->sector[i];
236  if (i > 0 && (i % 16) == 0) {
237  rz_strbuf_appendf(sb, "|%-16s|\n%s", readable, pad);
238  memset(readable, 0, sizeof(readable));
239  j = 0;
240  }
241  rz_strbuf_appendf(sb, "%02x ", c);
242  readable[j] = IS_PRINTABLE(c) ? c : '.';
243  }
244 
245  while ((i % 16) != 0) {
246  rz_strbuf_appendf(sb, " ");
247  i++;
248  }
249  rz_strbuf_appendf(sb, "|%-16s|", readable);
250  char *text = rz_strbuf_drain(sb);
251  RASN1String *asn1str = rz_asn1_create_string(text, true, strlen(text) + 1);
252  if (!asn1str) {
253  /* no memory left.. */
254  free(text);
255  }
256  return asn1str;
257 }
258 
260  ut32 i;
261  bool root = false;
262  if (!object) {
263  return NULL;
264  }
265  if (!sb) {
266  sb = rz_strbuf_new("");
267  root = true;
268  }
269  // this shall not be freed. it's a pointer into the buffer.
270  RASN1String *asn1str = NULL;
271  static char temp_name[4096] = { 0 };
272  const char *name = "";
273  const char *string = "";
274 
275  switch (object->klass) {
276  case CLASS_UNIVERSAL: // universal
277  switch (object->tag) {
278  case TAG_EOC:
279  name = "EOC";
280  break;
281  case TAG_BOOLEAN:
282  name = "BOOLEAN";
283  if (object->sector) {
284  string = (object->sector[0] != 0) ? "true" : "false";
285  }
286  break;
287  case TAG_INTEGER:
288  name = "INTEGER";
289  if (object->length < 16) {
290  rz_asn1_print_hex(object, temp_name, sizeof(temp_name), depth);
291  string = temp_name;
292  } else {
293  asn1str = rz_asn1_print_hexdump_padded(object, depth);
294  }
295  break;
296  case TAG_BITSTRING:
297  name = "BIT_STRING";
298  if (!object->list.objects) {
299  if (object->length < 16) {
300  rz_asn1_print_hex(object, temp_name, sizeof(temp_name), depth);
301  string = temp_name;
302  } else {
303  asn1str = rz_asn1_print_hexdump_padded(object, depth);
304  }
305  }
306  break;
307  case TAG_OCTETSTRING:
308  name = "OCTET_STRING";
309  if (rz_str_is_printable_limited((const char *)object->sector, object->length)) {
310  asn1str = rz_asn1_stringify_string(object->sector, object->length);
311  } else if (!object->list.objects) {
312  if (object->length < 16) {
313  rz_asn1_print_hex(object, temp_name, sizeof(temp_name), depth);
314  string = temp_name;
315  } else {
316  asn1str = rz_asn1_print_hexdump_padded(object, depth);
317  }
318  }
319  break;
320  case TAG_NULL:
321  name = "NULL";
322  break;
323  case TAG_OID:
324  name = "OBJECT_IDENTIFIER";
325  asn1str = rz_asn1_stringify_oid(object->sector, object->length);
326  break;
327  case TAG_OBJDESCRIPTOR:
328  name = "OBJECT_DESCRIPTOR";
329  break;
330  case TAG_EXTERNAL:
331  name = "EXTERNAL";
332  break;
333  case TAG_REAL:
334  name = "REAL";
335  asn1str = rz_asn1_print_hexdump_padded(object, depth);
336  break;
337  case TAG_ENUMERATED:
338  name = "ENUMERATED";
339  break;
340  case TAG_EMBEDDED_PDV:
341  name = "EMBEDDED_PDV";
342  break;
343  case TAG_UTF8STRING:
344  name = "UTF8String";
345  asn1str = rz_asn1_stringify_string(object->sector, object->length);
346  break;
347  case TAG_SEQUENCE:
348  name = "SEQUENCE";
349  break;
350  case TAG_SET:
351  name = "SET";
352  break;
353  case TAG_NUMERICSTRING:
354  name = "NumericString";
355  asn1str = rz_asn1_stringify_string(object->sector, object->length);
356  break;
357  case TAG_PRINTABLESTRING:
358  name = "PrintableString"; // ASCII subset
359  asn1str = rz_asn1_stringify_string(object->sector, object->length);
360  break;
361  case TAG_T61STRING:
362  name = "TeletexString"; // aka T61String
363  asn1str = rz_asn1_stringify_string(object->sector, object->length);
364  break;
365  case TAG_VIDEOTEXSTRING:
366  name = "VideotexString";
367  asn1str = rz_asn1_stringify_string(object->sector, object->length);
368  break;
369  case TAG_IA5STRING:
370  name = "IA5String"; // ASCII
371  asn1str = rz_asn1_stringify_string(object->sector, object->length);
372  break;
373  case TAG_UTCTIME:
374  name = "UTCTime";
375  asn1str = rz_asn1_stringify_utctime(object->sector, object->length);
376  break;
377  case TAG_GENERALIZEDTIME:
378  name = "GeneralizedTime";
379  asn1str = rz_asn1_stringify_time(object->sector, object->length);
380  break;
381  case TAG_GRAPHICSTRING:
382  name = "GraphicString";
383  asn1str = rz_asn1_stringify_string(object->sector, object->length);
384  break;
385  case TAG_VISIBLESTRING:
386  name = "VisibleString"; // ASCII subset
387  asn1str = rz_asn1_stringify_string(object->sector, object->length);
388  break;
389  case TAG_GENERALSTRING:
390  name = "GeneralString";
391  break;
392  case TAG_UNIVERSALSTRING:
393  name = "UniversalString";
394  asn1str = rz_asn1_stringify_string(object->sector, object->length);
395  break;
396  case TAG_BMPSTRING:
397  name = "BMPString";
398  asn1str = rz_asn1_stringify_string(object->sector, object->length);
399  break;
400  default:
401  snprintf(temp_name, sizeof(temp_name), "Universal_%u", object->tag);
402  name = temp_name;
403  break;
404  }
405  break;
406  case CLASS_APPLICATION:
407  snprintf(temp_name, sizeof(temp_name), "Application_%u", object->tag);
408  name = temp_name;
409  break;
410  case CLASS_CONTEXT:
411  snprintf(temp_name, sizeof(temp_name), "Context [%u]", object->tag); // Context
412  name = temp_name;
413  break;
414  case CLASS_PRIVATE:
415  snprintf(temp_name, sizeof(temp_name), "Private_%u", object->tag);
416  name = temp_name;
417  break;
418  }
419  if (asn1str) {
420  string = asn1str->string;
421  }
422  if (ASN1_STD_FORMAT) {
423  rz_strbuf_appendf(sb, "%4" PFMT64d " ", object->offset);
424  rz_strbuf_appendf(sb, "%4u:%2d: %s %-20s: %s\n", object->length,
425  depth, object->form ? "cons" : "prim", name, string);
426  rz_asn1_free_string(asn1str);
427  if (object->list.objects) {
428  for (i = 0; i < object->list.length; i++) {
429  rz_asn1_to_string(object->list.objects[i], depth + 1, sb);
430  }
431  }
432  } else {
433  rz_asn1_print_padded(sb, object, depth, name, string);
434  rz_asn1_free_string(asn1str);
435  if (object->list.objects) {
436  for (i = 0; i < object->list.length; i++) {
437  RASN1Object *obj = object->list.objects[i];
438  rz_asn1_to_string(obj, depth + 1, sb);
439  }
440  }
441  }
442  return root ? rz_strbuf_drain(sb) : NULL;
443 }
444 
446  ut32 i;
447  if (!object) {
448  return;
449  }
450  // This shall not be freed. it's a pointer into the buffer.
451  object->sector = NULL;
452  if (object->list.objects) {
453  for (i = 0; i < object->list.length; i++) {
454  rz_asn1_free_object(object->list.objects[i]);
455  }
456  RZ_FREE(object->list.objects);
457  }
458  object->list.objects = NULL;
459  object->list.length = 0;
460  free(object);
461 }
462 
464  if (bin) {
465  free(bin->binary);
466  free(bin);
467  }
468 }
lzma_index ** i
Definition: index.h:629
static int ASN1_STD_FORMAT
Definition: asn1.c:10
RZ_API char * rz_asn1_to_string(RASN1Object *object, ut32 depth, RzStrBuf *sb)
Definition: asn1.c:259
RZ_API void rz_asn1_free_object(RASN1Object *object)
Definition: asn1.c:445
static ut32 rz_asn1_count_objects(const ut8 *buffer, ut32 length)
Definition: asn1.c:97
RZ_API void asn1_setformat(int fmt)
Definition: asn1.c:12
static RASN1String * rz_asn1_print_hexdump_padded(RASN1Object *object, ut32 depth)
Definition: asn1.c:219
static void rz_asn1_print_padded(RzStrBuf *sb, RASN1Object *object, int depth, const char *k, const char *v)
Definition: asn1.c:194
RZ_API RASN1Binary * rz_asn1_create_binary(const ut8 *buffer, ut32 length)
Definition: asn1.c:152
RZ_API void rz_asn1_free_binary(RASN1Binary *bin)
Definition: asn1.c:463
RZ_API RASN1Object * rz_asn1_create_object(const ut8 *buffer, ut32 length, const ut8 *start_pointer)
Definition: asn1.c:120
RZ_API void rz_asn1_print_hex(RASN1Object *object, char *buffer, ut32 size, ut32 depth)
Definition: asn1.c:171
static RASN1Object * asn1_parse_header(const ut8 *buffer, ut32 length, const ut8 *start_pointer)
Definition: asn1.c:39
static ut32 asn1_ber_indefinite(const ut8 *buffer, ut32 length)
Definition: asn1.c:16
static SblHeader sb
Definition: bin_mbn.c:26
struct buffer buffer
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
uint32_t ut32
const char * k
Definition: dsignal.c:11
const char * v
Definition: dsignal.c:12
int root
Definition: enough.c:226
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static void pad(RzStrBuf *sb, ut32 count)
Definition: protobuf.c:36
#define TAG_ENUMERATED
Definition: rz_asn1.h:45
#define TAG_EOC
Definition: rz_asn1.h:35
#define CLASS_UNIVERSAL
Definition: rz_asn1.h:25
#define TAG_GRAPHICSTRING
Definition: rz_asn1.h:57
RZ_API void rz_asn1_free_string(RASN1String *string)
Definition: astr.c:313
#define TAG_INTEGER
Definition: rz_asn1.h:37
#define TAG_BITSTRING
Definition: rz_asn1.h:38
#define TAG_OCTETSTRING
Definition: rz_asn1.h:39
#define TAG_EMBEDDED_PDV
Definition: rz_asn1.h:46
#define TAG_BOOLEAN
Definition: rz_asn1.h:36
RZ_API RASN1String * rz_asn1_stringify_time(const ut8 *buffer, ut32 length)
Definition: astr.c:108
#define TAG_OID
Definition: rz_asn1.h:41
#define ASN1_LENSHORT
Definition: rz_asn1.h:22
#define TAG_GENERALIZEDTIME
Definition: rz_asn1.h:56
#define TAG_GENERALSTRING
Definition: rz_asn1.h:59
#define TAG_T61STRING
Definition: rz_asn1.h:52
#define TAG_SET
Definition: rz_asn1.h:49
#define CLASS_PRIVATE
Definition: rz_asn1.h:28
#define ASN1_TAG
Definition: rz_asn1.h:20
RZ_API RASN1String * rz_asn1_create_string(const char *string, bool allocated, ut32 length)
Definition: astr.c:10
#define TAG_NULL
Definition: rz_asn1.h:40
#define TAG_IA5STRING
Definition: rz_asn1.h:54
#define TAG_UNIVERSALSTRING
Definition: rz_asn1.h:60
RZ_API RASN1String * rz_asn1_stringify_utctime(const ut8 *buffer, ut32 length)
Definition: astr.c:67
#define TAG_EXTERNAL
Definition: rz_asn1.h:43
#define TAG_OBJDESCRIPTOR
Definition: rz_asn1.h:42
RZ_API RASN1String * rz_asn1_stringify_oid(const ut8 *buffer, ut32 length)
Definition: astr.c:249
#define TAG_REAL
Definition: rz_asn1.h:44
#define TAG_PRINTABLESTRING
Definition: rz_asn1.h:51
#define ASN1_CLASS
Definition: rz_asn1.h:18
#define TAG_VISIBLESTRING
Definition: rz_asn1.h:58
#define ASN1_FORM
Definition: rz_asn1.h:19
#define ASN1_LENLONG
Definition: rz_asn1.h:21
#define CLASS_CONTEXT
Definition: rz_asn1.h:27
RZ_API RASN1String * rz_asn1_stringify_string(const ut8 *buffer, ut32 length)
Definition: astr.c:55
#define TAG_BMPSTRING
Definition: rz_asn1.h:61
#define CLASS_APPLICATION
Definition: rz_asn1.h:26
#define FORM_CONSTRUCTED
Definition: rz_asn1.h:32
#define TAG_NUMERICSTRING
Definition: rz_asn1.h:50
#define TAG_UTF8STRING
Definition: rz_asn1.h:47
#define TAG_SEQUENCE
Definition: rz_asn1.h:48
#define TAG_VIDEOTEXSTRING
Definition: rz_asn1.h:53
#define TAG_UTCTIME
Definition: rz_asn1.h:55
RZ_API bool rz_str_is_printable_limited(const char *str, int size)
Definition: str.c:2053
RZ_API const char * rz_str_trim_head_ro(const char *str)
Definition: str_trim.c:86
RZ_API const char * rz_str_pad(const char ch, int len)
Definition: str.c:3236
#define IS_PRINTABLE(x)
Definition: rz_str_util.h:10
RZ_API RZ_OWN char * rz_strbuf_drain(RzStrBuf *sb)
Definition: strbuf.c:342
RZ_API RzStrBuf * rz_strbuf_new(const char *s)
Definition: strbuf.c:8
RZ_API bool rz_strbuf_appendf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
#define RZ_FREE(x)
Definition: rz_types.h:369
#define c(i)
Definition: sha256.c:43
Definition: malloc.c:26
Definition: buffer.h:15
zip_uint64_t offset
Definition: z80asm.h:102
struct rz_asn1_object_t ** objects
Definition: rz_asn1.h:71
ASN1List list
Definition: rz_asn1.h:86
const ut8 * sector
Definition: rz_asn1.h:83
const char * string
Definition: rz_asn1.h:65
int64_t counter
Definition: main.c:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()