1/* 2 * X.509 base functions for creating certificates / CSRs 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_X509_CREATE_C) 11 12#include "x509_internal.h" 13#include "mbedtls/asn1write.h" 14#include "mbedtls/error.h" 15#include "mbedtls/oid.h" 16 17#include <string.h> 18 19#include "mbedtls/platform.h" 20 21#include "mbedtls/asn1.h" 22 23/* Structure linking OIDs for X.509 DN AttributeTypes to their 24 * string representations and default string encodings used by Mbed TLS. */ 25typedef struct { 26 const char *name; /* String representation of AttributeType, e.g. 27 * "CN" or "emailAddress". */ 28 size_t name_len; /* Length of 'name', without trailing 0 byte. */ 29 const char *oid; /* String representation of OID of AttributeType, 30 * as per RFC 5280, Appendix A.1. encoded as per 31 * X.690 */ 32 int default_tag; /* The default character encoding used for the 33 * given attribute type, e.g. 34 * MBEDTLS_ASN1_UTF8_STRING for UTF-8. */ 35} x509_attr_descriptor_t; 36 37#define ADD_STRLEN(s) s, sizeof(s) - 1 38 39/* X.509 DN attributes from RFC 5280, Appendix A.1. */ 40static const x509_attr_descriptor_t x509_attrs[] = 41{ 42 { ADD_STRLEN("CN"), 43 MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING }, 44 { ADD_STRLEN("commonName"), 45 MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING }, 46 { ADD_STRLEN("C"), 47 MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING }, 48 { ADD_STRLEN("countryName"), 49 MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING }, 50 { ADD_STRLEN("O"), 51 MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING }, 52 { ADD_STRLEN("organizationName"), 53 MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING }, 54 { ADD_STRLEN("L"), 55 MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING }, 56 { ADD_STRLEN("locality"), 57 MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING }, 58 { ADD_STRLEN("R"), 59 MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING }, 60 { ADD_STRLEN("OU"), 61 MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING }, 62 { ADD_STRLEN("organizationalUnitName"), 63 MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING }, 64 { ADD_STRLEN("ST"), 65 MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING }, 66 { ADD_STRLEN("stateOrProvinceName"), 67 MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING }, 68 { ADD_STRLEN("emailAddress"), 69 MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING }, 70 { ADD_STRLEN("serialNumber"), 71 MBEDTLS_OID_AT_SERIAL_NUMBER, MBEDTLS_ASN1_PRINTABLE_STRING }, 72 { ADD_STRLEN("postalAddress"), 73 MBEDTLS_OID_AT_POSTAL_ADDRESS, MBEDTLS_ASN1_PRINTABLE_STRING }, 74 { ADD_STRLEN("postalCode"), 75 MBEDTLS_OID_AT_POSTAL_CODE, MBEDTLS_ASN1_PRINTABLE_STRING }, 76 { ADD_STRLEN("dnQualifier"), 77 MBEDTLS_OID_AT_DN_QUALIFIER, MBEDTLS_ASN1_PRINTABLE_STRING }, 78 { ADD_STRLEN("title"), 79 MBEDTLS_OID_AT_TITLE, MBEDTLS_ASN1_UTF8_STRING }, 80 { ADD_STRLEN("surName"), 81 MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING }, 82 { ADD_STRLEN("SN"), 83 MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING }, 84 { ADD_STRLEN("givenName"), 85 MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING }, 86 { ADD_STRLEN("GN"), 87 MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING }, 88 { ADD_STRLEN("initials"), 89 MBEDTLS_OID_AT_INITIALS, MBEDTLS_ASN1_UTF8_STRING }, 90 { ADD_STRLEN("pseudonym"), 91 MBEDTLS_OID_AT_PSEUDONYM, MBEDTLS_ASN1_UTF8_STRING }, 92 { ADD_STRLEN("generationQualifier"), 93 MBEDTLS_OID_AT_GENERATION_QUALIFIER, MBEDTLS_ASN1_UTF8_STRING }, 94 { ADD_STRLEN("domainComponent"), 95 MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING }, 96 { ADD_STRLEN("DC"), 97 MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING }, 98 { NULL, 0, NULL, MBEDTLS_ASN1_NULL } 99}; 100 101static const x509_attr_descriptor_t *x509_attr_descr_from_name(const char *name, size_t name_len) 102{ 103 const x509_attr_descriptor_t *cur; 104 105 for (cur = x509_attrs; cur->name != NULL; cur++) { 106 if (cur->name_len == name_len && 107 strncmp(cur->name, name, name_len) == 0) { 108 break; 109 } 110 } 111 112 if (cur->name == NULL) { 113 return NULL; 114 } 115 116 return cur; 117} 118 119static int hex_to_int(char c) 120{ 121 return ('0' <= c && c <= '9') ? (c - '0') : 122 ('a' <= c && c <= 'f') ? (c - 'a' + 10) : 123 ('A' <= c && c <= 'F') ? (c - 'A' + 10) : -1; 124} 125 126static int hexpair_to_int(const char *hexpair) 127{ 128 int n1 = hex_to_int(*hexpair); 129 int n2 = hex_to_int(*(hexpair + 1)); 130 131 if (n1 != -1 && n2 != -1) { 132 return (n1 << 4) | n2; 133 } else { 134 return -1; 135 } 136} 137 138static int parse_attribute_value_string(const char *s, 139 int len, 140 unsigned char *data, 141 size_t *data_len) 142{ 143 const char *c; 144 const char *end = s + len; 145 unsigned char *d = data; 146 int n; 147 148 for (c = s; c < end; c++) { 149 if (*c == '\\') { 150 c++; 151 152 /* Check for valid escaped characters as per RFC 4514 Section 3 */ 153 if (c + 1 < end && (n = hexpair_to_int(c)) != -1) { 154 if (n == 0) { 155 return MBEDTLS_ERR_X509_INVALID_NAME; 156 } 157 *(d++) = n; 158 c++; 159 } else if (c < end && strchr(" ,=+<>#;\"\\", *c)) { 160 *(d++) = *c; 161 } else { 162 return MBEDTLS_ERR_X509_INVALID_NAME; 163 } 164 } else { 165 *(d++) = *c; 166 } 167 168 if (d - data == MBEDTLS_X509_MAX_DN_NAME_SIZE) { 169 return MBEDTLS_ERR_X509_INVALID_NAME; 170 } 171 } 172 *data_len = (size_t) (d - data); 173 return 0; 174} 175 176/** Parse a hexstring containing a DER-encoded string. 177 * 178 * \param s A string of \p len bytes hexadecimal digits. 179 * \param len Number of bytes to read from \p s. 180 * \param data Output buffer of size \p data_size. 181 * On success, it contains the payload that's DER-encoded 182 * in the input (content without the tag and length). 183 * If the DER tag is a string tag, the payload is guaranteed 184 * not to contain null bytes. 185 * \param data_size Length of the \p data buffer. 186 * \param data_len On success, the length of the parsed string. 187 * It is guaranteed to be less than 188 * #MBEDTLS_X509_MAX_DN_NAME_SIZE. 189 * \param tag The ASN.1 tag that the payload in \p data is encoded in. 190 * 191 * \retval 0 on success. 192 * \retval #MBEDTLS_ERR_X509_INVALID_NAME if \p s does not contain 193 * a valid hexstring, 194 * or if the decoded hexstring is not valid DER, 195 * or if the payload does not fit in \p data, 196 * or if the payload is more than 197 * #MBEDTLS_X509_MAX_DN_NAME_SIZE bytes, 198 * of if \p *tag is an ASN.1 string tag and the payload 199 * contains a null byte. 200 * \retval #MBEDTLS_ERR_X509_ALLOC_FAILED on low memory. 201 */ 202static int parse_attribute_value_hex_der_encoded(const char *s, 203 size_t len, 204 unsigned char *data, 205 size_t data_size, 206 size_t *data_len, 207 int *tag) 208{ 209 /* Step 1: preliminary length checks. */ 210 /* Each byte is encoded by exactly two hexadecimal digits. */ 211 if (len % 2 != 0) { 212 /* Odd number of hex digits */ 213 return MBEDTLS_ERR_X509_INVALID_NAME; 214 } 215 size_t const der_length = len / 2; 216 if (der_length > MBEDTLS_X509_MAX_DN_NAME_SIZE + 4) { 217 /* The payload would be more than MBEDTLS_X509_MAX_DN_NAME_SIZE 218 * (after subtracting the ASN.1 tag and length). Reject this early 219 * to avoid allocating a large intermediate buffer. */ 220 return MBEDTLS_ERR_X509_INVALID_NAME; 221 } 222 if (der_length < 1) { 223 /* Avoid empty-buffer shenanigans. A valid DER encoding is never 224 * empty. */ 225 return MBEDTLS_ERR_X509_INVALID_NAME; 226 } 227 228 /* Step 2: Decode the hex string into an intermediate buffer. */ 229 unsigned char *der = mbedtls_calloc(1, der_length); 230 if (der == NULL) { 231 return MBEDTLS_ERR_X509_ALLOC_FAILED; 232 } 233 /* Beyond this point, der needs to be freed on exit. */ 234 for (size_t i = 0; i < der_length; i++) { 235 int c = hexpair_to_int(s + 2 * i); 236 if (c < 0) { 237 goto error; 238 } 239 der[i] = c; 240 } 241 242 /* Step 3: decode the DER. */ 243 /* We've checked that der_length >= 1 above. */ 244 *tag = der[0]; 245 { 246 unsigned char *p = der + 1; 247 if (mbedtls_asn1_get_len(&p, der + der_length, data_len) != 0) { 248 goto error; 249 } 250 /* Now p points to the first byte of the payload inside der, 251 * and *data_len is the length of the payload. */ 252 253 /* Step 4: payload validation */ 254 if (*data_len > MBEDTLS_X509_MAX_DN_NAME_SIZE) { 255 goto error; 256 } 257 /* Strings must not contain null bytes. */ 258 if (MBEDTLS_ASN1_IS_STRING_TAG(*tag)) { 259 for (size_t i = 0; i < *data_len; i++) { 260 if (p[i] == 0) { 261 goto error; 262 } 263 } 264 } 265 266 /* Step 5: output the payload. */ 267 if (*data_len > data_size) { 268 goto error; 269 } 270 memcpy(data, p, *data_len); 271 } 272 mbedtls_free(der); 273 274 return 0; 275 276error: 277 mbedtls_free(der); 278 return MBEDTLS_ERR_X509_INVALID_NAME; 279} 280 281int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *name) 282{ 283 int ret = MBEDTLS_ERR_X509_INVALID_NAME; 284 int parse_ret = 0; 285 const char *s = name, *c = s; 286 const char *end = s + strlen(s); 287 mbedtls_asn1_buf oid = { .p = NULL, .len = 0, .tag = MBEDTLS_ASN1_NULL }; 288 const x509_attr_descriptor_t *attr_descr = NULL; 289 int in_attr_type = 1; 290 int tag; 291 int numericoid = 0; 292 unsigned char data[MBEDTLS_X509_MAX_DN_NAME_SIZE]; 293 size_t data_len = 0; 294 295 /* Clear existing chain if present */ 296 mbedtls_asn1_free_named_data_list(head); 297 298 while (c <= end) { 299 if (in_attr_type && *c == '=') { 300 if ((attr_descr = x509_attr_descr_from_name(s, (size_t) (c - s))) == NULL) { 301 if ((mbedtls_oid_from_numeric_string(&oid, s, (size_t) (c - s))) != 0) { 302 return MBEDTLS_ERR_X509_INVALID_NAME; 303 } else { 304 numericoid = 1; 305 } 306 } else { 307 oid.len = strlen(attr_descr->oid); 308 oid.p = mbedtls_calloc(1, oid.len); 309 memcpy(oid.p, attr_descr->oid, oid.len); 310 numericoid = 0; 311 } 312 313 s = c + 1; 314 in_attr_type = 0; 315 } 316 317 if (!in_attr_type && ((*c == ',' && *(c-1) != '\\') || c == end)) { 318 if (s == c) { 319 mbedtls_free(oid.p); 320 return MBEDTLS_ERR_X509_INVALID_NAME; 321 } else if (*s == '#') { 322 /* We know that c >= s (loop invariant) and c != s (in this 323 * else branch), hence c - s - 1 >= 0. */ 324 parse_ret = parse_attribute_value_hex_der_encoded( 325 s + 1, (size_t) (c - s) - 1, 326 data, sizeof(data), &data_len, &tag); 327 if (parse_ret != 0) { 328 mbedtls_free(oid.p); 329 return parse_ret; 330 } 331 } else { 332 if (numericoid) { 333 mbedtls_free(oid.p); 334 return MBEDTLS_ERR_X509_INVALID_NAME; 335 } else { 336 if ((parse_ret = 337 parse_attribute_value_string(s, (int) (c - s), data, 338 &data_len)) != 0) { 339 mbedtls_free(oid.p); 340 return parse_ret; 341 } 342 tag = attr_descr->default_tag; 343 } 344 } 345 346 mbedtls_asn1_named_data *cur = 347 mbedtls_asn1_store_named_data(head, (char *) oid.p, oid.len, 348 (unsigned char *) data, 349 data_len); 350 mbedtls_free(oid.p); 351 oid.p = NULL; 352 if (cur == NULL) { 353 return MBEDTLS_ERR_X509_ALLOC_FAILED; 354 } 355 356 // set tagType 357 cur->val.tag = tag; 358 359 while (c < end && *(c + 1) == ' ') { 360 c++; 361 } 362 363 s = c + 1; 364 in_attr_type = 1; 365 366 /* Successfully parsed one name, update ret to success */ 367 ret = 0; 368 } 369 c++; 370 } 371 if (oid.p != NULL) { 372 mbedtls_free(oid.p); 373 } 374 return ret; 375} 376 377/* The first byte of the value in the mbedtls_asn1_named_data structure is reserved 378 * to store the critical boolean for us 379 */ 380int mbedtls_x509_set_extension(mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, 381 int critical, const unsigned char *val, size_t val_len) 382{ 383 mbedtls_asn1_named_data *cur; 384 385 if (val_len > (SIZE_MAX - 1)) { 386 return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 387 } 388 389 if ((cur = mbedtls_asn1_store_named_data(head, oid, oid_len, 390 NULL, val_len + 1)) == NULL) { 391 return MBEDTLS_ERR_X509_ALLOC_FAILED; 392 } 393 394 cur->val.p[0] = critical; 395 memcpy(cur->val.p + 1, val, val_len); 396 397 return 0; 398} 399 400/* 401 * RelativeDistinguishedName ::= 402 * SET OF AttributeTypeAndValue 403 * 404 * AttributeTypeAndValue ::= SEQUENCE { 405 * type AttributeType, 406 * value AttributeValue } 407 * 408 * AttributeType ::= OBJECT IDENTIFIER 409 * 410 * AttributeValue ::= ANY DEFINED BY AttributeType 411 */ 412static int x509_write_name(unsigned char **p, 413 unsigned char *start, 414 mbedtls_asn1_named_data *cur_name) 415{ 416 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 417 size_t len = 0; 418 const char *oid = (const char *) cur_name->oid.p; 419 size_t oid_len = cur_name->oid.len; 420 const unsigned char *name = cur_name->val.p; 421 size_t name_len = cur_name->val.len; 422 423 // Write correct string tag and value 424 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tagged_string(p, start, 425 cur_name->val.tag, 426 (const char *) name, 427 name_len)); 428 // Write OID 429 // 430 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, 431 oid_len)); 432 433 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); 434 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, 435 MBEDTLS_ASN1_CONSTRUCTED | 436 MBEDTLS_ASN1_SEQUENCE)); 437 438 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); 439 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, 440 MBEDTLS_ASN1_CONSTRUCTED | 441 MBEDTLS_ASN1_SET)); 442 443 return (int) len; 444} 445 446int mbedtls_x509_write_names(unsigned char **p, unsigned char *start, 447 mbedtls_asn1_named_data *first) 448{ 449 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 450 size_t len = 0; 451 mbedtls_asn1_named_data *cur = first; 452 453 while (cur != NULL) { 454 MBEDTLS_ASN1_CHK_ADD(len, x509_write_name(p, start, cur)); 455 cur = cur->next; 456 } 457 458 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); 459 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | 460 MBEDTLS_ASN1_SEQUENCE)); 461 462 return (int) len; 463} 464 465int mbedtls_x509_write_sig(unsigned char **p, unsigned char *start, 466 const char *oid, size_t oid_len, 467 unsigned char *sig, size_t size, 468 mbedtls_pk_type_t pk_alg) 469{ 470 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 471 int write_null_par; 472 size_t len = 0; 473 474 if (*p < start || (size_t) (*p - start) < size) { 475 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 476 } 477 478 len = size; 479 (*p) -= len; 480 memcpy(*p, sig, len); 481 482 if (*p - start < 1) { 483 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 484 } 485 486 *--(*p) = 0; 487 len += 1; 488 489 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); 490 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_BIT_STRING)); 491 492 // Write OID 493 // 494 if (pk_alg == MBEDTLS_PK_ECDSA) { 495 /* 496 * The AlgorithmIdentifier's parameters field must be absent for DSA/ECDSA signature 497 * algorithms, see https://www.rfc-editor.org/rfc/rfc5480#page-17 and 498 * https://www.rfc-editor.org/rfc/rfc5758#section-3. 499 */ 500 write_null_par = 0; 501 } else { 502 write_null_par = 1; 503 } 504 MBEDTLS_ASN1_CHK_ADD(len, 505 mbedtls_asn1_write_algorithm_identifier_ext(p, start, oid, oid_len, 506 0, write_null_par)); 507 508 return (int) len; 509} 510 511static int x509_write_extension(unsigned char **p, unsigned char *start, 512 mbedtls_asn1_named_data *ext) 513{ 514 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 515 size_t len = 0; 516 517 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start, ext->val.p + 1, 518 ext->val.len - 1)); 519 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, ext->val.len - 1)); 520 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OCTET_STRING)); 521 522 if (ext->val.p[0] != 0) { 523 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_bool(p, start, 1)); 524 } 525 526 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start, ext->oid.p, 527 ext->oid.len)); 528 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, ext->oid.len)); 529 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_OID)); 530 531 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); 532 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED | 533 MBEDTLS_ASN1_SEQUENCE)); 534 535 return (int) len; 536} 537 538/* 539 * Extension ::= SEQUENCE { 540 * extnID OBJECT IDENTIFIER, 541 * critical BOOLEAN DEFAULT FALSE, 542 * extnValue OCTET STRING 543 * -- contains the DER encoding of an ASN.1 value 544 * -- corresponding to the extension type identified 545 * -- by extnID 546 * } 547 */ 548int mbedtls_x509_write_extensions(unsigned char **p, unsigned char *start, 549 mbedtls_asn1_named_data *first) 550{ 551 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 552 size_t len = 0; 553 mbedtls_asn1_named_data *cur_ext = first; 554 555 while (cur_ext != NULL) { 556 MBEDTLS_ASN1_CHK_ADD(len, x509_write_extension(p, start, cur_ext)); 557 cur_ext = cur_ext->next; 558 } 559 560 return (int) len; 561} 562 563#endif /* MBEDTLS_X509_CREATE_C */ 564