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_encode_custom_type.c
15   ASN.1 DER, encode a Custom Type, Steffen Jaeckel
16 */
17 
18 #ifdef LTC_DER
19 
20 /**
21    Encode a Custom Type
22 
23    This function is a bit special compared to the others, as it requires the
24    root-ltc_asn1_list where the type is defined.
25 
26    @param root      The root of the list of items to encode
27    @param out       [out] The destination
28    @param outlen    [in/out] The size of the output
29    @return CRYPT_OK on success
30 */
der_encode_custom_type(const ltc_asn1_list * root,unsigned char * out,unsigned long * outlen)31 int der_encode_custom_type(const ltc_asn1_list *root,
32                                  unsigned char *out,  unsigned long *outlen)
33 {
34    int           err;
35    ltc_asn1_type type;
36    const ltc_asn1_list *list;
37    unsigned long size, x, y, z, i, inlen, id_len;
38    void          *data;
39 
40    LTC_ARGCHK(root    != NULL);
41    LTC_ARGCHK(out     != NULL);
42    LTC_ARGCHK(outlen  != NULL);
43 
44    /* get size of output that will be required */
45    y = 0; z = 0;
46    if ((err = der_length_custom_type(root, &y, &z)) != CRYPT_OK) return CRYPT_INVALID_ARG;
47 
48    /* too big ? */
49    if (*outlen < y) {
50       *outlen = y;
51       err = CRYPT_BUFFER_OVERFLOW;
52       goto LBL_ERR;
53    }
54 
55    /* get length of the identifier, so we know the offset where to start writing */
56    if ((err = der_length_asn1_identifier(root, &id_len)) != CRYPT_OK) return CRYPT_INVALID_ARG;
57    x = id_len;
58 
59 
60    if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
61       list = root;
62       inlen = 1;
63       /* In case it's a PRIMITIVE type we encode directly to the output
64        * but leave space for a potentially longer identifier as it will
65        * simply be replaced afterwards.
66        */
67       x -= 1;
68    } else {
69       list = root->data;
70       inlen = root->size;
71       /* store length, identifier will be added later */
72       y = *outlen - x;
73       if ((err = der_encode_asn1_length(z, &out[x], &y)) != CRYPT_OK) {
74          goto LBL_ERR;
75       }
76       x += y;
77    }
78 
79    /* store data */
80    *outlen -= x;
81    for (i = 0; i < inlen; i++) {
82        if (root->pc == LTC_ASN1_PC_PRIMITIVE) {
83           type = (ltc_asn1_type)list[i].used;
84        } else {
85           type = list[i].type;
86        }
87        size = list[i].size;
88        data = list[i].data;
89 
90        if (type == LTC_ASN1_EOL) {
91           break;
92        }
93 
94        switch (type) {
95             case LTC_ASN1_BOOLEAN:
96                z = *outlen;
97                if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) {
98                   goto LBL_ERR;
99                }
100                break;
101 
102            case LTC_ASN1_INTEGER:
103                z = *outlen;
104                if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) {
105                   goto LBL_ERR;
106                }
107                break;
108 
109            case LTC_ASN1_SHORT_INTEGER:
110                z = *outlen;
111                if ((err = der_encode_short_integer(*((unsigned long*)data), out + x, &z)) != CRYPT_OK) {
112                   goto LBL_ERR;
113                }
114                break;
115 
116            case LTC_ASN1_BIT_STRING:
117                z = *outlen;
118                if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
119                   goto LBL_ERR;
120                }
121                break;
122 
123            case LTC_ASN1_RAW_BIT_STRING:
124                z = *outlen;
125                if ((err = der_encode_raw_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
126                   goto LBL_ERR;
127                }
128                break;
129 
130            case LTC_ASN1_OCTET_STRING:
131                z = *outlen;
132                if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) {
133                   goto LBL_ERR;
134                }
135                break;
136 
137            case LTC_ASN1_NULL:
138                out[x] = 0x05;
139                out[x+1] = 0x00;
140                z = 2;
141                break;
142 
143            case LTC_ASN1_OBJECT_IDENTIFIER:
144                z = *outlen;
145                if ((err = der_encode_object_identifier(data, size, out + x, &z)) != CRYPT_OK) {
146                   goto LBL_ERR;
147                }
148                break;
149 
150            case LTC_ASN1_IA5_STRING:
151                z = *outlen;
152                if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) {
153                   goto LBL_ERR;
154                }
155                break;
156 
157            case LTC_ASN1_PRINTABLE_STRING:
158                z = *outlen;
159                if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) {
160                   goto LBL_ERR;
161                }
162                break;
163 
164            case LTC_ASN1_UTF8_STRING:
165                z = *outlen;
166                if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) {
167                   goto LBL_ERR;
168                }
169                break;
170 
171            case LTC_ASN1_UTCTIME:
172                z = *outlen;
173                if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) {
174                   goto LBL_ERR;
175                }
176                break;
177 
178            case LTC_ASN1_GENERALIZEDTIME:
179                z = *outlen;
180                if ((err = der_encode_generalizedtime(data, out + x, &z)) != CRYPT_OK) {
181                   goto LBL_ERR;
182                }
183                break;
184 
185            case LTC_ASN1_SET:
186                z = *outlen;
187                if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) {
188                   goto LBL_ERR;
189                }
190                break;
191 
192            case LTC_ASN1_SETOF:
193                z = *outlen;
194                if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) {
195                   goto LBL_ERR;
196                }
197                break;
198 
199            case LTC_ASN1_SEQUENCE:
200                z = *outlen;
201                if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) {
202                   goto LBL_ERR;
203                }
204                break;
205 
206            case LTC_ASN1_CUSTOM_TYPE:
207                z = *outlen;
208                if ((err = der_encode_custom_type(&list[i], out + x, &z)) != CRYPT_OK) {
209                   goto LBL_ERR;
210                }
211                break;
212 
213            case LTC_ASN1_CHOICE:
214            case LTC_ASN1_EOL:
215            case LTC_ASN1_TELETEX_STRING:
216            default:
217                err = CRYPT_INVALID_ARG;
218                goto LBL_ERR;
219        }
220 
221 
222        x       += z;
223        *outlen -= z;
224    }
225 
226    if ((err = der_encode_asn1_identifier(root, out, &id_len)) != CRYPT_OK) {
227       goto LBL_ERR;
228    }
229    *outlen = x;
230    err = CRYPT_OK;
231 
232 LBL_ERR:
233    return err;
234 }
235 
236 #endif
237 
238 /* ref:         $Format:%D$ */
239 /* git commit:  $Format:%H$ */
240 /* commit time: $Format:%ai$ */
241