blob: 4a65939c3acd68a3c477424ec8d82d544e21550d [file] [log] [blame]
Paul Bakker7c6b2c32013-09-16 13:49:26 +02001/*
2 * X.509 certificate writing
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
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 */
19/*
20 * References:
21 * - certificates: RFC 5280, updated by RFC 6818
22 * - CSRs: PKCS#10 v1.7 aka RFC 2986
23 * - attributes: PKCS#9 v2.0 aka RFC 2985
24 */
25
Gilles Peskinedb09ef62020-06-03 01:43:33 +020026#include "common.h"
Paul Bakker7c6b2c32013-09-16 13:49:26 +020027
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if defined(MBEDTLS_X509_CRT_WRITE_C)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020029
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000030#include "mbedtls/x509_crt.h"
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/asn1write.h"
Janos Follath73c616b2019-12-18 15:07:04 +000032#include "mbedtls/error.h"
33#include "mbedtls/oid.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050034#include "mbedtls/platform_util.h"
Janos Follath73c616b2019-12-18 15:07:04 +000035#include "mbedtls/sha1.h"
Paul Bakker7c6b2c32013-09-16 13:49:26 +020036
Rich Evans00ab4702015-02-06 13:43:58 +000037#include <string.h>
38
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020039#if defined(MBEDTLS_PEM_WRITE_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000040#include "mbedtls/pem.h"
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020041#endif /* MBEDTLS_PEM_WRITE_C */
Paul Bakker7c6b2c32013-09-16 13:49:26 +020042
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010043void mbedtls_x509write_crt_init(mbedtls_x509write_cert *ctx)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020044{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010045 memset(ctx, 0, sizeof(mbedtls_x509write_cert));
Paul Bakker7c6b2c32013-09-16 13:49:26 +020046
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010047 mbedtls_mpi_init(&ctx->serial);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020048 ctx->version = MBEDTLS_X509_CRT_VERSION_3;
Paul Bakker7c6b2c32013-09-16 13:49:26 +020049}
50
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010051void mbedtls_x509write_crt_free(mbedtls_x509write_cert *ctx)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020052{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010053 mbedtls_mpi_free(&ctx->serial);
Paul Bakker7c6b2c32013-09-16 13:49:26 +020054
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010055 mbedtls_asn1_free_named_data_list(&ctx->subject);
56 mbedtls_asn1_free_named_data_list(&ctx->issuer);
57 mbedtls_asn1_free_named_data_list(&ctx->extensions);
Paul Bakker7c6b2c32013-09-16 13:49:26 +020058
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010059 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_x509write_cert));
Paul Bakker7c6b2c32013-09-16 13:49:26 +020060}
61
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010062void mbedtls_x509write_crt_set_version(mbedtls_x509write_cert *ctx,
63 int version)
Paul Bakker5191e922013-10-11 10:54:28 +020064{
65 ctx->version = version;
66}
67
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010068void mbedtls_x509write_crt_set_md_alg(mbedtls_x509write_cert *ctx,
69 mbedtls_md_type_t md_alg)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020070{
71 ctx->md_alg = md_alg;
72}
73
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010074void mbedtls_x509write_crt_set_subject_key(mbedtls_x509write_cert *ctx,
75 mbedtls_pk_context *key)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020076{
77 ctx->subject_key = key;
78}
79
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010080void mbedtls_x509write_crt_set_issuer_key(mbedtls_x509write_cert *ctx,
81 mbedtls_pk_context *key)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020082{
83 ctx->issuer_key = key;
84}
85
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010086int mbedtls_x509write_crt_set_subject_name(mbedtls_x509write_cert *ctx,
87 const char *subject_name)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020088{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010089 return mbedtls_x509_string_to_names(&ctx->subject, subject_name);
Paul Bakker7c6b2c32013-09-16 13:49:26 +020090}
91
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010092int mbedtls_x509write_crt_set_issuer_name(mbedtls_x509write_cert *ctx,
93 const char *issuer_name)
Paul Bakker7c6b2c32013-09-16 13:49:26 +020094{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010095 return mbedtls_x509_string_to_names(&ctx->issuer, issuer_name);
Paul Bakker7c6b2c32013-09-16 13:49:26 +020096}
97
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010098int mbedtls_x509write_crt_set_serial(mbedtls_x509write_cert *ctx,
99 const mbedtls_mpi *serial)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200100{
Janos Follath865b3eb2019-12-16 11:46:15 +0000101 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200102
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100103 if ((ret = mbedtls_mpi_copy(&ctx->serial, serial)) != 0) {
104 return ret;
105 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200106
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100107 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200108}
109
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100110int mbedtls_x509write_crt_set_validity(mbedtls_x509write_cert *ctx,
111 const char *not_before,
112 const char *not_after)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200113{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100114 if (strlen(not_before) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ||
115 strlen(not_after) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1) {
116 return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200117 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100118 strncpy(ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN);
119 strncpy(ctx->not_after, not_after, MBEDTLS_X509_RFC5280_UTC_TIME_LEN);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200120 ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
121 ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200122
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100123 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200124}
125
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100126int mbedtls_x509write_crt_set_extension(mbedtls_x509write_cert *ctx,
127 const char *oid, size_t oid_len,
128 int critical,
129 const unsigned char *val, size_t val_len)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200130{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100131 return mbedtls_x509_set_extension(&ctx->extensions, oid, oid_len,
132 critical, val, val_len);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200133}
134
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100135int mbedtls_x509write_crt_set_basic_constraints(mbedtls_x509write_cert *ctx,
136 int is_ca, int max_pathlen)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200137{
Janos Follath865b3eb2019-12-16 11:46:15 +0000138 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200139 unsigned char buf[9];
140 unsigned char *c = buf + sizeof(buf);
141 size_t len = 0;
142
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100143 memset(buf, 0, sizeof(buf));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200144
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100145 if (is_ca && max_pathlen > 127) {
146 return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200147 }
148
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100149 if (is_ca) {
150 if (max_pathlen >= 0) {
151 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(&c, buf,
152 max_pathlen));
153 }
154 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_bool(&c, buf, 1));
155 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200156
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100157 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
158 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf,
159 MBEDTLS_ASN1_CONSTRUCTED |
160 MBEDTLS_ASN1_SEQUENCE));
161
162 return
163 mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
164 MBEDTLS_OID_SIZE(MBEDTLS_OID_BASIC_CONSTRAINTS),
165 is_ca, buf + sizeof(buf) - len, len);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200166}
167
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200168#if defined(MBEDTLS_SHA1_C)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100169int mbedtls_x509write_crt_set_subject_key_identifier(mbedtls_x509write_cert *ctx)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200170{
Janos Follath865b3eb2019-12-16 11:46:15 +0000171 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200172 unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200173 unsigned char *c = buf + sizeof(buf);
174 size_t len = 0;
175
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100176 memset(buf, 0, sizeof(buf));
177 MBEDTLS_ASN1_CHK_ADD(len,
178 mbedtls_pk_write_pubkey(&c, buf, ctx->subject_key));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200179
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100180 ret = mbedtls_sha1_ret(buf + sizeof(buf) - len, len,
181 buf + sizeof(buf) - 20);
182 if (ret != 0) {
183 return ret;
184 }
185 c = buf + sizeof(buf) - 20;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200186 len = 20;
187
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100188 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
189 MBEDTLS_ASN1_CHK_ADD(len,
190 mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_OCTET_STRING));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200191
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100192 return mbedtls_x509write_crt_set_extension(ctx,
193 MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
194 MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER),
195 0, buf + sizeof(buf) - len, len);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200196}
197
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100198int mbedtls_x509write_crt_set_authority_key_identifier(mbedtls_x509write_cert *ctx)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200199{
Janos Follath865b3eb2019-12-16 11:46:15 +0000200 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200201 unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100202 unsigned char *c = buf + sizeof(buf);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200203 size_t len = 0;
204
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100205 memset(buf, 0, sizeof(buf));
206 MBEDTLS_ASN1_CHK_ADD(len,
207 mbedtls_pk_write_pubkey(&c, buf, ctx->issuer_key));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200208
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100209 ret = mbedtls_sha1_ret(buf + sizeof(buf) - len, len,
210 buf + sizeof(buf) - 20);
211 if (ret != 0) {
212 return ret;
213 }
214 c = buf + sizeof(buf) - 20;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200215 len = 20;
216
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100217 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
218 MBEDTLS_ASN1_CHK_ADD(len,
219 mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200220
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100221 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
222 MBEDTLS_ASN1_CHK_ADD(len,
223 mbedtls_asn1_write_tag(&c, buf,
224 MBEDTLS_ASN1_CONSTRUCTED |
225 MBEDTLS_ASN1_SEQUENCE));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200226
Hanno Becker6ad3fd12019-05-04 07:37:58 +0100227 return mbedtls_x509write_crt_set_extension(
228 ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100229 MBEDTLS_OID_SIZE(MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER),
230 0, buf + sizeof(buf) - len, len);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200231}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200232#endif /* MBEDTLS_SHA1_C */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200233
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100234int mbedtls_x509write_crt_set_key_usage(mbedtls_x509write_cert *ctx,
235 unsigned int key_usage)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200236{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100237 unsigned char buf[5] = { 0 }, ku[2] = { 0 };
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200238 unsigned char *c;
Janos Follath865b3eb2019-12-16 11:46:15 +0000239 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100240 const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100241 MBEDTLS_X509_KU_NON_REPUDIATION |
242 MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
243 MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
244 MBEDTLS_X509_KU_KEY_AGREEMENT |
245 MBEDTLS_X509_KU_KEY_CERT_SIGN |
246 MBEDTLS_X509_KU_CRL_SIGN |
247 MBEDTLS_X509_KU_ENCIPHER_ONLY |
248 MBEDTLS_X509_KU_DECIPHER_ONLY;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200249
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100250 /* Check that nothing other than the allowed flags is set */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100251 if ((key_usage & ~allowed_bits) != 0) {
252 return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
253 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200254
Andres Amaya Garcia6e959142018-09-26 10:48:24 +0100255 c = buf + 5;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100256 MBEDTLS_PUT_UINT16_LE(key_usage, ku, 0);
257 ret = mbedtls_asn1_write_named_bitstring(&c, buf, ku, 9);
Manuel Pégourié-Gonnard1cd10ad2015-06-23 11:07:37 +0200258
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100259 if (ret < 0) {
260 return ret;
261 } else if (ret < 3 || ret > 5) {
262 return MBEDTLS_ERR_X509_INVALID_FORMAT;
263 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200264
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100265 ret = mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_KEY_USAGE,
266 MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE),
267 1, c, (size_t) ret);
268 if (ret != 0) {
269 return ret;
270 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200271
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100272 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200273}
274
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100275int mbedtls_x509write_crt_set_ns_cert_type(mbedtls_x509write_cert *ctx,
276 unsigned char ns_cert_type)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200277{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100278 unsigned char buf[4] = { 0 };
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200279 unsigned char *c;
Janos Follath865b3eb2019-12-16 11:46:15 +0000280 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200281
282 c = buf + 4;
283
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100284 ret = mbedtls_asn1_write_named_bitstring(&c, buf, &ns_cert_type, 8);
285 if (ret < 3 || ret > 4) {
286 return ret;
287 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200288
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100289 ret = mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_NS_CERT_TYPE,
290 MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE),
291 0, c, (size_t) ret);
292 if (ret != 0) {
293 return ret;
294 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200295
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100296 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200297}
298
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100299static int x509_write_time(unsigned char **p, unsigned char *start,
300 const char *t, size_t size)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200301{
Janos Follath865b3eb2019-12-16 11:46:15 +0000302 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200303 size_t len = 0;
304
305 /*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200306 * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200307 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100308 if (t[0] < '2' || (t[0] == '2' && t[1] == '0' && t[2] < '5')) {
309 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start,
310 (const unsigned char *) t + 2,
311 size - 2));
312 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
313 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start,
314 MBEDTLS_ASN1_UTC_TIME));
315 } else {
316 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(p, start,
317 (const unsigned char *) t,
318 size));
319 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
320 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start,
321 MBEDTLS_ASN1_GENERALIZED_TIME));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200322 }
323
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100324 return (int) len;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200325}
326
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100327int mbedtls_x509write_crt_der(mbedtls_x509write_cert *ctx,
328 unsigned char *buf, size_t size,
329 int (*f_rng)(void *, unsigned char *, size_t),
330 void *p_rng)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200331{
Janos Follath865b3eb2019-12-16 11:46:15 +0000332 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200333 const char *sig_oid;
334 size_t sig_oid_len = 0;
335 unsigned char *c, *c2;
336 unsigned char hash[64];
Gilles Peskinebf887802019-11-08 19:21:51 +0100337 unsigned char sig[MBEDTLS_PK_SIGNATURE_MAX_SIZE];
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200338 size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
339 size_t len = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200340 mbedtls_pk_type_t pk_alg;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200341
342 /*
Hanno Beckerdef43052019-05-04 07:54:36 +0100343 * Prepare data to be signed at the end of the target buffer
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200344 */
Hanno Beckerdef43052019-05-04 07:54:36 +0100345 c = buf + size;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200346
347 /* Signature algorithm needed in TBS, and later for actual signature */
Hanno Beckerfc771442017-09-13 08:45:48 +0100348
349 /* There's no direct way of extracting a signature algorithm
350 * (represented as an element of mbedtls_pk_type_t) from a PK instance. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100351 if (mbedtls_pk_can_do(ctx->issuer_key, MBEDTLS_PK_RSA)) {
Hanno Beckerfc771442017-09-13 08:45:48 +0100352 pk_alg = MBEDTLS_PK_RSA;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100353 } else if (mbedtls_pk_can_do(ctx->issuer_key, MBEDTLS_PK_ECDSA)) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200354 pk_alg = MBEDTLS_PK_ECDSA;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100355 } else {
356 return MBEDTLS_ERR_X509_INVALID_ALG;
357 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200358
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100359 if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg,
360 &sig_oid, &sig_oid_len)) != 0) {
361 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200362 }
363
364 /*
365 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
366 */
Hanno Beckerd7f35202017-09-13 12:00:15 +0100367
368 /* Only for v3 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100369 if (ctx->version == MBEDTLS_X509_CRT_VERSION_3) {
370 MBEDTLS_ASN1_CHK_ADD(len,
371 mbedtls_x509_write_extensions(&c,
372 buf, ctx->extensions));
373 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
374 MBEDTLS_ASN1_CHK_ADD(len,
375 mbedtls_asn1_write_tag(&c, buf,
376 MBEDTLS_ASN1_CONSTRUCTED |
377 MBEDTLS_ASN1_SEQUENCE));
378 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
379 MBEDTLS_ASN1_CHK_ADD(len,
380 mbedtls_asn1_write_tag(&c, buf,
381 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
382 MBEDTLS_ASN1_CONSTRUCTED | 3));
Hanno Beckerd7f35202017-09-13 12:00:15 +0100383 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200384
385 /*
386 * SubjectPublicKeyInfo
387 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 MBEDTLS_ASN1_CHK_ADD(pub_len,
389 mbedtls_pk_write_pubkey_der(ctx->subject_key,
390 buf, c - buf));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200391 c -= pub_len;
392 len += pub_len;
393
394 /*
395 * Subject ::= Name
396 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100397 MBEDTLS_ASN1_CHK_ADD(len,
398 mbedtls_x509_write_names(&c, buf,
399 ctx->subject));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200400
401 /*
402 * Validity ::= SEQUENCE {
403 * notBefore Time,
404 * notAfter Time }
405 */
406 sub_len = 0;
407
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100408 MBEDTLS_ASN1_CHK_ADD(sub_len,
409 x509_write_time(&c, buf, ctx->not_after,
410 MBEDTLS_X509_RFC5280_UTC_TIME_LEN));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200411
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100412 MBEDTLS_ASN1_CHK_ADD(sub_len,
413 x509_write_time(&c, buf, ctx->not_before,
414 MBEDTLS_X509_RFC5280_UTC_TIME_LEN));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200415
416 len += sub_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100417 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, sub_len));
418 MBEDTLS_ASN1_CHK_ADD(len,
419 mbedtls_asn1_write_tag(&c, buf,
420 MBEDTLS_ASN1_CONSTRUCTED |
421 MBEDTLS_ASN1_SEQUENCE));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200422
423 /*
424 * Issuer ::= Name
425 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100426 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf,
427 ctx->issuer));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200428
429 /*
430 * Signature ::= AlgorithmIdentifier
431 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100432 MBEDTLS_ASN1_CHK_ADD(len,
433 mbedtls_asn1_write_algorithm_identifier(&c, buf,
434 sig_oid, strlen(sig_oid), 0));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200435
436 /*
437 * Serial ::= INTEGER
438 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100439 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&c, buf,
440 &ctx->serial));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200441
442 /*
443 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
444 */
Hanno Becker47698652017-09-13 11:59:26 +0100445
446 /* Can be omitted for v1 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100447 if (ctx->version != MBEDTLS_X509_CRT_VERSION_1) {
Hanno Becker47698652017-09-13 11:59:26 +0100448 sub_len = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100449 MBEDTLS_ASN1_CHK_ADD(sub_len,
450 mbedtls_asn1_write_int(&c, buf, ctx->version));
Hanno Becker47698652017-09-13 11:59:26 +0100451 len += sub_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100452 MBEDTLS_ASN1_CHK_ADD(len,
453 mbedtls_asn1_write_len(&c, buf, sub_len));
454 MBEDTLS_ASN1_CHK_ADD(len,
455 mbedtls_asn1_write_tag(&c, buf,
456 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
457 MBEDTLS_ASN1_CONSTRUCTED | 0));
Hanno Becker47698652017-09-13 11:59:26 +0100458 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200459
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100460 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
461 MBEDTLS_ASN1_CHK_ADD(len,
462 mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED |
463 MBEDTLS_ASN1_SEQUENCE));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200464
465 /*
466 * Make signature
467 */
Hanno Beckerdef43052019-05-04 07:54:36 +0100468
469 /* Compute hash of CRT. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100470 if ((ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c,
471 len, hash)) != 0) {
472 return ret;
Andres Amaya Garcia8d8204f2017-06-28 11:07:30 +0100473 }
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200474
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100475 if ((ret = mbedtls_pk_sign(ctx->issuer_key, ctx->md_alg,
476 hash, 0, sig, &sig_len,
477 f_rng, p_rng)) != 0) {
478 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200479 }
480
Hanno Beckerdef43052019-05-04 07:54:36 +0100481 /* Move CRT to the front of the buffer to have space
482 * for the signature. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100483 memmove(buf, c, len);
Hanno Beckerdef43052019-05-04 07:54:36 +0100484 c = buf + len;
485
486 /* Add signature at the end of the buffer,
487 * making sure that it doesn't underflow
488 * into the CRT buffer. */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200489 c2 = buf + size;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100490 MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len, mbedtls_x509_write_sig(&c2, c,
491 sig_oid, sig_oid_len, sig,
492 sig_len));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200493
Hanno Beckerdef43052019-05-04 07:54:36 +0100494 /*
495 * Memory layout after this step:
496 *
497 * buf c=buf+len c2 buf+size
498 * [CRT0,...,CRTn, UNUSED, ..., UNUSED, SIG0, ..., SIGm]
499 */
Andres AG60dbc932016-09-02 15:23:48 +0100500
Hanno Beckerdef43052019-05-04 07:54:36 +0100501 /* Move raw CRT to just before the signature. */
502 c = c2 - len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100503 memmove(c, buf, len);
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200504
505 len += sig_and_oid_len;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100506 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
507 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf,
508 MBEDTLS_ASN1_CONSTRUCTED |
509 MBEDTLS_ASN1_SEQUENCE));
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200510
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100511 return (int) len;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200512}
513
514#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
515#define PEM_END_CRT "-----END CERTIFICATE-----\n"
516
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200517#if defined(MBEDTLS_PEM_WRITE_C)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100518int mbedtls_x509write_crt_pem(mbedtls_x509write_cert *crt,
519 unsigned char *buf, size_t size,
520 int (*f_rng)(void *, unsigned char *, size_t),
521 void *p_rng)
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200522{
Janos Follath865b3eb2019-12-16 11:46:15 +0000523 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker67d42592019-05-04 08:13:23 +0100524 size_t olen;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200525
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100526 if ((ret = mbedtls_x509write_crt_der(crt, buf, size,
527 f_rng, p_rng)) < 0) {
528 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200529 }
530
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100531 if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT,
532 buf + size - ret, ret,
533 buf, size, &olen)) != 0) {
534 return ret;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200535 }
536
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100537 return 0;
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200538}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200539#endif /* MBEDTLS_PEM_WRITE_C */
Paul Bakker7c6b2c32013-09-16 13:49:26 +0200540
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200541#endif /* MBEDTLS_X509_CRT_WRITE_C */