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_asn1_identifier.c
14   ASN.1 DER, decode the ASN.1 Identifier, Steffen Jaeckel
15 */
16 
17 #ifdef LTC_DER
18 /* c.f. X.680 & X.690, some decisions backed by X.690 ch. 10.2 */
19 static const unsigned char tag_constructed_map[] =
20 {
21  /*  0 */
22  255,
23  LTC_ASN1_PC_PRIMITIVE,
24  LTC_ASN1_PC_PRIMITIVE,
25  LTC_ASN1_PC_PRIMITIVE,
26  LTC_ASN1_PC_PRIMITIVE,
27  /*  5 */
28  LTC_ASN1_PC_PRIMITIVE,
29  LTC_ASN1_PC_PRIMITIVE,
30  LTC_ASN1_PC_PRIMITIVE,
31  LTC_ASN1_PC_PRIMITIVE,
32  LTC_ASN1_PC_PRIMITIVE,
33  /* 10 */
34  LTC_ASN1_PC_PRIMITIVE,
35  LTC_ASN1_PC_PRIMITIVE,
36  LTC_ASN1_PC_PRIMITIVE,
37  LTC_ASN1_PC_PRIMITIVE,
38  LTC_ASN1_PC_PRIMITIVE,
39  /* 15 */
40  255,
41  LTC_ASN1_PC_CONSTRUCTED,
42  LTC_ASN1_PC_CONSTRUCTED,
43  LTC_ASN1_PC_PRIMITIVE,
44  LTC_ASN1_PC_PRIMITIVE,
45  /* 20 */
46  LTC_ASN1_PC_PRIMITIVE,
47  LTC_ASN1_PC_PRIMITIVE,
48  LTC_ASN1_PC_PRIMITIVE,
49  LTC_ASN1_PC_PRIMITIVE,
50  LTC_ASN1_PC_PRIMITIVE,
51  /* 25 */
52  LTC_ASN1_PC_PRIMITIVE,
53  LTC_ASN1_PC_PRIMITIVE,
54  LTC_ASN1_PC_PRIMITIVE,
55  LTC_ASN1_PC_PRIMITIVE,
56 };
57  static const unsigned long tag_constructed_map_sz = sizeof(tag_constructed_map)/sizeof(tag_constructed_map[0]);
58 
59 /**
60   Decode the ASN.1 Identifier
61   @param id    Where to store the decoded Identifier
62   @param in    Where to read the Identifier from
63   @param inlen [in/out] The size of in available/read
64   @return CRYPT_OK if successful
65 */
der_decode_asn1_identifier(const unsigned char * in,unsigned long * inlen,ltc_asn1_list * id)66 int der_decode_asn1_identifier(const unsigned char *in, unsigned long *inlen, ltc_asn1_list *id)
67 {
68    ulong64 tmp;
69    unsigned long tag_len;
70    int err;
71 
72    LTC_ARGCHK(id    != NULL);
73    LTC_ARGCHK(in    != NULL);
74    LTC_ARGCHK(inlen != NULL);
75 
76    if (*inlen == 0) {
77       return CRYPT_BUFFER_OVERFLOW;
78    }
79 
80    tag_len = 1;
81    id->klass = (in[0] >> 6) & 0x3;
82    id->pc = (in[0] >> 5) & 0x1;
83    id->tag = in[0] & 0x1f;
84 
85    err = CRYPT_OK;
86    if (id->tag == 0x1f) {
87       id->tag = 0;
88       do {
89          if (*inlen < tag_len) {
90             /* break the loop and trigger the BOF error-code */
91             tmp = 0xff;
92             break;
93          }
94          id->tag <<= 7;
95          id->tag |= in[tag_len] & 0x7f;
96          tmp = in[tag_len] & 0x80;
97          tag_len++;
98       } while ((tmp != 0) && (tag_len < 10));
99 
100       if (tmp != 0) {
101          err = CRYPT_BUFFER_OVERFLOW;
102       } else if (id->tag < 0x1f) {
103          err = CRYPT_PK_ASN1_ERROR;
104       }
105    }
106 
107    if (err != CRYPT_OK) {
108       id->pc = 0;
109       id->klass = 0;
110       id->tag = 0;
111    } else {
112       *inlen = tag_len;
113       if ((id->klass == LTC_ASN1_CL_UNIVERSAL) &&
114             (id->tag < der_asn1_tag_to_type_map_sz) &&
115             (id->tag < tag_constructed_map_sz) &&
116             (id->pc == tag_constructed_map[id->tag])) {
117          id->type = der_asn1_tag_to_type_map[id->tag];
118       } else {
119          if ((id->klass == LTC_ASN1_CL_UNIVERSAL) && (id->tag == 0)) {
120             id->type = LTC_ASN1_EOL;
121          } else {
122             id->type = LTC_ASN1_CUSTOM_TYPE;
123          }
124       }
125    }
126 
127    return CRYPT_OK;
128 }
129 
130 #endif
131 
132 /* ref:         $Format:%D$ */
133 /* git commit:  $Format:%H$ */
134 /* commit time: $Format:%ai$ */
135