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