1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4
5 /**
6 @file der_decode_sequence_flexi.c
7 ASN.1 DER, decode an array of ASN.1 types with a flexi parser, Tom St Denis
8 */
9
10 #ifdef LTC_DER
11
s_new_element(ltc_asn1_list ** l)12 static int s_new_element(ltc_asn1_list **l)
13 {
14 /* alloc new link */
15 if (*l == NULL) {
16 *l = XCALLOC(1, sizeof(ltc_asn1_list));
17 if (*l == NULL) {
18 return CRYPT_MEM;
19 }
20 } else {
21 (*l)->next = XCALLOC(1, sizeof(ltc_asn1_list));
22 if ((*l)->next == NULL) {
23 return CRYPT_MEM;
24 }
25 (*l)->next->prev = *l;
26 *l = (*l)->next;
27 }
28 return CRYPT_OK;
29 }
30
31 /**
32 ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
33 @param in The input buffer
34 @param inlen [in/out] The length of the input buffer and on output the amount of decoded data
35 @param out [out] A pointer to the linked list
36 @param depth The depth/level of decoding recursion we've already reached
37 @return CRYPT_OK on success.
38 */
s_der_decode_sequence_flexi(const unsigned char * in,unsigned long * inlen,ltc_asn1_list ** out,unsigned long depth)39 static int s_der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out, unsigned long depth)
40 {
41 ltc_asn1_list *l;
42 unsigned long err, identifier, len, totlen, data_offset, id_len, len_len;
43 void *realloc_tmp;
44
45 LTC_ARGCHK(in != NULL);
46 LTC_ARGCHK(inlen != NULL);
47 LTC_ARGCHK(out != NULL);
48
49 l = NULL;
50 totlen = 0;
51
52 if (*inlen == 0) {
53 /* alloc new link */
54 if ((err = s_new_element(&l)) != CRYPT_OK) {
55 goto error;
56 }
57 }
58
59 /* scan the input and and get lengths and what not */
60 while (*inlen) {
61 /* alloc new link */
62 if ((err = s_new_element(&l)) != CRYPT_OK) {
63 goto error;
64 }
65
66 id_len = *inlen;
67 if ((err = der_decode_asn1_identifier(in, &id_len, l)) != CRYPT_OK) {
68 goto error;
69 }
70 /* read the type byte */
71 identifier = *in;
72
73 if (l->type != LTC_ASN1_EOL) {
74 /* fetch length */
75 len_len = *inlen - id_len;
76 #if defined(LTC_TEST_DBG)
77 data_offset = 666;
78 len = 0;
79 #endif
80 if ((err = der_decode_asn1_length(&in[id_len], &len_len, &len)) != CRYPT_OK) {
81 #if defined(LTC_TEST_DBG)
82 fprintf(stderr, "E1 %02lx: hl=%4lu l=%4lu - %s (%s)\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag], error_to_string(err));
83 #endif
84 goto error;
85 } else if (len > (*inlen - id_len - len_len)) {
86 err = CRYPT_INVALID_PACKET;
87 #if defined(LTC_TEST_DBG)
88 fprintf(stderr, "E2 %02lx: hl=%4lu l=%4lu - %s (%s)\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag], error_to_string(err));
89 #endif
90 goto error;
91 }
92 data_offset = id_len + len_len;
93 #if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
94 if (l->type == LTC_ASN1_CUSTOM_TYPE && l->klass == LTC_ASN1_CL_CONTEXT_SPECIFIC) {
95 fprintf(stderr, "OK %02lx: hl=%4lu l=%4lu - Context Specific[%s %llu]\n", identifier, data_offset, len, der_asn1_pc_to_string_map[l->pc], l->tag);
96 } else {
97 fprintf(stderr, "OK %02lx: hl=%4lu l=%4lu - %s\n", identifier, data_offset, len, der_asn1_tag_to_string_map[l->tag]);
98 }
99 #endif
100 len += data_offset;
101
102 if (l->type == LTC_ASN1_CUSTOM_TYPE) {
103 /* Custom type, use the 'used' field to store the original identifier */
104 l->used = identifier;
105 if (l->pc == LTC_ASN1_PC_CONSTRUCTED) {
106 /* treat constructed elements like SEQUENCEs */
107 identifier = 0x20;
108 } else {
109 /* primitive elements are treated as opaque data */
110 identifier = 0x80;
111 }
112 }
113 } else {
114 /* Init this so gcc won't complain,
115 * as this case will only be hit when we
116 * can't decode the identifier so the
117 * switch-case should go to default anyway...
118 */
119 data_offset = 0;
120 len = 0;
121 }
122
123 /* now switch on type */
124 switch (identifier) {
125 case 0x01: /* BOOLEAN */
126 if (l->type != LTC_ASN1_BOOLEAN) {
127 err = CRYPT_PK_ASN1_ERROR;
128 goto error;
129 }
130
131 /* init field */
132 l->size = 1;
133 l->data = XCALLOC(1, sizeof(int));
134
135 if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) {
136 goto error;
137 }
138
139 if ((err = der_length_boolean(&len)) != CRYPT_OK) {
140 goto error;
141 }
142 break;
143
144 case 0x02: /* INTEGER */
145 if (l->type != LTC_ASN1_INTEGER) {
146 err = CRYPT_PK_ASN1_ERROR;
147 goto error;
148 }
149
150 /* init field */
151 l->size = 1;
152 if ((err = mp_init(&l->data)) != CRYPT_OK) {
153 goto error;
154 }
155
156 /* decode field */
157 if ((err = der_decode_integer(in, *inlen, l->data)) != CRYPT_OK) {
158 goto error;
159 }
160
161 /* calc length of object */
162 if ((err = der_length_integer(l->data, &len)) != CRYPT_OK) {
163 goto error;
164 }
165 break;
166
167 case 0x03: /* BIT */
168 if (l->type != LTC_ASN1_BIT_STRING) {
169 err = CRYPT_PK_ASN1_ERROR;
170 goto error;
171 }
172
173 /* init field */
174 l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char. */
175
176 if ((l->data = XCALLOC(1, l->size)) == NULL) {
177 err = CRYPT_MEM;
178 goto error;
179 }
180
181 if ((err = der_decode_bit_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
182 goto error;
183 }
184
185 if ((err = der_length_bit_string(l->size, &len)) != CRYPT_OK) {
186 goto error;
187 }
188 break;
189
190 case 0x04: /* OCTET */
191 if (l->type != LTC_ASN1_OCTET_STRING) {
192 err = CRYPT_PK_ASN1_ERROR;
193 goto error;
194 }
195
196 /* init field */
197 l->size = len;
198
199 if ((l->data = XCALLOC(1, l->size)) == NULL) {
200 err = CRYPT_MEM;
201 goto error;
202 }
203
204 if ((err = der_decode_octet_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
205 goto error;
206 }
207
208 if ((err = der_length_octet_string(l->size, &len)) != CRYPT_OK) {
209 goto error;
210 }
211 break;
212
213 case 0x05: /* NULL */
214 if (l->type != LTC_ASN1_NULL) {
215 err = CRYPT_PK_ASN1_ERROR;
216 goto error;
217 }
218
219 /* valid NULL is 0x05 0x00 */
220 if (in[0] != 0x05 || in[1] != 0x00) {
221 err = CRYPT_INVALID_PACKET;
222 goto error;
223 }
224
225 /* simple to store ;-) */
226 l->data = NULL;
227 l->size = 0;
228 len = 2;
229
230 break;
231
232 case 0x06: /* OID */
233 if (l->type != LTC_ASN1_OBJECT_IDENTIFIER) {
234 err = CRYPT_PK_ASN1_ERROR;
235 goto error;
236 }
237
238 /* init field */
239 l->size = len;
240
241 if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
242 err = CRYPT_MEM;
243 goto error;
244 }
245
246 if ((err = der_decode_object_identifier(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
247 goto error;
248 }
249
250 if ((err = der_length_object_identifier(l->data, l->size, &len)) != CRYPT_OK) {
251 goto error;
252 }
253
254 /* resize it to save a bunch of mem */
255 if ((realloc_tmp = XREALLOC(l->data, l->size * sizeof(unsigned long))) == NULL) {
256 /* out of heap but this is not an error */
257 break;
258 }
259 l->data = realloc_tmp;
260 break;
261
262 case 0x0C: /* UTF8 */
263
264 /* init field */
265 if (l->type != LTC_ASN1_UTF8_STRING) {
266 err = CRYPT_PK_ASN1_ERROR;
267 goto error;
268 }
269 l->size = len;
270
271 if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
272 err = CRYPT_MEM;
273 goto error;
274 }
275
276 if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
277 goto error;
278 }
279
280 if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
281 goto error;
282 }
283 break;
284
285 case 0x13: /* PRINTABLE */
286 if (l->type != LTC_ASN1_PRINTABLE_STRING) {
287 err = CRYPT_PK_ASN1_ERROR;
288 goto error;
289 }
290
291 /* init field */
292 l->size = len;
293
294 if ((l->data = XCALLOC(1, l->size)) == NULL) {
295 err = CRYPT_MEM;
296 goto error;
297 }
298
299 if ((err = der_decode_printable_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
300 goto error;
301 }
302
303 if ((err = der_length_printable_string(l->data, l->size, &len)) != CRYPT_OK) {
304 goto error;
305 }
306 break;
307
308 case 0x14: /* TELETEXT */
309 if (l->type != LTC_ASN1_TELETEX_STRING) {
310 err = CRYPT_PK_ASN1_ERROR;
311 goto error;
312 }
313
314 /* init field */
315 l->size = len;
316
317 if ((l->data = XCALLOC(1, l->size)) == NULL) {
318 err = CRYPT_MEM;
319 goto error;
320 }
321
322 if ((err = der_decode_teletex_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
323 goto error;
324 }
325
326 if ((err = der_length_teletex_string(l->data, l->size, &len)) != CRYPT_OK) {
327 goto error;
328 }
329 break;
330
331 case 0x16: /* IA5 */
332 if (l->type != LTC_ASN1_IA5_STRING) {
333 err = CRYPT_PK_ASN1_ERROR;
334 goto error;
335 }
336
337 /* init field */
338 l->size = len;
339
340 if ((l->data = XCALLOC(1, l->size)) == NULL) {
341 err = CRYPT_MEM;
342 goto error;
343 }
344
345 if ((err = der_decode_ia5_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
346 goto error;
347 }
348
349 if ((err = der_length_ia5_string(l->data, l->size, &len)) != CRYPT_OK) {
350 goto error;
351 }
352 break;
353
354 case 0x17: /* UTC TIME */
355 if (l->type != LTC_ASN1_UTCTIME) {
356 err = CRYPT_PK_ASN1_ERROR;
357 goto error;
358 }
359
360 /* init field */
361 l->size = 1;
362
363 if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
364 err = CRYPT_MEM;
365 goto error;
366 }
367
368 len = *inlen;
369 if ((err = der_decode_utctime(in, &len, l->data)) != CRYPT_OK) {
370 goto error;
371 }
372
373 if ((err = der_length_utctime(l->data, &len)) != CRYPT_OK) {
374 goto error;
375 }
376 break;
377
378 case 0x18:
379 if (l->type != LTC_ASN1_GENERALIZEDTIME) {
380 err = CRYPT_PK_ASN1_ERROR;
381 goto error;
382 }
383
384 /* init field */
385 l->size = len;
386
387 if ((l->data = XCALLOC(1, sizeof(ltc_generalizedtime))) == NULL) {
388 err = CRYPT_MEM;
389 goto error;
390 }
391
392 if ((err = der_decode_generalizedtime(in, &len, l->data)) != CRYPT_OK) {
393 goto error;
394 }
395
396 if ((err = der_length_generalizedtime(l->data, &len)) != CRYPT_OK) {
397 goto error;
398 }
399
400 break;
401
402 case 0x20: /* Any CONSTRUCTED element that is neither SEQUENCE nor SET */
403 case 0x30: /* SEQUENCE */
404 case 0x31: /* SET */
405
406 /* init field */
407 if (identifier == 0x20) {
408 if (l->type != LTC_ASN1_CUSTOM_TYPE) {
409 err = CRYPT_PK_ASN1_ERROR;
410 goto error;
411 }
412 }
413 else if (identifier == 0x30) {
414 if (l->type != LTC_ASN1_SEQUENCE) {
415 err = CRYPT_PK_ASN1_ERROR;
416 goto error;
417 }
418 }
419 else {
420 if (l->type != LTC_ASN1_SET) {
421 err = CRYPT_PK_ASN1_ERROR;
422 goto error;
423 }
424 }
425
426 /* check that we don't go over the recursion limit */
427 if (depth > LTC_DER_MAX_RECURSION) {
428 err = CRYPT_PK_ASN1_ERROR;
429 goto error;
430 }
431
432 if ((l->data = XMALLOC(len)) == NULL) {
433 err = CRYPT_MEM;
434 goto error;
435 }
436
437 XMEMCPY(l->data, in, len);
438 l->size = len;
439
440
441 /* jump to the start of the data */
442 in += data_offset;
443 *inlen -= data_offset;
444 len -= data_offset;
445
446 /* save the decoded ASN.1 len */
447 len_len = len;
448
449 /* Sequence elements go as child */
450 if ((err = s_der_decode_sequence_flexi(in, &len, &(l->child), depth+1)) != CRYPT_OK) {
451 goto error;
452 }
453 if (len_len != len) {
454 err = CRYPT_PK_ASN1_ERROR;
455 goto error;
456 }
457
458 /* len update */
459 totlen += data_offset;
460
461 /* the flexi decoder can also do nothing, so make sure a child has been allocated */
462 if (l->child) {
463 /* link them up y0 */
464 l->child->parent = l;
465 }
466
467 break;
468
469 case 0x80: /* Context-specific */
470 if (l->type != LTC_ASN1_CUSTOM_TYPE) {
471 err = CRYPT_PK_ASN1_ERROR;
472 goto error;
473 }
474
475 if ((l->data = XCALLOC(1, len - data_offset)) == NULL) {
476 err = CRYPT_MEM;
477 goto error;
478 }
479
480 XMEMCPY(l->data, in + data_offset, len - data_offset);
481 l->size = len - data_offset;
482
483 break;
484
485 default:
486 /* invalid byte ... this is a soft error */
487 /* remove link */
488 if (l->prev) {
489 l = l->prev;
490 XFREE(l->next);
491 l->next = NULL;
492 }
493 goto outside;
494 }
495
496 /* advance pointers */
497 totlen += len;
498 in += len;
499 *inlen -= len;
500 }
501
502 outside:
503
504 /* in case we processed anything */
505 if (totlen) {
506 /* rewind l please */
507 while (l->prev != NULL || l->parent != NULL) {
508 if (l->parent != NULL) {
509 l = l->parent;
510 } else {
511 l = l->prev;
512 }
513 }
514 }
515
516 /* return */
517 *out = l;
518 *inlen = totlen;
519 return CRYPT_OK;
520
521 error:
522 /* free list */
523 der_sequence_free(l);
524
525 return err;
526 }
527
528 /**
529 ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
530 @param in The input buffer
531 @param inlen [in/out] The length of the input buffer and on output the amount of decoded data
532 @param out [out] A pointer to the linked list
533 @return CRYPT_OK on success.
534 */
der_decode_sequence_flexi(const unsigned char * in,unsigned long * inlen,ltc_asn1_list ** out)535 int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
536 {
537 return s_der_decode_sequence_flexi(in, inlen, out, 0);
538 }
539
540 #endif
541
542