11 #define STRINGIFY(x) #x
12 #define ASN1_STR STRINGIFY(ASN1_TEXT)
17 static const struct encoding_map {
20 enum asn_transfer_syntax syntax;
22 {"DER", "der", ATS_DER},
23 {"OER", "oer", ATS_CANONICAL_OER},
24 {"UPER", "uper", ATS_UNALIGNED_CANONICAL_PER},
25 {"XER", "xer", ATS_CANONICAL_XER},
28 static enum asn_transfer_syntax
29 lookup_syntax(const char *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) {
42 #ifdef ENABLE_LIBFUZZER
44 static int initialized;
45 static enum asn_transfer_syntax syntax;
46 static void __attribute__((constructor)) initialize() {
48 const char *data_dir = getenv("ASN1_DATA_DIR");
49 if(data_dir && strrchr(data_dir, '/')) {
50 data_dir = strrchr(data_dir, '/') + 1;
52 syntax = lookup_syntax(data_dir);
53 if(syntax == ATS_INVALID) {
55 "Expected ASN1_DATA_DIR={der,oer,uper,xer} environment "
61 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
64 LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
65 if(!initialized) exit(0);
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.
73 (void)asn_decode(0, syntax, &asn_DEF_T, (void **)&structure, Data, Size);
74 ASN_STRUCT_FREE(asn_DEF_T, structure);
79 #else /* The usual check */
82 usage(const char *progname) {
84 "Usage: %s {-c|-g <dir>} [-n <number>] [-e <encoding> ...]\n"
86 " -c Check encode-decode round-trip on random data\n"
87 " -g <dir> Generate random data for selected encodings\n"
88 " -s <size> Approximate max random value size for -c and -g\n"
89 " -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 "
94 " OER Canonical Octet Encoding Rules\n"
95 " UPER Canonical Unaligned Packed Encoding Rules\n"
96 " XER XML Encoding Rules\n",
101 file_write_cb(const void *data, size_t size, void *key) {
102 return fwrite(data, 1, size, (FILE *)key) == size ? 0 : -1;
110 generate_random_data(enum asn_transfer_syntax syntax, const char *top_dirname, size_t max_random_value_size, int iterations, int debug) {
111 char dirname[PATH_MAX];
112 size_t dirname_len = 0;
113 dirname[dirname_len] = '\0';
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,
120 if(r < 0 || (size_t)r >= sizeof(dirname) - sizeof("filename.bin")) {
121 fprintf(stderr, "Too long filenames\n");
125 fprintf(stderr, "Generating %d random %s values of %s into %s\n",
126 iterations, enc.name, asn_DEF_T.name, dirname);
132 (void)mkdir(top_dirname, 0777);
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",
144 size_t generated_ok = 0;
145 for(int i = 0; i < iterations; i++) {
148 snprintf(&dirname[dirname_len], sizeof(dirname) - dirname_len,
151 if(asn_random_fill(&asn_DEF_T, (void **)&structure,
152 max_random_value_size)
154 assert(structure == 0);
155 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
158 assert(structure != 0);
160 const char *filename = dirname;
161 f = fopen(filename, "wb");
167 asn_enc_rval_t rval =
168 asn_encode(0, syntax, &asn_DEF_T, structure, file_write_cb, f);
170 if(rval.encoded == -1) {
171 fprintf(stderr, "Cannot encode a random value of T into %s:\n",
173 if(rval.failed_type) {
174 fprintf(stderr, "(Failed type: %s)\n", rval.failed_type->name);
176 asn_fprint(stderr, &asn_DEF_T, structure);
181 if(i < 5 || debug > 1) {
182 fprintf(stderr, "[%s] ", &filename[dirname_len+1]);
183 asn_fprint(stderr, &asn_DEF_T, structure);
185 fprintf(stderr, "... and so on\n");
189 ASN_STRUCT_FREE(asn_DEF_T, structure);
194 fprintf(stderr, "Requested to generate %d values, but failed.\n",
202 check_random_roundtrip(enum asn_transfer_syntax syntax, size_t max_random_value_size, int iterations, int debug) {
203 struct encoding_map enc;
205 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
207 if(enc.syntax == syntax) {
208 fprintf(stderr, "Testing %d iterations of round-trip for %s\n",
209 iterations, enc.name);
214 for(int i = 0; i < iterations; i++) {
215 char tmp_buffer[512];
216 char *buffer = tmp_buffer;
217 size_t buffer_size = sizeof(tmp_buffer);
219 T_t *decoded_structure = 0;
221 if(asn_random_fill(&asn_DEF_T, (void **)&structure,
222 max_random_value_size)
224 assert(structure == 0);
225 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
228 assert(structure != 0);
231 fprintf(stderr, "Random structure %s:\n",
232 sizeof(ASN1_STR) > 60 ? "T" : ASN1_STR);
233 asn_fprint(stderr, &asn_DEF_T, structure);
234 xer_fprint(stderr, &asn_DEF_T, structure);
239 er = asn_encode_to_buffer(
240 0, syntax, &asn_DEF_T, structure, buffer, buffer_size);
242 fprintf(stderr, "Encoded T into %zd bytes\n", er.encoded);
243 fprintf(stderr, "Structure %s:\n",
244 sizeof(ASN1_STR) > 60 ? "T" : ASN1_STR);
245 asn_fprint(stderr, &asn_DEF_T, structure);
246 assert(er.encoded >= 0);
249 if((size_t)er.encoded > buffer_size && buffer == tmp_buffer) {
253 "Reallocate output buffer %zu -> %zu (iteration %d)\n",
254 buffer_size, er.encoded, i);
256 buffer = malloc(er.encoded + 1);
258 buffer[er.encoded] = '\0';
259 buffer_size = er.encoded;
264 if((size_t)er.encoded > buffer_size) {
265 fprintf(stderr, "Data %zd does not fit into buffer %zu\n",
266 er.encoded, buffer_size);
267 assert((size_t)er.encoded <= buffer_size);
270 asn_dec_rval_t rval =
271 asn_decode(0, syntax, &asn_DEF_T, (void **)&decoded_structure,
273 if(rval.code == RC_OK) {
274 /* Everything's cool... or is it? Expecting a proper consumed */
275 if((ssize_t)rval.consumed != er.encoded) {
276 fprintf(stderr, "Encoded into %zd, yet consumed %zu\n",
277 er.encoded, rval.consumed);
278 fprintf(stderr, "Original random structure:\n");
279 asn_fprint(stderr, &asn_DEF_T, structure);
280 fprintf(stderr, "Partially decoded %s value:\n", ASN1_STR);
281 asn_fprint(stderr, &asn_DEF_T, decoded_structure);
282 assert((ssize_t)rval.consumed == er.encoded);
287 "Decoding %zu bytes of T yielded %s after byte %zu\n",
288 er.encoded, rval.code == RC_FAIL ? "RC_FAIL" : "RC_WMORE",
290 fprintf(stderr, "Original random structure:\n");
291 asn_fprint(stderr, &asn_DEF_T, structure);
296 * Confirm that we decoded the same data.
298 int cmp = asn_DEF_T.op->compare_struct(&asn_DEF_T, structure,
300 if(cmp != 0 || debug) {
301 fprintf(stderr, "Random %s value:\n", ASN1_STR);
302 asn_fprint(stderr, &asn_DEF_T, structure);
303 xer_fprint(stderr, &asn_DEF_T, structure);
304 fprintf(stderr, "Decoded %s value:\n", ASN1_STR);
305 asn_fprint(stderr, &asn_DEF_T, decoded_structure);
306 xer_fprint(stderr, &asn_DEF_T, decoded_structure);
309 ASN_STRUCT_FREE(asn_DEF_T, structure);
310 ASN_STRUCT_FREE(asn_DEF_T, decoded_structure);
312 if(buffer != tmp_buffer) {
317 fprintf(stderr, "[%03d] round-trip in %zd bytes OK\n", i,
320 fprintf(stderr, "... and so on\n");
324 fprintf(stderr, "OK %d iterations of round-trip for %s\n", iterations,
328 int main(int argc, char **argv) {
329 uint32_t enabled_encodings = 0;
332 MODE_GENERATE_RANDOM_DATA,
333 MODE_CHECK_RANDOM_ROUNDTRIP
334 } mode = MODE_UNKNOWN;
335 const char *generate_into_dir = NULL;
336 int iterations = 100;
337 size_t max_random_value_size = 128;
341 while((c = getopt(argc, argv, "cde:g:hn:s:")) != -1) {
344 mode = MODE_CHECK_RANDOM_ROUNDTRIP;
350 enabled_encodings |= 1 << lookup_syntax(optarg);
351 if(enabled_encodings & (1 << ATS_INVALID)) {
352 fprintf(stderr, "-e %s: Unknown (unsupported?) encoding\n",
354 exit(EX_UNAVAILABLE);
358 mode = MODE_GENERATE_RANDOM_DATA;
359 generate_into_dir = optarg;
365 iterations = atoi(optarg);
366 if(iterations <= 0) {
367 fprintf(stderr, "-n %s: positive value expected\n", optarg);
372 if(atoi(optarg) <= 0) {
373 fprintf(stderr, "-s %s: positive value expected\n", optarg);
376 max_random_value_size = atoi(optarg);
384 if(mode == MODE_UNKNOWN) {
387 } else if(!enabled_encodings) {
388 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
389 enabled_encodings |= 1 << encodings[i].syntax;
393 /* Enumerate requested encodings (-e ...) */
394 for(unsigned i = 0; i < 8*sizeof(enabled_encodings)-1; i++) {
395 if(enabled_encodings & (1 << i)) {
396 enum asn_transfer_syntax syntax = i;
399 assert(mode != MODE_UNKNOWN);
401 case MODE_GENERATE_RANDOM_DATA:
402 generate_random_data(syntax, generate_into_dir,
403 max_random_value_size, iterations, debug);
405 case MODE_CHECK_RANDOM_ROUNDTRIP:
406 check_random_roundtrip(syntax, max_random_value_size,