1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * X.509 Certificate Signing Request writing 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 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 * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander /* 22817466cbSJens Wiklander * References: 23817466cbSJens Wiklander * - CSRs: PKCS#10 v1.7 aka RFC 2986 24817466cbSJens Wiklander * - attributes: PKCS#9 v2.0 aka RFC 2985 25817466cbSJens Wiklander */ 26817466cbSJens Wiklander 27817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 28817466cbSJens Wiklander #include "mbedtls/config.h" 29817466cbSJens Wiklander #else 30817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 31817466cbSJens Wiklander #endif 32817466cbSJens Wiklander 33817466cbSJens Wiklander #if defined(MBEDTLS_X509_CSR_WRITE_C) 34817466cbSJens Wiklander 35817466cbSJens Wiklander #include "mbedtls/x509_csr.h" 36817466cbSJens Wiklander #include "mbedtls/oid.h" 37817466cbSJens Wiklander #include "mbedtls/asn1write.h" 383d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 39817466cbSJens Wiklander 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*5b25c76aSJerome Forissier /* 48*5b25c76aSJerome Forissier * For the currently used signature algorithms the buffer to store any signature 49*5b25c76aSJerome Forissier * must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE) 50*5b25c76aSJerome Forissier */ 51*5b25c76aSJerome Forissier #if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE 52*5b25c76aSJerome Forissier #define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN 53*5b25c76aSJerome Forissier #else 54*5b25c76aSJerome Forissier #define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE 55*5b25c76aSJerome Forissier #endif 56*5b25c76aSJerome Forissier 57817466cbSJens Wiklander void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) 58817466cbSJens Wiklander { 59817466cbSJens Wiklander memset( ctx, 0, sizeof( mbedtls_x509write_csr ) ); 60817466cbSJens Wiklander } 61817466cbSJens Wiklander 62817466cbSJens Wiklander void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) 63817466cbSJens Wiklander { 64817466cbSJens Wiklander mbedtls_asn1_free_named_data_list( &ctx->subject ); 65817466cbSJens Wiklander mbedtls_asn1_free_named_data_list( &ctx->extensions ); 66817466cbSJens Wiklander 673d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_csr ) ); 68817466cbSJens Wiklander } 69817466cbSJens Wiklander 70817466cbSJens Wiklander void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ) 71817466cbSJens Wiklander { 72817466cbSJens Wiklander ctx->md_alg = md_alg; 73817466cbSJens Wiklander } 74817466cbSJens Wiklander 75817466cbSJens Wiklander void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ) 76817466cbSJens Wiklander { 77817466cbSJens Wiklander ctx->key = key; 78817466cbSJens Wiklander } 79817466cbSJens Wiklander 80817466cbSJens Wiklander int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, 81817466cbSJens Wiklander const char *subject_name ) 82817466cbSJens Wiklander { 83817466cbSJens Wiklander return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); 84817466cbSJens Wiklander } 85817466cbSJens Wiklander 86817466cbSJens Wiklander int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, 87817466cbSJens Wiklander const char *oid, size_t oid_len, 88817466cbSJens Wiklander const unsigned char *val, size_t val_len ) 89817466cbSJens Wiklander { 90817466cbSJens Wiklander return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, 91817466cbSJens Wiklander 0, val, val_len ); 92817466cbSJens Wiklander } 93817466cbSJens Wiklander 94*5b25c76aSJerome Forissier static size_t csr_get_unused_bits_for_named_bitstring( unsigned char bitstring, 95*5b25c76aSJerome Forissier size_t bit_offset ) 96*5b25c76aSJerome Forissier { 97*5b25c76aSJerome Forissier size_t unused_bits; 98*5b25c76aSJerome Forissier 99*5b25c76aSJerome Forissier /* Count the unused bits removing trailing 0s */ 100*5b25c76aSJerome Forissier for( unused_bits = bit_offset; unused_bits < 8; unused_bits++ ) 101*5b25c76aSJerome Forissier if( ( ( bitstring >> unused_bits ) & 0x1 ) != 0 ) 102*5b25c76aSJerome Forissier break; 103*5b25c76aSJerome Forissier 104*5b25c76aSJerome Forissier return( unused_bits ); 105*5b25c76aSJerome Forissier } 106*5b25c76aSJerome Forissier 107817466cbSJens Wiklander int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ) 108817466cbSJens Wiklander { 109817466cbSJens Wiklander unsigned char buf[4]; 110817466cbSJens Wiklander unsigned char *c; 111*5b25c76aSJerome Forissier size_t unused_bits; 112817466cbSJens Wiklander int ret; 113817466cbSJens Wiklander 114817466cbSJens Wiklander c = buf + 4; 115817466cbSJens Wiklander 116*5b25c76aSJerome Forissier unused_bits = csr_get_unused_bits_for_named_bitstring( key_usage, 0 ); 117*5b25c76aSJerome Forissier ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 8 - unused_bits ); 118*5b25c76aSJerome Forissier 119*5b25c76aSJerome Forissier if( ret < 0 ) 120817466cbSJens Wiklander return( ret ); 121*5b25c76aSJerome Forissier else if( ret < 3 || ret > 4 ) 122*5b25c76aSJerome Forissier return( MBEDTLS_ERR_X509_INVALID_FORMAT ); 123817466cbSJens Wiklander 124817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, 125817466cbSJens Wiklander MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), 126*5b25c76aSJerome Forissier c, (size_t)ret ); 127817466cbSJens Wiklander if( ret != 0 ) 128817466cbSJens Wiklander return( ret ); 129817466cbSJens Wiklander 130817466cbSJens Wiklander return( 0 ); 131817466cbSJens Wiklander } 132817466cbSJens Wiklander 133817466cbSJens Wiklander int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, 134817466cbSJens Wiklander unsigned char ns_cert_type ) 135817466cbSJens Wiklander { 136817466cbSJens Wiklander unsigned char buf[4]; 137817466cbSJens Wiklander unsigned char *c; 138*5b25c76aSJerome Forissier size_t unused_bits; 139817466cbSJens Wiklander int ret; 140817466cbSJens Wiklander 141817466cbSJens Wiklander c = buf + 4; 142817466cbSJens Wiklander 143*5b25c76aSJerome Forissier unused_bits = csr_get_unused_bits_for_named_bitstring( ns_cert_type, 0 ); 144*5b25c76aSJerome Forissier ret = mbedtls_asn1_write_bitstring( &c, 145*5b25c76aSJerome Forissier buf, 146*5b25c76aSJerome Forissier &ns_cert_type, 147*5b25c76aSJerome Forissier 8 - unused_bits ); 148*5b25c76aSJerome Forissier 149*5b25c76aSJerome Forissier if( ret < 0 ) 150*5b25c76aSJerome Forissier return( ret ); 151*5b25c76aSJerome Forissier else if( ret < 3 || ret > 4 ) 152817466cbSJens Wiklander return( ret ); 153817466cbSJens Wiklander 154817466cbSJens Wiklander ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, 155817466cbSJens Wiklander MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), 156*5b25c76aSJerome Forissier c, (size_t)ret ); 157817466cbSJens Wiklander if( ret != 0 ) 158817466cbSJens Wiklander return( ret ); 159817466cbSJens Wiklander 160817466cbSJens Wiklander return( 0 ); 161817466cbSJens Wiklander } 162817466cbSJens Wiklander 163817466cbSJens Wiklander int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, 164817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 165817466cbSJens Wiklander void *p_rng ) 166817466cbSJens Wiklander { 167817466cbSJens Wiklander int ret; 168817466cbSJens Wiklander const char *sig_oid; 169817466cbSJens Wiklander size_t sig_oid_len = 0; 170817466cbSJens Wiklander unsigned char *c, *c2; 171817466cbSJens Wiklander unsigned char hash[64]; 172*5b25c76aSJerome Forissier unsigned char sig[SIGNATURE_MAX_SIZE]; 173817466cbSJens Wiklander unsigned char tmp_buf[2048]; 174817466cbSJens Wiklander size_t pub_len = 0, sig_and_oid_len = 0, sig_len; 175817466cbSJens Wiklander size_t len = 0; 176817466cbSJens Wiklander mbedtls_pk_type_t pk_alg; 177817466cbSJens Wiklander 178817466cbSJens Wiklander /* 179817466cbSJens Wiklander * Prepare data to be signed in tmp_buf 180817466cbSJens Wiklander */ 181817466cbSJens Wiklander c = tmp_buf + sizeof( tmp_buf ); 182817466cbSJens Wiklander 183817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); 184817466cbSJens Wiklander 185817466cbSJens Wiklander if( len ) 186817466cbSJens Wiklander { 187817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); 188817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | 189817466cbSJens Wiklander MBEDTLS_ASN1_SEQUENCE ) ); 190817466cbSJens Wiklander 191817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); 192817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | 193817466cbSJens Wiklander MBEDTLS_ASN1_SET ) ); 194817466cbSJens Wiklander 195817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( &c, tmp_buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ, 196817466cbSJens Wiklander MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_CSR_EXT_REQ ) ) ); 197817466cbSJens Wiklander 198817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); 199817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | 200817466cbSJens Wiklander MBEDTLS_ASN1_SEQUENCE ) ); 201817466cbSJens Wiklander } 202817466cbSJens Wiklander 203817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); 204817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | 205817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ); 206817466cbSJens Wiklander 207817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->key, 208817466cbSJens Wiklander tmp_buf, c - tmp_buf ) ); 209817466cbSJens Wiklander c -= pub_len; 210817466cbSJens Wiklander len += pub_len; 211817466cbSJens Wiklander 212817466cbSJens Wiklander /* 213817466cbSJens Wiklander * Subject ::= Name 214817466cbSJens Wiklander */ 215817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) ); 216817466cbSJens Wiklander 217817466cbSJens Wiklander /* 218817466cbSJens Wiklander * Version ::= INTEGER { v1(0), v2(1), v3(2) } 219817466cbSJens Wiklander */ 220817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, tmp_buf, 0 ) ); 221817466cbSJens Wiklander 222817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); 223817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | 224817466cbSJens Wiklander MBEDTLS_ASN1_SEQUENCE ) ); 225817466cbSJens Wiklander 226817466cbSJens Wiklander /* 227817466cbSJens Wiklander * Prepare signature 228817466cbSJens Wiklander */ 229*5b25c76aSJerome Forissier ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); 230*5b25c76aSJerome Forissier if( ret != 0 ) 231*5b25c76aSJerome Forissier return( ret ); 232817466cbSJens Wiklander 233817466cbSJens Wiklander if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, 2343d3b0591SJens Wiklander f_rng, p_rng ) ) != 0 ) 2353d3b0591SJens Wiklander { 2363d3b0591SJens Wiklander return( ret ); 2373d3b0591SJens Wiklander } 2383d3b0591SJens Wiklander 2393d3b0591SJens Wiklander if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_RSA ) ) 2403d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_RSA; 2413d3b0591SJens Wiklander else if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_ECDSA ) ) 2423d3b0591SJens Wiklander pk_alg = MBEDTLS_PK_ECDSA; 2433d3b0591SJens Wiklander else 2443d3b0591SJens Wiklander return( MBEDTLS_ERR_X509_INVALID_ALG ); 2453d3b0591SJens Wiklander 2463d3b0591SJens Wiklander if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, 247817466cbSJens Wiklander &sig_oid, &sig_oid_len ) ) != 0 ) 248817466cbSJens Wiklander { 249817466cbSJens Wiklander return( ret ); 250817466cbSJens Wiklander } 251817466cbSJens Wiklander 252817466cbSJens Wiklander /* 253817466cbSJens Wiklander * Write data to output buffer 254817466cbSJens Wiklander */ 255817466cbSJens Wiklander c2 = buf + size; 256817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, 257817466cbSJens Wiklander sig_oid, sig_oid_len, sig, sig_len ) ); 258817466cbSJens Wiklander 259817466cbSJens Wiklander if( len > (size_t)( c2 - buf ) ) 260817466cbSJens Wiklander return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 261817466cbSJens Wiklander 262817466cbSJens Wiklander c2 -= len; 263817466cbSJens Wiklander memcpy( c2, c, len ); 264817466cbSJens Wiklander 265817466cbSJens Wiklander len += sig_and_oid_len; 266817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); 267817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED | 268817466cbSJens Wiklander MBEDTLS_ASN1_SEQUENCE ) ); 269817466cbSJens Wiklander 270817466cbSJens Wiklander return( (int) len ); 271817466cbSJens Wiklander } 272817466cbSJens Wiklander 273817466cbSJens Wiklander #define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" 274817466cbSJens Wiklander #define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" 275817466cbSJens Wiklander 276817466cbSJens Wiklander #if defined(MBEDTLS_PEM_WRITE_C) 277817466cbSJens Wiklander int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, 278817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 279817466cbSJens Wiklander void *p_rng ) 280817466cbSJens Wiklander { 281817466cbSJens Wiklander int ret; 282817466cbSJens Wiklander unsigned char output_buf[4096]; 283817466cbSJens Wiklander size_t olen = 0; 284817466cbSJens Wiklander 285817466cbSJens Wiklander if( ( ret = mbedtls_x509write_csr_der( ctx, output_buf, sizeof(output_buf), 286817466cbSJens Wiklander f_rng, p_rng ) ) < 0 ) 287817466cbSJens Wiklander { 288817466cbSJens Wiklander return( ret ); 289817466cbSJens Wiklander } 290817466cbSJens Wiklander 291817466cbSJens Wiklander if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR, 292817466cbSJens Wiklander output_buf + sizeof(output_buf) - ret, 293817466cbSJens Wiklander ret, buf, size, &olen ) ) != 0 ) 294817466cbSJens Wiklander { 295817466cbSJens Wiklander return( ret ); 296817466cbSJens Wiklander } 297817466cbSJens Wiklander 298817466cbSJens Wiklander return( 0 ); 299817466cbSJens Wiklander } 300817466cbSJens Wiklander #endif /* MBEDTLS_PEM_WRITE_C */ 301817466cbSJens Wiklander 302817466cbSJens Wiklander #endif /* MBEDTLS_X509_CSR_WRITE_C */ 303