2 * X.509 certificate writing
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
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.
19 * This file is part of mbed TLS (https://tls.mbed.org)
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
28 #if !defined(MBEDTLS_CONFIG_FILE)
29 #include "mbedtls/config.h"
31 #include MBEDTLS_CONFIG_FILE
34 #if defined(MBEDTLS_X509_CRT_WRITE_C)
36 #include "mbedtls/x509_crt.h"
37 #include "mbedtls/oid.h"
38 #include "mbedtls/asn1write.h"
39 #include "mbedtls/sha1.h"
43 #if defined(MBEDTLS_PEM_WRITE_C)
44 #include "mbedtls/pem.h"
45 #endif /* MBEDTLS_PEM_WRITE_C */
47 /* Implementation that should never be optimized out by the compiler */
48 static void mbedtls_zeroize( void *v
, size_t n
) {
49 volatile unsigned char *p
= v
; while( n
-- ) *p
++ = 0;
52 void mbedtls_x509write_crt_init( mbedtls_x509write_cert
*ctx
)
54 memset( ctx
, 0, sizeof(mbedtls_x509write_cert
) );
56 mbedtls_mpi_init( &ctx
->serial
);
57 ctx
->version
= MBEDTLS_X509_CRT_VERSION_3
;
60 void mbedtls_x509write_crt_free( mbedtls_x509write_cert
*ctx
)
62 mbedtls_mpi_free( &ctx
->serial
);
64 mbedtls_asn1_free_named_data_list( &ctx
->subject
);
65 mbedtls_asn1_free_named_data_list( &ctx
->issuer
);
66 mbedtls_asn1_free_named_data_list( &ctx
->extensions
);
68 mbedtls_zeroize( ctx
, sizeof(mbedtls_x509write_cert
) );
71 void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert
*ctx
, int version
)
73 ctx
->version
= version
;
76 void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert
*ctx
, mbedtls_md_type_t md_alg
)
81 void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert
*ctx
, mbedtls_pk_context
*key
)
83 ctx
->subject_key
= key
;
86 void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert
*ctx
, mbedtls_pk_context
*key
)
88 ctx
->issuer_key
= key
;
91 int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert
*ctx
,
92 const char *subject_name
)
94 return mbedtls_x509_string_to_names( &ctx
->subject
, subject_name
);
97 int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert
*ctx
,
98 const char *issuer_name
)
100 return mbedtls_x509_string_to_names( &ctx
->issuer
, issuer_name
);
103 int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert
*ctx
, const mbedtls_mpi
*serial
)
107 if( ( ret
= mbedtls_mpi_copy( &ctx
->serial
, serial
) ) != 0 )
113 int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert
*ctx
, const char *not_before
,
114 const char *not_after
)
116 if( strlen( not_before
) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1 ||
117 strlen( not_after
) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1 )
119 return( MBEDTLS_ERR_X509_BAD_INPUT_DATA
);
121 strncpy( ctx
->not_before
, not_before
, MBEDTLS_X509_RFC5280_UTC_TIME_LEN
);
122 strncpy( ctx
->not_after
, not_after
, MBEDTLS_X509_RFC5280_UTC_TIME_LEN
);
123 ctx
->not_before
[MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1] = 'Z';
124 ctx
->not_after
[MBEDTLS_X509_RFC5280_UTC_TIME_LEN
- 1] = 'Z';
129 int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert
*ctx
,
130 const char *oid
, size_t oid_len
,
132 const unsigned char *val
, size_t val_len
)
134 return mbedtls_x509_set_extension( &ctx
->extensions
, oid
, oid_len
,
135 critical
, val
, val_len
);
138 int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert
*ctx
,
139 int is_ca
, int max_pathlen
)
142 unsigned char buf
[9];
143 unsigned char *c
= buf
+ sizeof(buf
);
146 memset( buf
, 0, sizeof(buf
) );
148 if( is_ca
&& max_pathlen
> 127 )
149 return( MBEDTLS_ERR_X509_BAD_INPUT_DATA
);
153 if( max_pathlen
>= 0 )
155 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_int( &c
, buf
, max_pathlen
) );
157 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_bool( &c
, buf
, 1 ) );
160 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, buf
, len
) );
161 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, buf
, MBEDTLS_ASN1_CONSTRUCTED
|
162 MBEDTLS_ASN1_SEQUENCE
) );
164 return mbedtls_x509write_crt_set_extension( ctx
, MBEDTLS_OID_BASIC_CONSTRAINTS
,
165 MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS
),
166 0, buf
+ sizeof(buf
) - len
, len
);
169 #if defined(MBEDTLS_SHA1_C)
170 int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert
*ctx
)
173 unsigned char buf
[MBEDTLS_MPI_MAX_SIZE
* 2 + 20]; /* tag, length + 2xMPI */
174 unsigned char *c
= buf
+ sizeof(buf
);
177 memset( buf
, 0, sizeof(buf
) );
178 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_pk_write_pubkey( &c
, buf
, ctx
->subject_key
) );
180 mbedtls_sha1( buf
+ sizeof(buf
) - len
, len
, buf
+ sizeof(buf
) - 20 );
181 c
= buf
+ sizeof(buf
) - 20;
184 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, buf
, len
) );
185 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, buf
, MBEDTLS_ASN1_OCTET_STRING
) );
187 return mbedtls_x509write_crt_set_extension( ctx
, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER
,
188 MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER
),
189 0, buf
+ sizeof(buf
) - len
, len
);
192 int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert
*ctx
)
195 unsigned char buf
[MBEDTLS_MPI_MAX_SIZE
* 2 + 20]; /* tag, length + 2xMPI */
196 unsigned char *c
= buf
+ sizeof(buf
);
199 memset( buf
, 0, sizeof(buf
) );
200 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_pk_write_pubkey( &c
, buf
, ctx
->issuer_key
) );
202 mbedtls_sha1( buf
+ sizeof(buf
) - len
, len
, buf
+ sizeof(buf
) - 20 );
203 c
= buf
+ sizeof(buf
) - 20;
206 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, buf
, len
) );
207 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, buf
, MBEDTLS_ASN1_CONTEXT_SPECIFIC
| 0 ) );
209 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, buf
, len
) );
210 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, buf
, MBEDTLS_ASN1_CONSTRUCTED
|
211 MBEDTLS_ASN1_SEQUENCE
) );
213 return mbedtls_x509write_crt_set_extension( ctx
, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER
,
214 MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER
),
215 0, buf
+ sizeof(buf
) - len
, len
);
217 #endif /* MBEDTLS_SHA1_C */
219 int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert
*ctx
,
220 unsigned int key_usage
)
222 unsigned char buf
[4], ku
;
226 /* We currently only support 7 bits, from 0x80 to 0x02 */
227 if( ( key_usage
& ~0xfe ) != 0 )
228 return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE
);
231 ku
= (unsigned char) key_usage
;
233 if( ( ret
= mbedtls_asn1_write_bitstring( &c
, buf
, &ku
, 7 ) ) != 4 )
236 ret
= mbedtls_x509write_crt_set_extension( ctx
, MBEDTLS_OID_KEY_USAGE
,
237 MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE
),
245 int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert
*ctx
,
246 unsigned char ns_cert_type
)
248 unsigned char buf
[4];
254 if( ( ret
= mbedtls_asn1_write_bitstring( &c
, buf
, &ns_cert_type
, 8 ) ) != 4 )
257 ret
= mbedtls_x509write_crt_set_extension( ctx
, MBEDTLS_OID_NS_CERT_TYPE
,
258 MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE
),
266 static int x509_write_time( unsigned char **p
, unsigned char *start
,
267 const char *time
, size_t size
)
273 * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
275 if( time
[0] == '2' && time
[1] == '0' && time
[2] < '5' )
277 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_raw_buffer( p
, start
,
278 (const unsigned char *) time
+ 2,
280 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( p
, start
, len
) );
281 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( p
, start
, MBEDTLS_ASN1_UTC_TIME
) );
285 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_raw_buffer( p
, start
,
286 (const unsigned char *) time
,
288 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( p
, start
, len
) );
289 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( p
, start
, MBEDTLS_ASN1_GENERALIZED_TIME
) );
295 int mbedtls_x509write_crt_der( mbedtls_x509write_cert
*ctx
, unsigned char *buf
, size_t size
,
296 int (*f_rng
)(void *, unsigned char *, size_t),
301 size_t sig_oid_len
= 0;
302 unsigned char *c
, *c2
;
303 unsigned char hash
[64];
304 unsigned char sig
[MBEDTLS_MPI_MAX_SIZE
];
305 unsigned char tmp_buf
[2048];
306 size_t sub_len
= 0, pub_len
= 0, sig_and_oid_len
= 0, sig_len
;
308 mbedtls_pk_type_t pk_alg
;
311 * Prepare data to be signed in tmp_buf
313 c
= tmp_buf
+ sizeof( tmp_buf
);
315 /* Signature algorithm needed in TBS, and later for actual signature */
316 pk_alg
= mbedtls_pk_get_type( ctx
->issuer_key
);
317 if( pk_alg
== MBEDTLS_PK_ECKEY
)
318 pk_alg
= MBEDTLS_PK_ECDSA
;
320 if( ( ret
= mbedtls_oid_get_oid_by_sig_alg( pk_alg
, ctx
->md_alg
,
321 &sig_oid
, &sig_oid_len
) ) != 0 )
327 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
329 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_x509_write_extensions( &c
, tmp_buf
, ctx
->extensions
) );
330 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, tmp_buf
, len
) );
331 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, tmp_buf
, MBEDTLS_ASN1_CONSTRUCTED
|
332 MBEDTLS_ASN1_SEQUENCE
) );
333 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, tmp_buf
, len
) );
334 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, tmp_buf
, MBEDTLS_ASN1_CONTEXT_SPECIFIC
|
335 MBEDTLS_ASN1_CONSTRUCTED
| 3 ) );
338 * SubjectPublicKeyInfo
340 MBEDTLS_ASN1_CHK_ADD( pub_len
, mbedtls_pk_write_pubkey_der( ctx
->subject_key
,
341 tmp_buf
, c
- tmp_buf
) );
348 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_x509_write_names( &c
, tmp_buf
, ctx
->subject
) );
351 * Validity ::= SEQUENCE {
357 MBEDTLS_ASN1_CHK_ADD( sub_len
, x509_write_time( &c
, tmp_buf
, ctx
->not_after
,
358 MBEDTLS_X509_RFC5280_UTC_TIME_LEN
) );
360 MBEDTLS_ASN1_CHK_ADD( sub_len
, x509_write_time( &c
, tmp_buf
, ctx
->not_before
,
361 MBEDTLS_X509_RFC5280_UTC_TIME_LEN
) );
364 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, tmp_buf
, sub_len
) );
365 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, tmp_buf
, MBEDTLS_ASN1_CONSTRUCTED
|
366 MBEDTLS_ASN1_SEQUENCE
) );
371 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_x509_write_names( &c
, tmp_buf
, ctx
->issuer
) );
374 * Signature ::= AlgorithmIdentifier
376 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_algorithm_identifier( &c
, tmp_buf
,
377 sig_oid
, strlen( sig_oid
), 0 ) );
382 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_mpi( &c
, tmp_buf
, &ctx
->serial
) );
385 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
388 MBEDTLS_ASN1_CHK_ADD( sub_len
, mbedtls_asn1_write_int( &c
, tmp_buf
, ctx
->version
) );
390 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, tmp_buf
, sub_len
) );
391 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, tmp_buf
, MBEDTLS_ASN1_CONTEXT_SPECIFIC
|
392 MBEDTLS_ASN1_CONSTRUCTED
| 0 ) );
394 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c
, tmp_buf
, len
) );
395 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c
, tmp_buf
, MBEDTLS_ASN1_CONSTRUCTED
|
396 MBEDTLS_ASN1_SEQUENCE
) );
401 mbedtls_md( mbedtls_md_info_from_type( ctx
->md_alg
), c
, len
, hash
);
403 if( ( ret
= mbedtls_pk_sign( ctx
->issuer_key
, ctx
->md_alg
, hash
, 0, sig
, &sig_len
,
404 f_rng
, p_rng
) ) != 0 )
410 * Write data to output buffer
413 MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len
, mbedtls_x509_write_sig( &c2
, buf
,
414 sig_oid
, sig_oid_len
, sig
, sig_len
) );
417 memcpy( c2
, c
, len
);
419 len
+= sig_and_oid_len
;
420 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_len( &c2
, buf
, len
) );
421 MBEDTLS_ASN1_CHK_ADD( len
, mbedtls_asn1_write_tag( &c2
, buf
, MBEDTLS_ASN1_CONSTRUCTED
|
422 MBEDTLS_ASN1_SEQUENCE
) );
427 #define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
428 #define PEM_END_CRT "-----END CERTIFICATE-----\n"
430 #if defined(MBEDTLS_PEM_WRITE_C)
431 int mbedtls_x509write_crt_pem( mbedtls_x509write_cert
*crt
, unsigned char *buf
, size_t size
,
432 int (*f_rng
)(void *, unsigned char *, size_t),
436 unsigned char output_buf
[4096];
439 if( ( ret
= mbedtls_x509write_crt_der( crt
, output_buf
, sizeof(output_buf
),
440 f_rng
, p_rng
) ) < 0 )
445 if( ( ret
= mbedtls_pem_write_buffer( PEM_BEGIN_CRT
, PEM_END_CRT
,
446 output_buf
+ sizeof(output_buf
) - ret
,
447 ret
, buf
, size
, &olen
) ) != 0 )
454 #endif /* MBEDTLS_PEM_WRITE_C */
456 #endif /* MBEDTLS_X509_CRT_WRITE_C */