Coverage Report

Created: 2025-08-26 06:04

/src/hostap/tests/fuzzing/asn1/asn1.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Fuzzing tool for ASN.1 routines
3
 * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
4
 *
5
 * This software may be distributed under the terms of the BSD license.
6
 * See README for more details.
7
 */
8
9
#include "includes.h"
10
11
#include "common.h"
12
#include "tls/asn1.h"
13
#include "../fuzzer-common.h"
14
15
16
static const char * asn1_class_str(int class)
17
283k
{
18
283k
  switch (class) {
19
7.94k
  case ASN1_CLASS_UNIVERSAL:
20
7.94k
    return "Universal";
21
929
  case ASN1_CLASS_APPLICATION:
22
929
    return "Application";
23
1.75k
  case ASN1_CLASS_CONTEXT_SPECIFIC:
24
1.75k
    return "Context-specific";
25
272k
  case ASN1_CLASS_PRIVATE:
26
272k
    return "Private";
27
0
  default:
28
0
    return "?";
29
283k
  }
30
283k
}
31
32
33
static int asn1_parse(const u8 *buf, size_t len, int level)
34
3.88k
{
35
3.88k
  const u8 *pos, *prev, *end;
36
3.88k
  char prefix[10], str[100];
37
3.88k
  int _level;
38
3.88k
  struct asn1_hdr hdr;
39
3.88k
  struct asn1_oid oid;
40
3.88k
  u8 tmp;
41
42
3.88k
  _level = level;
43
3.88k
  if ((size_t) _level > sizeof(prefix) - 1)
44
785
    _level = sizeof(prefix) - 1;
45
3.88k
  memset(prefix, ' ', _level);
46
3.88k
  prefix[_level] = '\0';
47
48
3.88k
  pos = buf;
49
3.88k
  end = buf + len;
50
51
286k
  while (pos < end) {
52
283k
    if (asn1_get_next(pos, end - pos, &hdr) < 0)
53
392
      return -1;
54
55
283k
    prev = pos;
56
283k
    pos = hdr.payload;
57
58
283k
    wpa_printf(MSG_MSGDUMP, "ASN.1:%s Class %d(%s) P/C %d(%s) "
59
283k
         "Tag %u Length %u",
60
283k
         prefix, hdr.class, asn1_class_str(hdr.class),
61
283k
         hdr.constructed,
62
283k
         hdr.constructed ? "Constructed" : "Primitive",
63
283k
         hdr.tag, hdr.length);
64
65
283k
    if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC &&
66
283k
        hdr.constructed) {
67
1.19k
      if (asn1_parse(pos, hdr.length, level + 1) < 0)
68
461
        return -1;
69
733
      pos += hdr.length;
70
733
    }
71
72
283k
    if (hdr.class != ASN1_CLASS_UNIVERSAL)
73
275k
      continue;
74
75
7.94k
    switch (hdr.tag) {
76
312
    case ASN1_TAG_EOC:
77
312
      if (hdr.length) {
78
21
        wpa_printf(MSG_DEBUG, "ASN.1: Non-zero "
79
21
             "end-of-contents length (%u)",
80
21
             hdr.length);
81
21
        return -1;
82
21
      }
83
291
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s EOC", prefix);
84
291
      break;
85
1.04k
    case ASN1_TAG_BOOLEAN:
86
1.04k
      if (hdr.length != 1) {
87
0
        wpa_printf(MSG_DEBUG, "ASN.1: Unexpected "
88
0
             "Boolean length (%u)", hdr.length);
89
0
        return -1;
90
0
      }
91
1.04k
      tmp = *pos++;
92
1.04k
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s",
93
1.04k
           prefix, tmp ? "TRUE" : "FALSE");
94
1.04k
      break;
95
269
    case ASN1_TAG_INTEGER:
96
269
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER",
97
269
            pos, hdr.length);
98
269
      pos += hdr.length;
99
269
      break;
100
608
    case ASN1_TAG_BITSTRING:
101
608
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString",
102
608
            pos, hdr.length);
103
608
      pos += hdr.length;
104
608
      break;
105
274
    case ASN1_TAG_OCTETSTRING:
106
274
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString",
107
274
            pos, hdr.length);
108
274
      pos += hdr.length;
109
274
      break;
110
347
    case ASN1_TAG_NULL:
111
347
      if (hdr.length) {
112
0
        wpa_printf(MSG_DEBUG, "ASN.1: Non-zero Null "
113
0
             "length (%u)", hdr.length);
114
0
        return -1;
115
0
      }
116
347
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix);
117
347
      break;
118
1.52k
    case ASN1_TAG_OID:
119
1.52k
      if (asn1_get_oid(prev, end - prev, &oid, &prev) < 0) {
120
40
        wpa_printf(MSG_DEBUG, "ASN.1: Invalid OID");
121
40
        return -1;
122
40
      }
123
1.48k
      asn1_oid_to_str(&oid, str, sizeof(str));
124
1.48k
      wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str);
125
1.48k
      pos += hdr.length;
126
1.48k
      break;
127
207
    case ANS1_TAG_RELATIVE_OID:
128
207
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID",
129
207
            pos, hdr.length);
130
207
      pos += hdr.length;
131
207
      break;
132
1.20k
    case ASN1_TAG_SEQUENCE:
133
1.20k
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix);
134
1.20k
      if (asn1_parse(pos, hdr.length, level + 1) < 0)
135
146
        return -1;
136
1.06k
      pos += hdr.length;
137
1.06k
      break;
138
530
    case ASN1_TAG_SET:
139
530
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix);
140
530
      if (asn1_parse(pos, hdr.length, level + 1) < 0)
141
91
        return -1;
142
439
      pos += hdr.length;
143
439
      break;
144
611
    case ASN1_TAG_PRINTABLESTRING:
145
611
      wpa_hexdump_ascii(MSG_MSGDUMP,
146
611
            "ASN.1: PrintableString",
147
611
            pos, hdr.length);
148
611
      pos += hdr.length;
149
611
      break;
150
364
    case ASN1_TAG_IA5STRING:
151
364
      wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String",
152
364
            pos, hdr.length);
153
364
      pos += hdr.length;
154
364
      break;
155
272
    case ASN1_TAG_UTCTIME:
156
272
      wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME",
157
272
            pos, hdr.length);
158
272
      pos += hdr.length;
159
272
      break;
160
205
    case ASN1_TAG_VISIBLESTRING:
161
205
      wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString",
162
205
            pos, hdr.length);
163
205
      pos += hdr.length;
164
205
      break;
165
168
    default:
166
168
      wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d",
167
168
           hdr.tag);
168
168
      return -1;
169
7.94k
    }
170
7.94k
  }
171
172
2.57k
  return 0;
173
3.88k
}
174
175
176
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
177
958
{
178
958
  wpa_fuzzer_set_debug_level();
179
180
958
  if (asn1_parse(data, size, 0) < 0)
181
621
    wpa_printf(MSG_DEBUG, "Failed to parse DER ASN.1");
182
183
958
  return 0;
184
958
}