aboutsummaryrefslogtreecommitdiff
path: root/programs/x509/cert_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'programs/x509/cert_write.c')
-rw-r--r--programs/x509/cert_write.c890
1 files changed, 890 insertions, 0 deletions
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
new file mode 100644
index 000000000..a8910d7f6
--- /dev/null
+++ b/programs/x509/cert_write.c
@@ -0,0 +1,890 @@
+/*
+ * Certificate generation and signing
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if !defined(MBEDTLS_X509_CRT_WRITE_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) || \
+ !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
+ !defined(MBEDTLS_ERROR_C) || !defined(MBEDTLS_SHA256_C) || \
+ !defined(MBEDTLS_PEM_WRITE_C)
+int main( void )
+{
+ mbedtls_printf( "MBEDTLS_X509_CRT_WRITE_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
+ "MBEDTLS_FS_IO and/or MBEDTLS_SHA256_C and/or "
+ "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
+ "MBEDTLS_ERROR_C not defined.\n");
+ mbedtls_exit( 0 );
+}
+#else
+
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_csr.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/md.h"
+#include "mbedtls/error.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SET_OID(x, oid) \
+ do { x.len = MBEDTLS_OID_SIZE(oid); x.p = (unsigned char*)oid; } while( 0 )
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+#define USAGE_CSR \
+ " request_file=%%s default: (empty)\n" \
+ " If request_file is specified, subject_key,\n" \
+ " subject_pwd and subject_name are ignored!\n"
+#else
+#define USAGE_CSR ""
+#endif /* MBEDTLS_X509_CSR_PARSE_C */
+
+#define FORMAT_PEM 0
+#define FORMAT_DER 1
+
+#define DFL_ISSUER_CRT ""
+#define DFL_REQUEST_FILE ""
+#define DFL_SUBJECT_KEY "subject.key"
+#define DFL_ISSUER_KEY "ca.key"
+#define DFL_SUBJECT_PWD ""
+#define DFL_ISSUER_PWD ""
+#define DFL_OUTPUT_FILENAME "cert.crt"
+#define DFL_SUBJECT_NAME "CN=Cert,O=mbed TLS,C=UK"
+#define DFL_ISSUER_NAME "CN=CA,O=mbed TLS,C=UK"
+#define DFL_NOT_BEFORE "20010101000000"
+#define DFL_NOT_AFTER "20301231235959"
+#define DFL_SERIAL "1"
+#define DFL_SELFSIGN 0
+#define DFL_IS_CA 0
+#define DFL_MAX_PATHLEN -1
+#define DFL_SIG_ALG MBEDTLS_MD_SHA256
+#define DFL_KEY_USAGE 0
+#define DFL_EXT_KEY_USAGE NULL
+#define DFL_NS_CERT_TYPE 0
+#define DFL_VERSION 3
+#define DFL_AUTH_IDENT 1
+#define DFL_SUBJ_IDENT 1
+#define DFL_CONSTRAINTS 1
+#define DFL_DIGEST MBEDTLS_MD_SHA256
+#define DFL_FORMAT FORMAT_PEM
+
+#define USAGE \
+ "\n usage: cert_write param=<>...\n" \
+ "\n acceptable parameters:\n" \
+ USAGE_CSR \
+ " subject_key=%%s default: subject.key\n" \
+ " subject_pwd=%%s default: (empty)\n" \
+ " subject_name=%%s default: CN=Cert,O=mbed TLS,C=UK\n" \
+ "\n" \
+ " issuer_crt=%%s default: (empty)\n" \
+ " If issuer_crt is specified, issuer_name is\n" \
+ " ignored!\n" \
+ " issuer_name=%%s default: CN=CA,O=mbed TLS,C=UK\n" \
+ "\n" \
+ " selfsign=%%d default: 0 (false)\n" \
+ " If selfsign is enabled, issuer_name and\n" \
+ " issuer_key are required (issuer_crt and\n" \
+ " subject_* are ignored\n" \
+ " issuer_key=%%s default: ca.key\n" \
+ " issuer_pwd=%%s default: (empty)\n" \
+ " output_file=%%s default: cert.crt\n" \
+ " serial=%%s default: 1\n" \
+ " not_before=%%s default: 20010101000000\n"\
+ " not_after=%%s default: 20301231235959\n"\
+ " is_ca=%%d default: 0 (disabled)\n" \
+ " max_pathlen=%%d default: -1 (none)\n" \
+ " md=%%s default: SHA256\n" \
+ " Supported values (if enabled):\n" \
+ " MD5, RIPEMD160, SHA1,\n" \
+ " SHA224, SHA256, SHA384, SHA512\n" \
+ " version=%%d default: 3\n" \
+ " Possible values: 1, 2, 3\n"\
+ " subject_identifier=%%s default: 1\n" \
+ " Possible values: 0, 1\n" \
+ " (Considered for v3 only)\n"\
+ " authority_identifier=%%s default: 1\n" \
+ " Possible values: 0, 1\n" \
+ " (Considered for v3 only)\n"\
+ " basic_constraints=%%d default: 1\n" \
+ " Possible values: 0, 1\n" \
+ " (Considered for v3 only)\n"\
+ " key_usage=%%s default: (empty)\n" \
+ " Comma-separated-list of values:\n" \
+ " digital_signature\n" \
+ " non_repudiation\n" \
+ " key_encipherment\n" \
+ " data_encipherment\n" \
+ " key_agreement\n" \
+ " key_cert_sign\n" \
+ " crl_sign\n" \
+ " (Considered for v3 only)\n"\
+ " ext_key_usage=%%s default: (empty)\n" \
+ " Comma-separated-list of values:\n" \
+ " serverAuth\n" \
+ " clientAuth\n" \
+ " codeSigning\n" \
+ " emailProtection\n" \
+ " timeStamping\n" \
+ " OCSPSigning\n" \
+ " ns_cert_type=%%s default: (empty)\n" \
+ " Comma-separated-list of values:\n" \
+ " ssl_client\n" \
+ " ssl_server\n" \
+ " email\n" \
+ " object_signing\n" \
+ " ssl_ca\n" \
+ " email_ca\n" \
+ " object_signing_ca\n" \
+ " format=pem|der default: pem\n" \
+ "\n"
+
+
+/*
+ * global options
+ */
+struct options
+{
+ const char *issuer_crt; /* filename of the issuer certificate */
+ const char *request_file; /* filename of the certificate request */
+ const char *subject_key; /* filename of the subject key file */
+ const char *issuer_key; /* filename of the issuer key file */
+ const char *subject_pwd; /* password for the subject key file */
+ const char *issuer_pwd; /* password for the issuer key file */
+ const char *output_file; /* where to store the constructed CRT */
+ const char *subject_name; /* subject name for certificate */
+ const char *issuer_name; /* issuer name for certificate */
+ const char *not_before; /* validity period not before */
+ const char *not_after; /* validity period not after */
+ const char *serial; /* serial number string */
+ int selfsign; /* selfsign the certificate */
+ int is_ca; /* is a CA certificate */
+ int max_pathlen; /* maximum CA path length */
+ int authority_identifier; /* add authority identifier to CRT */
+ int subject_identifier; /* add subject identifier to CRT */
+ int basic_constraints; /* add basic constraints ext to CRT */
+ int version; /* CRT version */
+ mbedtls_md_type_t md; /* Hash used for signing */
+ unsigned char key_usage; /* key usage flags */
+ mbedtls_asn1_sequence *ext_key_usage; /* extended key usages */
+ unsigned char ns_cert_type; /* NS cert type */
+ int format; /* format */
+} opt;
+
+int write_certificate( mbedtls_x509write_cert *crt, const char *output_file,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ FILE *f;
+ unsigned char output_buf[4096];
+ unsigned char *output_start;
+ size_t len = 0;
+
+ memset( output_buf, 0, 4096 );
+ if ( opt.format == FORMAT_DER )
+ {
+ ret = mbedtls_x509write_crt_der( crt, output_buf, 4096,
+ f_rng, p_rng );
+ if( ret < 0 )
+ return( ret );
+
+ len = ret;
+ output_start = output_buf + 4096 - len;
+ } else {
+ ret = mbedtls_x509write_crt_pem( crt, output_buf, 4096,
+ f_rng, p_rng );
+ if( ret < 0 )
+ return( ret );
+
+ len = strlen( (char *) output_buf );
+ output_start = output_buf;
+ }
+
+ if( ( f = fopen( output_file, "w" ) ) == NULL )
+ return( -1 );
+
+ if( fwrite( output_start, 1, len, f ) != len )
+ {
+ fclose( f );
+ return( -1 );
+ }
+
+ fclose( f );
+
+ return( 0 );
+}
+
+int main( int argc, char *argv[] )
+{
+ int ret = 1;
+ int exit_code = MBEDTLS_EXIT_FAILURE;
+ mbedtls_x509_crt issuer_crt;
+ mbedtls_pk_context loaded_issuer_key, loaded_subject_key;
+ mbedtls_pk_context *issuer_key = &loaded_issuer_key,
+ *subject_key = &loaded_subject_key;
+ char buf[1024];
+ char issuer_name[256];
+ int i;
+ char *p, *q, *r;
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+ char subject_name[256];
+ mbedtls_x509_csr csr;
+#endif
+ mbedtls_x509write_cert crt;
+ mbedtls_mpi serial;
+ mbedtls_asn1_sequence *ext_key_usage;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ const char *pers = "crt example app";
+
+ /*
+ * Set to sane values
+ */
+ mbedtls_x509write_crt_init( &crt );
+ mbedtls_pk_init( &loaded_issuer_key );
+ mbedtls_pk_init( &loaded_subject_key );
+ mbedtls_mpi_init( &serial );
+ mbedtls_ctr_drbg_init( &ctr_drbg );
+ mbedtls_entropy_init( &entropy );
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+ mbedtls_x509_csr_init( &csr );
+#endif
+ mbedtls_x509_crt_init( &issuer_crt );
+ memset( buf, 0, sizeof(buf) );
+
+ if( argc == 0 )
+ {
+ usage:
+ mbedtls_printf( USAGE );
+ goto exit;
+ }
+
+ opt.issuer_crt = DFL_ISSUER_CRT;
+ opt.request_file = DFL_REQUEST_FILE;
+ opt.subject_key = DFL_SUBJECT_KEY;
+ opt.issuer_key = DFL_ISSUER_KEY;
+ opt.subject_pwd = DFL_SUBJECT_PWD;
+ opt.issuer_pwd = DFL_ISSUER_PWD;
+ opt.output_file = DFL_OUTPUT_FILENAME;
+ opt.subject_name = DFL_SUBJECT_NAME;
+ opt.issuer_name = DFL_ISSUER_NAME;
+ opt.not_before = DFL_NOT_BEFORE;
+ opt.not_after = DFL_NOT_AFTER;
+ opt.serial = DFL_SERIAL;
+ opt.selfsign = DFL_SELFSIGN;
+ opt.is_ca = DFL_IS_CA;
+ opt.max_pathlen = DFL_MAX_PATHLEN;
+ opt.key_usage = DFL_KEY_USAGE;
+ opt.ext_key_usage = DFL_EXT_KEY_USAGE;
+ opt.ns_cert_type = DFL_NS_CERT_TYPE;
+ opt.version = DFL_VERSION - 1;
+ opt.md = DFL_DIGEST;
+ opt.subject_identifier = DFL_SUBJ_IDENT;
+ opt.authority_identifier = DFL_AUTH_IDENT;
+ opt.basic_constraints = DFL_CONSTRAINTS;
+ opt.format = DFL_FORMAT;
+
+ for( i = 1; i < argc; i++ )
+ {
+
+ p = argv[i];
+ if( ( q = strchr( p, '=' ) ) == NULL )
+ goto usage;
+ *q++ = '\0';
+
+ if( strcmp( p, "request_file" ) == 0 )
+ opt.request_file = q;
+ else if( strcmp( p, "subject_key" ) == 0 )
+ opt.subject_key = q;
+ else if( strcmp( p, "issuer_key" ) == 0 )
+ opt.issuer_key = q;
+ else if( strcmp( p, "subject_pwd" ) == 0 )
+ opt.subject_pwd = q;
+ else if( strcmp( p, "issuer_pwd" ) == 0 )
+ opt.issuer_pwd = q;
+ else if( strcmp( p, "issuer_crt" ) == 0 )
+ opt.issuer_crt = q;
+ else if( strcmp( p, "output_file" ) == 0 )
+ opt.output_file = q;
+ else if( strcmp( p, "subject_name" ) == 0 )
+ {
+ opt.subject_name = q;
+ }
+ else if( strcmp( p, "issuer_name" ) == 0 )
+ {
+ opt.issuer_name = q;
+ }
+ else if( strcmp( p, "not_before" ) == 0 )
+ {
+ opt.not_before = q;
+ }
+ else if( strcmp( p, "not_after" ) == 0 )
+ {
+ opt.not_after = q;
+ }
+ else if( strcmp( p, "serial" ) == 0 )
+ {
+ opt.serial = q;
+ }
+ else if( strcmp( p, "authority_identifier" ) == 0 )
+ {
+ opt.authority_identifier = atoi( q );
+ if( opt.authority_identifier != 0 &&
+ opt.authority_identifier != 1 )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ }
+ else if( strcmp( p, "subject_identifier" ) == 0 )
+ {
+ opt.subject_identifier = atoi( q );
+ if( opt.subject_identifier != 0 &&
+ opt.subject_identifier != 1 )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ }
+ else if( strcmp( p, "basic_constraints" ) == 0 )
+ {
+ opt.basic_constraints = atoi( q );
+ if( opt.basic_constraints != 0 &&
+ opt.basic_constraints != 1 )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ }
+ else if( strcmp( p, "md" ) == 0 )
+ {
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_string( q );
+ if( md_info == NULL )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ opt.md = mbedtls_md_get_type( md_info );
+ }
+ else if( strcmp( p, "version" ) == 0 )
+ {
+ opt.version = atoi( q );
+ if( opt.version < 1 || opt.version > 3 )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ opt.version--;
+ }
+ else if( strcmp( p, "selfsign" ) == 0 )
+ {
+ opt.selfsign = atoi( q );
+ if( opt.selfsign < 0 || opt.selfsign > 1 )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ }
+ else if( strcmp( p, "is_ca" ) == 0 )
+ {
+ opt.is_ca = atoi( q );
+ if( opt.is_ca < 0 || opt.is_ca > 1 )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ }
+ else if( strcmp( p, "max_pathlen" ) == 0 )
+ {
+ opt.max_pathlen = atoi( q );
+ if( opt.max_pathlen < -1 || opt.max_pathlen > 127 )
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ }
+ else if( strcmp( p, "key_usage" ) == 0 )
+ {
+ while( q != NULL )
+ {
+ if( ( r = strchr( q, ',' ) ) != NULL )
+ *r++ = '\0';
+
+ if( strcmp( q, "digital_signature" ) == 0 )
+ opt.key_usage |= MBEDTLS_X509_KU_DIGITAL_SIGNATURE;
+ else if( strcmp( q, "non_repudiation" ) == 0 )
+ opt.key_usage |= MBEDTLS_X509_KU_NON_REPUDIATION;
+ else if( strcmp( q, "key_encipherment" ) == 0 )
+ opt.key_usage |= MBEDTLS_X509_KU_KEY_ENCIPHERMENT;
+ else if( strcmp( q, "data_encipherment" ) == 0 )
+ opt.key_usage |= MBEDTLS_X509_KU_DATA_ENCIPHERMENT;
+ else if( strcmp( q, "key_agreement" ) == 0 )
+ opt.key_usage |= MBEDTLS_X509_KU_KEY_AGREEMENT;
+ else if( strcmp( q, "key_cert_sign" ) == 0 )
+ opt.key_usage |= MBEDTLS_X509_KU_KEY_CERT_SIGN;
+ else if( strcmp( q, "crl_sign" ) == 0 )
+ opt.key_usage |= MBEDTLS_X509_KU_CRL_SIGN;
+ else
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+
+ q = r;
+ }
+ }
+ else if( strcmp( p, "ext_key_usage" ) == 0 )
+ {
+ mbedtls_asn1_sequence **tail = &opt.ext_key_usage;
+
+ while( q != NULL )
+ {
+ if( ( r = strchr( q, ',' ) ) != NULL )
+ *r++ = '\0';
+
+ ext_key_usage = mbedtls_calloc( 1, sizeof(mbedtls_asn1_sequence) );
+ ext_key_usage->buf.tag = MBEDTLS_ASN1_OID;
+ if( strcmp( q, "serverAuth" ) == 0 )
+ SET_OID( ext_key_usage->buf, MBEDTLS_OID_SERVER_AUTH );
+ else if( strcmp( q, "clientAuth" ) == 0 )
+ SET_OID( ext_key_usage->buf, MBEDTLS_OID_CLIENT_AUTH );
+ else if( strcmp( q, "codeSigning" ) == 0 )
+ SET_OID( ext_key_usage->buf, MBEDTLS_OID_CODE_SIGNING );
+ else if( strcmp( q, "emailProtection" ) == 0 )
+ SET_OID( ext_key_usage->buf, MBEDTLS_OID_EMAIL_PROTECTION );
+ else if( strcmp( q, "timeStamping" ) == 0 )
+ SET_OID( ext_key_usage->buf, MBEDTLS_OID_TIME_STAMPING );
+ else if( strcmp( q, "OCSPSigning" ) == 0 )
+ SET_OID( ext_key_usage->buf, MBEDTLS_OID_OCSP_SIGNING );
+ else
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+
+ *tail = ext_key_usage;
+ tail = &ext_key_usage->next;
+
+ q = r;
+ }
+ }
+ else if( strcmp( p, "ns_cert_type" ) == 0 )
+ {
+ while( q != NULL )
+ {
+ if( ( r = strchr( q, ',' ) ) != NULL )
+ *r++ = '\0';
+
+ if( strcmp( q, "ssl_client" ) == 0 )
+ opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT;
+ else if( strcmp( q, "ssl_server" ) == 0 )
+ opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER;
+ else if( strcmp( q, "email" ) == 0 )
+ opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL;
+ else if( strcmp( q, "object_signing" ) == 0 )
+ opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING;
+ else if( strcmp( q, "ssl_ca" ) == 0 )
+ opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_SSL_CA;
+ else if( strcmp( q, "email_ca" ) == 0 )
+ opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA;
+ else if( strcmp( q, "object_signing_ca" ) == 0 )
+ opt.ns_cert_type |= MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA;
+ else
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+
+ q = r;
+ }
+ }
+ else if( strcmp( p, "format" ) == 0 )
+ {
+ if ( strcmp(q, "der" ) == 0 ) opt.format = FORMAT_DER;
+ else if ( strcmp(q, "pem" ) == 0 ) opt.format = FORMAT_PEM;
+ else
+ {
+ mbedtls_printf( "Invalid argument for option %s\n", p );
+ goto usage;
+ }
+ }
+ else
+ goto usage;
+ }
+
+ mbedtls_printf("\n");
+
+ /*
+ * 0. Seed the PRNG
+ */
+ mbedtls_printf( " . Seeding the random number generator..." );
+ fflush( stdout );
+
+ if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen( pers ) ) ) != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d - %s\n",
+ ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+
+ // Parse serial to MPI
+ //
+ mbedtls_printf( " . Reading serial number..." );
+ fflush( stdout );
+
+ if( ( ret = mbedtls_mpi_read_string( &serial, 10, opt.serial ) ) != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_mpi_read_string "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+
+ // Parse issuer certificate if present
+ //
+ if( !opt.selfsign && strlen( opt.issuer_crt ) )
+ {
+ /*
+ * 1.0.a. Load the certificates
+ */
+ mbedtls_printf( " . Loading the issuer certificate ..." );
+ fflush( stdout );
+
+ if( ( ret = mbedtls_x509_crt_parse_file( &issuer_crt, opt.issuer_crt ) ) != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse_file "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ ret = mbedtls_x509_dn_gets( issuer_name, sizeof(issuer_name),
+ &issuer_crt.subject );
+ if( ret < 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509_dn_gets "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ opt.issuer_name = issuer_name;
+
+ mbedtls_printf( " ok\n" );
+ }
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+ // Parse certificate request if present
+ //
+ if( !opt.selfsign && strlen( opt.request_file ) )
+ {
+ /*
+ * 1.0.b. Load the CSR
+ */
+ mbedtls_printf( " . Loading the certificate request ..." );
+ fflush( stdout );
+
+ if( ( ret = mbedtls_x509_csr_parse_file( &csr, opt.request_file ) ) != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509_csr_parse_file "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ ret = mbedtls_x509_dn_gets( subject_name, sizeof(subject_name),
+ &csr.subject );
+ if( ret < 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509_dn_gets "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ opt.subject_name = subject_name;
+ subject_key = &csr.pk;
+
+ mbedtls_printf( " ok\n" );
+ }
+#endif /* MBEDTLS_X509_CSR_PARSE_C */
+
+ /*
+ * 1.1. Load the keys
+ */
+ if( !opt.selfsign && !strlen( opt.request_file ) )
+ {
+ mbedtls_printf( " . Loading the subject key ..." );
+ fflush( stdout );
+
+ ret = mbedtls_pk_parse_keyfile( &loaded_subject_key, opt.subject_key,
+ opt.subject_pwd, mbedtls_ctr_drbg_random, &ctr_drbg );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_pk_parse_keyfile "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+ }
+
+ mbedtls_printf( " . Loading the issuer key ..." );
+ fflush( stdout );
+
+ ret = mbedtls_pk_parse_keyfile( &loaded_issuer_key, opt.issuer_key,
+ opt.issuer_pwd, mbedtls_ctr_drbg_random, &ctr_drbg );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_pk_parse_keyfile "
+ "returned -x%02x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ // Check if key and issuer certificate match
+ //
+ if( strlen( opt.issuer_crt ) )
+ {
+ if( mbedtls_pk_check_pair( &issuer_crt.pk, issuer_key,
+ mbedtls_ctr_drbg_random, &ctr_drbg ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! issuer_key does not match "
+ "issuer certificate\n\n" );
+ goto exit;
+ }
+ }
+
+ mbedtls_printf( " ok\n" );
+
+ if( opt.selfsign )
+ {
+ opt.subject_name = opt.issuer_name;
+ subject_key = issuer_key;
+ }
+
+ mbedtls_x509write_crt_set_subject_key( &crt, subject_key );
+ mbedtls_x509write_crt_set_issuer_key( &crt, issuer_key );
+
+ /*
+ * 1.0. Check the names for validity
+ */
+ if( ( ret = mbedtls_x509write_crt_set_subject_name( &crt, opt.subject_name ) ) != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_subject_name "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ if( ( ret = mbedtls_x509write_crt_set_issuer_name( &crt, opt.issuer_name ) ) != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_issuer_name "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " . Setting certificate values ..." );
+ fflush( stdout );
+
+ mbedtls_x509write_crt_set_version( &crt, opt.version );
+ mbedtls_x509write_crt_set_md_alg( &crt, opt.md );
+
+ ret = mbedtls_x509write_crt_set_serial( &crt, &serial );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_serial "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ ret = mbedtls_x509write_crt_set_validity( &crt, opt.not_before, opt.not_after );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_validity "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+
+ if( opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
+ opt.basic_constraints != 0 )
+ {
+ mbedtls_printf( " . Adding the Basic Constraints extension ..." );
+ fflush( stdout );
+
+ ret = mbedtls_x509write_crt_set_basic_constraints( &crt, opt.is_ca,
+ opt.max_pathlen );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! x509write_crt_set_basic_constraints "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+ }
+
+#if defined(MBEDTLS_SHA1_C)
+ if( opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
+ opt.subject_identifier != 0 )
+ {
+ mbedtls_printf( " . Adding the Subject Key Identifier ..." );
+ fflush( stdout );
+
+ ret = mbedtls_x509write_crt_set_subject_key_identifier( &crt );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_subject"
+ "_key_identifier returned -0x%04x - %s\n\n",
+ (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+ }
+
+ if( opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
+ opt.authority_identifier != 0 )
+ {
+ mbedtls_printf( " . Adding the Authority Key Identifier ..." );
+ fflush( stdout );
+
+ ret = mbedtls_x509write_crt_set_authority_key_identifier( &crt );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_authority_"
+ "key_identifier returned -0x%04x - %s\n\n",
+ (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+ }
+#endif /* MBEDTLS_SHA1_C */
+
+ if( opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
+ opt.key_usage != 0 )
+ {
+ mbedtls_printf( " . Adding the Key Usage extension ..." );
+ fflush( stdout );
+
+ ret = mbedtls_x509write_crt_set_key_usage( &crt, opt.key_usage );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_key_usage "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+ }
+
+ if( opt.ext_key_usage )
+ {
+ mbedtls_printf( " . Adding the Extended Key Usage extension ..." );
+ fflush( stdout );
+
+ ret = mbedtls_x509write_crt_set_ext_key_usage( &crt, opt.ext_key_usage );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_ext_key_usage returned -0x%02x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+ }
+
+ if( opt.version == MBEDTLS_X509_CRT_VERSION_3 &&
+ opt.ns_cert_type != 0 )
+ {
+ mbedtls_printf( " . Adding the NS Cert Type extension ..." );
+ fflush( stdout );
+
+ ret = mbedtls_x509write_crt_set_ns_cert_type( &crt, opt.ns_cert_type );
+ if( ret != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! mbedtls_x509write_crt_set_ns_cert_type "
+ "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+ }
+
+ /*
+ * 1.2. Writing the certificate
+ */
+ mbedtls_printf( " . Writing the certificate..." );
+ fflush( stdout );
+
+ if( ( ret = write_certificate( &crt, opt.output_file,
+ mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
+ {
+ mbedtls_strerror( ret, buf, sizeof(buf) );
+ mbedtls_printf( " failed\n ! write_certificate -0x%04x - %s\n\n",
+ (unsigned int) -ret, buf );
+ goto exit;
+ }
+
+ mbedtls_printf( " ok\n" );
+
+ exit_code = MBEDTLS_EXIT_SUCCESS;
+
+exit:
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+ mbedtls_x509_csr_free( &csr );
+#endif /* MBEDTLS_X509_CSR_PARSE_C */
+ mbedtls_x509_crt_free( &issuer_crt );
+ mbedtls_x509write_crt_free( &crt );
+ mbedtls_pk_free( &loaded_subject_key );
+ mbedtls_pk_free( &loaded_issuer_key );
+ mbedtls_mpi_free( &serial );
+ mbedtls_ctr_drbg_free( &ctr_drbg );
+ mbedtls_entropy_free( &entropy );
+
+ mbedtls_exit( exit_code );
+}
+#endif /* MBEDTLS_X509_CRT_WRITE_C && MBEDTLS_X509_CRT_PARSE_C &&
+ MBEDTLS_FS_IO && MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C &&
+ MBEDTLS_ERROR_C && MBEDTLS_PEM_WRITE_C */