Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
pkwrite.c
00001 /* 00002 * Public Key layer for writing key files and structures 00003 * 00004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 00005 * SPDX-License-Identifier: Apache-2.0 00006 * 00007 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00008 * not use this file except in compliance with the License. 00009 * You may obtain a copy of the License at 00010 * 00011 * http://www.apache.org/licenses/LICENSE-2.0 00012 * 00013 * Unless required by applicable law or agreed to in writing, software 00014 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00015 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 * See the License for the specific language governing permissions and 00017 * limitations under the License. 00018 * 00019 * This file is part of mbed TLS (https://tls.mbed.org) 00020 */ 00021 00022 #if !defined(MBEDTLS_CONFIG_FILE) 00023 #include "mbedtls/config.h" 00024 #else 00025 #include MBEDTLS_CONFIG_FILE 00026 #endif 00027 00028 #if defined(MBEDTLS_PK_WRITE_C) 00029 00030 #include "mbedtls/pk.h" 00031 #include "mbedtls/asn1write.h" 00032 #include "mbedtls/oid.h" 00033 00034 #include <string.h> 00035 00036 #if defined(MBEDTLS_RSA_C) 00037 #include "mbedtls/rsa.h" 00038 #endif 00039 #if defined(MBEDTLS_ECP_C) 00040 #include "mbedtls/ecp.h" 00041 #endif 00042 #if defined(MBEDTLS_ECDSA_C) 00043 #include "mbedtls/ecdsa.h" 00044 #endif 00045 #if defined(MBEDTLS_PEM_WRITE_C) 00046 #include "mbedtls/pem.h" 00047 #endif 00048 00049 #if defined(MBEDTLS_PLATFORM_C) 00050 #include "mbedtls/platform.h" 00051 #else 00052 #include <stdlib.h> 00053 #define mbedtls_calloc calloc 00054 #define mbedtls_free free 00055 #endif 00056 00057 #if defined(MBEDTLS_RSA_C) 00058 /* 00059 * RSAPublicKey ::= SEQUENCE { 00060 * modulus INTEGER, -- n 00061 * publicExponent INTEGER -- e 00062 * } 00063 */ 00064 static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start, 00065 mbedtls_rsa_context *rsa ) 00066 { 00067 int ret; 00068 size_t len = 0; 00069 mbedtls_mpi T; 00070 00071 mbedtls_mpi_init( &T ); 00072 00073 /* Export E */ 00074 if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, NULL, NULL, &T ) ) != 0 || 00075 ( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 ) 00076 goto end_of_export; 00077 len += ret; 00078 00079 /* Export N */ 00080 if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL, NULL, NULL, NULL ) ) != 0 || 00081 ( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 ) 00082 goto end_of_export; 00083 len += ret; 00084 00085 end_of_export: 00086 00087 mbedtls_mpi_free( &T ); 00088 if( ret < 0 ) 00089 return( ret ); 00090 00091 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); 00092 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | 00093 MBEDTLS_ASN1_SEQUENCE ) ); 00094 00095 return( (int) len ); 00096 } 00097 #endif /* MBEDTLS_RSA_C */ 00098 00099 #if defined(MBEDTLS_ECP_C) 00100 /* 00101 * EC public key is an EC point 00102 */ 00103 static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start, 00104 mbedtls_ecp_keypair *ec ) 00105 { 00106 int ret; 00107 size_t len = 0; 00108 unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN]; 00109 00110 if( ( ret = mbedtls_ecp_point_write_binary( &ec->grp , &ec->Q , 00111 MBEDTLS_ECP_PF_UNCOMPRESSED, 00112 &len, buf, sizeof( buf ) ) ) != 0 ) 00113 { 00114 return( ret ); 00115 } 00116 00117 if( *p < start || (size_t)( *p - start ) < len ) 00118 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 00119 00120 *p -= len; 00121 memcpy( *p, buf, len ); 00122 00123 return( (int) len ); 00124 } 00125 00126 /* 00127 * ECParameters ::= CHOICE { 00128 * namedCurve OBJECT IDENTIFIER 00129 * } 00130 */ 00131 static int pk_write_ec_param( unsigned char **p, unsigned char *start, 00132 mbedtls_ecp_keypair *ec ) 00133 { 00134 int ret; 00135 size_t len = 0; 00136 const char *oid; 00137 size_t oid_len; 00138 00139 if( ( ret = mbedtls_oid_get_oid_by_ec_grp( ec->grp .id , &oid, &oid_len ) ) != 0 ) 00140 return( ret ); 00141 00142 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); 00143 00144 return( (int) len ); 00145 } 00146 #endif /* MBEDTLS_ECP_C */ 00147 00148 int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, 00149 const mbedtls_pk_context *key ) 00150 { 00151 int ret; 00152 size_t len = 0; 00153 00154 #if defined(MBEDTLS_RSA_C) 00155 if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) 00156 MBEDTLS_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedtls_pk_rsa( *key ) ) ); 00157 else 00158 #endif 00159 #if defined(MBEDTLS_ECP_C) 00160 if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) 00161 MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, mbedtls_pk_ec( *key ) ) ); 00162 else 00163 #endif 00164 return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 00165 00166 return( (int) len ); 00167 } 00168 00169 int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) 00170 { 00171 int ret; 00172 unsigned char *c; 00173 size_t len = 0, par_len = 0, oid_len; 00174 const char *oid; 00175 00176 c = buf + size; 00177 00178 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) ); 00179 00180 if( c - buf < 1 ) 00181 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 00182 00183 /* 00184 * SubjectPublicKeyInfo ::= SEQUENCE { 00185 * algorithm AlgorithmIdentifier, 00186 * subjectPublicKey BIT STRING } 00187 */ 00188 *--c = 0; 00189 len += 1; 00190 00191 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 00192 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); 00193 00194 if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ), 00195 &oid, &oid_len ) ) != 0 ) 00196 { 00197 return( ret ); 00198 } 00199 00200 #if defined(MBEDTLS_ECP_C) 00201 if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) 00202 { 00203 MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) ); 00204 } 00205 #endif 00206 00207 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len, 00208 par_len ) ); 00209 00210 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 00211 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | 00212 MBEDTLS_ASN1_SEQUENCE ) ); 00213 00214 return( (int) len ); 00215 } 00216 00217 int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) 00218 { 00219 int ret; 00220 unsigned char *c = buf + size; 00221 size_t len = 0; 00222 00223 #if defined(MBEDTLS_RSA_C) 00224 if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) 00225 { 00226 mbedtls_mpi T; /* Temporary holding the exported parameters */ 00227 mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *key ); 00228 00229 /* 00230 * Export the parameters one after another to avoid simultaneous copies. 00231 */ 00232 00233 mbedtls_mpi_init( &T ); 00234 00235 /* Export QP */ 00236 if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, NULL, &T ) ) != 0 || 00237 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00238 goto end_of_export; 00239 len += ret; 00240 00241 /* Export DQ */ 00242 if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, &T, NULL ) ) != 0 || 00243 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00244 goto end_of_export; 00245 len += ret; 00246 00247 /* Export DP */ 00248 if( ( ret = mbedtls_rsa_export_crt( rsa, &T, NULL, NULL ) ) != 0 || 00249 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00250 goto end_of_export; 00251 len += ret; 00252 00253 /* Export Q */ 00254 if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, 00255 &T, NULL, NULL ) ) != 0 || 00256 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00257 goto end_of_export; 00258 len += ret; 00259 00260 /* Export P */ 00261 if ( ( ret = mbedtls_rsa_export( rsa, NULL, &T, 00262 NULL, NULL, NULL ) ) != 0 || 00263 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00264 goto end_of_export; 00265 len += ret; 00266 00267 /* Export D */ 00268 if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, 00269 NULL, &T, NULL ) ) != 0 || 00270 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00271 goto end_of_export; 00272 len += ret; 00273 00274 /* Export E */ 00275 if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, 00276 NULL, NULL, &T ) ) != 0 || 00277 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00278 goto end_of_export; 00279 len += ret; 00280 00281 /* Export N */ 00282 if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL, 00283 NULL, NULL, NULL ) ) != 0 || 00284 ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) 00285 goto end_of_export; 00286 len += ret; 00287 00288 end_of_export: 00289 00290 mbedtls_mpi_free( &T ); 00291 if( ret < 0 ) 00292 return( ret ); 00293 00294 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) ); 00295 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 00296 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, 00297 buf, MBEDTLS_ASN1_CONSTRUCTED | 00298 MBEDTLS_ASN1_SEQUENCE ) ); 00299 } 00300 else 00301 #endif /* MBEDTLS_RSA_C */ 00302 #if defined(MBEDTLS_ECP_C) 00303 if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) 00304 { 00305 mbedtls_ecp_keypair *ec = mbedtls_pk_ec( *key ); 00306 size_t pub_len = 0, par_len = 0; 00307 00308 /* 00309 * RFC 5915, or SEC1 Appendix C.4 00310 * 00311 * ECPrivateKey ::= SEQUENCE { 00312 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), 00313 * privateKey OCTET STRING, 00314 * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, 00315 * publicKey [1] BIT STRING OPTIONAL 00316 * } 00317 */ 00318 00319 /* publicKey */ 00320 MBEDTLS_ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) ); 00321 00322 if( c - buf < 1 ) 00323 return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); 00324 *--c = 0; 00325 pub_len += 1; 00326 00327 MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); 00328 MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); 00329 00330 MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); 00331 MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, 00332 MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ); 00333 len += pub_len; 00334 00335 /* parameters */ 00336 MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) ); 00337 00338 MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_len( &c, buf, par_len ) ); 00339 MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_tag( &c, buf, 00340 MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); 00341 len += par_len; 00342 00343 /* privateKey: write as MPI then fix tag */ 00344 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) ); 00345 *c = MBEDTLS_ASN1_OCTET_STRING; 00346 00347 /* version */ 00348 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) ); 00349 00350 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); 00351 MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | 00352 MBEDTLS_ASN1_SEQUENCE ) ); 00353 } 00354 else 00355 #endif /* MBEDTLS_ECP_C */ 00356 return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 00357 00358 return( (int) len ); 00359 } 00360 00361 #if defined(MBEDTLS_PEM_WRITE_C) 00362 00363 #define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n" 00364 #define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n" 00365 00366 #define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n" 00367 #define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n" 00368 #define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n" 00369 #define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n" 00370 00371 /* 00372 * Max sizes of key per types. Shown as tag + len (+ content). 00373 */ 00374 00375 #if defined(MBEDTLS_RSA_C) 00376 /* 00377 * RSA public keys: 00378 * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3 00379 * algorithm AlgorithmIdentifier, 1 + 1 (sequence) 00380 * + 1 + 1 + 9 (rsa oid) 00381 * + 1 + 1 (params null) 00382 * subjectPublicKey BIT STRING } 1 + 3 + (1 + below) 00383 * RSAPublicKey ::= SEQUENCE { 1 + 3 00384 * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1 00385 * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1 00386 * } 00387 */ 00388 #define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE 00389 00390 /* 00391 * RSA private keys: 00392 * RSAPrivateKey ::= SEQUENCE { 1 + 3 00393 * version Version, 1 + 1 + 1 00394 * modulus INTEGER, 1 + 3 + MPI_MAX + 1 00395 * publicExponent INTEGER, 1 + 3 + MPI_MAX + 1 00396 * privateExponent INTEGER, 1 + 3 + MPI_MAX + 1 00397 * prime1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 00398 * prime2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 00399 * exponent1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 00400 * exponent2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 00401 * coefficient INTEGER, 1 + 3 + MPI_MAX / 2 + 1 00402 * otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported) 00403 * } 00404 */ 00405 #define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \ 00406 MBEDTLS_MPI_MAX_SIZE % 2 00407 #define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \ 00408 + 5 * MPI_MAX_SIZE_2 00409 00410 #else /* MBEDTLS_RSA_C */ 00411 00412 #define RSA_PUB_DER_MAX_BYTES 0 00413 #define RSA_PRV_DER_MAX_BYTES 0 00414 00415 #endif /* MBEDTLS_RSA_C */ 00416 00417 #if defined(MBEDTLS_ECP_C) 00418 /* 00419 * EC public keys: 00420 * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2 00421 * algorithm AlgorithmIdentifier, 1 + 1 (sequence) 00422 * + 1 + 1 + 7 (ec oid) 00423 * + 1 + 1 + 9 (namedCurve oid) 00424 * subjectPublicKey BIT STRING 1 + 2 + 1 [1] 00425 * + 1 (point format) [1] 00426 * + 2 * ECP_MAX (coords) [1] 00427 * } 00428 */ 00429 #define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES 00430 00431 /* 00432 * EC private keys: 00433 * ECPrivateKey ::= SEQUENCE { 1 + 2 00434 * version INTEGER , 1 + 1 + 1 00435 * privateKey OCTET STRING, 1 + 1 + ECP_MAX 00436 * parameters [0] ECParameters OPTIONAL, 1 + 1 + (1 + 1 + 9) 00437 * publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above 00438 * } 00439 */ 00440 #define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES 00441 00442 #else /* MBEDTLS_ECP_C */ 00443 00444 #define ECP_PUB_DER_MAX_BYTES 0 00445 #define ECP_PRV_DER_MAX_BYTES 0 00446 00447 #endif /* MBEDTLS_ECP_C */ 00448 00449 #define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ 00450 RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES 00451 #define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \ 00452 RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES 00453 00454 int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) 00455 { 00456 int ret; 00457 unsigned char output_buf[PUB_DER_MAX_BYTES]; 00458 size_t olen = 0; 00459 00460 if( ( ret = mbedtls_pk_write_pubkey_der( key, output_buf, 00461 sizeof(output_buf) ) ) < 0 ) 00462 { 00463 return( ret ); 00464 } 00465 00466 if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, 00467 output_buf + sizeof(output_buf) - ret, 00468 ret, buf, size, &olen ) ) != 0 ) 00469 { 00470 return( ret ); 00471 } 00472 00473 return( 0 ); 00474 } 00475 00476 int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) 00477 { 00478 int ret; 00479 unsigned char output_buf[PRV_DER_MAX_BYTES]; 00480 const char *begin, *end; 00481 size_t olen = 0; 00482 00483 if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) 00484 return( ret ); 00485 00486 #if defined(MBEDTLS_RSA_C) 00487 if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) 00488 { 00489 begin = PEM_BEGIN_PRIVATE_KEY_RSA; 00490 end = PEM_END_PRIVATE_KEY_RSA; 00491 } 00492 else 00493 #endif 00494 #if defined(MBEDTLS_ECP_C) 00495 if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) 00496 { 00497 begin = PEM_BEGIN_PRIVATE_KEY_EC; 00498 end = PEM_END_PRIVATE_KEY_EC; 00499 } 00500 else 00501 #endif 00502 return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 00503 00504 if( ( ret = mbedtls_pem_write_buffer( begin, end, 00505 output_buf + sizeof(output_buf) - ret, 00506 ret, buf, size, &olen ) ) != 0 ) 00507 { 00508 return( ret ); 00509 } 00510 00511 return( 0 ); 00512 } 00513 #endif /* MBEDTLS_PEM_WRITE_C */ 00514 00515 #endif /* MBEDTLS_PK_WRITE_C */
Generated on Tue Jul 12 2022 18:18:46 by
