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