1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6   @file der_decode_choice.c
7   ASN.1 DER, decode a CHOICE, Tom St Denis
8 */
9 
10 #ifdef LTC_DER
11 
12 /**
13    Decode a CHOICE
14    @param in       The DER encoded input
15    @param inlen    [in/out] The size of the input and resulting size of read type
16    @param list     The list of items to decode
17    @param outlen   The number of items in the list
18    @return CRYPT_OK on success
19 */
der_decode_choice(const unsigned char * in,unsigned long * inlen,ltc_asn1_list * list,unsigned long outlen)20 int der_decode_choice(const unsigned char *in,   unsigned long *inlen,
21                             ltc_asn1_list *list, unsigned long  outlen)
22 {
23    unsigned long size, x, z;
24    void          *data;
25 
26    LTC_ARGCHK(in    != NULL);
27    LTC_ARGCHK(inlen != NULL);
28    LTC_ARGCHK(list  != NULL);
29 
30    /* get blk size */
31    if (*inlen < 2) {
32       return CRYPT_INVALID_PACKET;
33    }
34 
35    /* set all of the "used" flags to zero */
36    for (x = 0; x < outlen; x++) {
37        list[x].used = 0;
38    }
39 
40    /* now scan until we have a winner */
41    for (x = 0; x < outlen; x++) {
42        size = list[x].size;
43        data = list[x].data;
44 
45        switch (list[x].type) {
46            case LTC_ASN1_BOOLEAN:
47                if (der_decode_boolean(in, *inlen, data) == CRYPT_OK) {
48                   if (der_length_boolean(&z) == CRYPT_OK) {
49                       list[x].used = 1;
50                       *inlen       = z;
51                       return CRYPT_OK;
52                   }
53                }
54                break;
55 
56            case LTC_ASN1_INTEGER:
57                if (der_decode_integer(in, *inlen, data) == CRYPT_OK) {
58                   if (der_length_integer(data, &z) == CRYPT_OK) {
59                       list[x].used = 1;
60                       *inlen       = z;
61                       return CRYPT_OK;
62                   }
63                }
64                break;
65 
66            case LTC_ASN1_SHORT_INTEGER:
67                if (der_decode_short_integer(in, *inlen, data) == CRYPT_OK) {
68                   if (der_length_short_integer(size, &z) == CRYPT_OK) {
69                       list[x].used = 1;
70                       *inlen       = z;
71                       return CRYPT_OK;
72                   }
73                }
74                break;
75 
76            case LTC_ASN1_BIT_STRING:
77                if (der_decode_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
78                   if (der_length_bit_string(size, &z) == CRYPT_OK) {
79                      list[x].used = 1;
80                      list[x].size = size;
81                      *inlen       = z;
82                      return CRYPT_OK;
83                   }
84                }
85                break;
86 
87            case LTC_ASN1_RAW_BIT_STRING:
88                if (der_decode_raw_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
89                   if (der_length_bit_string(size, &z) == CRYPT_OK) {
90                      list[x].used = 1;
91                      list[x].size = size;
92                      *inlen       = z;
93                      return CRYPT_OK;
94                   }
95                }
96                break;
97 
98            case LTC_ASN1_OCTET_STRING:
99                if (der_decode_octet_string(in, *inlen, data, &size) == CRYPT_OK) {
100                   if (der_length_octet_string(size, &z) == CRYPT_OK) {
101                      list[x].used = 1;
102                      list[x].size = size;
103                      *inlen       = z;
104                      return CRYPT_OK;
105                   }
106                }
107                break;
108 
109            case LTC_ASN1_NULL:
110                if (*inlen == 2 && in[x] == 0x05 && in[x+1] == 0x00) {
111                   *inlen = 2;
112                   list[x].used   = 1;
113                   return CRYPT_OK;
114                }
115                break;
116 
117            case LTC_ASN1_OBJECT_IDENTIFIER:
118                if (der_decode_object_identifier(in, *inlen, data, &size) == CRYPT_OK) {
119                   if (der_length_object_identifier(data, size, &z) == CRYPT_OK) {
120                      list[x].used = 1;
121                      list[x].size = size;
122                      *inlen       = z;
123                      return CRYPT_OK;
124                   }
125                }
126                break;
127 
128            case LTC_ASN1_TELETEX_STRING:
129                if (der_decode_teletex_string(in, *inlen, data, &size) == CRYPT_OK) {
130                   if (der_length_teletex_string(data, size, &z) == CRYPT_OK) {
131                      list[x].used = 1;
132                      list[x].size = size;
133                      *inlen       = z;
134                      return CRYPT_OK;
135                   }
136                }
137                break;
138 
139            case LTC_ASN1_IA5_STRING:
140                if (der_decode_ia5_string(in, *inlen, data, &size) == CRYPT_OK) {
141                   if (der_length_ia5_string(data, size, &z) == CRYPT_OK) {
142                      list[x].used = 1;
143                      list[x].size = size;
144                      *inlen       = z;
145                      return CRYPT_OK;
146                   }
147                }
148                break;
149 
150            case LTC_ASN1_PRINTABLE_STRING:
151                if (der_decode_printable_string(in, *inlen, data, &size) == CRYPT_OK) {
152                   if (der_length_printable_string(data, size, &z) == CRYPT_OK) {
153                      list[x].used = 1;
154                      list[x].size = size;
155                      *inlen       = z;
156                      return CRYPT_OK;
157                   }
158                }
159                break;
160 
161            case LTC_ASN1_UTF8_STRING:
162                if (der_decode_utf8_string(in, *inlen, data, &size) == CRYPT_OK) {
163                   if (der_length_utf8_string(data, size, &z) == CRYPT_OK) {
164                      list[x].used = 1;
165                      list[x].size = size;
166                      *inlen       = z;
167                      return CRYPT_OK;
168                   }
169                }
170                break;
171 
172            case LTC_ASN1_UTCTIME:
173                z = *inlen;
174                if (der_decode_utctime(in, &z, data) == CRYPT_OK) {
175                   list[x].used = 1;
176                   *inlen       = z;
177                   return CRYPT_OK;
178                }
179                break;
180 
181            case LTC_ASN1_GENERALIZEDTIME:
182                z = *inlen;
183                if (der_decode_generalizedtime(in, &z, data) == CRYPT_OK) {
184                   list[x].used = 1;
185                   *inlen       = z;
186                   return CRYPT_OK;
187                }
188                break;
189 
190            case LTC_ASN1_SET:
191            case LTC_ASN1_SETOF:
192            case LTC_ASN1_SEQUENCE:
193                if (der_decode_sequence(in, *inlen, data, size) == CRYPT_OK) {
194                   if (der_length_sequence(data, size, &z) == CRYPT_OK) {
195                      list[x].used = 1;
196                      *inlen       = z;
197                      return CRYPT_OK;
198                   }
199                }
200                break;
201 
202            case LTC_ASN1_CUSTOM_TYPE:
203                if (der_decode_custom_type(in, *inlen, &list[x]) == CRYPT_OK) {
204                   if (der_length_custom_type(&list[x], &z, NULL) == CRYPT_OK) {
205                      list[x].used = 1;
206                      *inlen       = z;
207                      return CRYPT_OK;
208                   }
209                }
210                break;
211 
212            case LTC_ASN1_CHOICE:
213            case LTC_ASN1_EOL:
214            default:
215                return CRYPT_INVALID_ARG;
216        }
217    }
218 
219    return CRYPT_INVALID_PACKET;
220 }
221 
222 #endif
223