1 /*
2  *  X.509 certificate writing
3  *
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5  *  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.
18  *
19  *  This file is part of mbed TLS (https://tls.mbed.org)
20  */
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 
28 #if !defined(MBEDTLS_CONFIG_FILE)
29 #include "mbedtls/config.h"
30 #else
31 #include MBEDTLS_CONFIG_FILE
32 #endif
33 
34 #if defined(MBEDTLS_X509_CRT_WRITE_C)
35 
36 #include "mbedtls/x509_crt.h"
37 #include "mbedtls/oid.h"
38 #include "mbedtls/asn1write.h"
39 #include "mbedtls/sha1.h"
40 #include "mbedtls/platform_util.h"
41 
42 #include <string.h>
43 
44 #if defined(MBEDTLS_PEM_WRITE_C)
45 #include "mbedtls/pem.h"
46 #endif /* MBEDTLS_PEM_WRITE_C */
47 
mbedtls_x509write_crt_init(mbedtls_x509write_cert * ctx)48 void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx )
49 {
50     memset( ctx, 0, sizeof( mbedtls_x509write_cert ) );
51 
52     mbedtls_mpi_init( &ctx->serial );
53     ctx->version = MBEDTLS_X509_CRT_VERSION_3;
54 }
55 
mbedtls_x509write_crt_free(mbedtls_x509write_cert * ctx)56 void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx )
57 {
58     mbedtls_mpi_free( &ctx->serial );
59 
60     mbedtls_asn1_free_named_data_list( &ctx->subject );
61     mbedtls_asn1_free_named_data_list( &ctx->issuer );
62     mbedtls_asn1_free_named_data_list( &ctx->extensions );
63 
64     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
65 }
66 
mbedtls_x509write_crt_set_version(mbedtls_x509write_cert * ctx,int version)67 void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version )
68 {
69     ctx->version = version;
70 }
71 
mbedtls_x509write_crt_set_md_alg(mbedtls_x509write_cert * ctx,mbedtls_md_type_t md_alg)72 void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg )
73 {
74     ctx->md_alg = md_alg;
75 }
76 
mbedtls_x509write_crt_set_subject_key(mbedtls_x509write_cert * ctx,mbedtls_pk_context * key)77 void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
78 {
79     ctx->subject_key = key;
80 }
81 
mbedtls_x509write_crt_set_issuer_key(mbedtls_x509write_cert * ctx,mbedtls_pk_context * key)82 void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
83 {
84     ctx->issuer_key = key;
85 }
86 
mbedtls_x509write_crt_set_subject_name(mbedtls_x509write_cert * ctx,const char * subject_name)87 int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx,
88                                     const char *subject_name )
89 {
90     return mbedtls_x509_string_to_names( &ctx->subject, subject_name );
91 }
92 
mbedtls_x509write_crt_set_issuer_name(mbedtls_x509write_cert * ctx,const char * issuer_name)93 int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx,
94                                    const char *issuer_name )
95 {
96     return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name );
97 }
98 
mbedtls_x509write_crt_set_serial(mbedtls_x509write_cert * ctx,const mbedtls_mpi * serial)99 int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial )
100 {
101     int ret;
102 
103     if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 )
104         return( ret );
105 
106     return( 0 );
107 }
108 
mbedtls_x509write_crt_set_validity(mbedtls_x509write_cert * ctx,const char * not_before,const char * not_after)109 int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before,
110                                 const char *not_after )
111 {
112     if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ||
113         strlen( not_after )  != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 )
114     {
115         return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
116     }
117     strncpy( ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
118     strncpy( ctx->not_after , not_after , MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
119     ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
120     ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
121 
122     return( 0 );
123 }
124 
mbedtls_x509write_crt_set_extension(mbedtls_x509write_cert * ctx,const char * oid,size_t oid_len,int critical,const unsigned char * val,size_t val_len)125 int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx,
126                                  const char *oid, size_t oid_len,
127                                  int critical,
128                                  const unsigned char *val, size_t val_len )
129 {
130     return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len,
131                                critical, val, val_len );
132 }
133 
mbedtls_x509write_crt_set_basic_constraints(mbedtls_x509write_cert * ctx,int is_ca,int max_pathlen)134 int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx,
135                                          int is_ca, int max_pathlen )
136 {
137     int ret;
138     unsigned char buf[9];
139     unsigned char *c = buf + sizeof(buf);
140     size_t len = 0;
141 
142     memset( buf, 0, sizeof(buf) );
143 
144     if( is_ca && max_pathlen > 127 )
145         return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
146 
147     if( is_ca )
148     {
149         if( max_pathlen >= 0 )
150         {
151             MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) );
152         }
153         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) );
154     }
155 
156     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
157     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
158                                                 MBEDTLS_ASN1_SEQUENCE ) );
159 
160     return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
161                                         MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ),
162                                         0, buf + sizeof(buf) - len, len );
163 }
164 
165 #if defined(MBEDTLS_SHA1_C)
mbedtls_x509write_crt_set_subject_key_identifier(mbedtls_x509write_cert * ctx)166 int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx )
167 {
168     int ret;
169     unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
170     unsigned char *c = buf + sizeof(buf);
171     size_t len = 0;
172 
173     memset( buf, 0, sizeof(buf) );
174     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) );
175 
176     ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
177                             buf + sizeof( buf ) - 20 );
178     if( ret != 0 )
179         return( ret );
180     c = buf + sizeof( buf ) - 20;
181     len = 20;
182 
183     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
184     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) );
185 
186     return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
187                                         MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ),
188                                         0, buf + sizeof(buf) - len, len );
189 }
190 
mbedtls_x509write_crt_set_authority_key_identifier(mbedtls_x509write_cert * ctx)191 int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx )
192 {
193     int ret;
194     unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
195     unsigned char *c = buf + sizeof( buf );
196     size_t len = 0;
197 
198     memset( buf, 0, sizeof(buf) );
199     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) );
200 
201     ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
202                             buf + sizeof( buf ) - 20 );
203     if( ret != 0 )
204         return( ret );
205     c = buf + sizeof( buf ) - 20;
206     len = 20;
207 
208     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
209     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0 ) );
210 
211     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
212     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
213                                                 MBEDTLS_ASN1_SEQUENCE ) );
214 
215     return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
216                                    MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
217                                    0, buf + sizeof( buf ) - len, len );
218 }
219 #endif /* MBEDTLS_SHA1_C */
220 
mbedtls_x509write_crt_set_key_usage(mbedtls_x509write_cert * ctx,unsigned int key_usage)221 int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx,
222                                          unsigned int key_usage )
223 {
224     unsigned char buf[4], ku;
225     unsigned char *c;
226     int ret;
227 
228     /* We currently only support 7 bits, from 0x80 to 0x02 */
229     if( ( key_usage & ~0xfe ) != 0 )
230         return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
231 
232     c = buf + 4;
233     ku = (unsigned char) key_usage;
234 
235     if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 )
236         return( ret );
237 
238     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
239                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
240                                        1, buf, 4 );
241     if( ret != 0 )
242         return( ret );
243 
244     return( 0 );
245 }
246 
mbedtls_x509write_crt_set_ns_cert_type(mbedtls_x509write_cert * ctx,unsigned char ns_cert_type)247 int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
248                                     unsigned char ns_cert_type )
249 {
250     unsigned char buf[4];
251     unsigned char *c;
252     int ret;
253 
254     c = buf + 4;
255 
256     if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
257         return( ret );
258 
259     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
260                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
261                                        0, buf, 4 );
262     if( ret != 0 )
263         return( ret );
264 
265     return( 0 );
266 }
267 
x509_write_time(unsigned char ** p,unsigned char * start,const char * t,size_t size)268 static int x509_write_time( unsigned char **p, unsigned char *start,
269                             const char *t, size_t size )
270 {
271     int ret;
272     size_t len = 0;
273 
274     /*
275      * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
276      */
277     if( t[0] == '2' && t[1] == '0' && t[2] < '5' )
278     {
279         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
280                                              (const unsigned char *) t + 2,
281                                              size - 2 ) );
282         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
283         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_UTC_TIME ) );
284     }
285     else
286     {
287         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
288                                                   (const unsigned char *) t,
289                                                   size ) );
290         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
291         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_GENERALIZED_TIME ) );
292     }
293 
294     return( (int) len );
295 }
296 
mbedtls_x509write_crt_der(mbedtls_x509write_cert * ctx,unsigned char * buf,size_t size,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)297 int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size,
298                        int (*f_rng)(void *, unsigned char *, size_t),
299                        void *p_rng )
300 {
301     int ret;
302     const char *sig_oid;
303     size_t sig_oid_len = 0;
304     unsigned char *c, *c2;
305     unsigned char hash[64];
306     unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
307     unsigned char tmp_buf[2048];
308     size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
309     size_t len = 0;
310     mbedtls_pk_type_t pk_alg;
311 
312     /*
313      * Prepare data to be signed in tmp_buf
314      */
315     c = tmp_buf + sizeof( tmp_buf );
316 
317     /* Signature algorithm needed in TBS, and later for actual signature */
318 
319     /* There's no direct way of extracting a signature algorithm
320      * (represented as an element of mbedtls_pk_type_t) from a PK instance. */
321     if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_RSA ) )
322         pk_alg = MBEDTLS_PK_RSA;
323     else if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_ECDSA ) )
324         pk_alg = MBEDTLS_PK_ECDSA;
325     else
326         return( MBEDTLS_ERR_X509_INVALID_ALG );
327 
328     if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
329                                           &sig_oid, &sig_oid_len ) ) != 0 )
330     {
331         return( ret );
332     }
333 
334     /*
335      *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
336      */
337 
338     /* Only for v3 */
339     if( ctx->version == MBEDTLS_X509_CRT_VERSION_3 )
340     {
341         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
342         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
343         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
344                                                            MBEDTLS_ASN1_SEQUENCE ) );
345         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
346         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
347                                                            MBEDTLS_ASN1_CONSTRUCTED | 3 ) );
348     }
349 
350     /*
351      *  SubjectPublicKeyInfo
352      */
353     MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->subject_key,
354                                                 tmp_buf, c - tmp_buf ) );
355     c -= pub_len;
356     len += pub_len;
357 
358     /*
359      *  Subject  ::=  Name
360      */
361     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) );
362 
363     /*
364      *  Validity ::= SEQUENCE {
365      *       notBefore      Time,
366      *       notAfter       Time }
367      */
368     sub_len = 0;
369 
370     MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
371                                             MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
372 
373     MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
374                                             MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
375 
376     len += sub_len;
377     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
378     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
379                                                     MBEDTLS_ASN1_SEQUENCE ) );
380 
381     /*
382      *  Issuer  ::=  Name
383      */
384     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->issuer ) );
385 
386     /*
387      *  Signature   ::=  AlgorithmIdentifier
388      */
389     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, tmp_buf,
390                        sig_oid, strlen( sig_oid ), 0 ) );
391 
392     /*
393      *  Serial   ::=  INTEGER
394      */
395     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
396 
397     /*
398      *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
399      */
400 
401     /* Can be omitted for v1 */
402     if( ctx->version != MBEDTLS_X509_CRT_VERSION_1 )
403     {
404         sub_len = 0;
405         MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) );
406         len += sub_len;
407         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
408         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
409                                                            MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
410     }
411 
412     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
413     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
414                                                        MBEDTLS_ASN1_SEQUENCE ) );
415 
416     /*
417      * Make signature
418      */
419     if( ( ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c,
420                             len, hash ) ) != 0 )
421     {
422         return( ret );
423     }
424 
425     if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
426                          f_rng, p_rng ) ) != 0 )
427     {
428         return( ret );
429     }
430 
431     /*
432      * Write data to output buffer
433      */
434     c2 = buf + size;
435     MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf,
436                                         sig_oid, sig_oid_len, sig, sig_len ) );
437 
438     if( len > (size_t)( c2 - buf ) )
439         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
440 
441     c2 -= len;
442     memcpy( c2, c, len );
443 
444     len += sig_and_oid_len;
445     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) );
446     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED |
447                                                  MBEDTLS_ASN1_SEQUENCE ) );
448 
449     return( (int) len );
450 }
451 
452 #define PEM_BEGIN_CRT           "-----BEGIN CERTIFICATE-----\n"
453 #define PEM_END_CRT             "-----END CERTIFICATE-----\n"
454 
455 #if defined(MBEDTLS_PEM_WRITE_C)
mbedtls_x509write_crt_pem(mbedtls_x509write_cert * crt,unsigned char * buf,size_t size,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)456 int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, unsigned char *buf, size_t size,
457                        int (*f_rng)(void *, unsigned char *, size_t),
458                        void *p_rng )
459 {
460     int ret;
461     unsigned char output_buf[4096];
462     size_t olen = 0;
463 
464     if( ( ret = mbedtls_x509write_crt_der( crt, output_buf, sizeof(output_buf),
465                                    f_rng, p_rng ) ) < 0 )
466     {
467         return( ret );
468     }
469 
470     if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
471                                   output_buf + sizeof(output_buf) - ret,
472                                   ret, buf, size, &olen ) ) != 0 )
473     {
474         return( ret );
475     }
476 
477     return( 0 );
478 }
479 #endif /* MBEDTLS_PEM_WRITE_C */
480 
481 #endif /* MBEDTLS_X509_CRT_WRITE_C */
482