blob: 6be6d97f70838e293ad5562deb2444c85ef74cb9 [file] [log] [blame]
Lev Walkincb523912017-09-30 19:33:23 -07001#include <T.h>
2
Lev Walkinc3680372017-10-08 17:37:37 -07003#include <stdio.h>
Lev Walkincb523912017-09-30 19:33:23 -07004#include <string.h>
5#include <errno.h>
6#include <unistd.h>
7#include <sys/stat.h>
8#include <sysexits.h>
9
Lev Walkind3cce462017-10-01 13:43:36 -070010#ifdef ASN1_TEXT
11#define STRINGIFY(x) #x
12#define ASN1_STR STRINGIFY(ASN1_TEXT)
13#else
14#define ASN1_STR "T"
15#endif
16
17static const struct encoding_map {
18 const char *name;
19 const char *dir_name;
20 enum asn_transfer_syntax syntax;
21} encodings[] = {
22 {"DER", "der", ATS_DER},
23 {"OER", "oer", ATS_CANONICAL_OER},
24 {"UPER", "uper", ATS_UNALIGNED_CANONICAL_PER},
25 {"XER", "xer", ATS_CANONICAL_XER},
26};
27
28static enum asn_transfer_syntax
29lookup_syntax(const char *name) {
30 if(name) {
31 for(size_t i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++) {
32 struct encoding_map enc = encodings[i];
33 if(strcasecmp(name, enc.name) == 0) {
34 return enc.syntax;
35 }
36 }
37 }
38 return ATS_INVALID;
39}
40
41
Lev Walkincb523912017-09-30 19:33:23 -070042#ifdef ENABLE_LIBFUZZER
43
Lev Walkind3cce462017-10-01 13:43:36 -070044static int initialized;
45static enum asn_transfer_syntax syntax;
46static void __attribute__((constructor)) initialize() {
47 initialized = 1;
48 const char *data_dir = getenv("ASN1_DATA_DIR");
49 if(data_dir && strrchr(data_dir, '/')) {
50 data_dir = strrchr(data_dir, '/') + 1;
51 }
52 syntax = lookup_syntax(data_dir);
53 if(syntax == ATS_INVALID) {
54 fprintf(stderr,
55 "Expected ASN1_DATA_DIR={der,oer,uper,xer} environment "
56 "variable.\n");
57 exit(EX_UNAVAILABLE);
58 }
59}
60
Lev Walkincb523912017-09-30 19:33:23 -070061int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
62
63int
64LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
Lev Walkind3cce462017-10-01 13:43:36 -070065 if(!initialized) exit(0);
66
67 /*
68 * Try to decode whatever garbage that comes in Data/Size.
69 * The idea is that we should not crash, and we should not leak memory,
70 * no matter what garbage we're dealing with.
71 */
72 T_t *structure = 0;
73 (void)asn_decode(0, syntax, &asn_DEF_T, (void **)&structure, Data, Size);
74 ASN_STRUCT_FREE(asn_DEF_T, structure);
75
Lev Walkincb523912017-09-30 19:33:23 -070076 return 0;
77}
78
79#else /* The usual check */
80
81static void
82usage(const char *progname) {
83 fprintf(stderr,
84 "Usage: %s {-c|-g <dir>} [-n <number>] [-e <encoding> ...]\n"
85 "OPTIONS:\n"
86 " -c Check encode-decode round-trip on random data\n"
87 " -g <dir> Generate random data for selected encodings\n"
Lev Walkin791d3b72017-10-02 16:24:28 -070088 " -s <size> Approximate max random value size for -c and -g\n"
Lev Walkincb523912017-09-30 19:33:23 -070089 " -n <number> Number of iterations for -c and -g\n"
90 " -e <encoding> Encodings to test or generate random data for\n"
91 "Encodings (ASN.1 Transfer Syntaxes):\n"
92 " DER Distinguished Encoding Rules (compatible with "
93 "BER)\n"
94 " OER Canonical Octet Encoding Rules\n"
95 " UPER Canonical Unaligned Packed Encoding Rules\n"
96 " XER XML Encoding Rules\n",
97 progname);
98}
99
Lev Walkincb523912017-09-30 19:33:23 -0700100static int
101file_write_cb(const void *data, size_t size, void *key) {
102 return fwrite(data, 1, size, (FILE *)key) == size ? 0 : -1;
103}
104
Lev Walkinc3680372017-10-08 17:37:37 -0700105#ifndef PATH_MAX
106#define PATH_MAX 255
107#endif
108
Lev Walkincb523912017-09-30 19:33:23 -0700109static void
Lev Walkin791d3b72017-10-02 16:24:28 -0700110generate_random_data(enum asn_transfer_syntax syntax, const char *top_dirname, size_t max_random_value_size, int iterations, int debug) {
Lev Walkincb523912017-09-30 19:33:23 -0700111 char dirname[PATH_MAX];
112 size_t dirname_len = 0;
113 dirname[dirname_len] = '\0';
114
115 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
116 struct encoding_map enc = encodings[i];
117 if(enc.syntax == syntax) {
118 int r = snprintf(dirname, sizeof(dirname), "%s/%s", top_dirname,
Lev Walkind3cce462017-10-01 13:43:36 -0700119 enc.dir_name);
Lev Walkin1bde6d42017-10-18 16:49:27 -0700120 if(r < 0 || (size_t)r >= sizeof(dirname) - sizeof("filename.bin")) {
Lev Walkincb523912017-09-30 19:33:23 -0700121 fprintf(stderr, "Too long filenames\n");
122 exit(EX_SOFTWARE);
123 }
124 dirname_len = r;
125 fprintf(stderr, "Generating %d random %s values of %s into %s\n",
126 iterations, enc.name, asn_DEF_T.name, dirname);
127 break;
128 }
129 }
130 assert(dirname[0]);
131
132 (void)mkdir(top_dirname, 0777);
133
134 if(mkdir(dirname, 0777) == -1) {
135 if(errno == EEXIST) {
136 fprintf(stderr, "%s: is already present, remove.\n", dirname);
137 fprintf(stderr, "%s: not overwriting potentially valuable data.\n",
138 dirname);
139 }
140 perror(dirname);
141 exit(2);
142 }
143
Lev Walkince6b0a62017-10-01 16:59:20 -0700144 size_t generated_ok = 0;
Lev Walkincb523912017-09-30 19:33:23 -0700145 for(int i = 0; i < iterations; i++) {
146 T_t *structure = 0;
147 FILE *f;
148 snprintf(&dirname[dirname_len], sizeof(dirname) - dirname_len,
149 "/%03d.bin", i);
150
Lev Walkin791d3b72017-10-02 16:24:28 -0700151 if(asn_random_fill(&asn_DEF_T, (void **)&structure,
152 max_random_value_size)
153 == -1) {
Lev Walkincb523912017-09-30 19:33:23 -0700154 assert(structure == 0);
155 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
156 continue;
157 }
158 assert(structure != 0);
159
160 const char *filename = dirname;
161 f = fopen(filename, "wb");
162 if(!f) {
163 perror(filename);
164 assert(f);
165 exit(EX_SOFTWARE);
166 }
167 asn_enc_rval_t rval =
168 asn_encode(0, syntax, &asn_DEF_T, structure, file_write_cb, f);
169 fclose(f);
170 if(rval.encoded == -1) {
171 fprintf(stderr, "Cannot encode a random value of T into %s:\n",
172 filename);
173 if(rval.failed_type) {
174 fprintf(stderr, "(Failed type: %s)\n", rval.failed_type->name);
175 }
176 asn_fprint(stderr, &asn_DEF_T, structure);
177 exit(EX_SOFTWARE);
178 }
179
Lev Walkin791d3b72017-10-02 16:24:28 -0700180 if(debug) {
181 if(i < 5 || debug > 1) {
182 fprintf(stderr, "[%s] ", &filename[dirname_len+1]);
183 asn_fprint(stderr, &asn_DEF_T, structure);
184 } else if(i == 5) {
185 fprintf(stderr, "... and so on\n");
186 }
Lev Walkincb523912017-09-30 19:33:23 -0700187 }
188
189 ASN_STRUCT_FREE(asn_DEF_T, structure);
Lev Walkince6b0a62017-10-01 16:59:20 -0700190 generated_ok++;
191 }
192
193 if(!generated_ok) {
194 fprintf(stderr, "Requested to generate %d values, but failed.\n",
195 iterations);
196 exit(EX_SOFTWARE);
Lev Walkincb523912017-09-30 19:33:23 -0700197 }
198
199}
200
201static void
Lev Walkin791d3b72017-10-02 16:24:28 -0700202check_random_roundtrip(enum asn_transfer_syntax syntax, size_t max_random_value_size, int iterations, int debug) {
Lev Walkincb523912017-09-30 19:33:23 -0700203 struct encoding_map enc;
204
205 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
206 enc = encodings[i];
207 if(enc.syntax == syntax) {
208 fprintf(stderr, "Testing %d iterations of round-trip for %s\n",
209 iterations, enc.name);
210 break;
211 }
212 }
213
214 for(int i = 0; i < iterations; i++) {
Lev Walkina5b02882017-10-01 22:48:44 -0700215 char tmp_buffer[512];
216 char *buffer = tmp_buffer;
217 size_t buffer_size = sizeof(tmp_buffer);
Lev Walkincb523912017-09-30 19:33:23 -0700218 T_t *structure = 0;
219 T_t *decoded_structure = 0;
220
Lev Walkin791d3b72017-10-02 16:24:28 -0700221 if(asn_random_fill(&asn_DEF_T, (void **)&structure,
222 max_random_value_size)
223 == -1) {
Lev Walkincb523912017-09-30 19:33:23 -0700224 assert(structure == 0);
225 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
226 continue;
227 }
228 assert(structure != 0);
229
230 asn_enc_rval_t er;
231 for(;;) {
232 er = asn_encode_to_buffer(
233 0, syntax, &asn_DEF_T, structure, buffer, buffer_size);
Lev Walkin1bde6d42017-10-18 16:49:27 -0700234 if(er.encoded < 0) {
Lev Walkind3cce462017-10-01 13:43:36 -0700235 fprintf(stderr, "Encoded T into %zd bytes\n", er.encoded);
236 fprintf(stderr, "Structure %s:\n",
237 sizeof(ASN1_STR) > 60 ? "T" : ASN1_STR);
238 asn_fprint(stderr, &asn_DEF_T, structure);
239 assert(er.encoded >= 0);
240 exit(EX_SOFTWARE);
241 }
Lev Walkin1bde6d42017-10-18 16:49:27 -0700242 if((size_t)er.encoded > buffer_size && buffer == tmp_buffer) {
Lev Walkin791d3b72017-10-02 16:24:28 -0700243 if(debug) {
244 fprintf(
245 stderr,
246 "Reallocate output buffer %zu -> %zu (iteration %d)\n",
247 buffer_size, er.encoded, i);
248 }
Lev Walkincb523912017-09-30 19:33:23 -0700249 buffer = malloc(er.encoded + 1);
250 assert(buffer);
251 buffer[er.encoded] = '\0';
252 buffer_size = er.encoded;
253 continue;
254 }
255 break;
256 }
Lev Walkin1bde6d42017-10-18 16:49:27 -0700257 if((size_t)er.encoded > buffer_size) {
Lev Walkina5b02882017-10-01 22:48:44 -0700258 fprintf(stderr, "Data %zd does not fit into buffer %zu\n",
259 er.encoded, buffer_size);
Lev Walkin1bde6d42017-10-18 16:49:27 -0700260 assert((size_t)er.encoded <= buffer_size);
Lev Walkina5b02882017-10-01 22:48:44 -0700261 }
Lev Walkincb523912017-09-30 19:33:23 -0700262
263 asn_dec_rval_t rval =
264 asn_decode(0, syntax, &asn_DEF_T, (void **)&decoded_structure,
265 buffer, er.encoded);
266 if(rval.code == RC_OK) {
Lev Walkind3cce462017-10-01 13:43:36 -0700267 /* Everything's cool... or is it? Expecting a proper consumed */
Lev Walkin1bde6d42017-10-18 16:49:27 -0700268 if((ssize_t)rval.consumed != er.encoded) {
Lev Walkina5b02882017-10-01 22:48:44 -0700269 fprintf(stderr, "Encoded into %zd, yet consumed %zu\n",
Lev Walkind3cce462017-10-01 13:43:36 -0700270 er.encoded, rval.consumed);
Lev Walkina5b02882017-10-01 22:48:44 -0700271 fprintf(stderr, "Original random structure:\n");
Lev Walkind3cce462017-10-01 13:43:36 -0700272 asn_fprint(stderr, &asn_DEF_T, structure);
Lev Walkin1bde6d42017-10-18 16:49:27 -0700273 assert((ssize_t)rval.consumed == er.encoded);
Lev Walkind3cce462017-10-01 13:43:36 -0700274 exit(EX_SOFTWARE);
275 }
Lev Walkincb523912017-09-30 19:33:23 -0700276 } else {
277 fprintf(stderr,
278 "Decoding %zu bytes of T yielded %s after byte %zu\n",
279 er.encoded, rval.code == RC_FAIL ? "RC_FAIL" : "RC_WMORE",
280 rval.consumed);
Lev Walkina5b02882017-10-01 22:48:44 -0700281 fprintf(stderr, "Original random structure:\n");
Lev Walkincb523912017-09-30 19:33:23 -0700282 asn_fprint(stderr, &asn_DEF_T, structure);
283 exit(EX_SOFTWARE);
284 }
285
Lev Walkind3cce462017-10-01 13:43:36 -0700286 /*
287 * Confirm that we decoded the same data.
288 */
289 int cmp = asn_DEF_T.op->compare_struct(&asn_DEF_T, structure,
290 decoded_structure);
291 if(cmp != 0) {
292 fprintf(stderr, "Random %s value:\n", ASN1_STR);
293 asn_fprint(stderr, &asn_DEF_T, structure);
Lev Walkinf585ad62017-10-17 21:10:13 -0700294 xer_fprint(stderr, &asn_DEF_T, structure);
Lev Walkind3cce462017-10-01 13:43:36 -0700295 fprintf(stderr, "Decoded %s value:\n", ASN1_STR);
296 asn_fprint(stderr, &asn_DEF_T, decoded_structure);
Lev Walkinf585ad62017-10-17 21:10:13 -0700297 xer_fprint(stderr, &asn_DEF_T, decoded_structure);
Lev Walkind3cce462017-10-01 13:43:36 -0700298 assert(cmp == 0);
299 }
300 ASN_STRUCT_FREE(asn_DEF_T, structure);
301 ASN_STRUCT_FREE(asn_DEF_T, decoded_structure);
Lev Walkincb523912017-09-30 19:33:23 -0700302
303 if(buffer != tmp_buffer) {
304 free(buffer);
Lev Walkincb523912017-09-30 19:33:23 -0700305 }
306
307 if(i < 5) {
308 fprintf(stderr, "[%03d] round-trip in %zd bytes OK\n", i,
309 er.encoded);
310 } else if(i == 5) {
311 fprintf(stderr, "... and so on\n");
312 }
313 }
314
315 fprintf(stderr, "OK %d iterations of round-trip for %s\n", iterations,
316 enc.name);
317}
318
319int main(int argc, char **argv) {
320 uint32_t enabled_encodings = 0;
321 enum {
322 MODE_UNKNOWN,
323 MODE_GENERATE_RANDOM_DATA,
324 MODE_CHECK_RANDOM_ROUNDTRIP
325 } mode = MODE_UNKNOWN;
326 const char *generate_into_dir = NULL;
327 int iterations = 100;
Lev Walkin791d3b72017-10-02 16:24:28 -0700328 size_t max_random_value_size = 128;
329 int debug = 0;
Lev Walkincb523912017-09-30 19:33:23 -0700330 int c;
331
Lev Walkin791d3b72017-10-02 16:24:28 -0700332 while((c = getopt(argc, argv, "cde:g:hn:s:")) != -1) {
Lev Walkincb523912017-09-30 19:33:23 -0700333 switch(c) {
334 case 'c':
335 mode = MODE_CHECK_RANDOM_ROUNDTRIP;
336 break;
Lev Walkin791d3b72017-10-02 16:24:28 -0700337 case 'd':
338 debug = 1;
339 break;
Lev Walkincb523912017-09-30 19:33:23 -0700340 case 'e':
Lev Walkind3cce462017-10-01 13:43:36 -0700341 enabled_encodings |= 1 << lookup_syntax(optarg);
Lev Walkincb523912017-09-30 19:33:23 -0700342 if(enabled_encodings & (1 << ATS_INVALID)) {
343 fprintf(stderr, "-e %s: Unknown (unsupported?) encoding\n",
344 optarg);
345 exit(EX_UNAVAILABLE);
346 }
347 break;
348 case 'g':
349 mode = MODE_GENERATE_RANDOM_DATA;
350 generate_into_dir = optarg;
351 break;
352 case 'h':
353 usage(argv[0]);
354 exit(0);
355 case 'n':
356 iterations = atoi(optarg);
357 if(iterations <= 0) {
358 fprintf(stderr, "-n %s: positive value expected\n", optarg);
359 exit(EX_DATAERR);
360 }
361 break;
Lev Walkin791d3b72017-10-02 16:24:28 -0700362 case 's':
363 if(atoi(optarg) <= 0) {
364 fprintf(stderr, "-s %s: positive value expected\n", optarg);
365 exit(EX_DATAERR);
366 }
367 max_random_value_size = atoi(optarg);
368 break;
Lev Walkincb523912017-09-30 19:33:23 -0700369 default:
370 usage(argv[0]);
371 exit(2);
372 }
373 }
374
375 if(mode == MODE_UNKNOWN) {
376 usage(argv[0]);
377 exit(2);
378 } else if(!enabled_encodings) {
379 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
380 enabled_encodings |= 1 << encodings[i].syntax;
381 }
382 }
383
384 /* Enumerate requested encodings (-e ...) */
385 for(unsigned i = 0; i < 8*sizeof(enabled_encodings)-1; i++) {
386 if(enabled_encodings & (1 << i)) {
387 enum asn_transfer_syntax syntax = i;
388 switch(mode) {
389 case MODE_UNKNOWN:
390 assert(mode != MODE_UNKNOWN);
391 break;
392 case MODE_GENERATE_RANDOM_DATA:
Lev Walkin791d3b72017-10-02 16:24:28 -0700393 generate_random_data(syntax, generate_into_dir,
394 max_random_value_size, iterations, debug);
Lev Walkincb523912017-09-30 19:33:23 -0700395 break;
396 case MODE_CHECK_RANDOM_ROUNDTRIP:
Lev Walkin791d3b72017-10-02 16:24:28 -0700397 check_random_roundtrip(syntax, max_random_value_size,
398 iterations, debug);
Lev Walkincb523912017-09-30 19:33:23 -0700399 break;
400 }
401 }
402 }
403
404 return 0;
405}
406
407#endif