blob: 03fb3fd94533514eb74a64c77318531d3203bd02 [file] [log] [blame]
Paul Bakker7c6b2c32013-09-16 13:49:26 +02001/*
2 * X.509 certificate writing
3 *
Manuel Pégourié-Gonnard6fb81872015-07-27 11:11:48 +02004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakker7c6b2c32013-09-16 13:49:26 +020018 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +000019 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020020 */
21/*
22 * References:
23 * - certificates: RFC 5280, updated by RFC 6818
24 * - CSRs: PKCS#10 v1.7 aka RFC 2986
25 * - attributes: PKCS#9 v2.0 aka RFC 2985
26 */
27
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000029#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020030#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020031#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020032#endif
Paul Bakker7c6b2c32013-09-16 13:49:26 +020033
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020034#if defined(MBEDTLS_X509_CRT_WRITE_C)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020035
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000036#include "mbedtls/x509_crt.h"
37#include "mbedtls/oid.h"
38#include "mbedtls/asn1write.h"
39#include "mbedtls/sha1.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050040#include "mbedtls/platform_util.h"
Paul Bakker7c6b2c32013-09-16 13:49:26 +020041
Rich Evans00ab4702015-02-06 13:43:58 +000042#include <string.h>
43
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020044#if defined(MBEDTLS_PEM_WRITE_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000045#include "mbedtls/pem.h"
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020046#endif /* MBEDTLS_PEM_WRITE_C */
Paul Bakker7c6b2c32013-09-16 13:49:26 +020047
k-stachowiakc4638cc2019-05-31 20:11:26 +020048/*
49 * For the currently used signature algorithms the buffer to store any signature
50 * must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE)
51 */
52#if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE
53#define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN
54#else
55#define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE
56#endif
57
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020058void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx )
Paul Bakker7c6b2c32013-09-16 13:49:26 +020059{
Hanno Becker81535d02017-09-13 15:39:59 +010060 memset( ctx, 0, sizeof( mbedtls_x509write_cert ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +020061
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020062 mbedtls_mpi_init( &ctx->serial );
63 ctx->version = MBEDTLS_X509_CRT_VERSION_3;
Paul Bakker7c6b2c32013-09-16 13:49:26 +020064}
65
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020066void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx )
Paul Bakker7c6b2c32013-09-16 13:49:26 +020067{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020068 mbedtls_mpi_free( &ctx->serial );
Paul Bakker7c6b2c32013-09-16 13:49:26 +020069
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020070 mbedtls_asn1_free_named_data_list( &ctx->subject );
71 mbedtls_asn1_free_named_data_list( &ctx->issuer );
72 mbedtls_asn1_free_named_data_list( &ctx->extensions );
Paul Bakker7c6b2c32013-09-16 13:49:26 +020073
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050074 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +020075}
76
Hanno Becker6ad3fd12019-05-04 07:37:58 +010077void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx,
78 int version )
Paul Bakker5191e922013-10-11 10:54:28 +020079{
80 ctx->version = version;
81}
82
Hanno Becker6ad3fd12019-05-04 07:37:58 +010083void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx,
84 mbedtls_md_type_t md_alg )
Paul Bakker7c6b2c32013-09-16 13:49:26 +020085{
86 ctx->md_alg = md_alg;
87}
88
Hanno Becker6ad3fd12019-05-04 07:37:58 +010089void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx,
90 mbedtls_pk_context *key )
Paul Bakker7c6b2c32013-09-16 13:49:26 +020091{
92 ctx->subject_key = key;
93}
94
Hanno Becker6ad3fd12019-05-04 07:37:58 +010095void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx,
96 mbedtls_pk_context *key )
Paul Bakker7c6b2c32013-09-16 13:49:26 +020097{
98 ctx->issuer_key = key;
99}
100
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200101int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100102 const char *subject_name )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200103{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200104 return mbedtls_x509_string_to_names( &ctx->subject, subject_name );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200105}
106
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200107int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100108 const char *issuer_name )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200109{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200110 return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200111}
112
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100113int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx,
114 const mbedtls_mpi *serial )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200115{
116 int ret;
117
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200118 if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200119 return( ret );
120
121 return( 0 );
122}
123
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100124int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx,
125 const char *not_before,
126 const char *not_after )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200127{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200128 if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ||
129 strlen( not_after ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200130 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200131 return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200132 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200133 strncpy( ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
134 strncpy( ctx->not_after , not_after , MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
135 ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
136 ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200137
138 return( 0 );
139}
140
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200141int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx,
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200142 const char *oid, size_t oid_len,
143 int critical,
144 const unsigned char *val, size_t val_len )
145{
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100146 return( mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len,
147 critical, val, val_len ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200148}
149
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200150int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100151 int is_ca, int max_pathlen )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200152{
153 int ret;
154 unsigned char buf[9];
155 unsigned char *c = buf + sizeof(buf);
156 size_t len = 0;
157
158 memset( buf, 0, sizeof(buf) );
159
160 if( is_ca && max_pathlen > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200161 return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200162
163 if( is_ca )
164 {
165 if( max_pathlen >= 0 )
166 {
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100167 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf,
168 max_pathlen ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200169 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200170 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200171 }
172
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200173 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100174 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf,
175 MBEDTLS_ASN1_CONSTRUCTED |
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200176 MBEDTLS_ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200177
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100178 return(
179 mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
180 MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ),
181 0, buf + sizeof(buf) - len, len ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200182}
183
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200184#if defined(MBEDTLS_SHA1_C)
185int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200186{
187 int ret;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200188 unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200189 unsigned char *c = buf + sizeof(buf);
190 size_t len = 0;
191
Paul Bakker66d5d072014-06-17 16:39:18 +0200192 memset( buf, 0, sizeof(buf) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100193 MBEDTLS_ASN1_CHK_ADD( len,
194 mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200195
Gilles Peskine9e4f77c2018-01-22 11:48:08 +0100196 ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
Andres Amaya Garcia8d8204f2017-06-28 11:07:30 +0100197 buf + sizeof( buf ) - 20 );
198 if( ret != 0 )
199 return( ret );
200 c = buf + sizeof( buf ) - 20;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200201 len = 20;
202
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200203 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100204 MBEDTLS_ASN1_CHK_ADD( len,
205 mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200206
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100207 return mbedtls_x509write_crt_set_extension( ctx,
208 MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
209 MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ),
210 0, buf + sizeof(buf) - len, len );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200211}
212
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200213int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200214{
215 int ret;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200216 unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
Hanno Becker81535d02017-09-13 15:39:59 +0100217 unsigned char *c = buf + sizeof( buf );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200218 size_t len = 0;
219
Paul Bakker66d5d072014-06-17 16:39:18 +0200220 memset( buf, 0, sizeof(buf) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100221 MBEDTLS_ASN1_CHK_ADD( len,
222 mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200223
Gilles Peskine9e4f77c2018-01-22 11:48:08 +0100224 ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
Andres Amaya Garcia8d8204f2017-06-28 11:07:30 +0100225 buf + sizeof( buf ) - 20 );
226 if( ret != 0 )
227 return( ret );
228 c = buf + sizeof( buf ) - 20;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200229 len = 20;
230
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200231 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100232 MBEDTLS_ASN1_CHK_ADD( len,
233 mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0 ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200234
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200235 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100236 MBEDTLS_ASN1_CHK_ADD( len,
237 mbedtls_asn1_write_tag( &c, buf,
238 MBEDTLS_ASN1_CONSTRUCTED |
239 MBEDTLS_ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200240
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100241 return mbedtls_x509write_crt_set_extension(
242 ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
243 MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
244 0, buf + sizeof( buf ) - len, len );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200245}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200246#endif /* MBEDTLS_SHA1_C */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200247
Manuel Pégourié-Gonnard1cd10ad2015-06-23 11:07:37 +0200248int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx,
249 unsigned int key_usage )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200250{
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100251 unsigned char buf[5], ku[2];
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200252 unsigned char *c;
253 int ret;
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100254 const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
255 MBEDTLS_X509_KU_NON_REPUDIATION |
256 MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
257 MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
258 MBEDTLS_X509_KU_KEY_AGREEMENT |
259 MBEDTLS_X509_KU_KEY_CERT_SIGN |
260 MBEDTLS_X509_KU_CRL_SIGN |
261 MBEDTLS_X509_KU_ENCIPHER_ONLY |
262 MBEDTLS_X509_KU_DECIPHER_ONLY;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200263
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100264 /* Check that nothing other than the allowed flags is set */
265 if( ( key_usage & ~allowed_bits ) != 0 )
Manuel Pégourié-Gonnard1cd10ad2015-06-23 11:07:37 +0200266 return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200267
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100268 c = buf + 5;
269 ku[0] = (unsigned char)( key_usage );
270 ku[1] = (unsigned char)( key_usage >> 8 );
271 ret = mbedtls_asn1_write_named_bitstring( &c, buf, ku, 9 );
Manuel Pégourié-Gonnard1cd10ad2015-06-23 11:07:37 +0200272
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100273 if( ret < 0 )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200274 return( ret );
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100275 else if( ret < 3 || ret > 5 )
276 return( MBEDTLS_ERR_X509_INVALID_FORMAT );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200277
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200278 ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100279 MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
280 1, c, (size_t)ret );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200281 if( ret != 0 )
282 return( ret );
283
284 return( 0 );
285}
286
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200287int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200288 unsigned char ns_cert_type )
289{
290 unsigned char buf[4];
291 unsigned char *c;
292 int ret;
293
294 c = buf + 4;
295
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100296 ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 );
297 if( ret < 3 || ret > 4 )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200298 return( ret );
299
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200300 ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100301 MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
302 0, c, (size_t)ret );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200303 if( ret != 0 )
304 return( ret );
305
306 return( 0 );
307}
308
309static int x509_write_time( unsigned char **p, unsigned char *start,
Hanno Becker61937d42017-04-26 15:01:23 +0100310 const char *t, size_t size )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200311{
312 int ret;
313 size_t len = 0;
314
315 /*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200316 * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200317 */
Hanno Becker61937d42017-04-26 15:01:23 +0100318 if( t[0] == '2' && t[1] == '0' && t[2] < '5' )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200319 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200320 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
Hanno Becker61937d42017-04-26 15:01:23 +0100321 (const unsigned char *) t + 2,
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200322 size - 2 ) );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200323 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100324 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
325 MBEDTLS_ASN1_UTC_TIME ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200326 }
327 else
328 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200329 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
Hanno Becker61937d42017-04-26 15:01:23 +0100330 (const unsigned char *) t,
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200331 size ) );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200332 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100333 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
334 MBEDTLS_ASN1_GENERALIZED_TIME ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200335 }
336
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200337 return( (int) len );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200338}
339
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100340int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx,
341 unsigned char *buf, size_t size,
342 int (*f_rng)(void *, unsigned char *, size_t),
343 void *p_rng )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200344{
345 int ret;
346 const char *sig_oid;
347 size_t sig_oid_len = 0;
348 unsigned char *c, *c2;
349 unsigned char hash[64];
k-stachowiakc4638cc2019-05-31 20:11:26 +0200350 unsigned char sig[SIGNATURE_MAX_SIZE];
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200351 size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
352 size_t len = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200353 mbedtls_pk_type_t pk_alg;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200354
355 /*
Hanno Beckerdef43052019-05-04 07:54:36 +0100356 * Prepare data to be signed at the end of the target buffer
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200357 */
Hanno Beckerdef43052019-05-04 07:54:36 +0100358 c = buf + size;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200359
360 /* Signature algorithm needed in TBS, and later for actual signature */
Hanno Beckerfc771442017-09-13 08:45:48 +0100361
362 /* There's no direct way of extracting a signature algorithm
363 * (represented as an element of mbedtls_pk_type_t) from a PK instance. */
364 if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_RSA ) )
365 pk_alg = MBEDTLS_PK_RSA;
366 else if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_ECDSA ) )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200367 pk_alg = MBEDTLS_PK_ECDSA;
Hanno Beckerfc771442017-09-13 08:45:48 +0100368 else
Hanno Beckerd8a6f7c2017-09-22 16:05:43 +0100369 return( MBEDTLS_ERR_X509_INVALID_ALG );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200370
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200371 if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
Hanno Becker81535d02017-09-13 15:39:59 +0100372 &sig_oid, &sig_oid_len ) ) != 0 )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200373 {
374 return( ret );
375 }
376
377 /*
378 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
379 */
Hanno Beckerd7f35202017-09-13 12:00:15 +0100380
381 /* Only for v3 */
Hanno Beckera20e33a2017-09-22 15:40:01 +0100382 if( ctx->version == MBEDTLS_X509_CRT_VERSION_3 )
Hanno Beckerd7f35202017-09-13 12:00:15 +0100383 {
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100384 MBEDTLS_ASN1_CHK_ADD( len,
385 mbedtls_x509_write_extensions( &c,
Hanno Beckerdef43052019-05-04 07:54:36 +0100386 buf, ctx->extensions ) );
387 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100388 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100389 mbedtls_asn1_write_tag( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100390 MBEDTLS_ASN1_CONSTRUCTED |
391 MBEDTLS_ASN1_SEQUENCE ) );
Hanno Beckerdef43052019-05-04 07:54:36 +0100392 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100393 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100394 mbedtls_asn1_write_tag( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100395 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
396 MBEDTLS_ASN1_CONSTRUCTED | 3 ) );
Hanno Beckerd7f35202017-09-13 12:00:15 +0100397 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200398
399 /*
400 * SubjectPublicKeyInfo
401 */
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100402 MBEDTLS_ASN1_CHK_ADD( pub_len,
403 mbedtls_pk_write_pubkey_der( ctx->subject_key,
Hanno Beckerdef43052019-05-04 07:54:36 +0100404 buf, c - buf ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200405 c -= pub_len;
406 len += pub_len;
407
408 /*
409 * Subject ::= Name
410 */
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100411 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100412 mbedtls_x509_write_names( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100413 ctx->subject ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200414
415 /*
416 * Validity ::= SEQUENCE {
417 * notBefore Time,
418 * notAfter Time }
419 */
420 sub_len = 0;
421
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100422 MBEDTLS_ASN1_CHK_ADD( sub_len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100423 x509_write_time( &c, buf, ctx->not_after,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100424 MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200425
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100426 MBEDTLS_ASN1_CHK_ADD( sub_len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100427 x509_write_time( &c, buf, ctx->not_before,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100428 MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200429
430 len += sub_len;
Hanno Beckerdef43052019-05-04 07:54:36 +0100431 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, sub_len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100432 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100433 mbedtls_asn1_write_tag( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100434 MBEDTLS_ASN1_CONSTRUCTED |
435 MBEDTLS_ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200436
437 /*
438 * Issuer ::= Name
439 */
Hanno Beckerdef43052019-05-04 07:54:36 +0100440 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100441 ctx->issuer ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200442
443 /*
444 * Signature ::= AlgorithmIdentifier
445 */
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100446 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100447 mbedtls_asn1_write_algorithm_identifier( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100448 sig_oid, strlen( sig_oid ), 0 ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200449
450 /*
451 * Serial ::= INTEGER
452 */
Hanno Beckerdef43052019-05-04 07:54:36 +0100453 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100454 &ctx->serial ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200455
456 /*
457 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
458 */
Hanno Becker47698652017-09-13 11:59:26 +0100459
460 /* Can be omitted for v1 */
Hanno Beckera20e33a2017-09-22 15:40:01 +0100461 if( ctx->version != MBEDTLS_X509_CRT_VERSION_1 )
Hanno Becker47698652017-09-13 11:59:26 +0100462 {
463 sub_len = 0;
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100464 MBEDTLS_ASN1_CHK_ADD( sub_len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100465 mbedtls_asn1_write_int( &c, buf, ctx->version ) );
Hanno Becker47698652017-09-13 11:59:26 +0100466 len += sub_len;
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100467 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100468 mbedtls_asn1_write_len( &c, buf, sub_len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100469 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100470 mbedtls_asn1_write_tag( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100471 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
472 MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
Hanno Becker47698652017-09-13 11:59:26 +0100473 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200474
Hanno Beckerdef43052019-05-04 07:54:36 +0100475 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100476 MBEDTLS_ASN1_CHK_ADD( len,
Hanno Beckerdef43052019-05-04 07:54:36 +0100477 mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100478 MBEDTLS_ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200479
480 /*
481 * Make signature
482 */
Hanno Beckerdef43052019-05-04 07:54:36 +0100483
484 /* Compute hash of CRT. */
Andres Amaya Garcia8d8204f2017-06-28 11:07:30 +0100485 if( ( ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c,
486 len, hash ) ) != 0 )
487 {
488 return( ret );
489 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200490
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100491 if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg,
492 hash, 0, sig, &sig_len,
493 f_rng, p_rng ) ) != 0 )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200494 {
495 return( ret );
496 }
497
Hanno Beckerdef43052019-05-04 07:54:36 +0100498 /* Move CRT to the front of the buffer to have space
499 * for the signature. */
500 memmove( buf, c, len );
501 c = buf + len;
502
503 /* Add signature at the end of the buffer,
504 * making sure that it doesn't underflow
505 * into the CRT buffer. */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200506 c2 = buf + size;
Hanno Beckerdef43052019-05-04 07:54:36 +0100507 MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, c,
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200508 sig_oid, sig_oid_len, sig, sig_len ) );
509
Hanno Beckerdef43052019-05-04 07:54:36 +0100510 /*
511 * Memory layout after this step:
512 *
513 * buf c=buf+len c2 buf+size
514 * [CRT0,...,CRTn, UNUSED, ..., UNUSED, SIG0, ..., SIGm]
515 */
Andres AG60dbc932016-09-02 15:23:48 +0100516
Hanno Beckerdef43052019-05-04 07:54:36 +0100517 /* Move raw CRT to just before the signature. */
518 c = c2 - len;
519 memmove( c, buf, len );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200520
521 len += sig_and_oid_len;
Hanno Beckerdef43052019-05-04 07:54:36 +0100522 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
523 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf,
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100524 MBEDTLS_ASN1_CONSTRUCTED |
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200525 MBEDTLS_ASN1_SEQUENCE ) );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200526
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200527 return( (int) len );
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200528}
529
530#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
531#define PEM_END_CRT "-----END CERTIFICATE-----\n"
532
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200533#if defined(MBEDTLS_PEM_WRITE_C)
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100534int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt,
535 unsigned char *buf, size_t size,
536 int (*f_rng)(void *, unsigned char *, size_t),
537 void *p_rng )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200538{
539 int ret;
Hanno Becker67d42592019-05-04 08:13:23 +0100540 size_t olen;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200541
Hanno Becker67d42592019-05-04 08:13:23 +0100542 if( ( ret = mbedtls_x509write_crt_der( crt, buf, size,
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200543 f_rng, p_rng ) ) < 0 )
544 {
545 return( ret );
546 }
547
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200548 if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
Hanno Becker67d42592019-05-04 08:13:23 +0100549 buf + size - ret, ret,
550 buf, size, &olen ) ) != 0 )
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200551 {
552 return( ret );
553 }
554
555 return( 0 );
556}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200557#endif /* MBEDTLS_PEM_WRITE_C */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200558
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200559#endif /* MBEDTLS_X509_CRT_WRITE_C */