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