2 * X.509 certificate writing
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
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
28 #if defined(MBEDTLS_X509_CRT_WRITE_C)
30 #include "mbedtls/x509_crt.h"
31 #include "mbedtls/asn1write.h"
32 #include "mbedtls/error.h"
33 #include "mbedtls/oid.h"
34 #include "mbedtls/platform_util.h"
35 #include "mbedtls/sha1.h"
39 #if defined(MBEDTLS_PEM_WRITE_C)
40 #include "mbedtls/pem.h"
41 #endif /* MBEDTLS_PEM_WRITE_C */
43 void mbedtls_x509write_crt_init(mbedtls_x509write_cert
*ctx
) {
44 memset(ctx
, 0, sizeof(mbedtls_x509write_cert
));
46 mbedtls_mpi_init(&ctx
->serial
);
47 ctx
->version
= MBEDTLS_X509_CRT_VERSION_3
;
50 void mbedtls_x509write_crt_free(mbedtls_x509write_cert
*ctx
) {
51 mbedtls_mpi_free(&ctx
->serial
);
53 mbedtls_asn1_free_named_data_list(&ctx
->subject
);
54 mbedtls_asn1_free_named_data_list(&ctx
->issuer
);
55 mbedtls_asn1_free_named_data_list(&ctx
->extensions
);
57 mbedtls_platform_zeroize(ctx
, sizeof(mbedtls_x509write_cert
));
60 void mbedtls_x509write_crt_set_version(mbedtls_x509write_cert
*ctx
,
62 ctx
->version
= version
;
65 void mbedtls_x509write_crt_set_md_alg(mbedtls_x509write_cert
*ctx
,
66 mbedtls_md_type_t md_alg
) {
70 void mbedtls_x509write_crt_set_subject_key(mbedtls_x509write_cert
*ctx
,
71 mbedtls_pk_context
*key
) {
72 ctx
->subject_key
= key
;
75 void mbedtls_x509write_crt_set_issuer_key(mbedtls_x509write_cert
*ctx
,
76 mbedtls_pk_context
*key
) {
77 ctx
->issuer_key
= key
;
80 int mbedtls_x509write_crt_set_subject_name(mbedtls_x509write_cert
*ctx
,
81 const char *subject_name
) {
82 return mbedtls_x509_string_to_names(&ctx
->subject
, subject_name
);
85 int mbedtls_x509write_crt_set_issuer_name(mbedtls_x509write_cert
*ctx
,
86 const char *issuer_name
) {
87 return mbedtls_x509_string_to_names(&ctx
->issuer
, issuer_name
);
90 int mbedtls_x509write_crt_set_serial(mbedtls_x509write_cert
*ctx
,
91 const mbedtls_mpi
*serial
) {
92 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
94 if ((ret
= mbedtls_mpi_copy(&ctx
->serial
, serial
)) != 0)
100 int mbedtls_x509write_crt_set_validity(mbedtls_x509write_cert
*ctx
,
101 const char *not_before
,
102 const char *not_after
) {
103 if (strlen(not_before
) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1 ||
104 strlen(not_after
) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1) {
105 return (MBEDTLS_ERR_X509_BAD_INPUT_DATA
);
107 strncpy(ctx
->not_before
, not_before
, MBEDTLS_X509_RFC5280_UTC_TIME_LEN
);
108 strncpy(ctx
->not_after
, not_after
, MBEDTLS_X509_RFC5280_UTC_TIME_LEN
);
109 ctx
->not_before
[MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1] = 'Z';
110 ctx
->not_after
[MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1] = 'Z';
115 int mbedtls_x509write_crt_set_extension(mbedtls_x509write_cert
*ctx
,
116 const char *oid
, size_t oid_len
,
118 const unsigned char *val
, size_t val_len
) {
119 return (mbedtls_x509_set_extension(&ctx
->extensions
, oid
, oid_len
,
120 critical
, val
, val_len
));
123 int mbedtls_x509write_crt_set_basic_constraints(mbedtls_x509write_cert
*ctx
,
124 int is_ca
, int max_pathlen
) {
125 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
126 unsigned char buf
[9];
127 unsigned char *c
= buf
+ sizeof(buf
);
130 memset(buf
, 0, sizeof(buf
));
132 if (is_ca
&& max_pathlen
> 127)
133 return (MBEDTLS_ERR_X509_BAD_INPUT_DATA
);
136 if (max_pathlen
>= 0) {
137 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_int(&c
, buf
,
140 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_bool(&c
, buf
, 1));
143 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
144 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_tag(&c
, buf
,
145 MBEDTLS_ASN1_CONSTRUCTED
|
146 MBEDTLS_ASN1_SEQUENCE
));
149 mbedtls_x509write_crt_set_extension(ctx
, MBEDTLS_OID_BASIC_CONSTRAINTS
,
150 MBEDTLS_OID_SIZE(MBEDTLS_OID_BASIC_CONSTRAINTS
),
151 is_ca
, buf
+ sizeof(buf
) - len
, len
));
154 #if defined(MBEDTLS_SHA1_C)
155 int mbedtls_x509write_crt_set_subject_key_identifier(mbedtls_x509write_cert
*ctx
) {
156 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
157 unsigned char buf
[MBEDTLS_MPI_MAX_SIZE
* 2 + 20]; /* tag, length + 2xMPI */
158 unsigned char *c
= buf
+ sizeof(buf
);
161 memset(buf
, 0, sizeof(buf
));
162 MBEDTLS_ASN1_CHK_ADD(len
,
163 mbedtls_pk_write_pubkey(&c
, buf
, ctx
->subject_key
));
165 ret
= mbedtls_sha1_ret(buf
+ sizeof(buf
) - len
, len
,
166 buf
+ sizeof(buf
) - 20);
169 c
= buf
+ sizeof(buf
) - 20;
172 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
173 MBEDTLS_ASN1_CHK_ADD(len
,
174 mbedtls_asn1_write_tag(&c
, buf
, MBEDTLS_ASN1_OCTET_STRING
));
176 return mbedtls_x509write_crt_set_extension(ctx
,
177 MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER
,
178 MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER
),
179 0, buf
+ sizeof(buf
) - len
, len
);
182 int mbedtls_x509write_crt_set_authority_key_identifier(mbedtls_x509write_cert
*ctx
) {
183 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
184 unsigned char buf
[MBEDTLS_MPI_MAX_SIZE
* 2 + 20]; /* tag, length + 2xMPI */
185 unsigned char *c
= buf
+ sizeof(buf
);
188 memset(buf
, 0, sizeof(buf
));
189 MBEDTLS_ASN1_CHK_ADD(len
,
190 mbedtls_pk_write_pubkey(&c
, buf
, ctx
->issuer_key
));
192 ret
= mbedtls_sha1_ret(buf
+ sizeof(buf
) - len
, len
,
193 buf
+ sizeof(buf
) - 20);
196 c
= buf
+ sizeof(buf
) - 20;
199 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
200 MBEDTLS_ASN1_CHK_ADD(len
,
201 mbedtls_asn1_write_tag(&c
, buf
, MBEDTLS_ASN1_CONTEXT_SPECIFIC
| 0));
203 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
204 MBEDTLS_ASN1_CHK_ADD(len
,
205 mbedtls_asn1_write_tag(&c
, buf
,
206 MBEDTLS_ASN1_CONSTRUCTED
|
207 MBEDTLS_ASN1_SEQUENCE
));
209 return mbedtls_x509write_crt_set_extension(
210 ctx
, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER
,
211 MBEDTLS_OID_SIZE(MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER
),
212 0, buf
+ sizeof(buf
) - len
, len
);
214 #endif /* MBEDTLS_SHA1_C */
216 int mbedtls_x509write_crt_set_key_usage(mbedtls_x509write_cert
*ctx
,
217 unsigned int key_usage
) {
218 unsigned char buf
[5], ku
[2];
220 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
221 const unsigned int allowed_bits
= MBEDTLS_X509_KU_DIGITAL_SIGNATURE
|
222 MBEDTLS_X509_KU_NON_REPUDIATION
|
223 MBEDTLS_X509_KU_KEY_ENCIPHERMENT
|
224 MBEDTLS_X509_KU_DATA_ENCIPHERMENT
|
225 MBEDTLS_X509_KU_KEY_AGREEMENT
|
226 MBEDTLS_X509_KU_KEY_CERT_SIGN
|
227 MBEDTLS_X509_KU_CRL_SIGN
|
228 MBEDTLS_X509_KU_ENCIPHER_ONLY
|
229 MBEDTLS_X509_KU_DECIPHER_ONLY
;
231 /* Check that nothing other than the allowed flags is set */
232 if ((key_usage
& ~allowed_bits
) != 0)
233 return (MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE
);
236 ku
[0] = (unsigned char)(key_usage
);
237 ku
[1] = (unsigned char)(key_usage
>> 8);
238 ret
= mbedtls_asn1_write_named_bitstring(&c
, buf
, ku
, 9);
242 else if (ret
< 3 || ret
> 5)
243 return (MBEDTLS_ERR_X509_INVALID_FORMAT
);
245 ret
= mbedtls_x509write_crt_set_extension(ctx
, MBEDTLS_OID_KEY_USAGE
,
246 MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE
),
254 int mbedtls_x509write_crt_set_ns_cert_type(mbedtls_x509write_cert
*ctx
,
255 unsigned char ns_cert_type
) {
256 unsigned char buf
[4];
258 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
262 ret
= mbedtls_asn1_write_named_bitstring(&c
, buf
, &ns_cert_type
, 8);
263 if (ret
< 3 || ret
> 4)
266 ret
= mbedtls_x509write_crt_set_extension(ctx
, MBEDTLS_OID_NS_CERT_TYPE
,
267 MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE
),
275 static int x509_write_time(unsigned char **p
, unsigned char *start
,
276 const char *t
, size_t size
) {
277 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
281 * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
283 if (t
[0] == '2' && t
[1] == '0' && t
[2] < '5') {
284 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_raw_buffer(p
, start
,
285 (const unsigned char *) t
+ 2,
287 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(p
, start
, len
));
288 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_tag(p
, start
,
289 MBEDTLS_ASN1_UTC_TIME
));
291 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_raw_buffer(p
, start
,
292 (const unsigned char *) t
,
294 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(p
, start
, len
));
295 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_tag(p
, start
,
296 MBEDTLS_ASN1_GENERALIZED_TIME
));
302 int mbedtls_x509write_crt_der(mbedtls_x509write_cert
*ctx
,
303 unsigned char *buf
, size_t size
,
304 int (*f_rng
)(void *, unsigned char *, size_t),
306 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
308 size_t sig_oid_len
= 0;
309 unsigned char *c
, *c2
;
310 unsigned char hash
[64];
311 unsigned char sig
[MBEDTLS_PK_SIGNATURE_MAX_SIZE
];
312 size_t sub_len
= 0, pub_len
= 0, sig_and_oid_len
= 0, sig_len
;
314 mbedtls_pk_type_t pk_alg
;
317 * Prepare data to be signed at the end of the target buffer
321 /* Signature algorithm needed in TBS, and later for actual signature */
323 /* There's no direct way of extracting a signature algorithm
324 * (represented as an element of mbedtls_pk_type_t) from a PK instance. */
325 if (mbedtls_pk_can_do(ctx
->issuer_key
, MBEDTLS_PK_RSA
))
326 pk_alg
= MBEDTLS_PK_RSA
;
327 else if (mbedtls_pk_can_do(ctx
->issuer_key
, MBEDTLS_PK_ECDSA
))
328 pk_alg
= MBEDTLS_PK_ECDSA
;
330 return (MBEDTLS_ERR_X509_INVALID_ALG
);
332 if ((ret
= mbedtls_oid_get_oid_by_sig_alg(pk_alg
, ctx
->md_alg
,
333 &sig_oid
, &sig_oid_len
)) != 0) {
338 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
342 if (ctx
->version
== MBEDTLS_X509_CRT_VERSION_3
) {
343 MBEDTLS_ASN1_CHK_ADD(len
,
344 mbedtls_x509_write_extensions(&c
,
345 buf
, ctx
->extensions
));
346 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
347 MBEDTLS_ASN1_CHK_ADD(len
,
348 mbedtls_asn1_write_tag(&c
, buf
,
349 MBEDTLS_ASN1_CONSTRUCTED
|
350 MBEDTLS_ASN1_SEQUENCE
));
351 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
352 MBEDTLS_ASN1_CHK_ADD(len
,
353 mbedtls_asn1_write_tag(&c
, buf
,
354 MBEDTLS_ASN1_CONTEXT_SPECIFIC
|
355 MBEDTLS_ASN1_CONSTRUCTED
| 3));
359 * SubjectPublicKeyInfo
361 MBEDTLS_ASN1_CHK_ADD(pub_len
,
362 mbedtls_pk_write_pubkey_der(ctx
->subject_key
,
370 MBEDTLS_ASN1_CHK_ADD(len
,
371 mbedtls_x509_write_names(&c
, buf
,
375 * Validity ::= SEQUENCE {
381 MBEDTLS_ASN1_CHK_ADD(sub_len
,
382 x509_write_time(&c
, buf
, ctx
->not_after
,
383 MBEDTLS_X509_RFC5280_UTC_TIME_LEN
));
385 MBEDTLS_ASN1_CHK_ADD(sub_len
,
386 x509_write_time(&c
, buf
, ctx
->not_before
,
387 MBEDTLS_X509_RFC5280_UTC_TIME_LEN
));
390 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, sub_len
));
391 MBEDTLS_ASN1_CHK_ADD(len
,
392 mbedtls_asn1_write_tag(&c
, buf
,
393 MBEDTLS_ASN1_CONSTRUCTED
|
394 MBEDTLS_ASN1_SEQUENCE
));
399 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_x509_write_names(&c
, buf
,
403 * Signature ::= AlgorithmIdentifier
405 MBEDTLS_ASN1_CHK_ADD(len
,
406 mbedtls_asn1_write_algorithm_identifier(&c
, buf
,
407 sig_oid
, strlen(sig_oid
), 0));
412 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_mpi(&c
, buf
,
416 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
419 /* Can be omitted for v1 */
420 if (ctx
->version
!= MBEDTLS_X509_CRT_VERSION_1
) {
422 MBEDTLS_ASN1_CHK_ADD(sub_len
,
423 mbedtls_asn1_write_int(&c
, buf
, ctx
->version
));
425 MBEDTLS_ASN1_CHK_ADD(len
,
426 mbedtls_asn1_write_len(&c
, buf
, sub_len
));
427 MBEDTLS_ASN1_CHK_ADD(len
,
428 mbedtls_asn1_write_tag(&c
, buf
,
429 MBEDTLS_ASN1_CONTEXT_SPECIFIC
|
430 MBEDTLS_ASN1_CONSTRUCTED
| 0));
433 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
434 MBEDTLS_ASN1_CHK_ADD(len
,
435 mbedtls_asn1_write_tag(&c
, buf
, MBEDTLS_ASN1_CONSTRUCTED
|
436 MBEDTLS_ASN1_SEQUENCE
));
442 /* Compute hash of CRT. */
443 if ((ret
= mbedtls_md(mbedtls_md_info_from_type(ctx
->md_alg
), c
,
448 if ((ret
= mbedtls_pk_sign(ctx
->issuer_key
, ctx
->md_alg
,
449 hash
, 0, sig
, &sig_len
,
450 f_rng
, p_rng
)) != 0) {
454 /* Move CRT to the front of the buffer to have space
455 * for the signature. */
456 memmove(buf
, c
, len
);
459 /* Add signature at the end of the buffer,
460 * making sure that it doesn't underflow
461 * into the CRT buffer. */
463 MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len
, mbedtls_x509_write_sig(&c2
, c
,
464 sig_oid
, sig_oid_len
, sig
, sig_len
));
467 * Memory layout after this step:
469 * buf c=buf+len c2 buf+size
470 * [CRT0,...,CRTn, UNUSED, ..., UNUSED, SIG0, ..., SIGm]
473 /* Move raw CRT to just before the signature. */
475 memmove(c
, buf
, len
);
477 len
+= sig_and_oid_len
;
478 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_len(&c
, buf
, len
));
479 MBEDTLS_ASN1_CHK_ADD(len
, mbedtls_asn1_write_tag(&c
, buf
,
480 MBEDTLS_ASN1_CONSTRUCTED
|
481 MBEDTLS_ASN1_SEQUENCE
));
486 #define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
487 #define PEM_END_CRT "-----END CERTIFICATE-----\n"
489 #if defined(MBEDTLS_PEM_WRITE_C)
490 int mbedtls_x509write_crt_pem(mbedtls_x509write_cert
*crt
,
491 unsigned char *buf
, size_t size
,
492 int (*f_rng
)(void *, unsigned char *, size_t),
494 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
497 if ((ret
= mbedtls_x509write_crt_der(crt
, buf
, size
,
498 f_rng
, p_rng
)) < 0) {
502 if ((ret
= mbedtls_pem_write_buffer(PEM_BEGIN_CRT
, PEM_END_CRT
,
503 buf
+ size
- ret
, ret
,
504 buf
, size
, &olen
)) != 0) {
510 #endif /* MBEDTLS_PEM_WRITE_C */
512 #endif /* MBEDTLS_X509_CRT_WRITE_C */