1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * X.509 Certificate Signing Request writing 3817466cbSJens Wiklander * 4*7901324dSJerome Forissier * Copyright The Mbed TLS Contributors 5*7901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander /* 20817466cbSJens Wiklander * References: 21817466cbSJens Wiklander * - CSRs: PKCS#10 v1.7 aka RFC 2986 22817466cbSJens Wiklander * - attributes: PKCS#9 v2.0 aka RFC 2985 23817466cbSJens Wiklander */ 24817466cbSJens Wiklander 25*7901324dSJerome Forissier #include "common.h" 26817466cbSJens Wiklander 27817466cbSJens Wiklander #if defined(MBEDTLS_X509_CSR_WRITE_C) 28817466cbSJens Wiklander 29817466cbSJens Wiklander #include "mbedtls/x509_csr.h" 30817466cbSJens Wiklander #include "mbedtls/asn1write.h" 3111fa71b9SJerome Forissier #include "mbedtls/error.h" 3211fa71b9SJerome Forissier #include "mbedtls/oid.h" 333d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 34817466cbSJens Wiklander 3511fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 3611fa71b9SJerome Forissier #include "psa/crypto.h" 3711fa71b9SJerome Forissier #include "mbedtls/psa_util.h" 3811fa71b9SJerome Forissier #endif 3911fa71b9SJerome Forissier 40817466cbSJens Wiklander #include <string.h> 41817466cbSJens Wiklander #include <stdlib.h> 42817466cbSJens Wiklander 43817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C) 44817466cbSJens Wiklander #include "mbedtls/pem.h" 45817466cbSJens Wiklander #endif 46817466cbSJens Wiklander 47*7901324dSJerome Forissier #if defined(MBEDTLS_PLATFORM_C) 48*7901324dSJerome Forissier #include "mbedtls/platform.h" 49*7901324dSJerome Forissier #else 50*7901324dSJerome Forissier #include <stdlib.h> 51*7901324dSJerome Forissier #define mbedtls_calloc calloc 52*7901324dSJerome Forissier #define mbedtls_free free 53*7901324dSJerome Forissier #endif 54*7901324dSJerome Forissier 55817466cbSJens Wiklander void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) 56817466cbSJens Wiklander { 57817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_x509write_csr ) ); 58817466cbSJens Wiklander } 59817466cbSJens Wiklander 60817466cbSJens Wiklander void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) 61817466cbSJens Wiklander { 62817466cbSJens Wiklander mbedtls_asn1_free_named_data_list( &ctx->subject ); 63817466cbSJens Wiklander mbedtls_asn1_free_named_data_list( &ctx->extensions ); 64817466cbSJens Wiklander 653d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_csr ) ); 66817466cbSJens Wiklander } 67817466cbSJens Wiklander 68817466cbSJens Wiklander void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ) 69817466cbSJens Wiklander { 70817466cbSJens Wiklander ctx->md_alg = md_alg; 71817466cbSJens Wiklander } 72817466cbSJens Wiklander 73817466cbSJens Wiklander void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ) 74817466cbSJens Wiklander { 75817466cbSJens Wiklander ctx->key = key; 76817466cbSJens Wiklander } 77817466cbSJens Wiklander 78817466cbSJens Wiklander int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, 79817466cbSJens Wiklander const char *subject_name ) 80817466cbSJens Wiklander { 81817466cbSJens Wiklander return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); 82817466cbSJens Wiklander } 83817466cbSJens Wiklander 84817466cbSJens Wiklander int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, 85817466cbSJens Wiklander const char *oid, size_t oid_len, 86817466cbSJens Wiklander const unsigned char *val, size_t val_len ) 87817466cbSJens Wiklander { 88817466cbSJens Wiklander return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, 89817466cbSJens Wiklander 0, val, val_len ); 90817466cbSJens Wiklander } 91817466cbSJens Wiklander 92817466cbSJens Wiklander int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ) 93817466cbSJens Wiklander { 94*7901324dSJerome Forissier unsigned char buf[4] = {0}; 95817466cbSJens Wiklander unsigned char *c; 9611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 97817466cbSJens Wiklander 98817466cbSJens Wiklander c = buf + 4; 99817466cbSJens Wiklander 10011fa71b9SJerome Forissier ret = mbedtls_asn1_write_named_bitstring( &c, buf, &key_usage, 8 ); 10111fa71b9SJerome Forissier if( ret < 3 || ret > 4 ) 102817466cbSJens Wiklander return( ret ); 103817466cbSJens Wiklander 104817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, 105817466cbSJens Wiklander MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), 1065b25c76aSJerome Forissier c, (size_t)ret ); 107817466cbSJens Wiklander if( ret != 0 ) 108817466cbSJens Wiklander return( ret ); 109817466cbSJens Wiklander 110817466cbSJens Wiklander return( 0 ); 111817466cbSJens Wiklander } 112817466cbSJens Wiklander 113817466cbSJens Wiklander int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, 114817466cbSJens Wiklander unsigned char ns_cert_type ) 115817466cbSJens Wiklander { 116*7901324dSJerome Forissier unsigned char buf[4] = {0}; 117817466cbSJens Wiklander unsigned char *c; 11811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 119817466cbSJens Wiklander 120817466cbSJens Wiklander c = buf + 4; 121817466cbSJens Wiklander 12211fa71b9SJerome Forissier ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 ); 12311fa71b9SJerome Forissier if( ret < 3 || ret > 4 ) 124817466cbSJens Wiklander return( ret ); 125817466cbSJens Wiklander 126817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, 127817466cbSJens Wiklander MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), 1285b25c76aSJerome Forissier c, (size_t)ret ); 129817466cbSJens Wiklander if( ret != 0 ) 130817466cbSJens Wiklander return( ret ); 131817466cbSJens Wiklander 132817466cbSJens Wiklander return( 0 ); 133817466cbSJens Wiklander } 134817466cbSJens Wiklander 135*7901324dSJerome Forissier static int x509write_csr_der_internal( mbedtls_x509write_csr *ctx, 136*7901324dSJerome Forissier unsigned char *buf, 137*7901324dSJerome Forissier size_t size, 138*7901324dSJerome Forissier unsigned char *sig, 139817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 140817466cbSJens Wiklander void *p_rng ) 141817466cbSJens Wiklander { 14211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 143817466cbSJens Wiklander const char *sig_oid; 144817466cbSJens Wiklander size_t sig_oid_len = 0; 145817466cbSJens Wiklander unsigned char *c, *c2; 146817466cbSJens Wiklander unsigned char hash[64]; 147817466cbSJens Wiklander size_t pub_len = 0, sig_and_oid_len = 0, sig_len; 148817466cbSJens Wiklander size_t len = 0; 149817466cbSJens Wiklander mbedtls_pk_type_t pk_alg; 15011fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 15111fa71b9SJerome Forissier psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; 15211fa71b9SJerome Forissier size_t hash_len; 15311fa71b9SJerome Forissier psa_algorithm_t hash_alg = mbedtls_psa_translate_md( ctx->md_alg ); 15411fa71b9SJerome Forissier #endif /* MBEDTLS_USE_PSA_CRYPTO */ 155817466cbSJens Wiklander 156*7901324dSJerome Forissier /* Write the CSR backwards starting from the end of buf */ 157*7901324dSJerome Forissier c = buf + size; 158*7901324dSJerome Forissier 159*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, buf, 160*7901324dSJerome Forissier ctx->extensions ) ); 161817466cbSJens Wiklander 162817466cbSJens Wiklander if( len ) 163817466cbSJens Wiklander { 164*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 165*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, 166*7901324dSJerome Forissier mbedtls_asn1_write_tag( 167*7901324dSJerome Forissier &c, buf, 168*7901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); 169817466cbSJens Wiklander 170*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 171*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, 172*7901324dSJerome Forissier mbedtls_asn1_write_tag( 173*7901324dSJerome Forissier &c, buf, 174*7901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ); 175817466cbSJens Wiklander 176*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, 177*7901324dSJerome Forissier mbedtls_asn1_write_oid( 178*7901324dSJerome Forissier &c, buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ, 179817466cbSJens Wiklander MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_CSR_EXT_REQ ) ) ); 180817466cbSJens Wiklander 181*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 182*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, 183*7901324dSJerome Forissier mbedtls_asn1_write_tag( 184*7901324dSJerome Forissier &c, buf, 185*7901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); 186817466cbSJens Wiklander } 187817466cbSJens Wiklander 188*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 189*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, 190*7901324dSJerome Forissier mbedtls_asn1_write_tag( 191*7901324dSJerome Forissier &c, buf, 192*7901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ); 193817466cbSJens Wiklander 194817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->key, 195*7901324dSJerome Forissier buf, c - buf ) ); 196817466cbSJens Wiklander c -= pub_len; 197817466cbSJens Wiklander len += pub_len; 198817466cbSJens Wiklander 199817466cbSJens Wiklander /* 200817466cbSJens Wiklander * Subject ::= Name 201817466cbSJens Wiklander */ 202*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, buf, 203*7901324dSJerome Forissier ctx->subject ) ); 204817466cbSJens Wiklander 205817466cbSJens Wiklander /* 206817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 207817466cbSJens Wiklander */ 208*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) ); 209817466cbSJens Wiklander 210*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 211*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, 212*7901324dSJerome Forissier mbedtls_asn1_write_tag( 213*7901324dSJerome Forissier &c, buf, 214*7901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); 215817466cbSJens Wiklander 216817466cbSJens Wiklander /* 217*7901324dSJerome Forissier * Sign the written CSR data into the sig buffer 21811fa71b9SJerome Forissier * Note: hash errors can happen only after an internal error 219817466cbSJens Wiklander */ 22011fa71b9SJerome Forissier #if defined(MBEDTLS_USE_PSA_CRYPTO) 22111fa71b9SJerome Forissier if( psa_hash_setup( &hash_operation, hash_alg ) != PSA_SUCCESS ) 22211fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FATAL_ERROR ); 22311fa71b9SJerome Forissier 22411fa71b9SJerome Forissier if( psa_hash_update( &hash_operation, c, len ) != PSA_SUCCESS ) 22511fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FATAL_ERROR ); 22611fa71b9SJerome Forissier 22711fa71b9SJerome Forissier if( psa_hash_finish( &hash_operation, hash, sizeof( hash ), &hash_len ) 22811fa71b9SJerome Forissier != PSA_SUCCESS ) 22911fa71b9SJerome Forissier { 23011fa71b9SJerome Forissier return( MBEDTLS_ERR_X509_FATAL_ERROR ); 23111fa71b9SJerome Forissier } 23211fa71b9SJerome Forissier #else /* MBEDTLS_USE_PSA_CRYPTO */ 2335b25c76aSJerome Forissier ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); 2345b25c76aSJerome Forissier if( ret != 0 ) 2355b25c76aSJerome Forissier return( ret ); 23611fa71b9SJerome Forissier #endif 237817466cbSJens Wiklander if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, 2383d3b0591SJens Wiklander f_rng, p_rng ) ) != 0 ) 2393d3b0591SJens Wiklander { 2403d3b0591SJens Wiklander return( ret ); 2413d3b0591SJens Wiklander } 2423d3b0591SJens Wiklander 2433d3b0591SJens Wiklander if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_RSA ) ) 2443d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_RSA; 2453d3b0591SJens Wiklander else if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_ECDSA ) ) 2463d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_ECDSA; 2473d3b0591SJens Wiklander else 2483d3b0591SJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG ); 2493d3b0591SJens Wiklander 2503d3b0591SJens Wiklander if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, 251817466cbSJens Wiklander &sig_oid, &sig_oid_len ) ) != 0 ) 252817466cbSJens Wiklander { 253817466cbSJens Wiklander return( ret ); 254817466cbSJens Wiklander } 255817466cbSJens Wiklander 256817466cbSJens Wiklander /* 257*7901324dSJerome Forissier * Move the written CSR data to the start of buf to create space for 258*7901324dSJerome Forissier * writing the signature into buf. 259*7901324dSJerome Forissier */ 260*7901324dSJerome Forissier memmove( buf, c, len ); 261*7901324dSJerome Forissier 262*7901324dSJerome Forissier /* 263*7901324dSJerome Forissier * Write sig and its OID into buf backwards from the end of buf. 264*7901324dSJerome Forissier * Note: mbedtls_x509_write_sig will check for c2 - ( buf + len ) < sig_len 265*7901324dSJerome Forissier * and return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if needed. 266817466cbSJens Wiklander */ 267817466cbSJens Wiklander c2 = buf + size; 268*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, 269*7901324dSJerome Forissier mbedtls_x509_write_sig( &c2, buf + len, sig_oid, sig_oid_len, 270*7901324dSJerome Forissier sig, sig_len ) ); 271817466cbSJens Wiklander 272*7901324dSJerome Forissier /* 273*7901324dSJerome Forissier * Compact the space between the CSR data and signature by moving the 274*7901324dSJerome Forissier * CSR data to the start of the signature. 275*7901324dSJerome Forissier */ 276817466cbSJens Wiklander c2 -= len; 277*7901324dSJerome Forissier memmove( c2, buf, len ); 278817466cbSJens Wiklander 279*7901324dSJerome Forissier /* ASN encode the total size and tag the CSR data with it. */ 280817466cbSJens Wiklander len += sig_and_oid_len; 281817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); 282*7901324dSJerome Forissier MBEDTLS_ASN1_CHK_ADD( len, 283*7901324dSJerome Forissier mbedtls_asn1_write_tag( 284*7901324dSJerome Forissier &c2, buf, 285*7901324dSJerome Forissier MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); 286*7901324dSJerome Forissier 287*7901324dSJerome Forissier /* Zero the unused bytes at the start of buf */ 288*7901324dSJerome Forissier memset( buf, 0, c2 - buf); 289817466cbSJens Wiklander 290817466cbSJens Wiklander return( (int) len ); 291817466cbSJens Wiklander } 292817466cbSJens Wiklander 293*7901324dSJerome Forissier int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, 294*7901324dSJerome Forissier size_t size, 295*7901324dSJerome Forissier int (*f_rng)(void *, unsigned char *, size_t), 296*7901324dSJerome Forissier void *p_rng ) 297*7901324dSJerome Forissier { 298*7901324dSJerome Forissier int ret; 299*7901324dSJerome Forissier unsigned char *sig; 300*7901324dSJerome Forissier 301*7901324dSJerome Forissier if( ( sig = mbedtls_calloc( 1, MBEDTLS_PK_SIGNATURE_MAX_SIZE ) ) == NULL ) 302*7901324dSJerome Forissier { 303*7901324dSJerome Forissier return( MBEDTLS_ERR_X509_ALLOC_FAILED ); 304*7901324dSJerome Forissier } 305*7901324dSJerome Forissier 306*7901324dSJerome Forissier ret = x509write_csr_der_internal( ctx, buf, size, sig, f_rng, p_rng ); 307*7901324dSJerome Forissier 308*7901324dSJerome Forissier mbedtls_free( sig ); 309*7901324dSJerome Forissier 310*7901324dSJerome Forissier return( ret ); 311*7901324dSJerome Forissier } 312*7901324dSJerome Forissier 313817466cbSJens Wiklander #define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" 314817466cbSJens Wiklander #define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" 315817466cbSJens Wiklander 316817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C) 317817466cbSJens Wiklander int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, 318817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 319817466cbSJens Wiklander void *p_rng ) 320817466cbSJens Wiklander { 32111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 322817466cbSJens Wiklander size_t olen = 0; 323817466cbSJens Wiklander 32411fa71b9SJerome Forissier if( ( ret = mbedtls_x509write_csr_der( ctx, buf, size, 325817466cbSJens Wiklander f_rng, p_rng ) ) < 0 ) 326817466cbSJens Wiklander { 327817466cbSJens Wiklander return( ret ); 328817466cbSJens Wiklander } 329817466cbSJens Wiklander 330817466cbSJens Wiklander if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR, 33111fa71b9SJerome Forissier buf + size - ret, 332817466cbSJens Wiklander ret, buf, size, &olen ) ) != 0 ) 333817466cbSJens Wiklander { 334817466cbSJens Wiklander return( ret ); 335817466cbSJens Wiklander } 336817466cbSJens Wiklander 337817466cbSJens Wiklander return( 0 ); 338817466cbSJens Wiklander } 339817466cbSJens Wiklander #endif /* MBEDTLS_PEM_WRITE_C */ 340817466cbSJens Wiklander 341817466cbSJens Wiklander #endif /* MBEDTLS_X509_CSR_WRITE_C */ 342