1 /* 2 * X.509 certificate writing 3 * 4 * Copyright The Mbed TLS Contributors 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 /* 47 * References: 48 * - certificates: RFC 5280, updated by RFC 6818 49 * - CSRs: PKCS#10 v1.7 aka RFC 2986 50 * - attributes: PKCS#9 v2.0 aka RFC 2985 51 */ 52 53 #if !defined(MBEDTLS_CONFIG_FILE) 54 #include "mbedtls/config.h" 55 #else 56 #include MBEDTLS_CONFIG_FILE 57 #endif 58 59 #if defined(MBEDTLS_X509_CRT_WRITE_C) 60 61 #include "mbedtls/x509_crt.h" 62 #include "mbedtls/oid.h" 63 #include "mbedtls/asn1write.h" 64 #include "mbedtls/sha1.h" 65 #include "mbedtls/platform_util.h" 66 67 #include <string.h> 68 69 #if defined(MBEDTLS_PEM_WRITE_C) 70 #include "mbedtls/pem.h" 71 #endif /* MBEDTLS_PEM_WRITE_C */ 72 73 /* 74 * For the currently used signature algorithms the buffer to store any signature 75 * must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE) 76 */ 77 #if MBEDTLS_ECDSA_MAX_LEN > MBEDTLS_MPI_MAX_SIZE 78 #define SIGNATURE_MAX_SIZE MBEDTLS_ECDSA_MAX_LEN 79 #else 80 #define SIGNATURE_MAX_SIZE MBEDTLS_MPI_MAX_SIZE 81 #endif 82 83 void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ) 84 { 85 memset( ctx, 0, sizeof( mbedtls_x509write_cert ) ); 86 87 mbedtls_mpi_init( &ctx->serial ); 88 ctx->version = MBEDTLS_X509_CRT_VERSION_3; 89 } 90 91 void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ) 92 { 93 mbedtls_mpi_free( &ctx->serial ); 94 95 mbedtls_asn1_free_named_data_list( &ctx->subject ); 96 mbedtls_asn1_free_named_data_list( &ctx->issuer ); 97 mbedtls_asn1_free_named_data_list( &ctx->extensions ); 98 99 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_cert ) ); 100 } 101 102 void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, 103 int version ) 104 { 105 ctx->version = version; 106 } 107 108 void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, 109 mbedtls_md_type_t md_alg ) 110 { 111 ctx->md_alg = md_alg; 112 } 113 114 void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, 115 mbedtls_pk_context *key ) 116 { 117 ctx->subject_key = key; 118 } 119 120 void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, 121 mbedtls_pk_context *key ) 122 { 123 ctx->issuer_key = key; 124 } 125 126 int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, 127 const char *subject_name ) 128 { 129 return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); 130 } 131 132 int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, 133 const char *issuer_name ) 134 { 135 return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name ); 136 } 137 138 int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, 139 const mbedtls_mpi *serial ) 140 { 141 int ret; 142 143 if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 ) 144 return( ret ); 145 146 return( 0 ); 147 } 148 149 int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, 150 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, 193 max_pathlen ) ); 194 } 195 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) ); 196 } 197 198 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 199 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, 200 MBEDTLS_ASN1_CONSTRUCTED | 201 MBEDTLS_ASN1_SEQUENCE ) ); 202 203 return( 204 mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, 205 MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), 206 0, buf + sizeof(buf) - len, len ) ); 207 } 208 209 #if defined(MBEDTLS_SHA1_C) 210 int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ) 211 { 212 int ret; 213 unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ 214 unsigned char *c = buf + sizeof(buf); 215 size_t len = 0; 216 217 memset( buf, 0, sizeof(buf) ); 218 MBEDTLS_ASN1_CHK_ADD( len, 219 mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) ); 220 221 ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len, 222 buf + sizeof( buf ) - 20 ); 223 if( ret != 0 ) 224 return( ret ); 225 c = buf + sizeof( buf ) - 20; 226 len = 20; 227 228 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 229 MBEDTLS_ASN1_CHK_ADD( len, 230 mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) ); 231 232 return mbedtls_x509write_crt_set_extension( ctx, 233 MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER, 234 MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ), 235 0, buf + sizeof(buf) - len, len ); 236 } 237 238 int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ) 239 { 240 int ret; 241 unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ 242 unsigned char *c = buf + sizeof( buf ); 243 size_t len = 0; 244 245 memset( buf, 0, sizeof(buf) ); 246 MBEDTLS_ASN1_CHK_ADD( len, 247 mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) ); 248 249 ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len, 250 buf + sizeof( buf ) - 20 ); 251 if( ret != 0 ) 252 return( ret ); 253 c = buf + sizeof( buf ) - 20; 254 len = 20; 255 256 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 257 MBEDTLS_ASN1_CHK_ADD( len, 258 mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0 ) ); 259 260 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 261 MBEDTLS_ASN1_CHK_ADD( len, 262 mbedtls_asn1_write_tag( &c, buf, 263 MBEDTLS_ASN1_CONSTRUCTED | 264 MBEDTLS_ASN1_SEQUENCE ) ); 265 266 return mbedtls_x509write_crt_set_extension( 267 ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER, 268 MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ), 269 0, buf + sizeof( buf ) - len, len ); 270 } 271 #endif /* MBEDTLS_SHA1_C */ 272 273 static size_t crt_get_unused_bits_for_named_bitstring( unsigned char bitstring, 274 size_t bit_offset ) 275 { 276 size_t unused_bits; 277 278 /* Count the unused bits removing trailing 0s */ 279 for( unused_bits = bit_offset; unused_bits < 8; unused_bits++ ) 280 if( ( ( bitstring >> unused_bits ) & 0x1 ) != 0 ) 281 break; 282 283 return( unused_bits ); 284 } 285 286 int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, 287 unsigned int key_usage ) 288 { 289 unsigned char buf[4], ku; 290 unsigned char *c; 291 int ret; 292 size_t unused_bits; 293 const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE | 294 MBEDTLS_X509_KU_NON_REPUDIATION | 295 MBEDTLS_X509_KU_KEY_ENCIPHERMENT | 296 MBEDTLS_X509_KU_DATA_ENCIPHERMENT | 297 MBEDTLS_X509_KU_KEY_AGREEMENT | 298 MBEDTLS_X509_KU_KEY_CERT_SIGN | 299 MBEDTLS_X509_KU_CRL_SIGN; 300 301 /* Check that nothing other than the allowed flags is set */ 302 if( ( key_usage & ~allowed_bits ) != 0 ) 303 return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 304 305 c = buf + 4; 306 ku = (unsigned char)key_usage; 307 unused_bits = crt_get_unused_bits_for_named_bitstring( ku, 1 ); 308 ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 8 - unused_bits ); 309 310 if( ret < 0 ) 311 return( ret ); 312 else if( ret < 3 || ret > 4 ) 313 return( MBEDTLS_ERR_X509_INVALID_FORMAT ); 314 315 ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, 316 MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), 317 1, c, (size_t)ret ); 318 if( ret != 0 ) 319 return( ret ); 320 321 return( 0 ); 322 } 323 324 int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, 325 unsigned char ns_cert_type ) 326 { 327 unsigned char buf[4]; 328 unsigned char *c; 329 size_t unused_bits; 330 int ret; 331 332 c = buf + 4; 333 334 unused_bits = crt_get_unused_bits_for_named_bitstring( ns_cert_type, 0 ); 335 ret = mbedtls_asn1_write_bitstring( &c, 336 buf, 337 &ns_cert_type, 338 8 - unused_bits ); 339 if( ret < 3 || ret > 4 ) 340 return( ret ); 341 342 ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, 343 MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), 344 0, c, (size_t)ret ); 345 if( ret != 0 ) 346 return( ret ); 347 348 return( 0 ); 349 } 350 351 static int x509_write_time( unsigned char **p, unsigned char *start, 352 const char *t, size_t size ) 353 { 354 int ret; 355 size_t len = 0; 356 357 /* 358 * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) 359 */ 360 if( t[0] == '2' && t[1] == '0' && t[2] < '5' ) 361 { 362 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, 363 (const unsigned char *) t + 2, 364 size - 2 ) ); 365 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); 366 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, 367 MBEDTLS_ASN1_UTC_TIME ) ); 368 } 369 else 370 { 371 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, 372 (const unsigned char *) t, 373 size ) ); 374 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); 375 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, 376 MBEDTLS_ASN1_GENERALIZED_TIME ) ); 377 } 378 379 return( (int) len ); 380 } 381 382 int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, 383 unsigned char *buf, size_t size, 384 int (*f_rng)(void *, unsigned char *, size_t), 385 void *p_rng ) 386 { 387 int ret; 388 const char *sig_oid; 389 size_t sig_oid_len = 0; 390 unsigned char *c, *c2; 391 unsigned char hash[64]; 392 unsigned char sig[SIGNATURE_MAX_SIZE]; 393 size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len; 394 size_t len = 0; 395 mbedtls_pk_type_t pk_alg; 396 397 /* 398 * Prepare data to be signed at the end of the target buffer 399 */ 400 c = buf + size; 401 402 /* Signature algorithm needed in TBS, and later for actual signature */ 403 404 /* There's no direct way of extracting a signature algorithm 405 * (represented as an element of mbedtls_pk_type_t) from a PK instance. */ 406 if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_RSA ) ) 407 pk_alg = MBEDTLS_PK_RSA; 408 else if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_ECDSA ) ) 409 pk_alg = MBEDTLS_PK_ECDSA; 410 else 411 return( MBEDTLS_ERR_X509_INVALID_ALG ); 412 413 if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, 414 &sig_oid, &sig_oid_len ) ) != 0 ) 415 { 416 return( ret ); 417 } 418 419 /* 420 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension 421 */ 422 423 /* Only for v3 */ 424 if( ctx->version == MBEDTLS_X509_CRT_VERSION_3 ) 425 { 426 MBEDTLS_ASN1_CHK_ADD( len, 427 mbedtls_x509_write_extensions( &c, 428 buf, ctx->extensions ) ); 429 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 430 MBEDTLS_ASN1_CHK_ADD( len, 431 mbedtls_asn1_write_tag( &c, buf, 432 MBEDTLS_ASN1_CONSTRUCTED | 433 MBEDTLS_ASN1_SEQUENCE ) ); 434 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 435 MBEDTLS_ASN1_CHK_ADD( len, 436 mbedtls_asn1_write_tag( &c, buf, 437 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 438 MBEDTLS_ASN1_CONSTRUCTED | 3 ) ); 439 } 440 441 /* 442 * SubjectPublicKeyInfo 443 */ 444 MBEDTLS_ASN1_CHK_ADD( pub_len, 445 mbedtls_pk_write_pubkey_der( ctx->subject_key, 446 buf, c - buf ) ); 447 c -= pub_len; 448 len += pub_len; 449 450 /* 451 * Subject ::= Name 452 */ 453 MBEDTLS_ASN1_CHK_ADD( len, 454 mbedtls_x509_write_names( &c, buf, 455 ctx->subject ) ); 456 457 /* 458 * Validity ::= SEQUENCE { 459 * notBefore Time, 460 * notAfter Time } 461 */ 462 sub_len = 0; 463 464 MBEDTLS_ASN1_CHK_ADD( sub_len, 465 x509_write_time( &c, buf, ctx->not_after, 466 MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); 467 468 MBEDTLS_ASN1_CHK_ADD( sub_len, 469 x509_write_time( &c, buf, ctx->not_before, 470 MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); 471 472 len += sub_len; 473 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, sub_len ) ); 474 MBEDTLS_ASN1_CHK_ADD( len, 475 mbedtls_asn1_write_tag( &c, buf, 476 MBEDTLS_ASN1_CONSTRUCTED | 477 MBEDTLS_ASN1_SEQUENCE ) ); 478 479 /* 480 * Issuer ::= Name 481 */ 482 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, buf, 483 ctx->issuer ) ); 484 485 /* 486 * Signature ::= AlgorithmIdentifier 487 */ 488 MBEDTLS_ASN1_CHK_ADD( len, 489 mbedtls_asn1_write_algorithm_identifier( &c, buf, 490 sig_oid, strlen( sig_oid ), 0 ) ); 491 492 /* 493 * Serial ::= INTEGER 494 */ 495 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, 496 &ctx->serial ) ); 497 498 /* 499 * Version ::= INTEGER { v1(0), v2(1), v3(2) } 500 */ 501 502 /* Can be omitted for v1 */ 503 if( ctx->version != MBEDTLS_X509_CRT_VERSION_1 ) 504 { 505 sub_len = 0; 506 MBEDTLS_ASN1_CHK_ADD( sub_len, 507 mbedtls_asn1_write_int( &c, buf, ctx->version ) ); 508 len += sub_len; 509 MBEDTLS_ASN1_CHK_ADD( len, 510 mbedtls_asn1_write_len( &c, buf, sub_len ) ); 511 MBEDTLS_ASN1_CHK_ADD( len, 512 mbedtls_asn1_write_tag( &c, buf, 513 MBEDTLS_ASN1_CONTEXT_SPECIFIC | 514 MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); 515 } 516 517 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 518 MBEDTLS_ASN1_CHK_ADD( len, 519 mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | 520 MBEDTLS_ASN1_SEQUENCE ) ); 521 522 /* 523 * Make signature 524 */ 525 526 /* Compute hash of CRT. */ 527 if( ( ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, 528 len, hash ) ) != 0 ) 529 { 530 return( ret ); 531 } 532 533 if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, 534 hash, 0, sig, &sig_len, 535 f_rng, p_rng ) ) != 0 ) 536 { 537 return( ret ); 538 } 539 540 /* Move CRT to the front of the buffer to have space 541 * for the signature. */ 542 memmove( buf, c, len ); 543 c = buf + len; 544 545 /* Add signature at the end of the buffer, 546 * making sure that it doesn't underflow 547 * into the CRT buffer. */ 548 c2 = buf + size; 549 MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, c, 550 sig_oid, sig_oid_len, sig, sig_len ) ); 551 552 /* 553 * Memory layout after this step: 554 * 555 * buf c=buf+len c2 buf+size 556 * [CRT0,...,CRTn, UNUSED, ..., UNUSED, SIG0, ..., SIGm] 557 */ 558 559 /* Move raw CRT to just before the signature. */ 560 c = c2 - len; 561 memmove( c, buf, len ); 562 563 len += sig_and_oid_len; 564 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 565 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, 566 MBEDTLS_ASN1_CONSTRUCTED | 567 MBEDTLS_ASN1_SEQUENCE ) ); 568 569 return( (int) len ); 570 } 571 572 #define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" 573 #define PEM_END_CRT "-----END CERTIFICATE-----\n" 574 575 #if defined(MBEDTLS_PEM_WRITE_C) 576 int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, 577 unsigned char *buf, size_t size, 578 int (*f_rng)(void *, unsigned char *, size_t), 579 void *p_rng ) 580 { 581 int ret; 582 size_t olen; 583 584 if( ( ret = mbedtls_x509write_crt_der( crt, buf, size, 585 f_rng, p_rng ) ) < 0 ) 586 { 587 return( ret ); 588 } 589 590 if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT, 591 buf + size - ret, ret, 592 buf, size, &olen ) ) != 0 ) 593 { 594 return( ret ); 595 } 596 597 return( 0 ); 598 } 599 #endif /* MBEDTLS_PEM_WRITE_C */ 600 601 #endif /* MBEDTLS_X509_CRT_WRITE_C */ 602