Coverage Report

Created: 2025-08-28 07: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.61k
  case ASN1_CLASS_UNIVERSAL:
20
7.61k
    return "Universal";
21
695
  case ASN1_CLASS_APPLICATION:
22
695
    return "Application";
23
1.68k
  case ASN1_CLASS_CONTEXT_SPECIFIC:
24
1.68k
    return "Context-specific";
25
273k
  case ASN1_CLASS_PRIVATE:
26
273k
    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.79k
{
35
3.79k
  const u8 *pos, *prev, *end;
36
3.79k
  char prefix[10], str[100];
37
3.79k
  int _level;
38
3.79k
  struct asn1_hdr hdr;
39
3.79k
  struct asn1_oid oid;
40
3.79k
  u8 tmp;
41
42
3.79k
  _level = level;
43
3.79k
  if ((size_t) _level > sizeof(prefix) - 1)
44
783
    _level = sizeof(prefix) - 1;
45
3.79k
  memset(prefix, ' ', _level);
46
3.79k
  prefix[_level] = '\0';
47
48
3.79k
  pos = buf;
49
3.79k
  end = buf + len;
50
51
286k
  while (pos < end) {
52
283k
    if (asn1_get_next(pos, end - pos, &hdr) < 0)
53
381
      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.21k
      if (asn1_parse(pos, hdr.length, level + 1) < 0)
68
417
        return -1;
69
801
      pos += hdr.length;
70
801
    }
71
72
282k
    if (hdr.class != ASN1_CLASS_UNIVERSAL)
73
275k
      continue;
74
75
7.61k
    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.11k
    case ASN1_TAG_BOOLEAN:
86
1.11k
      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.11k
      tmp = *pos++;
92
1.11k
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s",
93
1.11k
           prefix, tmp ? "TRUE" : "FALSE");
94
1.11k
      break;
95
266
    case ASN1_TAG_INTEGER:
96
266
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER",
97
266
            pos, hdr.length);
98
266
      pos += hdr.length;
99
266
      break;
100
546
    case ASN1_TAG_BITSTRING:
101
546
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString",
102
546
            pos, hdr.length);
103
546
      pos += hdr.length;
104
546
      break;
105
270
    case ASN1_TAG_OCTETSTRING:
106
270
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString",
107
270
            pos, hdr.length);
108
270
      pos += hdr.length;
109
270
      break;
110
339
    case ASN1_TAG_NULL:
111
339
      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
339
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix);
117
339
      break;
118
1.45k
    case ASN1_TAG_OID:
119
1.45k
      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.41k
      asn1_oid_to_str(&oid, str, sizeof(str));
124
1.41k
      wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str);
125
1.41k
      pos += hdr.length;
126
1.41k
      break;
127
216
    case ANS1_TAG_RELATIVE_OID:
128
216
      wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID",
129
216
            pos, hdr.length);
130
216
      pos += hdr.length;
131
216
      break;
132
1.14k
    case ASN1_TAG_SEQUENCE:
133
1.14k
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix);
134
1.14k
      if (asn1_parse(pos, hdr.length, level + 1) < 0)
135
139
        return -1;
136
1.01k
      pos += hdr.length;
137
1.01k
      break;
138
486
    case ASN1_TAG_SET:
139
486
      wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix);
140
486
      if (asn1_parse(pos, hdr.length, level + 1) < 0)
141
88
        return -1;
142
398
      pos += hdr.length;
143
398
      break;
144
469
    case ASN1_TAG_PRINTABLESTRING:
145
469
      wpa_hexdump_ascii(MSG_MSGDUMP,
146
469
            "ASN.1: PrintableString",
147
469
            pos, hdr.length);
148
469
      pos += hdr.length;
149
469
      break;
150
349
    case ASN1_TAG_IA5STRING:
151
349
      wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String",
152
349
            pos, hdr.length);
153
349
      pos += hdr.length;
154
349
      break;
155
247
    case ASN1_TAG_UTCTIME:
156
247
      wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME",
157
247
            pos, hdr.length);
158
247
      pos += hdr.length;
159
247
      break;
160
237
    case ASN1_TAG_VISIBLESTRING:
161
237
      wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString",
162
237
            pos, hdr.length);
163
237
      pos += hdr.length;
164
237
      break;
165
165
    default:
166
165
      wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d",
167
165
           hdr.tag);
168
165
      return -1;
169
7.61k
    }
170
7.61k
  }
171
172
2.54k
  return 0;
173
3.79k
}
174
175
176
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
177
945
{
178
945
  wpa_fuzzer_set_debug_level();
179
180
945
  if (asn1_parse(data, size, 0) < 0)
181
607
    wpa_printf(MSG_DEBUG, "Failed to parse DER ASN.1");
182
183
945
  return 0;
184
945
}