xref: /optee_os/lib/libmbedtls/mbedtls/library/asn1write.c (revision 5b25c76ac40f830867e3d60800120ffd7874e8dc)
1 // SPDX-License-Identifier: Apache-2.0
2 /*
3  * ASN.1 buffer writing functionality
4  *
5  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  *  This file is part of mbed TLS (https://tls.mbed.org)
20  */
21 
22 #if !defined(MBEDTLS_CONFIG_FILE)
23 #include "mbedtls/config.h"
24 #else
25 #include MBEDTLS_CONFIG_FILE
26 #endif
27 
28 #if defined(MBEDTLS_ASN1_WRITE_C)
29 
30 #include "mbedtls/asn1write.h"
31 
32 #include <string.h>
33 
34 #if defined(MBEDTLS_PLATFORM_C)
35 #include "mbedtls/platform.h"
36 #else
37 #include <stdlib.h>
38 #define mbedtls_calloc    calloc
39 #define mbedtls_free       free
40 #endif
41 
42 int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len )
43 {
44     if( len < 0x80 )
45     {
46         if( *p - start < 1 )
47             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
48 
49         *--(*p) = (unsigned char) len;
50         return( 1 );
51     }
52 
53     if( len <= 0xFF )
54     {
55         if( *p - start < 2 )
56             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
57 
58         *--(*p) = (unsigned char) len;
59         *--(*p) = 0x81;
60         return( 2 );
61     }
62 
63     if( len <= 0xFFFF )
64     {
65         if( *p - start < 3 )
66             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
67 
68         *--(*p) = ( len       ) & 0xFF;
69         *--(*p) = ( len >>  8 ) & 0xFF;
70         *--(*p) = 0x82;
71         return( 3 );
72     }
73 
74     if( len <= 0xFFFFFF )
75     {
76         if( *p - start < 4 )
77             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
78 
79         *--(*p) = ( len       ) & 0xFF;
80         *--(*p) = ( len >>  8 ) & 0xFF;
81         *--(*p) = ( len >> 16 ) & 0xFF;
82         *--(*p) = 0x83;
83         return( 4 );
84     }
85 
86 #if SIZE_MAX > 0xFFFFFFFF
87     if( len <= 0xFFFFFFFF )
88 #endif
89     {
90         if( *p - start < 5 )
91             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
92 
93         *--(*p) = ( len       ) & 0xFF;
94         *--(*p) = ( len >>  8 ) & 0xFF;
95         *--(*p) = ( len >> 16 ) & 0xFF;
96         *--(*p) = ( len >> 24 ) & 0xFF;
97         *--(*p) = 0x84;
98         return( 5 );
99     }
100 
101 #if SIZE_MAX > 0xFFFFFFFF
102     return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
103 #endif
104 }
105 
106 int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
107 {
108     if( *p - start < 1 )
109         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
110 
111     *--(*p) = tag;
112 
113     return( 1 );
114 }
115 
116 int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
117                            const unsigned char *buf, size_t size )
118 {
119     size_t len = 0;
120 
121     if( *p < start || (size_t)( *p - start ) < size )
122         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
123 
124     len = size;
125     (*p) -= len;
126     memcpy( *p, buf, len );
127 
128     return( (int) len );
129 }
130 
131 #if defined(MBEDTLS_BIGNUM_C)
132 int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X )
133 {
134     int ret;
135     size_t len = 0;
136 
137     // Write the MPI
138     //
139     len = mbedtls_mpi_size( X );
140 
141     if( *p < start || (size_t)( *p - start ) < len )
142         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
143 
144     (*p) -= len;
145     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) );
146 
147     // DER format assumes 2s complement for numbers, so the leftmost bit
148     // should be 0 for positive numbers and 1 for negative numbers.
149     //
150     if( X->s ==1 && **p & 0x80 )
151     {
152         if( *p - start < 1 )
153             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
154 
155         *--(*p) = 0x00;
156         len += 1;
157     }
158 
159     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
160     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
161 
162     ret = (int) len;
163 
164 cleanup:
165     return( ret );
166 }
167 #endif /* MBEDTLS_BIGNUM_C */
168 
169 int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start )
170 {
171     int ret;
172     size_t len = 0;
173 
174     // Write NULL
175     //
176     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) );
177     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) );
178 
179     return( (int) len );
180 }
181 
182 int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start,
183                     const char *oid, size_t oid_len )
184 {
185     int ret;
186     size_t len = 0;
187 
188     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
189                                   (const unsigned char *) oid, oid_len ) );
190     MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) );
191     MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) );
192 
193     return( (int) len );
194 }
195 
196 int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
197                                      const char *oid, size_t oid_len,
198                                      size_t par_len )
199 {
200     int ret;
201     size_t len = 0;
202 
203     if( par_len == 0 )
204         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) );
205     else
206         len += par_len;
207 
208     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
209 
210     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
211     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
212                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
213 
214     return( (int) len );
215 }
216 
217 int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean )
218 {
219     int ret;
220     size_t len = 0;
221 
222     if( *p - start < 1 )
223         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
224 
225     *--(*p) = (boolean) ? 255 : 0;
226     len++;
227 
228     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
229     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) );
230 
231     return( (int) len );
232 }
233 
234 int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
235 {
236     int ret;
237     size_t len = 0;
238 
239     if( *p - start < 1 )
240         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
241 
242     len += 1;
243     *--(*p) = val;
244 
245     if( val > 0 && **p & 0x80 )
246     {
247         if( *p - start < 1 )
248             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
249 
250         *--(*p) = 0x00;
251         len += 1;
252     }
253 
254     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
255     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
256 
257     return( (int) len );
258 }
259 
260 int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, int tag,
261     const char *text, size_t text_len )
262 {
263     int ret;
264     size_t len = 0;
265 
266     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
267         (const unsigned char *) text, text_len ) );
268 
269     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
270     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) );
271 
272     return( (int) len );
273 }
274 
275 int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start,
276     const char *text, size_t text_len )
277 {
278     return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len) );
279 }
280 
281 int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
282                                  const char *text, size_t text_len )
283 {
284     return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text, text_len) );
285 }
286 
287 int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
288                            const char *text, size_t text_len )
289 {
290     return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) );
291 }
292 
293 int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
294                           const unsigned char *buf, size_t bits )
295 {
296     int ret;
297     size_t len = 0;
298     size_t unused_bits, byte_len;
299 
300     byte_len = ( bits + 7 ) / 8;
301     unused_bits = ( byte_len * 8 ) - bits;
302 
303     if( *p < start || (size_t)( *p - start ) < byte_len + 1 )
304         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
305 
306     len = byte_len + 1;
307 
308     /* Write the bitstring. Ensure the unused bits are zeroed */
309     if( byte_len > 0 )
310     {
311         byte_len--;
312         *--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 );
313         ( *p ) -= byte_len;
314         memcpy( *p, buf, byte_len );
315     }
316 
317     /* Write unused bits */
318     *--( *p ) = (unsigned char)unused_bits;
319 
320     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
321     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) );
322 
323     return( (int) len );
324 }
325 
326 int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start,
327                              const unsigned char *buf, size_t size )
328 {
329     int ret;
330     size_t len = 0;
331 
332     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) );
333 
334     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
335     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) );
336 
337     return( (int) len );
338 }
339 
340 
341 /* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(),
342  * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */
343 static mbedtls_asn1_named_data *asn1_find_named_data(
344                                                mbedtls_asn1_named_data *list,
345                                                const char *oid, size_t len )
346 {
347     while( list != NULL )
348     {
349         if( list->oid.len == len &&
350             memcmp( list->oid.p, oid, len ) == 0 )
351         {
352             break;
353         }
354 
355         list = list->next;
356     }
357 
358     return( list );
359 }
360 
361 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(
362                                         mbedtls_asn1_named_data **head,
363                                         const char *oid, size_t oid_len,
364                                         const unsigned char *val,
365                                         size_t val_len )
366 {
367     mbedtls_asn1_named_data *cur;
368 
369     if( ( cur = asn1_find_named_data( *head, oid, oid_len ) ) == NULL )
370     {
371         // Add new entry if not present yet based on OID
372         //
373         cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1,
374                                             sizeof(mbedtls_asn1_named_data) );
375         if( cur == NULL )
376             return( NULL );
377 
378         cur->oid.len = oid_len;
379         cur->oid.p = mbedtls_calloc( 1, oid_len );
380         if( cur->oid.p == NULL )
381         {
382             mbedtls_free( cur );
383             return( NULL );
384         }
385 
386         memcpy( cur->oid.p, oid, oid_len );
387 
388         cur->val.len = val_len;
389         cur->val.p = mbedtls_calloc( 1, val_len );
390         if( cur->val.p == NULL )
391         {
392             mbedtls_free( cur->oid.p );
393             mbedtls_free( cur );
394             return( NULL );
395         }
396 
397         cur->next = *head;
398         *head = cur;
399     }
400     else if( cur->val.len < val_len )
401     {
402         /*
403          * Enlarge existing value buffer if needed
404          * Preserve old data until the allocation succeeded, to leave list in
405          * a consistent state in case allocation fails.
406          */
407         void *p = mbedtls_calloc( 1, val_len );
408         if( p == NULL )
409             return( NULL );
410 
411         mbedtls_free( cur->val.p );
412         cur->val.p = p;
413         cur->val.len = val_len;
414     }
415 
416     if( val != NULL )
417         memcpy( cur->val.p, val, val_len );
418 
419     return( cur );
420 }
421 #endif /* MBEDTLS_ASN1_WRITE_C */
422