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