Coverage Report

Created: 2026-05-14 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ntopng/third-party/snmp/asn1.c
Line
Count
Source
1
#include "_asn1.h"
2
3
#include <stdlib.h>
4
#include <string.h>
5
#include <assert.h>
6
#include <stdio.h>
7
8
#define MAX_OID_PARTS   256
9
10
static void *render_byte(int byte, void *dest)
11
0
{
12
  
13
0
  *(unsigned char *) dest = (unsigned char) byte;
14
0
  return (unsigned char *)dest + 1;
15
0
}
16
17
static void *read_byte(void *src, int *x)
18
0
{
19
0
  *x = *(unsigned char *) src;
20
0
  return (unsigned char *)src + 1;
21
0
}
22
23
static int length_length(int len)
24
0
{
25
0
  if (len <= 127)
26
0
    return 1;
27
0
  else
28
0
    {
29
0
      int size = 1;
30
0
      while (len > 255)
31
0
        {
32
0
    len >>= 8;
33
0
    size += 1;
34
0
        }
35
            
36
0
      return size + 1;
37
0
    }
38
0
}
39
40
static void *render_length(int data_len, void *dest)
41
0
{
42
0
  if (data_len <= 127)
43
0
    {
44
0
      return render_byte(data_len, dest);
45
0
    }
46
0
  else
47
0
    {
48
0
      int size = length_length(data_len) - 1;
49
0
      int i;
50
        
51
0
      dest = render_byte(size | 0x80, dest);
52
0
      for (i = size - 1; i >= 0; i--)
53
0
        {
54
0
    int v = (data_len >> (8 * i)) & 0xFF;
55
0
    dest = render_byte(v, dest);
56
0
        }
57
0
      return dest;
58
0
    }
59
0
}
60
61
static void *read_length(void *src, int *len)
62
0
{
63
0
  int v;
64
0
  src = read_byte(src, &v);
65
0
  if (v <= 127)
66
0
    {
67
0
      *len = v;
68
0
    }
69
0
  else
70
0
    {
71
0
      int size = v & 0x7F;
72
0
      int val = 0;
73
0
      int i;
74
        
75
0
      for (i = 0; i < size; i++)
76
0
        {
77
0
    src = read_byte(src, &v);
78
0
    val = (val << 8) + v;
79
0
        }
80
0
      *len = val;
81
0
    }
82
0
  return src;
83
0
}
84
85
int header_length(int type, int data_len)
86
0
{
87
0
  return 1 + length_length(data_len);
88
0
}
89
90
void *render_header(int type, int data_len, void *dest)
91
0
{
92
0
  dest = render_byte(type, dest);
93
0
  return render_length(data_len, dest);
94
0
}
95
96
int sequence_header_length(int data_len)
97
0
{
98
0
  return header_length(NTOP_ASN1_SEQUENCE_TYPE, data_len);
99
0
}
100
101
void *render_sequence_header(int data_len, void *dest)
102
0
{
103
0
  return render_header(NTOP_ASN1_SEQUENCE_TYPE, data_len, dest);
104
0
}
105
106
static int null_length()
107
0
{
108
0
  return 0;
109
0
}
110
111
static void *render_null(void *dest)
112
0
{
113
0
  return dest;
114
0
}
115
116
int integer_length(int x)
117
0
{
118
0
  unsigned int i;
119
120
0
  for(i = sizeof(x); i >= 2; i--) {
121
0
    if((x >> (8 * (i - 1))) & 0xFF)
122
0
      return i;
123
0
  }
124
125
0
  return 1;
126
0
}
127
128
static void *render_integer(int x, void *dest)
129
0
{
130
0
  unsigned i, int_len = integer_length(x);
131
132
0
  for(i = int_len; i >= 1; i--)
133
0
    dest = render_byte((x >> (8 * (i - 1))) & 0xFF, dest);
134
135
0
  return dest;
136
0
}
137
138
void *render_integer_object(int x, void *dest)
139
0
{
140
0
  int data_len = integer_length(x);
141
0
  dest = render_header(NTOP_ASN1_INTEGER_TYPE, data_len, dest);
142
0
  return render_integer(x, dest);
143
0
}
144
145
int string_length(char *str)
146
0
{
147
0
  int data_len = strlen(str);
148
0
  return data_len;
149
0
}
150
151
static void *render_string(char *str, void *dest)
152
0
{
153
0
  int len = strlen(str);
154
0
  memmove(dest, str, len);
155
0
  return (unsigned char *)dest + len;
156
0
}
157
158
void *render_string_object(char *str, void *dest)
159
0
{
160
0
  int data_len = string_length(str);
161
0
  dest = render_header(NTOP_ASN1_STRING_TYPE, data_len, dest);
162
0
  return render_string(str, dest);
163
0
}
164
165
static int oid_parts(char *oid)
166
0
{
167
0
  int parts = 1;
168
0
  char *p = oid;
169
    
170
0
  while (*p)
171
0
    {
172
0
      if (*p == '.')
173
0
  parts++;
174
0
      p++;
175
0
    }
176
0
  return parts;
177
0
}
178
179
static void oid_split(char *oid, int *dest)
180
0
{
181
0
  int next_part = 0;
182
0
  char *temp = strdup(oid);
183
0
  char *save_ptr;
184
    
185
0
  char *p = strtok_r(temp, ".", &save_ptr);
186
0
  while (p)
187
0
    {
188
0
      dest[next_part] = atoi(p);
189
0
      next_part++;
190
0
      p = strtok_r(NULL, ".", &save_ptr);
191
0
    }
192
    
193
0
  free(temp);
194
0
}
195
196
static int oid_part_length(int part)
197
0
{
198
0
  int len = 1;
199
    
200
0
  while (part > 127)
201
0
    {
202
0
      part >>= 7;
203
0
      len++;
204
0
    }
205
    
206
0
  return len;
207
0
}
208
209
static void *render_oid_part(int part, void *dest)
210
0
{
211
0
  int len = oid_part_length(part);
212
0
  int i;
213
    
214
0
  for (i = len-1; i >= 0; i--)
215
0
    {
216
0
      int v = part & 0x7F;
217
0
      if (i != len-1)
218
0
  v |= 0x80;
219
0
      part >>= 7;
220
0
      *(unsigned char *) ((unsigned char *)dest + i) = (char) v;
221
0
    }
222
    
223
0
  return (unsigned char *)dest + len;
224
0
}
225
226
int oid_length(char *oid)
227
0
{
228
0
  int data_len = 1;
229
0
  int num_parts = oid_parts(oid);
230
0
  int parts[MAX_OID_PARTS];
231
0
  int i;
232
    
233
0
  oid_split(oid, parts);
234
    
235
0
  for (i = 2; i < num_parts; i++)
236
0
    {
237
0
      data_len += oid_part_length(parts[i]);
238
0
    }
239
    
240
0
  return data_len;
241
0
}
242
243
static void *render_oid(char *oid, void *dest)
244
0
{
245
0
  int num_parts = oid_parts(oid);
246
0
  int parts[MAX_OID_PARTS];
247
0
  int i;
248
0
  int first_two;
249
    
250
0
  oid_split(oid, parts);
251
        
252
0
  first_two = parts[0] * 40 + parts[1];
253
0
  dest = render_byte(first_two, dest);
254
0
  for (i = 2; i < num_parts; i++)
255
0
    dest = render_oid_part(parts[i], dest);
256
    
257
0
  return dest;
258
0
}
259
260
void *render_oid_object(char *oid, void *dest)
261
0
{
262
0
  int data_len = oid_length(oid);
263
0
  dest = render_header(NTOP_ASN1_OID_TYPE, data_len, dest);
264
0
  return render_oid(oid, dest);
265
0
}
266
267
static void *read_oid_part(void *src, u_int64_t *part)
268
0
{
269
0
  int v;
270
0
  u_int64_t val = 0LL;
271
0
  do
272
0
    {
273
0
      src = read_byte(src, &v);
274
0
      val = (val << 7) + (u_int64_t)(v & 0x7F);
275
0
    }
276
0
  while (v > 127);
277
0
  *part = val;
278
0
  return src;
279
0
}
280
281
static void *read_oid(void *src, char **oid, int size)
282
0
{
283
0
  u_int64_t parts[MAX_OID_PARTS + 1];
284
0
  int first_byte;
285
0
  int i;
286
0
  void *endp = (unsigned char *)src + size;
287
0
  int num_parts;
288
0
  int len;
289
0
  char *p;
290
    
291
0
  src = read_byte(src, &first_byte);
292
0
  parts[0] = first_byte / 40;
293
0
  parts[1] = first_byte % 40;
294
    
295
0
  i = 2;
296
    
297
0
  while (src < endp)
298
0
    {
299
0
      src = read_oid_part(src, &parts[i]);
300
0
      i++;
301
0
    }
302
0
  num_parts = i;
303
    
304
0
  len = num_parts-1;
305
0
  for (i = 0; i < num_parts; i++)
306
0
    {
307
0
      len += snprintf(NULL, 0, "%lu", (unsigned long)parts[i]);
308
0
    }
309
    
310
0
  *oid = (char*)malloc(len+1);
311
0
  p = *oid;
312
0
  p += snprintf(p, len, "%lu", (unsigned long)parts[0]);
313
  
314
0
  for (i =1; i < num_parts; i++)
315
0
    {
316
0
      p += snprintf(p, len, ".%lu", (unsigned long)parts[i]);
317
0
    }
318
    
319
0
  return src;
320
0
}
321
322
int value_length(int render_as_type, Value value)
323
0
{
324
0
  switch (render_as_type)
325
0
    {
326
0
    case NTOP_ASN1_NULL_TYPE:
327
0
      return null_length();
328
0
    case NTOP_ASN1_INTEGER_TYPE:
329
0
      return integer_length(value.int_value);
330
0
    case NTOP_ASN1_STRING_TYPE:
331
0
      return string_length(value.str_value);
332
0
    default:
333
0
      abort();
334
0
    }
335
0
}
336
337
char *render_value(int render_as_type, Value value, char *dest)
338
0
{
339
0
  switch (render_as_type)
340
0
    {
341
0
    case NTOP_ASN1_NULL_TYPE:
342
0
      return (char*)render_null(dest);
343
0
    case NTOP_ASN1_INTEGER_TYPE:
344
0
      return (char*)render_integer(value.int_value, dest);
345
0
    case NTOP_ASN1_STRING_TYPE:
346
0
      return (char*)render_string(value.str_value, dest);
347
0
    default:
348
0
      abort();
349
0
    }
350
0
}
351
352
char *render_value_object(int value_type, int render_as_type, Value value, char *dest)
353
0
{
354
0
  int data_len = value_length(render_as_type, value);
355
0
  dest = (char*)render_header(value_type, data_len, dest);
356
    
357
0
  switch (render_as_type)
358
0
    {
359
0
    case NTOP_ASN1_NULL_TYPE:
360
0
      return (char*)render_null(dest);
361
0
    case NTOP_ASN1_INTEGER_TYPE:
362
0
      return (char*)render_integer(value.int_value, dest);
363
0
    case NTOP_ASN1_STRING_TYPE:
364
0
      return (char*)render_string(value.str_value, dest);
365
0
    default:
366
0
      abort();
367
0
    }
368
0
}
369
370
371
int object_length(int data_len)
372
0
{
373
0
  return header_length(0, data_len) + data_len;
374
0
}
375
376
typedef struct ASN1ParserState
377
{
378
  void *buffer;
379
  int remaining;
380
    
381
  struct ASN1ParserState *next;
382
} ASN1ParserState;
383
384
385
struct ASN1Parser
386
{
387
  ASN1ParserState *state;
388
    
389
  int depth;
390
};
391
392
static int next_type(ASN1Parser *parser)
393
0
{
394
0
  if (parser->state->remaining == 0)
395
0
    return 0;
396
0
  return ((unsigned char *) parser->state->buffer)[0];
397
0
}
398
399
static int next_len(ASN1Parser *parser)
400
0
{
401
0
  int len;
402
0
  if (parser->state->remaining < 2)
403
0
    return 0;
404
0
  read_length((char*)parser->state->buffer + 1, &len);
405
0
  return len;
406
0
}
407
408
static void *next_payload(ASN1Parser *parser)
409
0
{
410
0
  int len;
411
0
  void *p;
412
0
  if (parser->state->remaining < 2)
413
0
    return 0;
414
0
  p = read_length((char*)parser->state->buffer + 1, &len);
415
0
  return p;
416
0
}
417
418
static void push_state(ASN1Parser *parser, void *buffer, int remaining)
419
0
{
420
0
  ASN1ParserState *state = (ASN1ParserState*)malloc(sizeof(ASN1ParserState));
421
0
  state->buffer = buffer;
422
0
  state->remaining = remaining;
423
0
  state->next = parser->state;
424
0
  parser->state = state;
425
0
  parser->depth++;
426
0
}
427
428
static void pop_state(ASN1Parser *parser)
429
0
{
430
0
  ASN1ParserState *next_state = parser->state->next;
431
0
  free(parser->state);
432
0
  parser->state = next_state;
433
0
  parser->depth--;
434
0
}
435
436
static void consume(ASN1Parser *parser)
437
0
{
438
0
  int len = next_len(parser);
439
0
  void *payload = next_payload(parser);
440
0
  parser->state->remaining -= len + (char*)payload - (char*)parser->state->buffer;
441
0
  parser->state->buffer = (char*)payload + len;
442
0
}
443
444
ASN1Parser *asn1_create_parser(void *buffer, int len)
445
0
{
446
0
  ASN1Parser *parser = (ASN1Parser*)malloc(sizeof(ASN1Parser));
447
0
  parser->state = NULL;
448
0
  push_state(parser, buffer, len);
449
0
  parser->depth = 0;
450
0
  return parser;
451
0
}
452
453
void asn1_destroy_parser(ASN1Parser *parser)
454
0
{
455
0
  while (parser->depth >= 0)
456
0
    {
457
0
      pop_state(parser);
458
0
    }
459
        
460
0
  free(parser);
461
0
}
462
463
int asn1_parse_peek(ASN1Parser *parser, int *type, int *len)
464
0
{
465
0
  if (parser->state->remaining == 0)
466
0
    return 0;
467
    
468
0
  if (type)
469
0
    *type = next_type(parser);
470
0
  if (len)
471
0
    *len = next_len(parser);
472
0
  return 1;
473
0
}
474
475
int asn1_parse_sequence(ASN1Parser *parser)
476
0
{
477
0
  int type;
478
0
  if (next_type(parser) != NTOP_ASN1_SEQUENCE_TYPE)
479
0
    return 0;
480
0
  return asn1_parse_structure(parser, &type);
481
0
}
482
483
int asn1_parse_structure(ASN1Parser *parser, int *type)
484
0
{
485
0
  int t = next_type(parser);
486
0
  if (!(t & 0x20))
487
0
    return 0;
488
    
489
0
  if (type)
490
0
    *type = t;
491
    
492
0
  int len = next_len(parser);
493
0
  void *payload = next_payload(parser);
494
0
  if ((char*)payload + len > (char*)parser->state->buffer + parser->state->remaining)
495
0
    return 0;
496
0
  consume(parser);
497
0
  push_state(parser, payload, len);
498
0
  return 1;
499
0
}
500
501
int asn1_parse_integer_type(ASN1Parser *parser, int *type, int64_t *dest)
502
0
{
503
0
  int size;
504
0
  void *payload;
505
0
  int i;
506
0
  int64_t val = 0LL;
507
    
508
0
  if (type)
509
0
    *type = next_type(parser);
510
    
511
0
  size = next_len(parser);
512
0
  payload = next_payload(parser);
513
    
514
0
  for (i = 0; i < size; i++)
515
0
    {
516
0
      int v;
517
0
      payload = read_byte(payload, &v);
518
0
      val = (val << 8) + v;
519
0
    }
520
    
521
0
  *dest = val;
522
0
  consume(parser);
523
0
  return 1;
524
0
}
525
526
int asn1_parse_integer(ASN1Parser *parser, int *dest)
527
0
{
528
0
  int64_t dest64;
529
530
0
  if (next_type(parser) != NTOP_ASN1_INTEGER_TYPE)
531
0
    return 0;
532
533
0
  asn1_parse_integer_type(parser, NULL, &dest64);
534
0
  *dest = (int)dest64;
535
536
0
  return 1;
537
0
}
538
539
int asn1_parse_integer64(ASN1Parser *parser, int64_t *dest)
540
0
{
541
0
  if (next_type(parser) != NTOP_ASN1_INTEGER_TYPE)
542
0
    return 0;
543
    
544
0
  return asn1_parse_integer_type(parser, NULL, dest);
545
0
}
546
547
int asn1_parse_string_type(ASN1Parser *parser, int *type, char **dest)
548
0
{
549
0
  int size;
550
0
  void *payload;
551
0
  int i;
552
553
0
  if (type)
554
0
    *type = next_type(parser);
555
    
556
0
  size = next_len(parser);
557
0
  payload = next_payload(parser);
558
    
559
0
  *dest = (char*)malloc(size + 1);
560
    
561
0
  for (i = 0; i < size; i++)
562
0
    {
563
0
      int v;
564
0
      payload = read_byte(payload, &v);
565
0
      (*dest)[i] = v;
566
0
    }
567
0
  (*dest)[i] = 0;
568
  
569
  /* Patch for detecting MAC addresses and thus format them properly */
570
0
  if(size == 6) {
571
0
    u_int all_printable = 1;
572
573
0
    for(i = 0; i<size; i++) {
574
0
      if(!isprint((*dest)[i])) {
575
0
  all_printable = 0;
576
0
  break;
577
0
      }
578
0
    }
579
580
0
    if(!all_printable) {
581
      /* This looks like a MAC address */
582
0
      char tmp[24];
583
584
0
      snprintf(tmp, sizeof(tmp), "%02X:%02X:%02X:%02X:%02X:%02X",
585
0
         (*dest)[0] & 0xFF, (*dest)[1] & 0xFF, (*dest)[2] & 0xFF, 
586
0
         (*dest)[3] & 0xFF, (*dest)[4] & 0xFF, (*dest)[5] & 0xFF);
587
588
0
      free(*dest);
589
0
      *dest = strdup(tmp);
590
0
    }
591
0
  } else if(size == 4) {
592
    /* Check for IPv4 addresses */
593
0
    u_int8_t v1 = (*dest)[0] & 0xFF, v2 = (*dest)[1] & 0xFF, v3 = (*dest)[2] & 0xFF, v4 = (*dest)[3] & 0xFF;
594
595
0
    if((isalnum(v1)    || ispunct(v1))
596
0
       && (isalnum(v2) || ispunct(v2))
597
0
       && (isalnum(v3) || ispunct(v3))
598
0
       && (isalnum(v4) || ispunct(v4))
599
0
      )
600
0
      /* this looks like a string */;
601
0
    else {
602
0
      char tmp[24];
603
      
604
0
      snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u", v1, v2, v3, v4);
605
0
      free(*dest);
606
0
      *dest = strdup(tmp);
607
0
    }
608
0
  }
609
  
610
0
  consume(parser);
611
0
  return 1;
612
0
}
613
614
int asn1_parse_string(ASN1Parser *parser, char **dest)
615
0
{
616
0
  if (next_type(parser) != NTOP_ASN1_STRING_TYPE)
617
0
    return 0;
618
0
  return asn1_parse_string_type(parser, NULL, dest);
619
0
}
620
621
int asn1_parse_oid(ASN1Parser *parser, char **dest)
622
0
{
623
0
  int size;
624
0
  void *payload;
625
    
626
0
  if (next_type(parser) != NTOP_ASN1_OID_TYPE)
627
0
    return 0;
628
0
  size = next_len(parser);
629
0
  payload = next_payload(parser);
630
    
631
0
  read_oid(payload, dest, size);
632
    
633
0
  consume(parser);
634
0
  return 1;
635
0
}
636
637
int asn1_parse_primitive_value(ASN1Parser *parser, int *type, Value *value)
638
0
{
639
0
  int the_type = next_type(parser);
640
    
641
0
  if (type)
642
0
    *type = the_type;
643
    
644
0
  switch (the_type)
645
0
    {
646
0
    case NTOP_ASN1_NULL_TYPE:
647
0
      consume(parser);
648
0
      return 1;
649
        
650
0
    case NTOP_ASN1_INTEGER_TYPE:
651
0
      return asn1_parse_integer64(parser, &value->int_value);
652
        
653
0
    case NTOP_ASN1_STRING_TYPE:
654
0
      return asn1_parse_string(parser, &value->str_value);
655
        
656
0
    default:
657
0
      return 0;
658
0
    }
659
0
}
660
661
int asn1_parse_pop(ASN1Parser *parser)
662
0
{
663
0
  if (parser->depth == 0)
664
0
    return 0;
665
    
666
  /* if (parser->state->remaining != 0) */
667
  /*   return 0; */
668
  
669
0
  pop_state(parser);
670
0
  return 1;
671
0
}