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