blob: dade655cff24be62717d3ef0858d40ecb916ca3e [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
9#ifdef ENABLE_LIBFUZZER
10
11int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
12
13int
14LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
15 return 0;
16}
17
18#else /* The usual check */
19
20static void
21usage(const char *progname) {
22 fprintf(stderr,
23 "Usage: %s {-c|-g <dir>} [-n <number>] [-e <encoding> ...]\n"
24 "OPTIONS:\n"
25 " -c Check encode-decode round-trip on random data\n"
26 " -g <dir> Generate random data for selected encodings\n"
27 " -n <number> Number of iterations for -c and -g\n"
28 " -e <encoding> Encodings to test or generate random data for\n"
29 "Encodings (ASN.1 Transfer Syntaxes):\n"
30 " DER Distinguished Encoding Rules (compatible with "
31 "BER)\n"
32 " OER Canonical Octet Encoding Rules\n"
33 " UPER Canonical Unaligned Packed Encoding Rules\n"
34 " XER XML Encoding Rules\n",
35 progname);
36}
37
38static const struct encoding_map {
39 const char *name;
40 enum asn_transfer_syntax syntax;
41} encodings[] = {
42 {"der", ATS_DER},
43 {"oer", ATS_CANONICAL_OER},
44 {"uper", ATS_UNALIGNED_CANONICAL_PER},
45 {"xer", ATS_CANONICAL_XER},
46};
47
48static enum asn_transfer_syntax
49lookup_encoding(const char *name) {
50 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
51 struct encoding_map enc = encodings[i];
52 if(strcasecmp(name, enc.name) == 0) {
53 return enc.syntax;
54 }
55 }
56 return ATS_INVALID;
57}
58
59static int
60file_write_cb(const void *data, size_t size, void *key) {
61 return fwrite(data, 1, size, (FILE *)key) == size ? 0 : -1;
62}
63
64static void
65generate_random_data(enum asn_transfer_syntax syntax, const char *top_dirname, int iterations) {
66 char dirname[PATH_MAX];
67 size_t dirname_len = 0;
68 dirname[dirname_len] = '\0';
69
70 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
71 struct encoding_map enc = encodings[i];
72 if(enc.syntax == syntax) {
73 int r = snprintf(dirname, sizeof(dirname), "%s/%s", top_dirname,
74 enc.name);
75 if(r >= sizeof(dirname) - sizeof("filename.bin")) {
76 fprintf(stderr, "Too long filenames\n");
77 exit(EX_SOFTWARE);
78 }
79 dirname_len = r;
80 fprintf(stderr, "Generating %d random %s values of %s into %s\n",
81 iterations, enc.name, asn_DEF_T.name, dirname);
82 break;
83 }
84 }
85 assert(dirname[0]);
86
87 (void)mkdir(top_dirname, 0777);
88
89 if(mkdir(dirname, 0777) == -1) {
90 if(errno == EEXIST) {
91 fprintf(stderr, "%s: is already present, remove.\n", dirname);
92 fprintf(stderr, "%s: not overwriting potentially valuable data.\n",
93 dirname);
94 }
95 perror(dirname);
96 exit(2);
97 }
98
99 for(int i = 0; i < iterations; i++) {
100 T_t *structure = 0;
101 FILE *f;
102 snprintf(&dirname[dirname_len], sizeof(dirname) - dirname_len,
103 "/%03d.bin", i);
104
105 if(asn_random_fill(&asn_DEF_T, (void **)&structure, 128) == -1) {
106 assert(structure == 0);
107 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
108 continue;
109 }
110 assert(structure != 0);
111
112 const char *filename = dirname;
113 f = fopen(filename, "wb");
114 if(!f) {
115 perror(filename);
116 assert(f);
117 exit(EX_SOFTWARE);
118 }
119 asn_enc_rval_t rval =
120 asn_encode(0, syntax, &asn_DEF_T, structure, file_write_cb, f);
121 fclose(f);
122 if(rval.encoded == -1) {
123 fprintf(stderr, "Cannot encode a random value of T into %s:\n",
124 filename);
125 if(rval.failed_type) {
126 fprintf(stderr, "(Failed type: %s)\n", rval.failed_type->name);
127 }
128 asn_fprint(stderr, &asn_DEF_T, structure);
129 exit(EX_SOFTWARE);
130 }
131
132 if(i < 5) {
133 fprintf(stderr, "[%s] ", &filename[dirname_len+1]);
134 asn_fprint(stderr, &asn_DEF_T, structure);
135 } else if(i == 5) {
136 fprintf(stderr, "... and so on\n");
137 }
138
139 ASN_STRUCT_FREE(asn_DEF_T, structure);
140 }
141
142}
143
144static void
145check_random_roundtrip(enum asn_transfer_syntax syntax, int iterations) {
146 char tmp_buffer[512];
147 char *buffer = tmp_buffer;
148 size_t buffer_size = sizeof(tmp_buffer);
149 struct encoding_map enc;
150
151 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
152 enc = encodings[i];
153 if(enc.syntax == syntax) {
154 fprintf(stderr, "Testing %d iterations of round-trip for %s\n",
155 iterations, enc.name);
156 break;
157 }
158 }
159
160 for(int i = 0; i < iterations; i++) {
161 T_t *structure = 0;
162 T_t *decoded_structure = 0;
163
164 if(asn_random_fill(&asn_DEF_T, (void **)&structure, 128) == -1) {
165 assert(structure == 0);
166 fprintf(stderr, "Can't generate %d'th value, skipping\n", i);
167 continue;
168 }
169 assert(structure != 0);
170
171 asn_enc_rval_t er;
172 for(;;) {
173 er = asn_encode_to_buffer(
174 0, syntax, &asn_DEF_T, structure, buffer, buffer_size);
175 if(er.encoded > buffer_size && buffer == tmp_buffer) {
176 buffer = malloc(er.encoded + 1);
177 assert(buffer);
178 buffer[er.encoded] = '\0';
179 buffer_size = er.encoded;
180 continue;
181 }
182 break;
183 }
184 assert(er.encoded <= buffer_size);
185
186 asn_dec_rval_t rval =
187 asn_decode(0, syntax, &asn_DEF_T, (void **)&decoded_structure,
188 buffer, er.encoded);
189 if(rval.code == RC_OK) {
190 assert(rval.consumed == er.encoded);
191 /* Everything's cool */
192 } else {
193 fprintf(stderr,
194 "Decoding %zu bytes of T yielded %s after byte %zu\n",
195 er.encoded, rval.code == RC_FAIL ? "RC_FAIL" : "RC_WMORE",
196 rval.consumed);
197 fprintf(stderr, "Structure:\n");
198 asn_fprint(stderr, &asn_DEF_T, structure);
199 exit(EX_SOFTWARE);
200 }
201
202
203 if(buffer != tmp_buffer) {
204 free(buffer);
205 buffer = tmp_buffer;
206 buffer_size = sizeof(tmp_buffer);
207 }
208
209 if(i < 5) {
210 fprintf(stderr, "[%03d] round-trip in %zd bytes OK\n", i,
211 er.encoded);
212 } else if(i == 5) {
213 fprintf(stderr, "... and so on\n");
214 }
215 }
216
217 fprintf(stderr, "OK %d iterations of round-trip for %s\n", iterations,
218 enc.name);
219}
220
221int main(int argc, char **argv) {
222 uint32_t enabled_encodings = 0;
223 enum {
224 MODE_UNKNOWN,
225 MODE_GENERATE_RANDOM_DATA,
226 MODE_CHECK_RANDOM_ROUNDTRIP
227 } mode = MODE_UNKNOWN;
228 const char *generate_into_dir = NULL;
229 int iterations = 100;
230 int c;
231
232 while((c = getopt(argc, argv, "ce:g:hn:")) != -1) {
233 switch(c) {
234 case 'c':
235 mode = MODE_CHECK_RANDOM_ROUNDTRIP;
236 break;
237 case 'e':
238 enabled_encodings |= 1 << lookup_encoding(optarg);
239 if(enabled_encodings & (1 << ATS_INVALID)) {
240 fprintf(stderr, "-e %s: Unknown (unsupported?) encoding\n",
241 optarg);
242 exit(EX_UNAVAILABLE);
243 }
244 break;
245 case 'g':
246 mode = MODE_GENERATE_RANDOM_DATA;
247 generate_into_dir = optarg;
248 break;
249 case 'h':
250 usage(argv[0]);
251 exit(0);
252 case 'n':
253 iterations = atoi(optarg);
254 if(iterations <= 0) {
255 fprintf(stderr, "-n %s: positive value expected\n", optarg);
256 exit(EX_DATAERR);
257 }
258 break;
259 default:
260 usage(argv[0]);
261 exit(2);
262 }
263 }
264
265 if(mode == MODE_UNKNOWN) {
266 usage(argv[0]);
267 exit(2);
268 } else if(!enabled_encodings) {
269 for(size_t i = 0; i < sizeof(encodings)/sizeof(encodings[0]); i++) {
270 enabled_encodings |= 1 << encodings[i].syntax;
271 }
272 }
273
274 /* Enumerate requested encodings (-e ...) */
275 for(unsigned i = 0; i < 8*sizeof(enabled_encodings)-1; i++) {
276 if(enabled_encodings & (1 << i)) {
277 enum asn_transfer_syntax syntax = i;
278 switch(mode) {
279 case MODE_UNKNOWN:
280 assert(mode != MODE_UNKNOWN);
281 break;
282 case MODE_GENERATE_RANDOM_DATA:
283 generate_random_data(syntax, generate_into_dir, iterations);
284 break;
285 case MODE_CHECK_RANDOM_ROUNDTRIP:
286 check_random_roundtrip(syntax, iterations);
287 break;
288 }
289 }
290 }
291
292 return 0;
293}
294
295#endif