1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * X.509 Certificate Signing Request writing 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 5*b0563631STom Van Eyck * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6817466cbSJens Wiklander */ 7817466cbSJens Wiklander /* 8817466cbSJens Wiklander * References: 9817466cbSJens Wiklander * - CSRs: PKCS#10 v1.7 aka RFC 2986 10817466cbSJens Wiklander * - attributes: PKCS#9 v2.0 aka RFC 2985 11817466cbSJens Wiklander */ 12817466cbSJens Wiklander 137901324dSJerome Forissier #include "common.h" 14817466cbSJens Wiklander 15817466cbSJens Wiklander #if defined(MBEDTLS_X509_CSR_WRITE_C) 16817466cbSJens Wiklander 17*b0563631STom Van Eyck #include "x509_internal.h" 18817466cbSJens Wiklander #include "mbedtls/x509_csr.h" 19817466cbSJens Wiklander #include "mbedtls/asn1write.h" 2011fa71b9SJerome Forissier #include "mbedtls/error.h" 2111fa71b9SJerome Forissier #include "mbedtls/oid.h" 223d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 23817466cbSJens Wiklander 2411fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 2511fa71b9SJerome Forissier #include "psa/crypto.h" 26*b0563631STom Van Eyck #include "psa_util_internal.h" 2711fa71b9SJerome Forissier #include "mbedtls/psa_util.h" 2832b31808SJens Wiklander #endif /* MBEDTLS_USE_PSA_CRYPTO */ 2911fa71b9SJerome Forissier 30817466cbSJens Wiklander #include <string.h> 31817466cbSJens Wiklander #include <stdlib.h> 32817466cbSJens Wiklander 33817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C) 34817466cbSJens Wiklander #include "mbedtls/pem.h" 35817466cbSJens Wiklander #endif 36817466cbSJens Wiklander 377901324dSJerome Forissier #include "mbedtls/platform.h" 387901324dSJerome Forissier 39817466cbSJens Wiklander void mbedtls_x509write_csr_init(mbedtls_x509write_csr *ctx) 40817466cbSJens Wiklander { 41817466cbSJens Wiklander memset(ctx, 0, sizeof(mbedtls_x509write_csr)); 42817466cbSJens Wiklander } 43817466cbSJens Wiklander 44817466cbSJens Wiklander void mbedtls_x509write_csr_free(mbedtls_x509write_csr *ctx) 45817466cbSJens Wiklander { 46817466cbSJens Wiklander mbedtls_asn1_free_named_data_list(&ctx->subject); 47817466cbSJens Wiklander mbedtls_asn1_free_named_data_list(&ctx->extensions); 48817466cbSJens Wiklander 493d3b0591SJens Wiklander mbedtls_platform_zeroize(ctx, sizeof(mbedtls_x509write_csr)); 50817466cbSJens Wiklander } 51817466cbSJens Wiklander 52817466cbSJens Wiklander void mbedtls_x509write_csr_set_md_alg(mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg) 53817466cbSJens Wiklander { 54817466cbSJens Wiklander ctx->md_alg = md_alg; 55817466cbSJens Wiklander } 56817466cbSJens Wiklander 57817466cbSJens Wiklander void mbedtls_x509write_csr_set_key(mbedtls_x509write_csr *ctx, mbedtls_pk_context *key) 58817466cbSJens Wiklander { 59817466cbSJens Wiklander ctx->key = key; 60817466cbSJens Wiklander } 61817466cbSJens Wiklander 62817466cbSJens Wiklander int mbedtls_x509write_csr_set_subject_name(mbedtls_x509write_csr *ctx, 63817466cbSJens Wiklander const char *subject_name) 64817466cbSJens Wiklander { 65817466cbSJens Wiklander return mbedtls_x509_string_to_names(&ctx->subject, subject_name); 66817466cbSJens Wiklander } 67817466cbSJens Wiklander 68817466cbSJens Wiklander int mbedtls_x509write_csr_set_extension(mbedtls_x509write_csr *ctx, 69817466cbSJens Wiklander const char *oid, size_t oid_len, 7032b31808SJens Wiklander int critical, 71817466cbSJens Wiklander const unsigned char *val, size_t val_len) 72817466cbSJens Wiklander { 73817466cbSJens Wiklander return mbedtls_x509_set_extension(&ctx->extensions, oid, oid_len, 7432b31808SJens Wiklander critical, val, val_len); 7532b31808SJens Wiklander } 7632b31808SJens Wiklander 7732b31808SJens Wiklander int mbedtls_x509write_csr_set_subject_alternative_name(mbedtls_x509write_csr *ctx, 7832b31808SJens Wiklander const mbedtls_x509_san_list *san_list) 7932b31808SJens Wiklander { 80*b0563631STom Van Eyck return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list); 81817466cbSJens Wiklander } 82817466cbSJens Wiklander 83817466cbSJens Wiklander int mbedtls_x509write_csr_set_key_usage(mbedtls_x509write_csr *ctx, unsigned char key_usage) 84817466cbSJens Wiklander { 857901324dSJerome Forissier unsigned char buf[4] = { 0 }; 86817466cbSJens Wiklander unsigned char *c; 8711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 88817466cbSJens Wiklander 89817466cbSJens Wiklander c = buf + 4; 90817466cbSJens Wiklander 9111fa71b9SJerome Forissier ret = mbedtls_asn1_write_named_bitstring(&c, buf, &key_usage, 8); 9232b31808SJens Wiklander if (ret < 3 || ret > 4) { 9332b31808SJens Wiklander return ret; 9432b31808SJens Wiklander } 95817466cbSJens Wiklander 96817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_KEY_USAGE, 97817466cbSJens Wiklander MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE), 9832b31808SJens Wiklander 0, c, (size_t) ret); 9932b31808SJens Wiklander if (ret != 0) { 10032b31808SJens Wiklander return ret; 10132b31808SJens Wiklander } 102817466cbSJens Wiklander 10332b31808SJens Wiklander return 0; 104817466cbSJens Wiklander } 105817466cbSJens Wiklander 106817466cbSJens Wiklander int mbedtls_x509write_csr_set_ns_cert_type(mbedtls_x509write_csr *ctx, 107817466cbSJens Wiklander unsigned char ns_cert_type) 108817466cbSJens Wiklander { 1097901324dSJerome Forissier unsigned char buf[4] = { 0 }; 110817466cbSJens Wiklander unsigned char *c; 11111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 112817466cbSJens Wiklander 113817466cbSJens Wiklander c = buf + 4; 114817466cbSJens Wiklander 11511fa71b9SJerome Forissier ret = mbedtls_asn1_write_named_bitstring(&c, buf, &ns_cert_type, 8); 11632b31808SJens Wiklander if (ret < 3 || ret > 4) { 11732b31808SJens Wiklander return ret; 11832b31808SJens Wiklander } 119817466cbSJens Wiklander 120817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_NS_CERT_TYPE, 121817466cbSJens Wiklander MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE), 12232b31808SJens Wiklander 0, c, (size_t) ret); 12332b31808SJens Wiklander if (ret != 0) { 12432b31808SJens Wiklander return ret; 12532b31808SJens Wiklander } 126817466cbSJens Wiklander 12732b31808SJens Wiklander return 0; 128817466cbSJens Wiklander } 129817466cbSJens Wiklander 1307901324dSJerome Forissier static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx, 1317901324dSJerome Forissier unsigned char *buf, 1327901324dSJerome Forissier size_t size, 13332b31808SJens Wiklander unsigned char *sig, size_t sig_size, 134817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 135817466cbSJens Wiklander void *p_rng) 136817466cbSJens Wiklander { 13711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 138817466cbSJens Wiklander const char *sig_oid; 139817466cbSJens Wiklander size_t sig_oid_len = 0; 140817466cbSJens Wiklander unsigned char *c, *c2; 141*b0563631STom Van Eyck unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 142817466cbSJens Wiklander size_t pub_len = 0, sig_and_oid_len = 0, sig_len; 143817466cbSJens Wiklander size_t len = 0; 144817466cbSJens Wiklander mbedtls_pk_type_t pk_alg; 14511fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 14611fa71b9SJerome Forissier size_t hash_len; 147*b0563631STom Van Eyck psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(ctx->md_alg); 14811fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */ 149817466cbSJens Wiklander 1507901324dSJerome Forissier /* Write the CSR backwards starting from the end of buf */ 1517901324dSJerome Forissier c = buf + size; 1527901324dSJerome Forissier 1537901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_extensions(&c, buf, 1547901324dSJerome Forissier ctx->extensions)); 155817466cbSJens Wiklander 15632b31808SJens Wiklander if (len) { 1577901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1587901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1597901324dSJerome Forissier mbedtls_asn1_write_tag( 1607901324dSJerome Forissier &c, buf, 1617901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 162817466cbSJens Wiklander 1637901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1647901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1657901324dSJerome Forissier mbedtls_asn1_write_tag( 1667901324dSJerome Forissier &c, buf, 1677901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)); 168817466cbSJens Wiklander 1697901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1707901324dSJerome Forissier mbedtls_asn1_write_oid( 1717901324dSJerome Forissier &c, buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ, 172817466cbSJens Wiklander MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_EXT_REQ))); 173817466cbSJens Wiklander 1747901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1757901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1767901324dSJerome Forissier mbedtls_asn1_write_tag( 1777901324dSJerome Forissier &c, buf, 1787901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 179817466cbSJens Wiklander } 180817466cbSJens Wiklander 1817901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1827901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1837901324dSJerome Forissier mbedtls_asn1_write_tag( 1847901324dSJerome Forissier &c, buf, 1857901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC)); 186817466cbSJens Wiklander 187817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_pk_write_pubkey_der(ctx->key, 188*b0563631STom Van Eyck buf, (size_t) (c - buf))); 189817466cbSJens Wiklander c -= pub_len; 190817466cbSJens Wiklander len += pub_len; 191817466cbSJens Wiklander 192817466cbSJens Wiklander /* 193817466cbSJens Wiklander * Subject ::= Name 194817466cbSJens Wiklander */ 1957901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf, 1967901324dSJerome Forissier ctx->subject)); 197817466cbSJens Wiklander 198817466cbSJens Wiklander /* 199817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 200817466cbSJens Wiklander */ 2017901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(&c, buf, 0)); 202817466cbSJens Wiklander 2037901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 2047901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 2057901324dSJerome Forissier mbedtls_asn1_write_tag( 2067901324dSJerome Forissier &c, buf, 2077901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 208817466cbSJens Wiklander 209817466cbSJens Wiklander /* 2107901324dSJerome Forissier * Sign the written CSR data into the sig buffer 21111fa71b9SJerome Forissier * Note: hash errors can happen only after an internal error 212817466cbSJens Wiklander */ 21311fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 21432b31808SJens Wiklander if (psa_hash_compute(hash_alg, 21532b31808SJens Wiklander c, 21632b31808SJens Wiklander len, 21732b31808SJens Wiklander hash, 21832b31808SJens Wiklander sizeof(hash), 21932b31808SJens Wiklander &hash_len) != PSA_SUCCESS) { 22032b31808SJens Wiklander return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED; 22111fa71b9SJerome Forissier } 22211fa71b9SJerome Forissier #else /* MBEDTLS_USE_PSA_CRYPTO */ 2235b25c76aSJerome Forissier ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c, len, hash); 22432b31808SJens Wiklander if (ret != 0) { 22532b31808SJens Wiklander return ret; 22632b31808SJens Wiklander } 22711fa71b9SJerome Forissier #endif 22832b31808SJens Wiklander if ((ret = mbedtls_pk_sign(ctx->key, ctx->md_alg, hash, 0, 22932b31808SJens Wiklander sig, sig_size, &sig_len, 23032b31808SJens Wiklander f_rng, p_rng)) != 0) { 23132b31808SJens Wiklander return ret; 2323d3b0591SJens Wiklander } 2333d3b0591SJens Wiklander 23432b31808SJens Wiklander if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_RSA)) { 2353d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_RSA; 23632b31808SJens Wiklander } else if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_ECDSA)) { 2373d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_ECDSA; 23832b31808SJens Wiklander } else { 23932b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_ALG; 24032b31808SJens Wiklander } 2413d3b0591SJens Wiklander 2423d3b0591SJens Wiklander if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg, 24332b31808SJens Wiklander &sig_oid, &sig_oid_len)) != 0) { 24432b31808SJens Wiklander return ret; 245817466cbSJens Wiklander } 246817466cbSJens Wiklander 247817466cbSJens Wiklander /* 2487901324dSJerome Forissier * Move the written CSR data to the start of buf to create space for 2497901324dSJerome Forissier * writing the signature into buf. 2507901324dSJerome Forissier */ 2517901324dSJerome Forissier memmove(buf, c, len); 2527901324dSJerome Forissier 2537901324dSJerome Forissier /* 2547901324dSJerome Forissier * Write sig and its OID into buf backwards from the end of buf. 2557901324dSJerome Forissier * Note: mbedtls_x509_write_sig will check for c2 - ( buf + len ) < sig_len 2567901324dSJerome Forissier * and return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if needed. 257817466cbSJens Wiklander */ 258817466cbSJens Wiklander c2 = buf + size; 2597901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len, 2607901324dSJerome Forissier mbedtls_x509_write_sig(&c2, buf + len, sig_oid, sig_oid_len, 261*b0563631STom Van Eyck sig, sig_len, pk_alg)); 262817466cbSJens Wiklander 2637901324dSJerome Forissier /* 2647901324dSJerome Forissier * Compact the space between the CSR data and signature by moving the 2657901324dSJerome Forissier * CSR data to the start of the signature. 2667901324dSJerome Forissier */ 267817466cbSJens Wiklander c2 -= len; 2687901324dSJerome Forissier memmove(c2, buf, len); 269817466cbSJens Wiklander 2707901324dSJerome Forissier /* ASN encode the total size and tag the CSR data with it. */ 271817466cbSJens Wiklander len += sig_and_oid_len; 272817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c2, buf, len)); 2737901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 2747901324dSJerome Forissier mbedtls_asn1_write_tag( 2757901324dSJerome Forissier &c2, buf, 2767901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 2777901324dSJerome Forissier 2787901324dSJerome Forissier /* Zero the unused bytes at the start of buf */ 279*b0563631STom Van Eyck memset(buf, 0, (size_t) (c2 - buf)); 280817466cbSJens Wiklander 28132b31808SJens Wiklander return (int) len; 282817466cbSJens Wiklander } 283817466cbSJens Wiklander 2847901324dSJerome Forissier int mbedtls_x509write_csr_der(mbedtls_x509write_csr *ctx, unsigned char *buf, 2857901324dSJerome Forissier size_t size, 2867901324dSJerome Forissier int (*f_rng)(void *, unsigned char *, size_t), 2877901324dSJerome Forissier void *p_rng) 2887901324dSJerome Forissier { 2897901324dSJerome Forissier int ret; 2907901324dSJerome Forissier unsigned char *sig; 2917901324dSJerome Forissier 29232b31808SJens Wiklander if ((sig = mbedtls_calloc(1, MBEDTLS_PK_SIGNATURE_MAX_SIZE)) == NULL) { 29332b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED; 2947901324dSJerome Forissier } 2957901324dSJerome Forissier 29632b31808SJens Wiklander ret = x509write_csr_der_internal(ctx, buf, size, 29732b31808SJens Wiklander sig, MBEDTLS_PK_SIGNATURE_MAX_SIZE, 29832b31808SJens Wiklander f_rng, p_rng); 2997901324dSJerome Forissier 3007901324dSJerome Forissier mbedtls_free(sig); 3017901324dSJerome Forissier 30232b31808SJens Wiklander return ret; 3037901324dSJerome Forissier } 3047901324dSJerome Forissier 305817466cbSJens Wiklander #define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" 306817466cbSJens Wiklander #define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" 307817466cbSJens Wiklander 308817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C) 309817466cbSJens Wiklander int mbedtls_x509write_csr_pem(mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, 310817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 311817466cbSJens Wiklander void *p_rng) 312817466cbSJens Wiklander { 31311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 314817466cbSJens Wiklander size_t olen = 0; 315817466cbSJens Wiklander 31611fa71b9SJerome Forissier if ((ret = mbedtls_x509write_csr_der(ctx, buf, size, 31732b31808SJens Wiklander f_rng, p_rng)) < 0) { 31832b31808SJens Wiklander return ret; 319817466cbSJens Wiklander } 320817466cbSJens Wiklander 321817466cbSJens Wiklander if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CSR, PEM_END_CSR, 32211fa71b9SJerome Forissier buf + size - ret, 32332b31808SJens Wiklander ret, buf, size, &olen)) != 0) { 32432b31808SJens Wiklander return ret; 325817466cbSJens Wiklander } 326817466cbSJens Wiklander 32732b31808SJens Wiklander return 0; 328817466cbSJens Wiklander } 329817466cbSJens Wiklander #endif /* MBEDTLS_PEM_WRITE_C */ 330817466cbSJens Wiklander 331817466cbSJens Wiklander #endif /* MBEDTLS_X509_CSR_WRITE_C */ 332