1 /*
2  *  X.509 certificate writing
3  *
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  *
7  *  This file is provided under the Apache License 2.0, or the
8  *  GNU General Public License v2.0 or later.
9  *
10  *  **********
11  *  Apache License 2.0:
12  *
13  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
14  *  not use this file except in compliance with the License.
15  *  You may obtain a copy of the License at
16  *
17  *  http://www.apache.org/licenses/LICENSE-2.0
18  *
19  *  Unless required by applicable law or agreed to in writing, software
20  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the License for the specific language governing permissions and
23  *  limitations under the License.
24  *
25  *  **********
26  *
27  *  **********
28  *  GNU General Public License v2.0 or later:
29  *
30  *  This program is free software; you can redistribute it and/or modify
31  *  it under the terms of the GNU General Public License as published by
32  *  the Free Software Foundation; either version 2 of the License, or
33  *  (at your option) any later version.
34  *
35  *  This program is distributed in the hope that it will be useful,
36  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
37  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  *  GNU General Public License for more details.
39  *
40  *  You should have received a copy of the GNU General Public License along
41  *  with this program; if not, write to the Free Software Foundation, Inc.,
42  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43  *
44  *  **********
45  *
46  *  This file is part of mbed TLS (https://tls.mbed.org)
47  */
48 /*
49  * References:
50  * - certificates: RFC 5280, updated by RFC 6818
51  * - CSRs: PKCS#10 v1.7 aka RFC 2986
52  * - attributes: PKCS#9 v2.0 aka RFC 2985
53  */
54 
55 #if !defined(MBEDTLS_CONFIG_FILE)
56 #include "mbedtls/config.h"
57 #else
58 #include MBEDTLS_CONFIG_FILE
59 #endif
60 
61 #if defined(MBEDTLS_X509_CRT_WRITE_C)
62 
63 #include "mbedtls/x509_crt.h"
64 #include "mbedtls/oid.h"
65 #include "mbedtls/asn1write.h"
66 #include "mbedtls/sha1.h"
67 
68 #include <string.h>
69 
70 #if defined(MBEDTLS_PEM_WRITE_C)
71 #include "mbedtls/pem.h"
72 #endif /* MBEDTLS_PEM_WRITE_C */
73 
74 /* Implementation that should never be optimized out by the compiler */
75 static void mbedtls_zeroize( void *v, size_t n ) {
76     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
77 }
78 
79 /*
80  * For the currently used signature algorithms the buffer to store any signature
81  * must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE)
82  */
83 #if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE
84 #define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN
85 #else
86 #define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE
87 #endif
88 
89 void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx )
90 {
91     memset( ctx, 0, sizeof( mbedtls_x509write_cert ) );
92 
93     mbedtls_mpi_init( &ctx->serial );
94     ctx->version = MBEDTLS_X509_CRT_VERSION_3;
95 }
96 
97 void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx )
98 {
99     mbedtls_mpi_free( &ctx->serial );
100 
101     mbedtls_asn1_free_named_data_list( &ctx->subject );
102     mbedtls_asn1_free_named_data_list( &ctx->issuer );
103     mbedtls_asn1_free_named_data_list( &ctx->extensions );
104 
105     mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
106 }
107 
108 void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version )
109 {
110     ctx->version = version;
111 }
112 
113 void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg )
114 {
115     ctx->md_alg = md_alg;
116 }
117 
118 void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
119 {
120     ctx->subject_key = key;
121 }
122 
123 void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
124 {
125     ctx->issuer_key = key;
126 }
127 
128 int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx,
129                                     const char *subject_name )
130 {
131     return mbedtls_x509_string_to_names( &ctx->subject, subject_name );
132 }
133 
134 int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx,
135                                    const char *issuer_name )
136 {
137     return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name );
138 }
139 
140 int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial )
141 {
142     int ret;
143 
144     if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 )
145         return( ret );
146 
147     return( 0 );
148 }
149 
150 int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before,
151                                 const char *not_after )
152 {
153     if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ||
154         strlen( not_after )  != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 )
155     {
156         return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
157     }
158     strncpy( ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
159     strncpy( ctx->not_after , not_after , MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
160     ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
161     ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
162 
163     return( 0 );
164 }
165 
166 int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx,
167                                  const char *oid, size_t oid_len,
168                                  int critical,
169                                  const unsigned char *val, size_t val_len )
170 {
171     return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len,
172                                critical, val, val_len );
173 }
174 
175 int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx,
176                                          int is_ca, int max_pathlen )
177 {
178     int ret;
179     unsigned char buf[9];
180     unsigned char *c = buf + sizeof(buf);
181     size_t len = 0;
182 
183     memset( buf, 0, sizeof(buf) );
184 
185     if( is_ca && max_pathlen > 127 )
186         return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
187 
188     if( is_ca )
189     {
190         if( max_pathlen >= 0 )
191         {
192             MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) );
193         }
194         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) );
195     }
196 
197     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
198     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
199                                                 MBEDTLS_ASN1_SEQUENCE ) );
200 
201     return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
202                                         MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ),
203                                         0, buf + sizeof(buf) - len, len );
204 }
205 
206 #if defined(MBEDTLS_SHA1_C)
207 int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx )
208 {
209     int ret;
210     unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
211     unsigned char *c = buf + sizeof(buf);
212     size_t len = 0;
213 
214     memset( buf, 0, sizeof(buf) );
215     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) );
216 
217     ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
218                             buf + sizeof( buf ) - 20 );
219     if( ret != 0 )
220         return( ret );
221     c = buf + sizeof( buf ) - 20;
222     len = 20;
223 
224     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
225     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) );
226 
227     return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
228                                         MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ),
229                                         0, buf + sizeof(buf) - len, len );
230 }
231 
232 int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx )
233 {
234     int ret;
235     unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
236     unsigned char *c = buf + sizeof( buf );
237     size_t len = 0;
238 
239     memset( buf, 0, sizeof(buf) );
240     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) );
241 
242     ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
243                             buf + sizeof( buf ) - 20 );
244     if( ret != 0 )
245         return( ret );
246     c = buf + sizeof( buf ) - 20;
247     len = 20;
248 
249     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
250     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0 ) );
251 
252     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
253     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
254                                                 MBEDTLS_ASN1_SEQUENCE ) );
255 
256     return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
257                                    MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
258                                    0, buf + sizeof( buf ) - len, len );
259 }
260 #endif /* MBEDTLS_SHA1_C */
261 
262 static size_t crt_get_unused_bits_for_named_bitstring( unsigned char bitstring,
263                                                        size_t bit_offset )
264 {
265     size_t unused_bits;
266 
267      /* Count the unused bits removing trailing 0s */
268     for( unused_bits = bit_offset; unused_bits < 8; unused_bits++ )
269         if( ( ( bitstring >> unused_bits ) & 0x1 ) != 0 )
270             break;
271 
272      return( unused_bits );
273 }
274 
275 int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx,
276                                          unsigned int key_usage )
277 {
278     unsigned char buf[4], ku;
279     unsigned char *c;
280     int ret;
281     size_t unused_bits;
282     const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
283         MBEDTLS_X509_KU_NON_REPUDIATION   |
284         MBEDTLS_X509_KU_KEY_ENCIPHERMENT  |
285         MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
286         MBEDTLS_X509_KU_KEY_AGREEMENT     |
287         MBEDTLS_X509_KU_KEY_CERT_SIGN     |
288         MBEDTLS_X509_KU_CRL_SIGN;
289 
290     /* Check that nothing other than the allowed flags is set */
291     if( ( key_usage & ~allowed_bits ) != 0 )
292         return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
293 
294     c = buf + 4;
295     ku = (unsigned char)key_usage;
296     unused_bits = crt_get_unused_bits_for_named_bitstring( ku, 1 );
297     ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 8 - unused_bits );
298 
299     if( ret < 0 )
300         return( ret );
301     else if( ret < 3 || ret > 4 )
302         return( MBEDTLS_ERR_X509_INVALID_FORMAT );
303 
304     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
305                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
306                                        1, c, (size_t)ret );
307     if( ret != 0 )
308         return( ret );
309 
310     return( 0 );
311 }
312 
313 int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
314                                     unsigned char ns_cert_type )
315 {
316     unsigned char buf[4];
317     unsigned char *c;
318     size_t unused_bits;
319     int ret;
320 
321     c = buf + 4;
322 
323     unused_bits = crt_get_unused_bits_for_named_bitstring( ns_cert_type, 0 );
324     ret = mbedtls_asn1_write_bitstring( &c,
325                                         buf,
326                                         &ns_cert_type,
327                                         8 - unused_bits );
328     if( ret < 3 || ret > 4 )
329         return( ret );
330 
331     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
332                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
333                                        0, c, (size_t)ret );
334     if( ret != 0 )
335         return( ret );
336 
337     return( 0 );
338 }
339 
340 static int x509_write_time( unsigned char **p, unsigned char *start,
341                             const char *t, size_t size )
342 {
343     int ret;
344     size_t len = 0;
345 
346     /*
347      * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
348      */
349     if( t[0] == '2' && t[1] == '0' && t[2] < '5' )
350     {
351         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
352                                              (const unsigned char *) t + 2,
353                                              size - 2 ) );
354         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
355         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_UTC_TIME ) );
356     }
357     else
358     {
359         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
360                                                   (const unsigned char *) t,
361                                                   size ) );
362         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
363         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_GENERALIZED_TIME ) );
364     }
365 
366     return( (int) len );
367 }
368 
369 int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size,
370                        int (*f_rng)(void *, unsigned char *, size_t),
371                        void *p_rng )
372 {
373     int ret;
374     const char *sig_oid;
375     size_t sig_oid_len = 0;
376     unsigned char *c, *c2;
377     unsigned char hash[64];
378     unsigned char sig[SIGNATURE_MAX_SIZE];
379     unsigned char tmp_buf[2048];
380     size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
381     size_t len = 0;
382     mbedtls_pk_type_t pk_alg;
383 
384     /*
385      * Prepare data to be signed in tmp_buf
386      */
387     c = tmp_buf + sizeof( tmp_buf );
388 
389     /* Signature algorithm needed in TBS, and later for actual signature */
390 
391     /* There's no direct way of extracting a signature algorithm
392      * (represented as an element of mbedtls_pk_type_t) from a PK instance. */
393     if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_RSA ) )
394         pk_alg = MBEDTLS_PK_RSA;
395     else if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_ECDSA ) )
396         pk_alg = MBEDTLS_PK_ECDSA;
397     else
398         return( MBEDTLS_ERR_X509_INVALID_ALG );
399 
400     if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
401                                           &sig_oid, &sig_oid_len ) ) != 0 )
402     {
403         return( ret );
404     }
405 
406     /*
407      *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
408      */
409 
410     /* Only for v3 */
411     if( ctx->version == MBEDTLS_X509_CRT_VERSION_3 )
412     {
413         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
414         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
415         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
416                                                            MBEDTLS_ASN1_SEQUENCE ) );
417         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
418         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
419                                                            MBEDTLS_ASN1_CONSTRUCTED | 3 ) );
420     }
421 
422     /*
423      *  SubjectPublicKeyInfo
424      */
425     MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->subject_key,
426                                                 tmp_buf, c - tmp_buf ) );
427     c -= pub_len;
428     len += pub_len;
429 
430     /*
431      *  Subject  ::=  Name
432      */
433     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) );
434 
435     /*
436      *  Validity ::= SEQUENCE {
437      *       notBefore      Time,
438      *       notAfter       Time }
439      */
440     sub_len = 0;
441 
442     MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
443                                             MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
444 
445     MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
446                                             MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
447 
448     len += sub_len;
449     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
450     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
451                                                     MBEDTLS_ASN1_SEQUENCE ) );
452 
453     /*
454      *  Issuer  ::=  Name
455      */
456     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->issuer ) );
457 
458     /*
459      *  Signature   ::=  AlgorithmIdentifier
460      */
461     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, tmp_buf,
462                        sig_oid, strlen( sig_oid ), 0 ) );
463 
464     /*
465      *  Serial   ::=  INTEGER
466      */
467     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
468 
469     /*
470      *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
471      */
472 
473     /* Can be omitted for v1 */
474     if( ctx->version != MBEDTLS_X509_CRT_VERSION_1 )
475     {
476         sub_len = 0;
477         MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) );
478         len += sub_len;
479         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
480         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
481                                                            MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
482     }
483 
484     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
485     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
486                                                        MBEDTLS_ASN1_SEQUENCE ) );
487 
488     /*
489      * Make signature
490      */
491     if( ( ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c,
492                             len, hash ) ) != 0 )
493     {
494         return( ret );
495     }
496 
497     if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
498                          f_rng, p_rng ) ) != 0 )
499     {
500         return( ret );
501     }
502 
503     /*
504      * Write data to output buffer
505      */
506     c2 = buf + size;
507     MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf,
508                                         sig_oid, sig_oid_len, sig, sig_len ) );
509 
510     if( len > (size_t)( c2 - buf ) )
511         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
512 
513     c2 -= len;
514     memcpy( c2, c, len );
515 
516     len += sig_and_oid_len;
517     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) );
518     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED |
519                                                  MBEDTLS_ASN1_SEQUENCE ) );
520 
521     return( (int) len );
522 }
523 
524 #define PEM_BEGIN_CRT           "-----BEGIN CERTIFICATE-----\n"
525 #define PEM_END_CRT             "-----END CERTIFICATE-----\n"
526 
527 #if defined(MBEDTLS_PEM_WRITE_C)
528 int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, unsigned char *buf, size_t size,
529                        int (*f_rng)(void *, unsigned char *, size_t),
530                        void *p_rng )
531 {
532     int ret;
533     unsigned char output_buf[4096];
534     size_t olen = 0;
535 
536     if( ( ret = mbedtls_x509write_crt_der( crt, output_buf, sizeof(output_buf),
537                                    f_rng, p_rng ) ) < 0 )
538     {
539         return( ret );
540     }
541 
542     if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
543                                   output_buf + sizeof(output_buf) - ret,
544                                   ret, buf, size, &olen ) ) != 0 )
545     {
546         return( ret );
547     }
548 
549     return( 0 );
550 }
551 #endif /* MBEDTLS_PEM_WRITE_C */
552 
553 #endif /* MBEDTLS_X509_CRT_WRITE_C */
554