blob: 1e2a86365407459b9b32aa18852a29c869ed9a12 [file] [log] [blame]
Lev Walkincb523912017-09-30 19:33:23 -07001#include <T.h>
2
3#include <string.h>
4#include <errno.h>
5#include <unistd.h>
6#include <sys/stat.h>
7#include <sysexits.h>
8
Lev Walkind3cce462017-10-01 13:43:36 -07009#ifdef ASN1_TEXT
10#define STRINGIFY(x) #x
11#define ASN1_STR STRINGIFY(ASN1_TEXT)
12#else
13#define ASN1_STR "T"
14#endif
15
16static const struct encoding_map {
17 const char *name;
18 const char *dir_name;
19 enum asn_transfer_syntax syntax;
20} encodings[] = {
21 {"DER", "der", ATS_DER},
22 {"OER", "oer", ATS_CANONICAL_OER},
23 {"UPER", "uper", ATS_UNALIGNED_CANONICAL_PER},
24 {"XER", "xer", ATS_CANONICAL_XER},
25};
26
27static enum asn_transfer_syntax
28lookup_syntax(const char *name) {
29 if(name) {
30 for(size_t i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++) {
31 struct encoding_map enc = encodings[i];
32 if(strcasecmp(name, enc.name) == 0) {
33 return enc.syntax;
34 }
35 }
36 }
37 return ATS_INVALID;
38}
39
40
Lev Walkincb523912017-09-30 19:33:23 -070041#ifdef ENABLE_LIBFUZZER
42
Lev Walkind3cce462017-10-01 13:43:36 -070043static int initialized;
44static enum asn_transfer_syntax syntax;
45static void __attribute__((constructor)) initialize() {
46 initialized = 1;
47 const char *data_dir = getenv("ASN1_DATA_DIR");
48 if(data_dir && strrchr(data_dir, '/')) {
49 data_dir = strrchr(data_dir, '/') + 1;
50 }
51 syntax = lookup_syntax(data_dir);
52 if(syntax == ATS_INVALID) {
53 fprintf(stderr,
54 "Expected ASN1_DATA_DIR={der,oer,uper,xer} environment "
55 "variable.\n");
56 exit(EX_UNAVAILABLE);
57 }
58}
59
Lev Walkincb523912017-09-30 19:33:23 -070060int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
61
62int
63LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
Lev Walkind3cce462017-10-01 13:43:36 -070064 if(!initialized) exit(0);
65
66 /*
67 * Try to decode whatever garbage that comes in Data/Size.
68 * The idea is that we should not crash, and we should not leak memory,
69 * no matter what garbage we're dealing with.
70 */
71 T_t *structure = 0;
72 (void)asn_decode(0, syntax, &asn_DEF_T, (void **)&structure, Data, Size);
73 ASN_STRUCT_FREE(asn_DEF_T, structure);
74
Lev Walkincb523912017-09-30 19:33:23 -070075 return 0;
76}
77
78#else /* The usual check */
79
80static void
81usage(const char *progname) {
82 fprintf(stderr,
83 "Usage: %s {-c|-g <dir>} [-n <number>] [-e <encoding> ...]\n"
84 "OPTIONS:\n"
85 " -c Check encode-decode round-trip on random data\n"
86 " -g <dir> Generate random data for selected encodings\n"
87 " -n <number> Number of iterations for -c and -g\n"
88 " -e <encoding> Encodings to test or generate random data for\n"
89 "Encodings (ASN.1 Transfer Syntaxes):\n"
90 " DER Distinguished Encoding Rules (compatible with "
91 "BER)\n"
92 " OER Canonical Octet Encoding Rules\n"
93 " UPER Canonical Unaligned Packed Encoding Rules\n"
94 " XER XML Encoding Rules\n",
95 progname);
96}
97
Lev Walkincb523912017-09-30 19:33:23 -070098static int
99file_write_cb(const void *data, size_t size, void *key) {
100 return fwrite(data, 1, size, (FILE *)key) == size ? 0 : -1;
101}
102
103static void
104generate_random_data(enum asn_transfer_syntax syntax, const char *top_dirname, int iterations) {
105 char dirname[PATH_MAX];
106 size_t dirname_len = 0;
107 dirname[dirname_len] = '\0';
108
109 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
110 struct encoding_map enc = encodings[i];
111 if(enc.syntax == syntax) {
112 int r = snprintf(dirname, sizeof(dirname), "%s/%s", top_dirname,
Lev Walkind3cce462017-10-01 13:43:36 -0700113 enc.dir_name);
Lev Walkincb523912017-09-30 19:33:23 -0700114 if(r >= sizeof(dirname) - sizeof("filename.bin")) {
115 fprintf(stderr, "Too long filenames\n");
116 exit(EX_SOFTWARE);
117 }
118 dirname_len = r;
119 fprintf(stderr, "Generating %d random %s values of %s into %s\n",
120 iterations, enc.name, asn_DEF_T.name, dirname);
121 break;
122 }
123 }
124 assert(dirname[0]);
125
126 (void)mkdir(top_dirname, 0777);
127
128 if(mkdir(dirname, 0777) == -1) {
129 if(errno == EEXIST) {
130 fprintf(stderr, "%s: is already present, remove.\n", dirname);
131 fprintf(stderr, "%s: not overwriting potentially valuable data.\n",
132 dirname);
133 }
134 perror(dirname);
135 exit(2);
136 }
137
138 for(int i = 0; i < iterations; i++) {
139 T_t *structure = 0;
140 FILE *f;
141 snprintf(&dirname[dirname_len], sizeof(dirname) - dirname_len,
142 "/%03d.bin", i);
143
144 if(asn_random_fill(&asn_DEF_T, (void **)&structure, 128) == -1) {
145 assert(structure == 0);
146 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
147 continue;
148 }
149 assert(structure != 0);
150
151 const char *filename = dirname;
152 f = fopen(filename, "wb");
153 if(!f) {
154 perror(filename);
155 assert(f);
156 exit(EX_SOFTWARE);
157 }
158 asn_enc_rval_t rval =
159 asn_encode(0, syntax, &asn_DEF_T, structure, file_write_cb, f);
160 fclose(f);
161 if(rval.encoded == -1) {
162 fprintf(stderr, "Cannot encode a random value of T into %s:\n",
163 filename);
164 if(rval.failed_type) {
165 fprintf(stderr, "(Failed type: %s)\n", rval.failed_type->name);
166 }
167 asn_fprint(stderr, &asn_DEF_T, structure);
168 exit(EX_SOFTWARE);
169 }
170
171 if(i < 5) {
172 fprintf(stderr, "[%s] ", &filename[dirname_len+1]);
173 asn_fprint(stderr, &asn_DEF_T, structure);
174 } else if(i == 5) {
175 fprintf(stderr, "... and so on\n");
176 }
177
178 ASN_STRUCT_FREE(asn_DEF_T, structure);
179 }
180
181}
182
183static void
184check_random_roundtrip(enum asn_transfer_syntax syntax, int iterations) {
185 char tmp_buffer[512];
186 char *buffer = tmp_buffer;
187 size_t buffer_size = sizeof(tmp_buffer);
188 struct encoding_map enc;
189
190 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
191 enc = encodings[i];
192 if(enc.syntax == syntax) {
193 fprintf(stderr, "Testing %d iterations of round-trip for %s\n",
194 iterations, enc.name);
195 break;
196 }
197 }
198
199 for(int i = 0; i < iterations; i++) {
200 T_t *structure = 0;
201 T_t *decoded_structure = 0;
202
203 if(asn_random_fill(&asn_DEF_T, (void **)&structure, 128) == -1) {
204 assert(structure == 0);
205 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
206 continue;
207 }
208 assert(structure != 0);
209
210 asn_enc_rval_t er;
211 for(;;) {
212 er = asn_encode_to_buffer(
213 0, syntax, &asn_DEF_T, structure, buffer, buffer_size);
Lev Walkind3cce462017-10-01 13:43:36 -0700214 if(er.encoded == -1) {
215 fprintf(stderr, "Encoded T into %zd bytes\n", er.encoded);
216 fprintf(stderr, "Structure %s:\n",
217 sizeof(ASN1_STR) > 60 ? "T" : ASN1_STR);
218 asn_fprint(stderr, &asn_DEF_T, structure);
219 assert(er.encoded >= 0);
220 exit(EX_SOFTWARE);
221 }
Lev Walkincb523912017-09-30 19:33:23 -0700222 if(er.encoded > buffer_size && buffer == tmp_buffer) {
223 buffer = malloc(er.encoded + 1);
224 assert(buffer);
225 buffer[er.encoded] = '\0';
226 buffer_size = er.encoded;
227 continue;
228 }
229 break;
230 }
231 assert(er.encoded <= buffer_size);
232
233 asn_dec_rval_t rval =
234 asn_decode(0, syntax, &asn_DEF_T, (void **)&decoded_structure,
235 buffer, er.encoded);
236 if(rval.code == RC_OK) {
Lev Walkind3cce462017-10-01 13:43:36 -0700237 /* Everything's cool... or is it? Expecting a proper consumed */
238 if(rval.consumed != er.encoded) {
239 fprintf(stderr, "Encoded into %zd, yet consumed %zu",
240 er.encoded, rval.consumed);
241 fprintf(stderr, "Structure:\n");
242 asn_fprint(stderr, &asn_DEF_T, structure);
243 assert(rval.consumed == er.encoded);
244 exit(EX_SOFTWARE);
245 }
Lev Walkincb523912017-09-30 19:33:23 -0700246 } else {
247 fprintf(stderr,
248 "Decoding %zu bytes of T yielded %s after byte %zu\n",
249 er.encoded, rval.code == RC_FAIL ? "RC_FAIL" : "RC_WMORE",
250 rval.consumed);
251 fprintf(stderr, "Structure:\n");
252 asn_fprint(stderr, &asn_DEF_T, structure);
253 exit(EX_SOFTWARE);
254 }
255
Lev Walkind3cce462017-10-01 13:43:36 -0700256 /*
257 * Confirm that we decoded the same data.
258 */
259 int cmp = asn_DEF_T.op->compare_struct(&asn_DEF_T, structure,
260 decoded_structure);
261 if(cmp != 0) {
262 fprintf(stderr, "Random %s value:\n", ASN1_STR);
263 asn_fprint(stderr, &asn_DEF_T, structure);
264 fprintf(stderr, "Decoded %s value:\n", ASN1_STR);
265 asn_fprint(stderr, &asn_DEF_T, decoded_structure);
266 assert(cmp == 0);
267 }
268 ASN_STRUCT_FREE(asn_DEF_T, structure);
269 ASN_STRUCT_FREE(asn_DEF_T, decoded_structure);
Lev Walkincb523912017-09-30 19:33:23 -0700270
271 if(buffer != tmp_buffer) {
272 free(buffer);
273 buffer = tmp_buffer;
274 buffer_size = sizeof(tmp_buffer);
275 }
276
277 if(i < 5) {
278 fprintf(stderr, "[%03d] round-trip in %zd bytes OK\n", i,
279 er.encoded);
280 } else if(i == 5) {
281 fprintf(stderr, "... and so on\n");
282 }
283 }
284
285 fprintf(stderr, "OK %d iterations of round-trip for %s\n", iterations,
286 enc.name);
287}
288
289int main(int argc, char **argv) {
290 uint32_t enabled_encodings = 0;
291 enum {
292 MODE_UNKNOWN,
293 MODE_GENERATE_RANDOM_DATA,
294 MODE_CHECK_RANDOM_ROUNDTRIP
295 } mode = MODE_UNKNOWN;
296 const char *generate_into_dir = NULL;
297 int iterations = 100;
298 int c;
299
300 while((c = getopt(argc, argv, "ce:g:hn:")) != -1) {
301 switch(c) {
302 case 'c':
303 mode = MODE_CHECK_RANDOM_ROUNDTRIP;
304 break;
305 case 'e':
Lev Walkind3cce462017-10-01 13:43:36 -0700306 enabled_encodings |= 1 << lookup_syntax(optarg);
Lev Walkincb523912017-09-30 19:33:23 -0700307 if(enabled_encodings & (1 << ATS_INVALID)) {
308 fprintf(stderr, "-e %s: Unknown (unsupported?) encoding\n",
309 optarg);
310 exit(EX_UNAVAILABLE);
311 }
312 break;
313 case 'g':
314 mode = MODE_GENERATE_RANDOM_DATA;
315 generate_into_dir = optarg;
316 break;
317 case 'h':
318 usage(argv[0]);
319 exit(0);
320 case 'n':
321 iterations = atoi(optarg);
322 if(iterations <= 0) {
323 fprintf(stderr, "-n %s: positive value expected\n", optarg);
324 exit(EX_DATAERR);
325 }
326 break;
327 default:
328 usage(argv[0]);
329 exit(2);
330 }
331 }
332
333 if(mode == MODE_UNKNOWN) {
334 usage(argv[0]);
335 exit(2);
336 } else if(!enabled_encodings) {
337 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
338 enabled_encodings |= 1 << encodings[i].syntax;
339 }
340 }
341
342 /* Enumerate requested encodings (-e ...) */
343 for(unsigned i = 0; i < 8*sizeof(enabled_encodings)-1; i++) {
344 if(enabled_encodings & (1 << i)) {
345 enum asn_transfer_syntax syntax = i;
346 switch(mode) {
347 case MODE_UNKNOWN:
348 assert(mode != MODE_UNKNOWN);
349 break;
350 case MODE_GENERATE_RANDOM_DATA:
351 generate_random_data(syntax, generate_into_dir, iterations);
352 break;
353 case MODE_CHECK_RANDOM_ROUNDTRIP:
354 check_random_roundtrip(syntax, iterations);
355 break;
356 }
357 }
358 }
359
360 return 0;
361}
362
363#endif