1 /*
2  * ASN.1 buffer writing functionality
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0
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 
20 #include "common.h"
21 
22 #if defined(MBEDTLS_ASN1_WRITE_C)
23 
24 #include "mbedtls/asn1write.h"
25 #include "mbedtls/error.h"
26 
27 #include <string.h>
28 
29 #include "mbedtls/platform.h"
30 
mbedtls_asn1_write_len(unsigned char ** p,const unsigned char * start,size_t len)31 int mbedtls_asn1_write_len( unsigned char **p, const unsigned char *start, size_t len )
32 {
33     if( len < 0x80 )
34     {
35         if( *p - start < 1 )
36             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
37 
38         *--(*p) = (unsigned char) len;
39         return( 1 );
40     }
41 
42     if( len <= 0xFF )
43     {
44         if( *p - start < 2 )
45             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
46 
47         *--(*p) = (unsigned char) len;
48         *--(*p) = 0x81;
49         return( 2 );
50     }
51 
52     if( len <= 0xFFFF )
53     {
54         if( *p - start < 3 )
55             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
56 
57         *--(*p) = MBEDTLS_BYTE_0( len );
58         *--(*p) = MBEDTLS_BYTE_1( len );
59         *--(*p) = 0x82;
60         return( 3 );
61     }
62 
63     if( len <= 0xFFFFFF )
64     {
65         if( *p - start < 4 )
66             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
67 
68         *--(*p) = MBEDTLS_BYTE_0( len );
69         *--(*p) = MBEDTLS_BYTE_1( len );
70         *--(*p) = MBEDTLS_BYTE_2( len );
71         *--(*p) = 0x83;
72         return( 4 );
73     }
74 
75     int len_is_valid = 1;
76 #if SIZE_MAX > 0xFFFFFFFF
77     len_is_valid = ( len <= 0xFFFFFFFF );
78 #endif
79     if( len_is_valid )
80     {
81         if( *p - start < 5 )
82             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
83 
84         *--(*p) = MBEDTLS_BYTE_0( len );
85         *--(*p) = MBEDTLS_BYTE_1( len );
86         *--(*p) = MBEDTLS_BYTE_2( len );
87         *--(*p) = MBEDTLS_BYTE_3( len );
88         *--(*p) = 0x84;
89         return( 5 );
90     }
91 
92     return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
93 }
94 
mbedtls_asn1_write_tag(unsigned char ** p,const unsigned char * start,unsigned char tag)95 int mbedtls_asn1_write_tag( unsigned char **p, const unsigned char *start, unsigned char tag )
96 {
97     if( *p - start < 1 )
98         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
99 
100     *--(*p) = tag;
101 
102     return( 1 );
103 }
104 
mbedtls_asn1_write_raw_buffer(unsigned char ** p,const unsigned char * start,const unsigned char * buf,size_t size)105 int mbedtls_asn1_write_raw_buffer( unsigned char **p, const unsigned char *start,
106                            const unsigned char *buf, size_t size )
107 {
108     size_t len = 0;
109 
110     if( *p < start || (size_t)( *p - start ) < size )
111         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
112 
113     len = size;
114     (*p) -= len;
115     memcpy( *p, buf, len );
116 
117     return( (int) len );
118 }
119 
120 #if defined(MBEDTLS_BIGNUM_C)
mbedtls_asn1_write_mpi(unsigned char ** p,const unsigned char * start,const mbedtls_mpi * X)121 int mbedtls_asn1_write_mpi( unsigned char **p, const unsigned char *start, const mbedtls_mpi *X )
122 {
123     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
124     size_t len = 0;
125 
126     // Write the MPI
127     //
128     len = mbedtls_mpi_size( X );
129 
130     /* DER represents 0 with a sign bit (0=nonnegative) and 7 value bits, not
131      * as 0 digits. We need to end up with 020100, not with 0200. */
132     if( len == 0 )
133         len = 1;
134 
135     if( *p < start || (size_t)( *p - start ) < len )
136         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
137 
138     (*p) -= len;
139     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) );
140 
141     // DER format assumes 2s complement for numbers, so the leftmost bit
142     // should be 0 for positive numbers and 1 for negative numbers.
143     //
144     if( X->s ==1 && **p & 0x80 )
145     {
146         if( *p - start < 1 )
147             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
148 
149         *--(*p) = 0x00;
150         len += 1;
151     }
152 
153     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
154     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
155 
156     ret = (int) len;
157 
158 cleanup:
159     return( ret );
160 }
161 #endif /* MBEDTLS_BIGNUM_C */
162 
mbedtls_asn1_write_null(unsigned char ** p,const unsigned char * start)163 int mbedtls_asn1_write_null( unsigned char **p, const unsigned char *start )
164 {
165     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
166     size_t len = 0;
167 
168     // Write NULL
169     //
170     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) );
171     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) );
172 
173     return( (int) len );
174 }
175 
mbedtls_asn1_write_oid(unsigned char ** p,const unsigned char * start,const char * oid,size_t oid_len)176 int mbedtls_asn1_write_oid( unsigned char **p, const unsigned char *start,
177                     const char *oid, size_t oid_len )
178 {
179     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
180     size_t len = 0;
181 
182     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
183                                   (const unsigned char *) oid, oid_len ) );
184     MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) );
185     MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) );
186 
187     return( (int) len );
188 }
189 
mbedtls_asn1_write_algorithm_identifier(unsigned char ** p,const unsigned char * start,const char * oid,size_t oid_len,size_t par_len)190 int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, const unsigned char *start,
191                                      const char *oid, size_t oid_len,
192                                      size_t par_len )
193 {
194     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
195     size_t len = 0;
196 
197     if( par_len == 0 )
198         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) );
199     else
200         len += par_len;
201 
202     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
203 
204     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
205     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
206                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
207 
208     return( (int) len );
209 }
210 
mbedtls_asn1_write_bool(unsigned char ** p,const unsigned char * start,int boolean)211 int mbedtls_asn1_write_bool( unsigned char **p, const unsigned char *start, int boolean )
212 {
213     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
214     size_t len = 0;
215 
216     if( *p - start < 1 )
217         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
218 
219     *--(*p) = (boolean) ? 255 : 0;
220     len++;
221 
222     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
223     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) );
224 
225     return( (int) len );
226 }
227 
asn1_write_tagged_int(unsigned char ** p,const unsigned char * start,int val,int tag)228 static int asn1_write_tagged_int( unsigned char **p, const unsigned char *start, int val, int tag )
229 {
230     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
231     size_t len = 0;
232 
233     do
234     {
235         if( *p - start < 1 )
236             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
237         len += 1;
238         *--(*p) = val & 0xff;
239         val >>= 8;
240     }
241     while( val > 0 );
242 
243     if( **p & 0x80 )
244     {
245         if( *p - start < 1 )
246             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
247         *--(*p) = 0x00;
248         len += 1;
249     }
250 
251     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
252     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) );
253 
254     return( (int) len );
255 }
256 
mbedtls_asn1_write_int(unsigned char ** p,const unsigned char * start,int val)257 int mbedtls_asn1_write_int( unsigned char **p, const unsigned char *start, int val )
258 {
259     return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_INTEGER ) );
260 }
261 
mbedtls_asn1_write_enum(unsigned char ** p,const unsigned char * start,int val)262 int mbedtls_asn1_write_enum( unsigned char **p, const unsigned char *start, int val )
263 {
264     return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_ENUMERATED ) );
265 }
266 
mbedtls_asn1_write_tagged_string(unsigned char ** p,const unsigned char * start,int tag,const char * text,size_t text_len)267 int mbedtls_asn1_write_tagged_string( unsigned char **p, const unsigned char *start, int tag,
268     const char *text, size_t text_len )
269 {
270     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
271     size_t len = 0;
272 
273     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
274         (const unsigned char *) text, text_len ) );
275 
276     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
277     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) );
278 
279     return( (int) len );
280 }
281 
mbedtls_asn1_write_utf8_string(unsigned char ** p,const unsigned char * start,const char * text,size_t text_len)282 int mbedtls_asn1_write_utf8_string( unsigned char **p, const unsigned char *start,
283     const char *text, size_t text_len )
284 {
285     return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len) );
286 }
287 
mbedtls_asn1_write_printable_string(unsigned char ** p,const unsigned char * start,const char * text,size_t text_len)288 int mbedtls_asn1_write_printable_string( unsigned char **p, const unsigned char *start,
289                                  const char *text, size_t text_len )
290 {
291     return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text, text_len) );
292 }
293 
mbedtls_asn1_write_ia5_string(unsigned char ** p,const unsigned char * start,const char * text,size_t text_len)294 int mbedtls_asn1_write_ia5_string( unsigned char **p, const unsigned char *start,
295                            const char *text, size_t text_len )
296 {
297     return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) );
298 }
299 
mbedtls_asn1_write_named_bitstring(unsigned char ** p,const unsigned char * start,const unsigned char * buf,size_t bits)300 int mbedtls_asn1_write_named_bitstring( unsigned char **p,
301                                         const unsigned char *start,
302                                         const unsigned char *buf,
303                                         size_t bits )
304 {
305     size_t unused_bits, byte_len;
306     const unsigned char *cur_byte;
307     unsigned char cur_byte_shifted;
308     unsigned char bit;
309 
310     byte_len = ( bits + 7 ) / 8;
311     unused_bits = ( byte_len * 8 ) - bits;
312 
313     /*
314      * Named bitstrings require that trailing 0s are excluded in the encoding
315      * of the bitstring. Trailing 0s are considered part of the 'unused' bits
316      * when encoding this value in the first content octet
317      */
318     if( bits != 0 )
319     {
320         cur_byte = buf + byte_len - 1;
321         cur_byte_shifted = *cur_byte >> unused_bits;
322 
323         for( ; ; )
324         {
325             bit = cur_byte_shifted & 0x1;
326             cur_byte_shifted >>= 1;
327 
328             if( bit != 0 )
329                 break;
330 
331             bits--;
332             if( bits == 0 )
333                 break;
334 
335             if( bits % 8 == 0 )
336                 cur_byte_shifted = *--cur_byte;
337         }
338     }
339 
340     return( mbedtls_asn1_write_bitstring( p, start, buf, bits ) );
341 }
342 
mbedtls_asn1_write_bitstring(unsigned char ** p,const unsigned char * start,const unsigned char * buf,size_t bits)343 int mbedtls_asn1_write_bitstring( unsigned char **p, const unsigned char *start,
344                           const unsigned char *buf, size_t bits )
345 {
346     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
347     size_t len = 0;
348     size_t unused_bits, byte_len;
349 
350     byte_len = ( bits + 7 ) / 8;
351     unused_bits = ( byte_len * 8 ) - bits;
352 
353     if( *p < start || (size_t)( *p - start ) < byte_len + 1 )
354         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
355 
356     len = byte_len + 1;
357 
358     /* Write the bitstring. Ensure the unused bits are zeroed */
359     if( byte_len > 0 )
360     {
361         byte_len--;
362         *--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 );
363         ( *p ) -= byte_len;
364         memcpy( *p, buf, byte_len );
365     }
366 
367     /* Write unused bits */
368     *--( *p ) = (unsigned char)unused_bits;
369 
370     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
371     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) );
372 
373     return( (int) len );
374 }
375 
mbedtls_asn1_write_octet_string(unsigned char ** p,const unsigned char * start,const unsigned char * buf,size_t size)376 int mbedtls_asn1_write_octet_string( unsigned char **p, const unsigned char *start,
377                              const unsigned char *buf, size_t size )
378 {
379     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
380     size_t len = 0;
381 
382     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) );
383 
384     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
385     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) );
386 
387     return( (int) len );
388 }
389 
390 
391 /* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(),
392  * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */
asn1_find_named_data(mbedtls_asn1_named_data * list,const char * oid,size_t len)393 static mbedtls_asn1_named_data *asn1_find_named_data(
394                                                mbedtls_asn1_named_data *list,
395                                                const char *oid, size_t len )
396 {
397     while( list != NULL )
398     {
399         if( list->oid.len == len &&
400             memcmp( list->oid.p, oid, len ) == 0 )
401         {
402             break;
403         }
404 
405         list = list->next;
406     }
407 
408     return( list );
409 }
410 
mbedtls_asn1_store_named_data(mbedtls_asn1_named_data ** head,const char * oid,size_t oid_len,const unsigned char * val,size_t val_len)411 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data(
412                                         mbedtls_asn1_named_data **head,
413                                         const char *oid, size_t oid_len,
414                                         const unsigned char *val,
415                                         size_t val_len )
416 {
417     mbedtls_asn1_named_data *cur;
418 
419     if( ( cur = asn1_find_named_data( *head, oid, oid_len ) ) == NULL )
420     {
421         // Add new entry if not present yet based on OID
422         //
423         cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1,
424                                             sizeof(mbedtls_asn1_named_data) );
425         if( cur == NULL )
426             return( NULL );
427 
428         cur->oid.len = oid_len;
429         cur->oid.p = mbedtls_calloc( 1, oid_len );
430         if( cur->oid.p == NULL )
431         {
432             mbedtls_free( cur );
433             return( NULL );
434         }
435 
436         memcpy( cur->oid.p, oid, oid_len );
437 
438         cur->val.len = val_len;
439         if( val_len != 0 )
440         {
441             cur->val.p = mbedtls_calloc( 1, val_len );
442             if( cur->val.p == NULL )
443             {
444                 mbedtls_free( cur->oid.p );
445                 mbedtls_free( cur );
446                 return( NULL );
447             }
448         }
449 
450         cur->next = *head;
451         *head = cur;
452     }
453     else if( val_len == 0 )
454     {
455         mbedtls_free( cur->val.p );
456         cur->val.p = NULL;
457     }
458     else if( cur->val.len != val_len )
459     {
460         /*
461          * Enlarge existing value buffer if needed
462          * Preserve old data until the allocation succeeded, to leave list in
463          * a consistent state in case allocation fails.
464          */
465         void *p = mbedtls_calloc( 1, val_len );
466         if( p == NULL )
467             return( NULL );
468 
469         mbedtls_free( cur->val.p );
470         cur->val.p = p;
471         cur->val.len = val_len;
472     }
473 
474     if( val != NULL && val_len != 0 )
475         memcpy( cur->val.p, val, val_len );
476 
477     return( cur );
478 }
479 #endif /* MBEDTLS_ASN1_WRITE_C */
480