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 #if defined(MBEDTLS_PLATFORM_C) 30 #include "mbedtls/platform.h" 31 #else 32 #include <stdlib.h> 33 #define mbedtls_calloc calloc 34 #define mbedtls_free free 35 #endif 36 37 int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) 38 { 39 if( len < 0x80 ) 40 { 41 if( *p - start < 1 ) 42 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 43 44 *--(*p) = (unsigned char) len; 45 return( 1 ); 46 } 47 48 if( len <= 0xFF ) 49 { 50 if( *p - start < 2 ) 51 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 52 53 *--(*p) = (unsigned char) len; 54 *--(*p) = 0x81; 55 return( 2 ); 56 } 57 58 if( len <= 0xFFFF ) 59 { 60 if( *p - start < 3 ) 61 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 62 63 *--(*p) = MBEDTLS_BYTE_0( len ); 64 *--(*p) = MBEDTLS_BYTE_1( len ); 65 *--(*p) = 0x82; 66 return( 3 ); 67 } 68 69 if( len <= 0xFFFFFF ) 70 { 71 if( *p - start < 4 ) 72 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 73 74 *--(*p) = MBEDTLS_BYTE_0( len ); 75 *--(*p) = MBEDTLS_BYTE_1( len ); 76 *--(*p) = MBEDTLS_BYTE_2( len ); 77 *--(*p) = 0x83; 78 return( 4 ); 79 } 80 81 #if SIZE_MAX > 0xFFFFFFFF 82 if( len <= 0xFFFFFFFF ) 83 #endif 84 { 85 if( *p - start < 5 ) 86 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 87 88 *--(*p) = MBEDTLS_BYTE_0( len ); 89 *--(*p) = MBEDTLS_BYTE_1( len ); 90 *--(*p) = MBEDTLS_BYTE_2( len ); 91 *--(*p) = MBEDTLS_BYTE_3( len ); 92 *--(*p) = 0x84; 93 return( 5 ); 94 } 95 96 #if SIZE_MAX > 0xFFFFFFFF 97 return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); 98 #endif 99 } 100 101 int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) 102 { 103 if( *p - start < 1 ) 104 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 105 106 *--(*p) = tag; 107 108 return( 1 ); 109 } 110 111 int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, 112 const unsigned char *buf, size_t size ) 113 { 114 size_t len = 0; 115 116 if( *p < start || (size_t)( *p - start ) < size ) 117 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 118 119 len = size; 120 (*p) -= len; 121 memcpy( *p, buf, len ); 122 123 return( (int) len ); 124 } 125 126 #if defined(MBEDTLS_BIGNUM_C) 127 int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ) 128 { 129 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 130 size_t len = 0; 131 132 // Write the MPI 133 // 134 len = mbedtls_mpi_size( X ); 135 136 /* DER represents 0 with a sign bit (0=nonnegative) and 7 value bits, not 137 * as 0 digits. We need to end up with 020100, not with 0200. */ 138 if( len == 0 ) 139 len = 1; 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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 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 = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 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 static int asn1_write_tagged_int( unsigned char **p, unsigned char *start, int val, int tag ) 235 { 236 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 237 size_t len = 0; 238 239 do 240 { 241 if( *p - start < 1 ) 242 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 243 len += 1; 244 *--(*p) = val & 0xff; 245 val >>= 8; 246 } 247 while( val > 0 ); 248 249 if( **p & 0x80 ) 250 { 251 if( *p - start < 1 ) 252 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 253 *--(*p) = 0x00; 254 len += 1; 255 } 256 257 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); 258 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) ); 259 260 return( (int) len ); 261 } 262 263 int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ) 264 { 265 return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_INTEGER ) ); 266 } 267 268 int mbedtls_asn1_write_enum( unsigned char **p, unsigned char *start, int val ) 269 { 270 return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_ENUMERATED ) ); 271 } 272 273 int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, int tag, 274 const char *text, size_t text_len ) 275 { 276 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 277 size_t len = 0; 278 279 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, 280 (const unsigned char *) text, text_len ) ); 281 282 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); 283 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) ); 284 285 return( (int) len ); 286 } 287 288 int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start, 289 const char *text, size_t text_len ) 290 { 291 return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len) ); 292 } 293 294 int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, 295 const char *text, size_t text_len ) 296 { 297 return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text, text_len) ); 298 } 299 300 int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, 301 const char *text, size_t text_len ) 302 { 303 return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) ); 304 } 305 306 int mbedtls_asn1_write_named_bitstring( unsigned char **p, 307 unsigned char *start, 308 const unsigned char *buf, 309 size_t bits ) 310 { 311 size_t unused_bits, byte_len; 312 const unsigned char *cur_byte; 313 unsigned char cur_byte_shifted; 314 unsigned char bit; 315 316 byte_len = ( bits + 7 ) / 8; 317 unused_bits = ( byte_len * 8 ) - bits; 318 319 /* 320 * Named bitstrings require that trailing 0s are excluded in the encoding 321 * of the bitstring. Trailing 0s are considered part of the 'unused' bits 322 * when encoding this value in the first content octet 323 */ 324 if( bits != 0 ) 325 { 326 cur_byte = buf + byte_len - 1; 327 cur_byte_shifted = *cur_byte >> unused_bits; 328 329 for( ; ; ) 330 { 331 bit = cur_byte_shifted & 0x1; 332 cur_byte_shifted >>= 1; 333 334 if( bit != 0 ) 335 break; 336 337 bits--; 338 if( bits == 0 ) 339 break; 340 341 if( bits % 8 == 0 ) 342 cur_byte_shifted = *--cur_byte; 343 } 344 } 345 346 return( mbedtls_asn1_write_bitstring( p, start, buf, bits ) ); 347 } 348 349 int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, 350 const unsigned char *buf, size_t bits ) 351 { 352 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 353 size_t len = 0; 354 size_t unused_bits, byte_len; 355 356 byte_len = ( bits + 7 ) / 8; 357 unused_bits = ( byte_len * 8 ) - bits; 358 359 if( *p < start || (size_t)( *p - start ) < byte_len + 1 ) 360 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 361 362 len = byte_len + 1; 363 364 /* Write the bitstring. Ensure the unused bits are zeroed */ 365 if( byte_len > 0 ) 366 { 367 byte_len--; 368 *--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 ); 369 ( *p ) -= byte_len; 370 memcpy( *p, buf, byte_len ); 371 } 372 373 /* Write unused bits */ 374 *--( *p ) = (unsigned char)unused_bits; 375 376 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); 377 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); 378 379 return( (int) len ); 380 } 381 382 int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, 383 const unsigned char *buf, size_t size ) 384 { 385 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 386 size_t len = 0; 387 388 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) ); 389 390 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); 391 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); 392 393 return( (int) len ); 394 } 395 396 397 /* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(), 398 * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */ 399 static mbedtls_asn1_named_data *asn1_find_named_data( 400 mbedtls_asn1_named_data *list, 401 const char *oid, size_t len ) 402 { 403 while( list != NULL ) 404 { 405 if( list->oid.len == len && 406 memcmp( list->oid.p, oid, len ) == 0 ) 407 { 408 break; 409 } 410 411 list = list->next; 412 } 413 414 return( list ); 415 } 416 417 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( 418 mbedtls_asn1_named_data **head, 419 const char *oid, size_t oid_len, 420 const unsigned char *val, 421 size_t val_len ) 422 { 423 mbedtls_asn1_named_data *cur; 424 425 if( ( cur = asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) 426 { 427 // Add new entry if not present yet based on OID 428 // 429 cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1, 430 sizeof(mbedtls_asn1_named_data) ); 431 if( cur == NULL ) 432 return( NULL ); 433 434 cur->oid.len = oid_len; 435 cur->oid.p = mbedtls_calloc( 1, oid_len ); 436 if( cur->oid.p == NULL ) 437 { 438 mbedtls_free( cur ); 439 return( NULL ); 440 } 441 442 memcpy( cur->oid.p, oid, oid_len ); 443 444 cur->val.len = val_len; 445 if( val_len != 0 ) 446 { 447 cur->val.p = mbedtls_calloc( 1, val_len ); 448 if( cur->val.p == NULL ) 449 { 450 mbedtls_free( cur->oid.p ); 451 mbedtls_free( cur ); 452 return( NULL ); 453 } 454 } 455 456 cur->next = *head; 457 *head = cur; 458 } 459 else if( val_len == 0 ) 460 { 461 mbedtls_free( cur->val.p ); 462 cur->val.p = NULL; 463 } 464 else if( cur->val.len != val_len ) 465 { 466 /* 467 * Enlarge existing value buffer if needed 468 * Preserve old data until the allocation succeeded, to leave list in 469 * a consistent state in case allocation fails. 470 */ 471 void *p = mbedtls_calloc( 1, val_len ); 472 if( p == NULL ) 473 return( NULL ); 474 475 mbedtls_free( cur->val.p ); 476 cur->val.p = p; 477 cur->val.len = val_len; 478 } 479 480 if( val != NULL && val_len != 0 ) 481 memcpy( cur->val.p, val, val_len ); 482 483 return( cur ); 484 } 485 #endif /* MBEDTLS_ASN1_WRITE_C */ 486