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