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