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 /**
14   @file der_decode_custom_type.c
15   ASN.1 DER, decode a Custom type, Steffen Jaeckel
16 */
17 
18 #ifdef LTC_DER
19 
20 /**
21    Decode a Custom type
22    @param in       The DER encoded input
23    @param inlen    The size of the input
24    @param root     The item that defines the custom type to decode
25    @return CRYPT_OK on success
26 */
der_decode_custom_type(const unsigned char * in,unsigned long inlen,ltc_asn1_list * root)27 int der_decode_custom_type(const unsigned char *in, unsigned long  inlen,
28                            ltc_asn1_list *root)
29 {
30    LTC_ARGCHK(root != NULL);
31    return der_decode_custom_type_ex(in, inlen, root, NULL, 0, LTC_DER_SEQ_ORDERED | LTC_DER_SEQ_RELAXED);
32 }
33 
34 /**
35    Extended-decode a Custom type
36 
37       This function is used to decode custom types and sequences/sets
38       For custom types root is used
39       For sequences/sets list and outlen are used
40 
41    @param in       The DER encoded input
42    @param inlen    The size of the input
43    @param root     The item that defines the custom type to decode
44    @param list     The list of items to decode
45    @param outlen   The number of items in the list
46    @param flags    c.f. enum ltc_der_seq
47    @return CRYPT_OK on success
48 */
der_decode_custom_type_ex(const unsigned char * in,unsigned long inlen,ltc_asn1_list * root,ltc_asn1_list * list,unsigned long outlen,unsigned int flags)49 int der_decode_custom_type_ex(const unsigned char *in,   unsigned long  inlen,
50                                     ltc_asn1_list *root,
51                                     ltc_asn1_list *list, unsigned long  outlen,
52                                     unsigned int   flags)
53 {
54    int           err, seq_err, i, ordered;
55    ltc_asn1_type type;
56    ltc_asn1_list ident;
57    unsigned long size, x, y, z, blksize;
58    unsigned char* in_new = NULL;
59    void          *data;
60 
61    LTC_ARGCHK(in   != NULL);
62 
63    /* get blk size */
64    if (inlen < 2) {
65       return CRYPT_INVALID_PACKET;
66    }
67    x = 0;
68 
69    if (root == NULL) {
70       LTC_ARGCHK(list != NULL);
71 
72       /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
73       if (in[x] != 0x30 && in[x] != 0x31) {
74          return CRYPT_INVALID_PACKET;
75       }
76       ++x;
77    } else {
78       if (root->type != LTC_ASN1_CUSTOM_TYPE) {
79          return CRYPT_INVALID_PACKET;
80       }
81 
82       /* Alloc a copy of the data for primitive handling. */
83       if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
84          in_new = XMALLOC(inlen);
85          if (in_new == NULL) {
86             return CRYPT_MEM;
87          }
88          XMEMCPY(in_new, in, inlen);
89          in = in_new;
90       }
91 
92       y = inlen;
93       if ((err = der_decode_asn1_identifier(in, &y, &ident)) != CRYPT_OK) {
94          goto LBL_ERR;
95       }
96       if ((ident.type != root->type) ||
97             (ident.klass != root->klass) ||
98             (ident.pc != root->pc) ||
99             (ident.tag != root->tag)) {
100          err = CRYPT_INVALID_PACKET;
101          goto LBL_ERR;
102       }
103       x += y;
104 
105       list = root->data;
106       outlen = root->size;
107    }
108 
109    if (root != NULL && root->pc == LTC_ASN1_PC_PRIMITIVE) {
110       if (((unsigned long)root->used >= der_asn1_type_to_identifier_map_sz) ||
111             (der_asn1_type_to_identifier_map[root->used] == -1)) {
112          err = CRYPT_INVALID_PACKET;
113          goto LBL_ERR;
114       }
115 
116       root->type = (ltc_asn1_type)root->used;
117       list = root;
118       outlen = 1;
119 
120       x -= 1;
121       in_new[x] = (unsigned char)der_asn1_type_to_identifier_map[list[0].type];
122       blksize = inlen - x;
123    } else {
124 
125       y = inlen - x;
126       if ((err = der_decode_asn1_length(&in[x], &y, &blksize)) != CRYPT_OK) {
127          goto LBL_ERR;
128       }
129       x += y;
130    }
131 
132    /* would this blksize overflow? */
133    if (blksize > (inlen - x)) {
134       err = CRYPT_INVALID_PACKET;
135       goto LBL_ERR;
136    }
137 
138    /* mark all as unused */
139    for (i = 0; i < (int)outlen; i++) {
140        list[i].used = 0;
141    }
142    ordered = flags & LTC_DER_SEQ_ORDERED;
143 
144    /* ok read data */
145    seq_err  = CRYPT_OK;
146    blksize += x;
147    inlen   -= x;
148    for (i = 0; i < (int)outlen; i++) {
149        z    = 0;
150        type = list[i].type;
151        size = list[i].size;
152        data = list[i].data;
153        if (!ordered && list[i].used == 1) { continue; }
154 
155        if (type == LTC_ASN1_EOL) {
156           break;
157        }
158 
159        if (root != NULL && root->pc == LTC_ASN1_PC_PRIMITIVE && i != 0) {
160           err = CRYPT_PK_ASN1_ERROR;
161           goto LBL_ERR;
162        }
163 
164        switch (type) {
165            case LTC_ASN1_BOOLEAN:
166                z = inlen;
167                if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
168                   if (!ordered || list[i].optional) { continue; }
169                   goto LBL_ERR;
170                }
171                if ((err = der_length_boolean(&z)) != CRYPT_OK) {
172                   goto LBL_ERR;
173                }
174                break;
175 
176            case LTC_ASN1_INTEGER:
177                z = inlen;
178                if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
179                   if (!ordered || list[i].optional) { continue; }
180                   goto LBL_ERR;
181                }
182                if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
183                   goto LBL_ERR;
184                }
185                break;
186 
187            case LTC_ASN1_SHORT_INTEGER:
188                z = inlen;
189                if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
190                   if (!ordered || list[i].optional) { continue; }
191                   goto LBL_ERR;
192                }
193                if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
194                   goto LBL_ERR;
195                }
196 
197                break;
198 
199            case LTC_ASN1_BIT_STRING:
200                z = inlen;
201                if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
202                   if (!ordered || list[i].optional) { continue; }
203                   goto LBL_ERR;
204                }
205                list[i].size = size;
206                if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
207                   goto LBL_ERR;
208                }
209                break;
210 
211            case LTC_ASN1_RAW_BIT_STRING:
212                z = inlen;
213                if ((err = der_decode_raw_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
214                   if (!ordered || list[i].optional) { continue; }
215                   goto LBL_ERR;
216                }
217                list[i].size = size;
218                if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
219                   goto LBL_ERR;
220                }
221                break;
222 
223            case LTC_ASN1_OCTET_STRING:
224                z = inlen;
225                if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
226                   if (!ordered || list[i].optional) { continue; }
227                   goto LBL_ERR;
228                }
229                list[i].size = size;
230                if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
231                   goto LBL_ERR;
232                }
233                break;
234 
235            case LTC_ASN1_NULL:
236                if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
237                   if (!ordered || list[i].optional) { continue; }
238                   err = CRYPT_INVALID_PACKET;
239                   goto LBL_ERR;
240                }
241                z = 2;
242                break;
243 
244            case LTC_ASN1_OBJECT_IDENTIFIER:
245                z = inlen;
246                if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
247                   if (!ordered || list[i].optional) { continue; }
248                   goto LBL_ERR;
249                }
250                list[i].size = size;
251                if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
252                   goto LBL_ERR;
253                }
254                break;
255 
256            case LTC_ASN1_TELETEX_STRING:
257                z = inlen;
258                if ((err = der_decode_teletex_string(in + x, z, data, &size)) != CRYPT_OK) {
259                   if (!ordered || list[i].optional) { continue; }
260                   goto LBL_ERR;
261                }
262                list[i].size = size;
263                if ((err = der_length_teletex_string(data, size, &z)) != CRYPT_OK) {
264                   goto LBL_ERR;
265                }
266                break;
267 
268            case LTC_ASN1_IA5_STRING:
269                z = inlen;
270                if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
271                   if (!ordered || list[i].optional) { continue; }
272                   goto LBL_ERR;
273                }
274                list[i].size = size;
275                if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
276                   goto LBL_ERR;
277                }
278                break;
279 
280            case LTC_ASN1_PRINTABLE_STRING:
281                z = inlen;
282                if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
283                   if (!ordered || list[i].optional) { continue; }
284                   goto LBL_ERR;
285                }
286                list[i].size = size;
287                if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
288                   goto LBL_ERR;
289                }
290                break;
291 
292            case LTC_ASN1_UTF8_STRING:
293                z = inlen;
294                if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
295                   if (!ordered || list[i].optional) { continue; }
296                   goto LBL_ERR;
297                }
298                list[i].size = size;
299                if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
300                   goto LBL_ERR;
301                }
302                break;
303 
304            case LTC_ASN1_UTCTIME:
305                z = inlen;
306                if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
307                   if (!ordered || list[i].optional) { continue; }
308                   goto LBL_ERR;
309                }
310                break;
311 
312            case LTC_ASN1_GENERALIZEDTIME:
313                z = inlen;
314                if ((err = der_decode_generalizedtime(in + x, &z, data)) != CRYPT_OK) {
315                   if (!ordered || list[i].optional) { continue; }
316                   goto LBL_ERR;
317                }
318                break;
319 
320            case LTC_ASN1_SET:
321                z = inlen;
322                if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
323                   if (!ordered || list[i].optional) { continue; }
324                   goto LBL_ERR;
325                }
326                if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
327                   goto LBL_ERR;
328                }
329                break;
330 
331            case LTC_ASN1_SETOF:
332            case LTC_ASN1_SEQUENCE:
333                /* detect if we have the right type */
334                if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
335                   err = CRYPT_INVALID_PACKET;
336                   goto LBL_ERR;
337                }
338 
339                z = inlen;
340                err = der_decode_sequence_ex(in + x, z, data, size, flags);
341                if (err == CRYPT_INPUT_TOO_LONG) {
342                   seq_err = CRYPT_INPUT_TOO_LONG;
343                   err = CRYPT_OK;
344                }
345                if (err != CRYPT_OK) {
346                   if (!ordered || list[i].optional) { continue; }
347                   goto LBL_ERR;
348                }
349                if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
350                   goto LBL_ERR;
351                }
352                break;
353 
354            case LTC_ASN1_CUSTOM_TYPE:
355                z = inlen;
356                err = der_decode_custom_type(in + x, z, &list[i]);
357                if (err == CRYPT_INPUT_TOO_LONG) {
358                   seq_err = CRYPT_INPUT_TOO_LONG;
359                   err = CRYPT_OK;
360                }
361                if (err != CRYPT_OK) {
362                   if (!ordered || list[i].optional) { continue; }
363                   goto LBL_ERR;
364                }
365                if ((err = der_length_custom_type(&list[i], &z, NULL)) != CRYPT_OK) {
366                   goto LBL_ERR;
367                }
368                break;
369 
370            case LTC_ASN1_CHOICE:
371                z = inlen;
372                if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
373                   if (!ordered || list[i].optional) { continue; }
374                   goto LBL_ERR;
375                }
376                break;
377 
378            case LTC_ASN1_EOL:
379            default:
380                err = CRYPT_INVALID_ARG;
381                goto LBL_ERR;
382        }
383        x           += z;
384        inlen       -= z;
385        list[i].used = 1;
386        if (!ordered) {
387           /* restart the decoder */
388           i = -1;
389        }
390    }
391 
392    for (i = 0; i < (int)outlen; i++) {
393       if (list[i].used == 0 && list[i].optional == 0) {
394           err = CRYPT_INVALID_PACKET;
395           goto LBL_ERR;
396       }
397    }
398 
399    if (blksize == x && seq_err == CRYPT_OK && inlen == 0) {
400       /* everything decoded and no errors in nested sequences */
401       err = CRYPT_OK;
402    } else if (blksize == x && seq_err == CRYPT_INPUT_TOO_LONG && inlen == 0) {
403       /* a sequence reported too-long input, but now we've decoded everything */
404       err = CRYPT_OK;
405    } else if (blksize != x && ((flags & LTC_DER_SEQ_STRICT) == LTC_DER_SEQ_STRICT)) {
406       err = CRYPT_INVALID_PACKET;
407    } else {
408       err = CRYPT_INPUT_TOO_LONG;
409    }
410 
411 LBL_ERR:
412    if (in_new != NULL) {
413       XFREE(in_new);
414    }
415    return err;
416 }
417 
418 #endif
419 
420 /* ref:         $Format:%D$ */
421 /* git commit:  $Format:%H$ */
422 /* commit time: $Format:%ai$ */
423