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