1 /*
2  * ASN.1 buffer writing functionality
3  *
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
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  *  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 
mbedtls_asn1_write_len(unsigned char ** p,unsigned char * start,size_t len)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( len <= 0xFFFFFFFF )
87     {
88         if( *p - start < 5 )
89             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
90 
91         *--(*p) = ( len       ) & 0xFF;
92         *--(*p) = ( len >>  8 ) & 0xFF;
93         *--(*p) = ( len >> 16 ) & 0xFF;
94         *--(*p) = ( len >> 24 ) & 0xFF;
95         *--(*p) = 0x84;
96         return( 5 );
97     }
98 
99     return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
100 }
101 
mbedtls_asn1_write_tag(unsigned char ** p,unsigned char * start,unsigned char tag)102 int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
103 {
104     if( *p - start < 1 )
105         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
106 
107     *--(*p) = tag;
108 
109     return( 1 );
110 }
111 
mbedtls_asn1_write_raw_buffer(unsigned char ** p,unsigned char * start,const unsigned char * buf,size_t size)112 int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
113                            const unsigned char *buf, size_t size )
114 {
115     size_t len = 0;
116 
117     if( *p < start || (size_t)( *p - start ) < size )
118         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
119 
120     len = size;
121     (*p) -= len;
122     memcpy( *p, buf, len );
123 
124     return( (int) len );
125 }
126 
127 #if defined(MBEDTLS_BIGNUM_C)
mbedtls_asn1_write_mpi(unsigned char ** p,unsigned char * start,const mbedtls_mpi * X)128 int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X )
129 {
130     int ret;
131     size_t len = 0;
132 
133     // Write the MPI
134     //
135     len = mbedtls_mpi_size( X );
136 
137     if( *p < start || (size_t)( *p - start ) < len )
138         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
139 
140     (*p) -= len;
141     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) );
142 
143     // DER format assumes 2s complement for numbers, so the leftmost bit
144     // should be 0 for positive numbers and 1 for negative numbers.
145     //
146     if( X->s ==1 && **p & 0x80 )
147     {
148         if( *p - start < 1 )
149             return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
150 
151         *--(*p) = 0x00;
152         len += 1;
153     }
154 
155     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
156     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
157 
158     ret = (int) len;
159 
160 cleanup:
161     return( ret );
162 }
163 #endif /* MBEDTLS_BIGNUM_C */
164 
mbedtls_asn1_write_null(unsigned char ** p,unsigned char * start)165 int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start )
166 {
167     int ret;
168     size_t len = 0;
169 
170     // Write NULL
171     //
172     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) );
173     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) );
174 
175     return( (int) len );
176 }
177 
mbedtls_asn1_write_oid(unsigned char ** p,unsigned char * start,const char * oid,size_t oid_len)178 int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start,
179                     const char *oid, size_t oid_len )
180 {
181     int ret;
182     size_t len = 0;
183 
184     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
185                                   (const unsigned char *) oid, oid_len ) );
186     MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) );
187     MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) );
188 
189     return( (int) len );
190 }
191 
mbedtls_asn1_write_algorithm_identifier(unsigned char ** p,unsigned char * start,const char * oid,size_t oid_len,size_t par_len)192 int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
193                                      const char *oid, size_t oid_len,
194                                      size_t par_len )
195 {
196     int ret;
197     size_t len = 0;
198 
199     if( par_len == 0 )
200         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) );
201     else
202         len += par_len;
203 
204     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
205 
206     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
207     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
208                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
209 
210     return( (int) len );
211 }
212 
mbedtls_asn1_write_bool(unsigned char ** p,unsigned char * start,int boolean)213 int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean )
214 {
215     int ret;
216     size_t len = 0;
217 
218     if( *p - start < 1 )
219         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
220 
221     *--(*p) = (boolean) ? 255 : 0;
222     len++;
223 
224     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
225     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) );
226 
227     return( (int) len );
228 }
229 
mbedtls_asn1_write_int(unsigned char ** p,unsigned char * start,int val)230 int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
231 {
232     int ret;
233     size_t len = 0;
234 
235     // TODO negative values and values larger than 128
236     // DER format assumes 2s complement for numbers, so the leftmost bit
237     // should be 0 for positive numbers and 1 for negative numbers.
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 
mbedtls_asn1_write_printable_string(unsigned char ** p,unsigned char * start,const char * text,size_t text_len)260 int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
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, MBEDTLS_ASN1_PRINTABLE_STRING ) );
271 
272     return( (int) len );
273 }
274 
mbedtls_asn1_write_ia5_string(unsigned char ** p,unsigned char * start,const char * text,size_t text_len)275 int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
276                            const char *text, size_t text_len )
277 {
278     int ret;
279     size_t len = 0;
280 
281     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
282                   (const unsigned char *) text, text_len ) );
283 
284     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
285     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_IA5_STRING ) );
286 
287     return( (int) len );
288 }
289 
mbedtls_asn1_write_bitstring(unsigned char ** p,unsigned char * start,const unsigned char * buf,size_t bits)290 int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
291                           const unsigned char *buf, size_t bits )
292 {
293     int ret;
294     size_t len = 0, size;
295 
296     size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 );
297 
298     // Calculate byte length
299     //
300     if( *p < start || (size_t)( *p - start ) < size + 1 )
301         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
302 
303     len = size + 1;
304     (*p) -= size;
305     memcpy( *p, buf, size );
306 
307     // Write unused bits
308     //
309     *--(*p) = (unsigned char) (size * 8 - bits);
310 
311     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
312     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) );
313 
314     return( (int) len );
315 }
316 
mbedtls_asn1_write_octet_string(unsigned char ** p,unsigned char * start,const unsigned char * buf,size_t size)317 int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start,
318                              const unsigned char *buf, size_t size )
319 {
320     int ret;
321     size_t len = 0;
322 
323     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) );
324 
325     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
326     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) );
327 
328     return( (int) len );
329 }
330 
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)331 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **head,
332                                         const char *oid, size_t oid_len,
333                                         const unsigned char *val,
334                                         size_t val_len )
335 {
336     mbedtls_asn1_named_data *cur;
337 
338     if( ( cur = mbedtls_asn1_find_named_data( *head, oid, oid_len ) ) == NULL )
339     {
340         // Add new entry if not present yet based on OID
341         //
342         cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1,
343                                             sizeof(mbedtls_asn1_named_data) );
344         if( cur == NULL )
345             return( NULL );
346 
347         cur->oid.len = oid_len;
348         cur->oid.p = mbedtls_calloc( 1, oid_len );
349         if( cur->oid.p == NULL )
350         {
351             mbedtls_free( cur );
352             return( NULL );
353         }
354 
355         memcpy( cur->oid.p, oid, oid_len );
356 
357         cur->val.len = val_len;
358         cur->val.p = mbedtls_calloc( 1, val_len );
359         if( cur->val.p == NULL )
360         {
361             mbedtls_free( cur->oid.p );
362             mbedtls_free( cur );
363             return( NULL );
364         }
365 
366         cur->next = *head;
367         *head = cur;
368     }
369     else if( cur->val.len < val_len )
370     {
371         /*
372          * Enlarge existing value buffer if needed
373          * Preserve old data until the allocation succeeded, to leave list in
374          * a consistent state in case allocation fails.
375          */
376         void *p = mbedtls_calloc( 1, val_len );
377         if( p == NULL )
378             return( NULL );
379 
380         mbedtls_free( cur->val.p );
381         cur->val.p = p;
382         cur->val.len = val_len;
383     }
384 
385     if( val != NULL )
386         memcpy( cur->val.p, val, val_len );
387 
388     return( cur );
389 }
390 #endif /* MBEDTLS_ASN1_WRITE_C */
391