1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * X.509 Certificate Signing Request writing 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 5b0563631STom 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 17b0563631STom 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" 26b0563631STom 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 { 46*cb034002SJerome Forissier if (ctx == NULL) { 47*cb034002SJerome Forissier return; 48*cb034002SJerome Forissier } 49*cb034002SJerome Forissier 50817466cbSJens Wiklander mbedtls_asn1_free_named_data_list(&ctx->subject); 51817466cbSJens Wiklander mbedtls_asn1_free_named_data_list(&ctx->extensions); 52817466cbSJens Wiklander 533d3b0591SJens Wiklander mbedtls_platform_zeroize(ctx, sizeof(mbedtls_x509write_csr)); 54817466cbSJens Wiklander } 55817466cbSJens Wiklander 56817466cbSJens Wiklander void mbedtls_x509write_csr_set_md_alg(mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg) 57817466cbSJens Wiklander { 58817466cbSJens Wiklander ctx->md_alg = md_alg; 59817466cbSJens Wiklander } 60817466cbSJens Wiklander 61817466cbSJens Wiklander void mbedtls_x509write_csr_set_key(mbedtls_x509write_csr *ctx, mbedtls_pk_context *key) 62817466cbSJens Wiklander { 63817466cbSJens Wiklander ctx->key = key; 64817466cbSJens Wiklander } 65817466cbSJens Wiklander 66817466cbSJens Wiklander int mbedtls_x509write_csr_set_subject_name(mbedtls_x509write_csr *ctx, 67817466cbSJens Wiklander const char *subject_name) 68817466cbSJens Wiklander { 69817466cbSJens Wiklander return mbedtls_x509_string_to_names(&ctx->subject, subject_name); 70817466cbSJens Wiklander } 71817466cbSJens Wiklander 72817466cbSJens Wiklander int mbedtls_x509write_csr_set_extension(mbedtls_x509write_csr *ctx, 73817466cbSJens Wiklander const char *oid, size_t oid_len, 7432b31808SJens Wiklander int critical, 75817466cbSJens Wiklander const unsigned char *val, size_t val_len) 76817466cbSJens Wiklander { 77817466cbSJens Wiklander return mbedtls_x509_set_extension(&ctx->extensions, oid, oid_len, 7832b31808SJens Wiklander critical, val, val_len); 7932b31808SJens Wiklander } 8032b31808SJens Wiklander 8132b31808SJens Wiklander int mbedtls_x509write_csr_set_subject_alternative_name(mbedtls_x509write_csr *ctx, 8232b31808SJens Wiklander const mbedtls_x509_san_list *san_list) 8332b31808SJens Wiklander { 84b0563631STom Van Eyck return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list); 85817466cbSJens Wiklander } 86817466cbSJens Wiklander 87817466cbSJens Wiklander int mbedtls_x509write_csr_set_key_usage(mbedtls_x509write_csr *ctx, unsigned char key_usage) 88817466cbSJens Wiklander { 897901324dSJerome Forissier unsigned char buf[4] = { 0 }; 90817466cbSJens Wiklander unsigned char *c; 9111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 92817466cbSJens Wiklander 93817466cbSJens Wiklander c = buf + 4; 94817466cbSJens Wiklander 9511fa71b9SJerome Forissier ret = mbedtls_asn1_write_named_bitstring(&c, buf, &key_usage, 8); 9632b31808SJens Wiklander if (ret < 3 || ret > 4) { 9732b31808SJens Wiklander return ret; 9832b31808SJens Wiklander } 99817466cbSJens Wiklander 100817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_KEY_USAGE, 101817466cbSJens Wiklander MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE), 10232b31808SJens Wiklander 0, c, (size_t) ret); 10332b31808SJens Wiklander if (ret != 0) { 10432b31808SJens Wiklander return ret; 10532b31808SJens Wiklander } 106817466cbSJens Wiklander 10732b31808SJens Wiklander return 0; 108817466cbSJens Wiklander } 109817466cbSJens Wiklander 110817466cbSJens Wiklander int mbedtls_x509write_csr_set_ns_cert_type(mbedtls_x509write_csr *ctx, 111817466cbSJens Wiklander unsigned char ns_cert_type) 112817466cbSJens Wiklander { 1137901324dSJerome Forissier unsigned char buf[4] = { 0 }; 114817466cbSJens Wiklander unsigned char *c; 11511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 116817466cbSJens Wiklander 117817466cbSJens Wiklander c = buf + 4; 118817466cbSJens Wiklander 11911fa71b9SJerome Forissier ret = mbedtls_asn1_write_named_bitstring(&c, buf, &ns_cert_type, 8); 12032b31808SJens Wiklander if (ret < 3 || ret > 4) { 12132b31808SJens Wiklander return ret; 12232b31808SJens Wiklander } 123817466cbSJens Wiklander 124817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_NS_CERT_TYPE, 125817466cbSJens Wiklander MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE), 12632b31808SJens Wiklander 0, c, (size_t) ret); 12732b31808SJens Wiklander if (ret != 0) { 12832b31808SJens Wiklander return ret; 12932b31808SJens Wiklander } 130817466cbSJens Wiklander 13132b31808SJens Wiklander return 0; 132817466cbSJens Wiklander } 133817466cbSJens Wiklander 1347901324dSJerome Forissier static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx, 1357901324dSJerome Forissier unsigned char *buf, 1367901324dSJerome Forissier size_t size, 13732b31808SJens Wiklander unsigned char *sig, size_t sig_size, 138817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 139817466cbSJens Wiklander void *p_rng) 140817466cbSJens Wiklander { 14111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 142817466cbSJens Wiklander const char *sig_oid; 143817466cbSJens Wiklander size_t sig_oid_len = 0; 144817466cbSJens Wiklander unsigned char *c, *c2; 145b0563631STom Van Eyck unsigned char hash[MBEDTLS_MD_MAX_SIZE]; 146817466cbSJens Wiklander size_t pub_len = 0, sig_and_oid_len = 0, sig_len; 147817466cbSJens Wiklander size_t len = 0; 148817466cbSJens Wiklander mbedtls_pk_type_t pk_alg; 14911fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 15011fa71b9SJerome Forissier size_t hash_len; 151b0563631STom Van Eyck psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(ctx->md_alg); 15211fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */ 153817466cbSJens Wiklander 1547901324dSJerome Forissier /* Write the CSR backwards starting from the end of buf */ 1557901324dSJerome Forissier c = buf + size; 1567901324dSJerome Forissier 1577901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_extensions(&c, buf, 1587901324dSJerome Forissier ctx->extensions)); 159817466cbSJens Wiklander 16032b31808SJens Wiklander if (len) { 1617901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1627901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1637901324dSJerome Forissier mbedtls_asn1_write_tag( 1647901324dSJerome Forissier &c, buf, 1657901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 166817466cbSJens Wiklander 1677901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1687901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1697901324dSJerome Forissier mbedtls_asn1_write_tag( 1707901324dSJerome Forissier &c, buf, 1717901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)); 172817466cbSJens Wiklander 1737901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1747901324dSJerome Forissier mbedtls_asn1_write_oid( 1757901324dSJerome Forissier &c, buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ, 176817466cbSJens Wiklander MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_EXT_REQ))); 177817466cbSJens Wiklander 1787901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1797901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1807901324dSJerome Forissier mbedtls_asn1_write_tag( 1817901324dSJerome Forissier &c, buf, 1827901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 183817466cbSJens Wiklander } 184817466cbSJens Wiklander 1857901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 1867901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 1877901324dSJerome Forissier mbedtls_asn1_write_tag( 1887901324dSJerome Forissier &c, buf, 1897901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC)); 190817466cbSJens Wiklander 191817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_pk_write_pubkey_der(ctx->key, 192b0563631STom Van Eyck buf, (size_t) (c - buf))); 193817466cbSJens Wiklander c -= pub_len; 194817466cbSJens Wiklander len += pub_len; 195817466cbSJens Wiklander 196817466cbSJens Wiklander /* 197817466cbSJens Wiklander * Subject ::= Name 198817466cbSJens Wiklander */ 1997901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf, 2007901324dSJerome Forissier ctx->subject)); 201817466cbSJens Wiklander 202817466cbSJens Wiklander /* 203817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 204817466cbSJens Wiklander */ 2057901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(&c, buf, 0)); 206817466cbSJens Wiklander 2077901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 2087901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 2097901324dSJerome Forissier mbedtls_asn1_write_tag( 2107901324dSJerome Forissier &c, buf, 2117901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 212817466cbSJens Wiklander 213817466cbSJens Wiklander /* 2147901324dSJerome Forissier * Sign the written CSR data into the sig buffer 21511fa71b9SJerome Forissier * Note: hash errors can happen only after an internal error 216817466cbSJens Wiklander */ 21711fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 21832b31808SJens Wiklander if (psa_hash_compute(hash_alg, 21932b31808SJens Wiklander c, 22032b31808SJens Wiklander len, 22132b31808SJens Wiklander hash, 22232b31808SJens Wiklander sizeof(hash), 22332b31808SJens Wiklander &hash_len) != PSA_SUCCESS) { 22432b31808SJens Wiklander return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED; 22511fa71b9SJerome Forissier } 22611fa71b9SJerome Forissier #else /* MBEDTLS_USE_PSA_CRYPTO */ 2275b25c76aSJerome Forissier ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c, len, hash); 22832b31808SJens Wiklander if (ret != 0) { 22932b31808SJens Wiklander return ret; 23032b31808SJens Wiklander } 23111fa71b9SJerome Forissier #endif 23232b31808SJens Wiklander if ((ret = mbedtls_pk_sign(ctx->key, ctx->md_alg, hash, 0, 23332b31808SJens Wiklander sig, sig_size, &sig_len, 23432b31808SJens Wiklander f_rng, p_rng)) != 0) { 23532b31808SJens Wiklander return ret; 2363d3b0591SJens Wiklander } 2373d3b0591SJens Wiklander 23832b31808SJens Wiklander if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_RSA)) { 2393d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_RSA; 24032b31808SJens Wiklander } else if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_ECDSA)) { 2413d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_ECDSA; 24232b31808SJens Wiklander } else { 24332b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_ALG; 24432b31808SJens Wiklander } 2453d3b0591SJens Wiklander 2463d3b0591SJens Wiklander if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg, 24732b31808SJens Wiklander &sig_oid, &sig_oid_len)) != 0) { 24832b31808SJens Wiklander return ret; 249817466cbSJens Wiklander } 250817466cbSJens Wiklander 251817466cbSJens Wiklander /* 2527901324dSJerome Forissier * Move the written CSR data to the start of buf to create space for 2537901324dSJerome Forissier * writing the signature into buf. 2547901324dSJerome Forissier */ 2557901324dSJerome Forissier memmove(buf, c, len); 2567901324dSJerome Forissier 2577901324dSJerome Forissier /* 2587901324dSJerome Forissier * Write sig and its OID into buf backwards from the end of buf. 2597901324dSJerome Forissier * Note: mbedtls_x509_write_sig will check for c2 - ( buf + len ) < sig_len 2607901324dSJerome Forissier * and return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if needed. 261817466cbSJens Wiklander */ 262817466cbSJens Wiklander c2 = buf + size; 2637901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len, 2647901324dSJerome Forissier mbedtls_x509_write_sig(&c2, buf + len, sig_oid, sig_oid_len, 265b0563631STom Van Eyck sig, sig_len, pk_alg)); 266817466cbSJens Wiklander 2677901324dSJerome Forissier /* 2687901324dSJerome Forissier * Compact the space between the CSR data and signature by moving the 2697901324dSJerome Forissier * CSR data to the start of the signature. 2707901324dSJerome Forissier */ 271817466cbSJens Wiklander c2 -= len; 2727901324dSJerome Forissier memmove(c2, buf, len); 273817466cbSJens Wiklander 2747901324dSJerome Forissier /* ASN encode the total size and tag the CSR data with it. */ 275817466cbSJens Wiklander len += sig_and_oid_len; 276817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c2, buf, len)); 2777901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD(len, 2787901324dSJerome Forissier mbedtls_asn1_write_tag( 2797901324dSJerome Forissier &c2, buf, 2807901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); 2817901324dSJerome Forissier 2827901324dSJerome Forissier /* Zero the unused bytes at the start of buf */ 283b0563631STom Van Eyck memset(buf, 0, (size_t) (c2 - buf)); 284817466cbSJens Wiklander 28532b31808SJens Wiklander return (int) len; 286817466cbSJens Wiklander } 287817466cbSJens Wiklander 2887901324dSJerome Forissier int mbedtls_x509write_csr_der(mbedtls_x509write_csr *ctx, unsigned char *buf, 2897901324dSJerome Forissier size_t size, 2907901324dSJerome Forissier int (*f_rng)(void *, unsigned char *, size_t), 2917901324dSJerome Forissier void *p_rng) 2927901324dSJerome Forissier { 2937901324dSJerome Forissier int ret; 2947901324dSJerome Forissier unsigned char *sig; 2957901324dSJerome Forissier 29632b31808SJens Wiklander if ((sig = mbedtls_calloc(1, MBEDTLS_PK_SIGNATURE_MAX_SIZE)) == NULL) { 29732b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED; 2987901324dSJerome Forissier } 2997901324dSJerome Forissier 30032b31808SJens Wiklander ret = x509write_csr_der_internal(ctx, buf, size, 30132b31808SJens Wiklander sig, MBEDTLS_PK_SIGNATURE_MAX_SIZE, 30232b31808SJens Wiklander f_rng, p_rng); 3037901324dSJerome Forissier 3047901324dSJerome Forissier mbedtls_free(sig); 3057901324dSJerome Forissier 30632b31808SJens Wiklander return ret; 3077901324dSJerome Forissier } 3087901324dSJerome Forissier 309817466cbSJens Wiklander #define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" 310817466cbSJens Wiklander #define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" 311817466cbSJens Wiklander 312817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C) 313817466cbSJens Wiklander int mbedtls_x509write_csr_pem(mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, 314817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 315817466cbSJens Wiklander void *p_rng) 316817466cbSJens Wiklander { 31711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 318817466cbSJens Wiklander size_t olen = 0; 319817466cbSJens Wiklander 32011fa71b9SJerome Forissier if ((ret = mbedtls_x509write_csr_der(ctx, buf, size, 32132b31808SJens Wiklander f_rng, p_rng)) < 0) { 32232b31808SJens Wiklander return ret; 323817466cbSJens Wiklander } 324817466cbSJens Wiklander 325817466cbSJens Wiklander if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CSR, PEM_END_CSR, 32611fa71b9SJerome Forissier buf + size - ret, 32732b31808SJens Wiklander ret, buf, size, &olen)) != 0) { 32832b31808SJens Wiklander return ret; 329817466cbSJens Wiklander } 330817466cbSJens Wiklander 33132b31808SJens Wiklander return 0; 332817466cbSJens Wiklander } 333817466cbSJens Wiklander #endif /* MBEDTLS_PEM_WRITE_C */ 334817466cbSJens Wiklander 335817466cbSJens Wiklander #endif /* MBEDTLS_X509_CSR_WRITE_C */ 336