1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4
5 /**
6 @file der_length_custom_type.c
7 ASN.1 DER, length of a custom type, Steffen Jaeckel
8 */
9
10 #ifdef LTC_DER
11
12 /**
13 Get the length of a DER custom type
14
15 This function is a bit special compared to the others, as it requires the
16 root-ltc_asn1_list where the type is defined.
17
18 @param root The root of the struct to encode
19 @param outlen [out] The length required in octets to store it
20 @param payloadlen [out] The length of the payload in octets
21 @return CRYPT_OK on success
22 */
der_length_custom_type(const ltc_asn1_list * root,unsigned long * outlen,unsigned long * payloadlen)23 int der_length_custom_type(const ltc_asn1_list *root, unsigned long *outlen, unsigned long *payloadlen)
24 {
25 int err;
26 const ltc_asn1_list *list;
27 ltc_asn1_type type;
28 unsigned long size, x, y, i, inlen, id_len;
29 void *data;
30
31 LTC_ARGCHK(root != NULL);
32 LTC_ARGCHK(outlen != NULL);
33
34 /* get size of output that will be required */
35 if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) {
36 return err;
37 }
38 y = id_len;
39
40 if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
41 list = root;
42 inlen = 1;
43 } else {
44 list = root->data;
45 inlen = root->size;
46 }
47 for (i = 0; i < inlen; i++) {
48 if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
49 type = (ltc_asn1_type)list[i].used;
50 } else {
51 type = list[i].type;
52 }
53 size = list[i].size;
54 data = list[i].data;
55
56 if (type == LTC_ASN1_EOL) {
57 break;
58 }
59
60 /* some items may be optional during import */
61 if (!list[i].used && list[i].optional) continue;
62
63 switch (type) {
64 case LTC_ASN1_BOOLEAN:
65 if ((err = der_length_boolean(&x)) != CRYPT_OK) {
66 goto LBL_ERR;
67 }
68 y += x;
69 break;
70
71 case LTC_ASN1_INTEGER:
72 if ((err = der_length_integer(data, &x)) != CRYPT_OK) {
73 goto LBL_ERR;
74 }
75 y += x;
76 break;
77
78 case LTC_ASN1_SHORT_INTEGER:
79 if ((err = der_length_short_integer(*((unsigned long *)data), &x)) != CRYPT_OK) {
80 goto LBL_ERR;
81 }
82 y += x;
83 break;
84
85 case LTC_ASN1_BIT_STRING:
86 case LTC_ASN1_RAW_BIT_STRING:
87 if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) {
88 goto LBL_ERR;
89 }
90 y += x;
91 break;
92
93 case LTC_ASN1_OCTET_STRING:
94 if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) {
95 goto LBL_ERR;
96 }
97 y += x;
98 break;
99
100 case LTC_ASN1_NULL:
101 y += 2;
102 break;
103
104 case LTC_ASN1_OBJECT_IDENTIFIER:
105 if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) {
106 goto LBL_ERR;
107 }
108 y += x;
109 break;
110
111 case LTC_ASN1_IA5_STRING:
112 if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) {
113 goto LBL_ERR;
114 }
115 y += x;
116 break;
117
118 case LTC_ASN1_TELETEX_STRING:
119 if ((err = der_length_teletex_string(data, size, &x)) != CRYPT_OK) {
120 goto LBL_ERR;
121 }
122 y += x;
123 break;
124
125 case LTC_ASN1_PRINTABLE_STRING:
126 if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) {
127 goto LBL_ERR;
128 }
129 y += x;
130 break;
131
132 case LTC_ASN1_UTCTIME:
133 if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
134 goto LBL_ERR;
135 }
136 y += x;
137 break;
138
139 case LTC_ASN1_GENERALIZEDTIME:
140 if ((err = der_length_generalizedtime(data, &x)) != CRYPT_OK) {
141 goto LBL_ERR;
142 }
143 y += x;
144 break;
145
146 case LTC_ASN1_UTF8_STRING:
147 if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) {
148 goto LBL_ERR;
149 }
150 y += x;
151 break;
152
153 case LTC_ASN1_CUSTOM_TYPE:
154 if ((err = der_length_custom_type(&list[i], &x, NULL)) != CRYPT_OK) {
155 goto LBL_ERR;
156 }
157 y += x;
158 break;
159
160 case LTC_ASN1_SET:
161 case LTC_ASN1_SETOF:
162 case LTC_ASN1_SEQUENCE:
163 if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) {
164 goto LBL_ERR;
165 }
166 y += x;
167 break;
168
169 case LTC_ASN1_CHOICE:
170 case LTC_ASN1_EOL:
171 default:
172 err = CRYPT_INVALID_ARG;
173 goto LBL_ERR;
174 }
175 }
176
177 if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
178 /* In case it's a PRIMITIVE element we're going
179 * to only replace the identifier of the one element
180 * by the custom identifier.
181 */
182 y -= 1;
183 if (payloadlen != NULL) {
184 *payloadlen = y - id_len;
185 }
186 } else {
187 /* calc length of length */
188 if ((err = der_length_asn1_length(y - id_len, &x)) != CRYPT_OK) {
189 goto LBL_ERR;
190 }
191 if (payloadlen != NULL) {
192 *payloadlen = y - id_len;
193 }
194 y += x;
195 }
196
197 /* store size */
198 *outlen = y;
199
200 LBL_ERR:
201 return err;
202 }
203
204 #endif
205