1a8e1175bSopenharmony_ci/* 2a8e1175bSopenharmony_ci * Public Key layer for writing key files and structures 3a8e1175bSopenharmony_ci * 4a8e1175bSopenharmony_ci * Copyright The Mbed TLS Contributors 5a8e1175bSopenharmony_ci * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6a8e1175bSopenharmony_ci */ 7a8e1175bSopenharmony_ci 8a8e1175bSopenharmony_ci#include "common.h" 9a8e1175bSopenharmony_ci 10a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_WRITE_C) 11a8e1175bSopenharmony_ci 12a8e1175bSopenharmony_ci#include "mbedtls/pk.h" 13a8e1175bSopenharmony_ci#include "mbedtls/asn1write.h" 14a8e1175bSopenharmony_ci#include "mbedtls/oid.h" 15a8e1175bSopenharmony_ci#include "mbedtls/platform_util.h" 16a8e1175bSopenharmony_ci#include "mbedtls/error.h" 17a8e1175bSopenharmony_ci#include "pk_internal.h" 18a8e1175bSopenharmony_ci 19a8e1175bSopenharmony_ci#include <string.h> 20a8e1175bSopenharmony_ci 21a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 22a8e1175bSopenharmony_ci#include "mbedtls/bignum.h" 23a8e1175bSopenharmony_ci#include "mbedtls/ecp.h" 24a8e1175bSopenharmony_ci#include "mbedtls/platform_util.h" 25a8e1175bSopenharmony_ci#endif 26a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 27a8e1175bSopenharmony_ci#include "pk_internal.h" 28a8e1175bSopenharmony_ci#endif 29a8e1175bSopenharmony_ci#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_PK_HAVE_ECC_KEYS) 30a8e1175bSopenharmony_ci#include "pkwrite.h" 31a8e1175bSopenharmony_ci#endif 32a8e1175bSopenharmony_ci#if defined(MBEDTLS_PEM_WRITE_C) 33a8e1175bSopenharmony_ci#include "mbedtls/pem.h" 34a8e1175bSopenharmony_ci#endif 35a8e1175bSopenharmony_ci#if defined(MBEDTLS_RSA_C) 36a8e1175bSopenharmony_ci#include "rsa_internal.h" 37a8e1175bSopenharmony_ci#endif 38a8e1175bSopenharmony_ci 39a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO) 40a8e1175bSopenharmony_ci#include "psa/crypto.h" 41a8e1175bSopenharmony_ci#include "psa_util_internal.h" 42a8e1175bSopenharmony_ci#endif 43a8e1175bSopenharmony_ci#include "mbedtls/platform.h" 44a8e1175bSopenharmony_ci 45a8e1175bSopenharmony_ci/* Helpers for properly sizing buffers aimed at holding public keys or 46a8e1175bSopenharmony_ci * key-pairs based on build symbols. */ 47a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_USE_PSA_EC_DATA) 48a8e1175bSopenharmony_ci#define PK_MAX_EC_PUBLIC_KEY_SIZE PSA_EXPORT_PUBLIC_KEY_MAX_SIZE 49a8e1175bSopenharmony_ci#define PK_MAX_EC_KEY_PAIR_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH 50a8e1175bSopenharmony_ci#elif defined(MBEDTLS_USE_PSA_CRYPTO) 51a8e1175bSopenharmony_ci#define PK_MAX_EC_PUBLIC_KEY_SIZE PSA_EXPORT_PUBLIC_KEY_MAX_SIZE 52a8e1175bSopenharmony_ci#define PK_MAX_EC_KEY_PAIR_SIZE MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH 53a8e1175bSopenharmony_ci#else 54a8e1175bSopenharmony_ci#define PK_MAX_EC_PUBLIC_KEY_SIZE MBEDTLS_ECP_MAX_PT_LEN 55a8e1175bSopenharmony_ci#define PK_MAX_EC_KEY_PAIR_SIZE MBEDTLS_ECP_MAX_BYTES 56a8e1175bSopenharmony_ci#endif 57a8e1175bSopenharmony_ci 58a8e1175bSopenharmony_ci/****************************************************************************** 59a8e1175bSopenharmony_ci * Internal functions for RSA keys. 60a8e1175bSopenharmony_ci ******************************************************************************/ 61a8e1175bSopenharmony_ci#if defined(MBEDTLS_RSA_C) 62a8e1175bSopenharmony_cistatic int pk_write_rsa_der(unsigned char **p, unsigned char *buf, 63a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 64a8e1175bSopenharmony_ci{ 65a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO) 66a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) { 67a8e1175bSopenharmony_ci uint8_t tmp[PSA_EXPORT_KEY_PAIR_MAX_SIZE]; 68a8e1175bSopenharmony_ci size_t len = 0, tmp_len = 0; 69a8e1175bSopenharmony_ci 70a8e1175bSopenharmony_ci if (psa_export_key(pk->priv_id, tmp, sizeof(tmp), &tmp_len) != PSA_SUCCESS) { 71a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_BAD_INPUT_DATA; 72a8e1175bSopenharmony_ci } 73a8e1175bSopenharmony_ci *p -= tmp_len; 74a8e1175bSopenharmony_ci memcpy(*p, tmp, tmp_len); 75a8e1175bSopenharmony_ci len += tmp_len; 76a8e1175bSopenharmony_ci mbedtls_platform_zeroize(tmp, sizeof(tmp)); 77a8e1175bSopenharmony_ci 78a8e1175bSopenharmony_ci return (int) len; 79a8e1175bSopenharmony_ci } 80a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */ 81a8e1175bSopenharmony_ci return mbedtls_rsa_write_key(mbedtls_pk_rsa(*pk), buf, p); 82a8e1175bSopenharmony_ci} 83a8e1175bSopenharmony_ci#endif /* MBEDTLS_RSA_C */ 84a8e1175bSopenharmony_ci 85a8e1175bSopenharmony_ci/****************************************************************************** 86a8e1175bSopenharmony_ci * Internal functions for EC keys. 87a8e1175bSopenharmony_ci ******************************************************************************/ 88a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 89a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_USE_PSA_EC_DATA) 90a8e1175bSopenharmony_cistatic int pk_write_ec_pubkey(unsigned char **p, unsigned char *start, 91a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 92a8e1175bSopenharmony_ci{ 93a8e1175bSopenharmony_ci size_t len = 0; 94a8e1175bSopenharmony_ci uint8_t buf[PK_MAX_EC_PUBLIC_KEY_SIZE]; 95a8e1175bSopenharmony_ci 96a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) { 97a8e1175bSopenharmony_ci if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) { 98a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_BAD_INPUT_DATA; 99a8e1175bSopenharmony_ci } 100a8e1175bSopenharmony_ci } else { 101a8e1175bSopenharmony_ci len = pk->pub_raw_len; 102a8e1175bSopenharmony_ci memcpy(buf, pk->pub_raw, len); 103a8e1175bSopenharmony_ci } 104a8e1175bSopenharmony_ci 105a8e1175bSopenharmony_ci if (*p < start || (size_t) (*p - start) < len) { 106a8e1175bSopenharmony_ci return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 107a8e1175bSopenharmony_ci } 108a8e1175bSopenharmony_ci 109a8e1175bSopenharmony_ci *p -= len; 110a8e1175bSopenharmony_ci memcpy(*p, buf, len); 111a8e1175bSopenharmony_ci 112a8e1175bSopenharmony_ci return (int) len; 113a8e1175bSopenharmony_ci} 114a8e1175bSopenharmony_ci#else /* MBEDTLS_PK_USE_PSA_EC_DATA */ 115a8e1175bSopenharmony_cistatic int pk_write_ec_pubkey(unsigned char **p, unsigned char *start, 116a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 117a8e1175bSopenharmony_ci{ 118a8e1175bSopenharmony_ci size_t len = 0; 119a8e1175bSopenharmony_ci unsigned char buf[PK_MAX_EC_PUBLIC_KEY_SIZE]; 120a8e1175bSopenharmony_ci mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*pk); 121a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 122a8e1175bSopenharmony_ci 123a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO) 124a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) { 125a8e1175bSopenharmony_ci if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) { 126a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_BAD_INPUT_DATA; 127a8e1175bSopenharmony_ci } 128a8e1175bSopenharmony_ci *p -= len; 129a8e1175bSopenharmony_ci memcpy(*p, buf, len); 130a8e1175bSopenharmony_ci return (int) len; 131a8e1175bSopenharmony_ci } else 132a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */ 133a8e1175bSopenharmony_ci { 134a8e1175bSopenharmony_ci if ((ret = mbedtls_ecp_point_write_binary(&ec->grp, &ec->Q, 135a8e1175bSopenharmony_ci MBEDTLS_ECP_PF_UNCOMPRESSED, 136a8e1175bSopenharmony_ci &len, buf, sizeof(buf))) != 0) { 137a8e1175bSopenharmony_ci return ret; 138a8e1175bSopenharmony_ci } 139a8e1175bSopenharmony_ci } 140a8e1175bSopenharmony_ci 141a8e1175bSopenharmony_ci if (*p < start || (size_t) (*p - start) < len) { 142a8e1175bSopenharmony_ci return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 143a8e1175bSopenharmony_ci } 144a8e1175bSopenharmony_ci 145a8e1175bSopenharmony_ci *p -= len; 146a8e1175bSopenharmony_ci memcpy(*p, buf, len); 147a8e1175bSopenharmony_ci 148a8e1175bSopenharmony_ci return (int) len; 149a8e1175bSopenharmony_ci} 150a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */ 151a8e1175bSopenharmony_ci 152a8e1175bSopenharmony_ci/* 153a8e1175bSopenharmony_ci * privateKey OCTET STRING -- always of length ceil(log2(n)/8) 154a8e1175bSopenharmony_ci */ 155a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_USE_PSA_EC_DATA) 156a8e1175bSopenharmony_cistatic int pk_write_ec_private(unsigned char **p, unsigned char *start, 157a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 158a8e1175bSopenharmony_ci{ 159a8e1175bSopenharmony_ci size_t byte_length; 160a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 161a8e1175bSopenharmony_ci unsigned char tmp[PK_MAX_EC_KEY_PAIR_SIZE]; 162a8e1175bSopenharmony_ci psa_status_t status; 163a8e1175bSopenharmony_ci 164a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) { 165a8e1175bSopenharmony_ci status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length); 166a8e1175bSopenharmony_ci if (status != PSA_SUCCESS) { 167a8e1175bSopenharmony_ci ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status); 168a8e1175bSopenharmony_ci return ret; 169a8e1175bSopenharmony_ci } 170a8e1175bSopenharmony_ci } else { 171a8e1175bSopenharmony_ci status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length); 172a8e1175bSopenharmony_ci if (status != PSA_SUCCESS) { 173a8e1175bSopenharmony_ci ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status); 174a8e1175bSopenharmony_ci goto exit; 175a8e1175bSopenharmony_ci } 176a8e1175bSopenharmony_ci } 177a8e1175bSopenharmony_ci 178a8e1175bSopenharmony_ci ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length); 179a8e1175bSopenharmony_ciexit: 180a8e1175bSopenharmony_ci mbedtls_platform_zeroize(tmp, sizeof(tmp)); 181a8e1175bSopenharmony_ci return ret; 182a8e1175bSopenharmony_ci} 183a8e1175bSopenharmony_ci#else /* MBEDTLS_PK_USE_PSA_EC_DATA */ 184a8e1175bSopenharmony_cistatic int pk_write_ec_private(unsigned char **p, unsigned char *start, 185a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 186a8e1175bSopenharmony_ci{ 187a8e1175bSopenharmony_ci size_t byte_length; 188a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 189a8e1175bSopenharmony_ci unsigned char tmp[PK_MAX_EC_KEY_PAIR_SIZE]; 190a8e1175bSopenharmony_ci 191a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO) 192a8e1175bSopenharmony_ci psa_status_t status; 193a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) { 194a8e1175bSopenharmony_ci status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length); 195a8e1175bSopenharmony_ci if (status != PSA_SUCCESS) { 196a8e1175bSopenharmony_ci ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status); 197a8e1175bSopenharmony_ci return ret; 198a8e1175bSopenharmony_ci } 199a8e1175bSopenharmony_ci } else 200a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */ 201a8e1175bSopenharmony_ci { 202a8e1175bSopenharmony_ci mbedtls_ecp_keypair *ec = mbedtls_pk_ec_rw(*pk); 203a8e1175bSopenharmony_ci byte_length = (ec->grp.pbits + 7) / 8; 204a8e1175bSopenharmony_ci 205a8e1175bSopenharmony_ci ret = mbedtls_ecp_write_key_ext(ec, &byte_length, tmp, sizeof(tmp)); 206a8e1175bSopenharmony_ci if (ret != 0) { 207a8e1175bSopenharmony_ci goto exit; 208a8e1175bSopenharmony_ci } 209a8e1175bSopenharmony_ci } 210a8e1175bSopenharmony_ci ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length); 211a8e1175bSopenharmony_ciexit: 212a8e1175bSopenharmony_ci mbedtls_platform_zeroize(tmp, sizeof(tmp)); 213a8e1175bSopenharmony_ci return ret; 214a8e1175bSopenharmony_ci} 215a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */ 216a8e1175bSopenharmony_ci 217a8e1175bSopenharmony_ci/* 218a8e1175bSopenharmony_ci * ECParameters ::= CHOICE { 219a8e1175bSopenharmony_ci * namedCurve OBJECT IDENTIFIER 220a8e1175bSopenharmony_ci * } 221a8e1175bSopenharmony_ci */ 222a8e1175bSopenharmony_cistatic int pk_write_ec_param(unsigned char **p, unsigned char *start, 223a8e1175bSopenharmony_ci mbedtls_ecp_group_id grp_id) 224a8e1175bSopenharmony_ci{ 225a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 226a8e1175bSopenharmony_ci size_t len = 0; 227a8e1175bSopenharmony_ci const char *oid; 228a8e1175bSopenharmony_ci size_t oid_len; 229a8e1175bSopenharmony_ci 230a8e1175bSopenharmony_ci if ((ret = mbedtls_oid_get_oid_by_ec_grp(grp_id, &oid, &oid_len)) != 0) { 231a8e1175bSopenharmony_ci return ret; 232a8e1175bSopenharmony_ci } 233a8e1175bSopenharmony_ci 234a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len)); 235a8e1175bSopenharmony_ci 236a8e1175bSopenharmony_ci return (int) len; 237a8e1175bSopenharmony_ci} 238a8e1175bSopenharmony_ci 239a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES) 240a8e1175bSopenharmony_ci/* 241a8e1175bSopenharmony_ci * RFC8410 section 7 242a8e1175bSopenharmony_ci * 243a8e1175bSopenharmony_ci * OneAsymmetricKey ::= SEQUENCE { 244a8e1175bSopenharmony_ci * version Version, 245a8e1175bSopenharmony_ci * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 246a8e1175bSopenharmony_ci * privateKey PrivateKey, 247a8e1175bSopenharmony_ci * attributes [0] IMPLICIT Attributes OPTIONAL, 248a8e1175bSopenharmony_ci * ..., 249a8e1175bSopenharmony_ci * [[2: publicKey [1] IMPLICIT PublicKey OPTIONAL ]], 250a8e1175bSopenharmony_ci * ... 251a8e1175bSopenharmony_ci * } 252a8e1175bSopenharmony_ci * ... 253a8e1175bSopenharmony_ci * CurvePrivateKey ::= OCTET STRING 254a8e1175bSopenharmony_ci */ 255a8e1175bSopenharmony_cistatic int pk_write_ec_rfc8410_der(unsigned char **p, unsigned char *buf, 256a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 257a8e1175bSopenharmony_ci{ 258a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 259a8e1175bSopenharmony_ci size_t len = 0; 260a8e1175bSopenharmony_ci size_t oid_len = 0; 261a8e1175bSopenharmony_ci const char *oid; 262a8e1175bSopenharmony_ci mbedtls_ecp_group_id grp_id; 263a8e1175bSopenharmony_ci 264a8e1175bSopenharmony_ci /* privateKey */ 265a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk)); 266a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len)); 267a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_OCTET_STRING)); 268a8e1175bSopenharmony_ci 269a8e1175bSopenharmony_ci grp_id = mbedtls_pk_get_ec_group_id(pk); 270a8e1175bSopenharmony_ci /* privateKeyAlgorithm */ 271a8e1175bSopenharmony_ci if ((ret = mbedtls_oid_get_oid_by_ec_grp_algid(grp_id, &oid, &oid_len)) != 0) { 272a8e1175bSopenharmony_ci return ret; 273a8e1175bSopenharmony_ci } 274a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, 275a8e1175bSopenharmony_ci mbedtls_asn1_write_algorithm_identifier_ext(p, buf, oid, oid_len, 0, 0)); 276a8e1175bSopenharmony_ci 277a8e1175bSopenharmony_ci /* version */ 278a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0)); 279a8e1175bSopenharmony_ci 280a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len)); 281a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED | 282a8e1175bSopenharmony_ci MBEDTLS_ASN1_SEQUENCE)); 283a8e1175bSopenharmony_ci 284a8e1175bSopenharmony_ci return (int) len; 285a8e1175bSopenharmony_ci} 286a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */ 287a8e1175bSopenharmony_ci 288a8e1175bSopenharmony_ci/* 289a8e1175bSopenharmony_ci * RFC 5915, or SEC1 Appendix C.4 290a8e1175bSopenharmony_ci * 291a8e1175bSopenharmony_ci * ECPrivateKey ::= SEQUENCE { 292a8e1175bSopenharmony_ci * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), 293a8e1175bSopenharmony_ci * privateKey OCTET STRING, 294a8e1175bSopenharmony_ci * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, 295a8e1175bSopenharmony_ci * publicKey [1] BIT STRING OPTIONAL 296a8e1175bSopenharmony_ci * } 297a8e1175bSopenharmony_ci */ 298a8e1175bSopenharmony_cistatic int pk_write_ec_der(unsigned char **p, unsigned char *buf, 299a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 300a8e1175bSopenharmony_ci{ 301a8e1175bSopenharmony_ci size_t len = 0; 302a8e1175bSopenharmony_ci int ret; 303a8e1175bSopenharmony_ci size_t pub_len = 0, par_len = 0; 304a8e1175bSopenharmony_ci mbedtls_ecp_group_id grp_id; 305a8e1175bSopenharmony_ci 306a8e1175bSopenharmony_ci /* publicKey */ 307a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(pub_len, pk_write_ec_pubkey(p, buf, pk)); 308a8e1175bSopenharmony_ci 309a8e1175bSopenharmony_ci if (*p - buf < 1) { 310a8e1175bSopenharmony_ci return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 311a8e1175bSopenharmony_ci } 312a8e1175bSopenharmony_ci (*p)--; 313a8e1175bSopenharmony_ci **p = 0; 314a8e1175bSopenharmony_ci pub_len += 1; 315a8e1175bSopenharmony_ci 316a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len)); 317a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_BIT_STRING)); 318a8e1175bSopenharmony_ci 319a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len)); 320a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf, 321a8e1175bSopenharmony_ci MBEDTLS_ASN1_CONTEXT_SPECIFIC | 322a8e1175bSopenharmony_ci MBEDTLS_ASN1_CONSTRUCTED | 1)); 323a8e1175bSopenharmony_ci len += pub_len; 324a8e1175bSopenharmony_ci 325a8e1175bSopenharmony_ci /* parameters */ 326a8e1175bSopenharmony_ci grp_id = mbedtls_pk_get_ec_group_id(pk); 327a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(p, buf, grp_id)); 328a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_len(p, buf, par_len)); 329a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_tag(p, buf, 330a8e1175bSopenharmony_ci MBEDTLS_ASN1_CONTEXT_SPECIFIC | 331a8e1175bSopenharmony_ci MBEDTLS_ASN1_CONSTRUCTED | 0)); 332a8e1175bSopenharmony_ci len += par_len; 333a8e1175bSopenharmony_ci 334a8e1175bSopenharmony_ci /* privateKey */ 335a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk)); 336a8e1175bSopenharmony_ci 337a8e1175bSopenharmony_ci /* version */ 338a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 1)); 339a8e1175bSopenharmony_ci 340a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len)); 341a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED | 342a8e1175bSopenharmony_ci MBEDTLS_ASN1_SEQUENCE)); 343a8e1175bSopenharmony_ci 344a8e1175bSopenharmony_ci return (int) len; 345a8e1175bSopenharmony_ci} 346a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ 347a8e1175bSopenharmony_ci 348a8e1175bSopenharmony_ci/****************************************************************************** 349a8e1175bSopenharmony_ci * Internal functions for Opaque keys. 350a8e1175bSopenharmony_ci ******************************************************************************/ 351a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO) 352a8e1175bSopenharmony_cistatic int pk_write_opaque_pubkey(unsigned char **p, unsigned char *start, 353a8e1175bSopenharmony_ci const mbedtls_pk_context *pk) 354a8e1175bSopenharmony_ci{ 355a8e1175bSopenharmony_ci size_t buffer_size; 356a8e1175bSopenharmony_ci size_t len = 0; 357a8e1175bSopenharmony_ci 358a8e1175bSopenharmony_ci if (*p < start) { 359a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_BAD_INPUT_DATA; 360a8e1175bSopenharmony_ci } 361a8e1175bSopenharmony_ci 362a8e1175bSopenharmony_ci buffer_size = (size_t) (*p - start); 363a8e1175bSopenharmony_ci if (psa_export_public_key(pk->priv_id, start, buffer_size, 364a8e1175bSopenharmony_ci &len) != PSA_SUCCESS) { 365a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_BAD_INPUT_DATA; 366a8e1175bSopenharmony_ci } 367a8e1175bSopenharmony_ci 368a8e1175bSopenharmony_ci *p -= len; 369a8e1175bSopenharmony_ci memmove(*p, start, len); 370a8e1175bSopenharmony_ci 371a8e1175bSopenharmony_ci return (int) len; 372a8e1175bSopenharmony_ci} 373a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */ 374a8e1175bSopenharmony_ci 375a8e1175bSopenharmony_ci/****************************************************************************** 376a8e1175bSopenharmony_ci * Generic helpers 377a8e1175bSopenharmony_ci ******************************************************************************/ 378a8e1175bSopenharmony_ci 379a8e1175bSopenharmony_ci/* Extend the public mbedtls_pk_get_type() by getting key type also in case of 380a8e1175bSopenharmony_ci * opaque keys. */ 381a8e1175bSopenharmony_cistatic mbedtls_pk_type_t pk_get_type_ext(const mbedtls_pk_context *pk) 382a8e1175bSopenharmony_ci{ 383a8e1175bSopenharmony_ci mbedtls_pk_type_t pk_type = mbedtls_pk_get_type(pk); 384a8e1175bSopenharmony_ci 385a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO) 386a8e1175bSopenharmony_ci if (pk_type == MBEDTLS_PK_OPAQUE) { 387a8e1175bSopenharmony_ci psa_key_attributes_t opaque_attrs = PSA_KEY_ATTRIBUTES_INIT; 388a8e1175bSopenharmony_ci psa_key_type_t opaque_key_type; 389a8e1175bSopenharmony_ci 390a8e1175bSopenharmony_ci if (psa_get_key_attributes(pk->priv_id, &opaque_attrs) != PSA_SUCCESS) { 391a8e1175bSopenharmony_ci return MBEDTLS_PK_NONE; 392a8e1175bSopenharmony_ci } 393a8e1175bSopenharmony_ci opaque_key_type = psa_get_key_type(&opaque_attrs); 394a8e1175bSopenharmony_ci psa_reset_key_attributes(&opaque_attrs); 395a8e1175bSopenharmony_ci 396a8e1175bSopenharmony_ci if (PSA_KEY_TYPE_IS_ECC(opaque_key_type)) { 397a8e1175bSopenharmony_ci return MBEDTLS_PK_ECKEY; 398a8e1175bSopenharmony_ci } else if (PSA_KEY_TYPE_IS_RSA(opaque_key_type)) { 399a8e1175bSopenharmony_ci return MBEDTLS_PK_RSA; 400a8e1175bSopenharmony_ci } else { 401a8e1175bSopenharmony_ci return MBEDTLS_PK_NONE; 402a8e1175bSopenharmony_ci } 403a8e1175bSopenharmony_ci } else 404a8e1175bSopenharmony_ci#endif 405a8e1175bSopenharmony_ci return pk_type; 406a8e1175bSopenharmony_ci} 407a8e1175bSopenharmony_ci 408a8e1175bSopenharmony_ci/****************************************************************************** 409a8e1175bSopenharmony_ci * Public functions for writing private/public DER keys. 410a8e1175bSopenharmony_ci ******************************************************************************/ 411a8e1175bSopenharmony_ciint mbedtls_pk_write_pubkey(unsigned char **p, unsigned char *start, 412a8e1175bSopenharmony_ci const mbedtls_pk_context *key) 413a8e1175bSopenharmony_ci{ 414a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 415a8e1175bSopenharmony_ci size_t len = 0; 416a8e1175bSopenharmony_ci 417a8e1175bSopenharmony_ci#if defined(MBEDTLS_RSA_C) 418a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) { 419a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_rsa_write_pubkey(mbedtls_pk_rsa(*key), start, p)); 420a8e1175bSopenharmony_ci } else 421a8e1175bSopenharmony_ci#endif 422a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 423a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) { 424a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_pubkey(p, start, key)); 425a8e1175bSopenharmony_ci } else 426a8e1175bSopenharmony_ci#endif 427a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO) 428a8e1175bSopenharmony_ci if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) { 429a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, pk_write_opaque_pubkey(p, start, key)); 430a8e1175bSopenharmony_ci } else 431a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */ 432a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE; 433a8e1175bSopenharmony_ci 434a8e1175bSopenharmony_ci return (int) len; 435a8e1175bSopenharmony_ci} 436a8e1175bSopenharmony_ci 437a8e1175bSopenharmony_ciint mbedtls_pk_write_pubkey_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size) 438a8e1175bSopenharmony_ci{ 439a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 440a8e1175bSopenharmony_ci unsigned char *c; 441a8e1175bSopenharmony_ci int has_par = 1; 442a8e1175bSopenharmony_ci size_t len = 0, par_len = 0, oid_len = 0; 443a8e1175bSopenharmony_ci mbedtls_pk_type_t pk_type; 444a8e1175bSopenharmony_ci const char *oid = NULL; 445a8e1175bSopenharmony_ci 446a8e1175bSopenharmony_ci if (size == 0) { 447a8e1175bSopenharmony_ci return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 448a8e1175bSopenharmony_ci } 449a8e1175bSopenharmony_ci 450a8e1175bSopenharmony_ci c = buf + size; 451a8e1175bSopenharmony_ci 452a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_pk_write_pubkey(&c, buf, key)); 453a8e1175bSopenharmony_ci 454a8e1175bSopenharmony_ci if (c - buf < 1) { 455a8e1175bSopenharmony_ci return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 456a8e1175bSopenharmony_ci } 457a8e1175bSopenharmony_ci 458a8e1175bSopenharmony_ci /* 459a8e1175bSopenharmony_ci * SubjectPublicKeyInfo ::= SEQUENCE { 460a8e1175bSopenharmony_ci * algorithm AlgorithmIdentifier, 461a8e1175bSopenharmony_ci * subjectPublicKey BIT STRING } 462a8e1175bSopenharmony_ci */ 463a8e1175bSopenharmony_ci *--c = 0; 464a8e1175bSopenharmony_ci len += 1; 465a8e1175bSopenharmony_ci 466a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 467a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_BIT_STRING)); 468a8e1175bSopenharmony_ci 469a8e1175bSopenharmony_ci pk_type = pk_get_type_ext(key); 470a8e1175bSopenharmony_ci 471a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 472a8e1175bSopenharmony_ci if (pk_get_type_ext(key) == MBEDTLS_PK_ECKEY) { 473a8e1175bSopenharmony_ci mbedtls_ecp_group_id ec_grp_id = mbedtls_pk_get_ec_group_id(key); 474a8e1175bSopenharmony_ci if (MBEDTLS_PK_IS_RFC8410_GROUP_ID(ec_grp_id)) { 475a8e1175bSopenharmony_ci ret = mbedtls_oid_get_oid_by_ec_grp_algid(ec_grp_id, &oid, &oid_len); 476a8e1175bSopenharmony_ci if (ret != 0) { 477a8e1175bSopenharmony_ci return ret; 478a8e1175bSopenharmony_ci } 479a8e1175bSopenharmony_ci has_par = 0; 480a8e1175bSopenharmony_ci } else { 481a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(&c, buf, ec_grp_id)); 482a8e1175bSopenharmony_ci } 483a8e1175bSopenharmony_ci } 484a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ 485a8e1175bSopenharmony_ci 486a8e1175bSopenharmony_ci /* At this point oid_len is not null only for EC Montgomery keys. */ 487a8e1175bSopenharmony_ci if (oid_len == 0) { 488a8e1175bSopenharmony_ci ret = mbedtls_oid_get_oid_by_pk_alg(pk_type, &oid, &oid_len); 489a8e1175bSopenharmony_ci if (ret != 0) { 490a8e1175bSopenharmony_ci return ret; 491a8e1175bSopenharmony_ci } 492a8e1175bSopenharmony_ci } 493a8e1175bSopenharmony_ci 494a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_algorithm_identifier_ext(&c, buf, oid, oid_len, 495a8e1175bSopenharmony_ci par_len, has_par)); 496a8e1175bSopenharmony_ci 497a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); 498a8e1175bSopenharmony_ci MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | 499a8e1175bSopenharmony_ci MBEDTLS_ASN1_SEQUENCE)); 500a8e1175bSopenharmony_ci 501a8e1175bSopenharmony_ci return (int) len; 502a8e1175bSopenharmony_ci} 503a8e1175bSopenharmony_ci 504a8e1175bSopenharmony_ciint mbedtls_pk_write_key_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size) 505a8e1175bSopenharmony_ci{ 506a8e1175bSopenharmony_ci unsigned char *c; 507a8e1175bSopenharmony_ci 508a8e1175bSopenharmony_ci if (size == 0) { 509a8e1175bSopenharmony_ci return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL; 510a8e1175bSopenharmony_ci } 511a8e1175bSopenharmony_ci 512a8e1175bSopenharmony_ci c = buf + size; 513a8e1175bSopenharmony_ci 514a8e1175bSopenharmony_ci#if defined(MBEDTLS_RSA_C) 515a8e1175bSopenharmony_ci if (pk_get_type_ext(key) == MBEDTLS_PK_RSA) { 516a8e1175bSopenharmony_ci return pk_write_rsa_der(&c, buf, key); 517a8e1175bSopenharmony_ci } else 518a8e1175bSopenharmony_ci#endif /* MBEDTLS_RSA_C */ 519a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 520a8e1175bSopenharmony_ci if (pk_get_type_ext(key) == MBEDTLS_PK_ECKEY) { 521a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES) 522a8e1175bSopenharmony_ci if (mbedtls_pk_is_rfc8410(key)) { 523a8e1175bSopenharmony_ci return pk_write_ec_rfc8410_der(&c, buf, key); 524a8e1175bSopenharmony_ci } 525a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */ 526a8e1175bSopenharmony_ci return pk_write_ec_der(&c, buf, key); 527a8e1175bSopenharmony_ci } else 528a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ 529a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE; 530a8e1175bSopenharmony_ci} 531a8e1175bSopenharmony_ci 532a8e1175bSopenharmony_ci/****************************************************************************** 533a8e1175bSopenharmony_ci * Public functions for wrinting private/public PEM keys. 534a8e1175bSopenharmony_ci ******************************************************************************/ 535a8e1175bSopenharmony_ci#if defined(MBEDTLS_PEM_WRITE_C) 536a8e1175bSopenharmony_ci 537a8e1175bSopenharmony_ci#define PUB_DER_MAX_BYTES \ 538a8e1175bSopenharmony_ci (MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES > MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES ? \ 539a8e1175bSopenharmony_ci MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES : MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES) 540a8e1175bSopenharmony_ci#define PRV_DER_MAX_BYTES \ 541a8e1175bSopenharmony_ci (MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES > MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES ? \ 542a8e1175bSopenharmony_ci MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES : MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES) 543a8e1175bSopenharmony_ci 544a8e1175bSopenharmony_ciint mbedtls_pk_write_pubkey_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size) 545a8e1175bSopenharmony_ci{ 546a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 547a8e1175bSopenharmony_ci unsigned char *output_buf = NULL; 548a8e1175bSopenharmony_ci output_buf = mbedtls_calloc(1, PUB_DER_MAX_BYTES); 549a8e1175bSopenharmony_ci if (output_buf == NULL) { 550a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_ALLOC_FAILED; 551a8e1175bSopenharmony_ci } 552a8e1175bSopenharmony_ci size_t olen = 0; 553a8e1175bSopenharmony_ci 554a8e1175bSopenharmony_ci if ((ret = mbedtls_pk_write_pubkey_der(key, output_buf, 555a8e1175bSopenharmony_ci PUB_DER_MAX_BYTES)) < 0) { 556a8e1175bSopenharmony_ci goto cleanup; 557a8e1175bSopenharmony_ci } 558a8e1175bSopenharmony_ci 559a8e1175bSopenharmony_ci if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_PUBLIC_KEY "\n", PEM_END_PUBLIC_KEY "\n", 560a8e1175bSopenharmony_ci output_buf + PUB_DER_MAX_BYTES - ret, 561a8e1175bSopenharmony_ci ret, buf, size, &olen)) != 0) { 562a8e1175bSopenharmony_ci goto cleanup; 563a8e1175bSopenharmony_ci } 564a8e1175bSopenharmony_ci 565a8e1175bSopenharmony_ci ret = 0; 566a8e1175bSopenharmony_cicleanup: 567a8e1175bSopenharmony_ci mbedtls_free(output_buf); 568a8e1175bSopenharmony_ci return ret; 569a8e1175bSopenharmony_ci} 570a8e1175bSopenharmony_ci 571a8e1175bSopenharmony_ciint mbedtls_pk_write_key_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size) 572a8e1175bSopenharmony_ci{ 573a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 574a8e1175bSopenharmony_ci unsigned char *output_buf = NULL; 575a8e1175bSopenharmony_ci output_buf = mbedtls_calloc(1, PRV_DER_MAX_BYTES); 576a8e1175bSopenharmony_ci if (output_buf == NULL) { 577a8e1175bSopenharmony_ci return MBEDTLS_ERR_PK_ALLOC_FAILED; 578a8e1175bSopenharmony_ci } 579a8e1175bSopenharmony_ci const char *begin, *end; 580a8e1175bSopenharmony_ci size_t olen = 0; 581a8e1175bSopenharmony_ci 582a8e1175bSopenharmony_ci if ((ret = mbedtls_pk_write_key_der(key, output_buf, PRV_DER_MAX_BYTES)) < 0) { 583a8e1175bSopenharmony_ci goto cleanup; 584a8e1175bSopenharmony_ci } 585a8e1175bSopenharmony_ci 586a8e1175bSopenharmony_ci#if defined(MBEDTLS_RSA_C) 587a8e1175bSopenharmony_ci if (pk_get_type_ext(key) == MBEDTLS_PK_RSA) { 588a8e1175bSopenharmony_ci begin = PEM_BEGIN_PRIVATE_KEY_RSA "\n"; 589a8e1175bSopenharmony_ci end = PEM_END_PRIVATE_KEY_RSA "\n"; 590a8e1175bSopenharmony_ci } else 591a8e1175bSopenharmony_ci#endif 592a8e1175bSopenharmony_ci#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) 593a8e1175bSopenharmony_ci if (pk_get_type_ext(key) == MBEDTLS_PK_ECKEY) { 594a8e1175bSopenharmony_ci if (mbedtls_pk_is_rfc8410(key)) { 595a8e1175bSopenharmony_ci begin = PEM_BEGIN_PRIVATE_KEY_PKCS8 "\n"; 596a8e1175bSopenharmony_ci end = PEM_END_PRIVATE_KEY_PKCS8 "\n"; 597a8e1175bSopenharmony_ci } else { 598a8e1175bSopenharmony_ci begin = PEM_BEGIN_PRIVATE_KEY_EC "\n"; 599a8e1175bSopenharmony_ci end = PEM_END_PRIVATE_KEY_EC "\n"; 600a8e1175bSopenharmony_ci } 601a8e1175bSopenharmony_ci } else 602a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ 603a8e1175bSopenharmony_ci { 604a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE; 605a8e1175bSopenharmony_ci goto cleanup; 606a8e1175bSopenharmony_ci } 607a8e1175bSopenharmony_ci 608a8e1175bSopenharmony_ci if ((ret = mbedtls_pem_write_buffer(begin, end, 609a8e1175bSopenharmony_ci output_buf + PRV_DER_MAX_BYTES - ret, 610a8e1175bSopenharmony_ci ret, buf, size, &olen)) != 0) { 611a8e1175bSopenharmony_ci goto cleanup; 612a8e1175bSopenharmony_ci } 613a8e1175bSopenharmony_ci 614a8e1175bSopenharmony_ci ret = 0; 615a8e1175bSopenharmony_cicleanup: 616a8e1175bSopenharmony_ci mbedtls_zeroize_and_free(output_buf, PRV_DER_MAX_BYTES); 617a8e1175bSopenharmony_ci return ret; 618a8e1175bSopenharmony_ci} 619a8e1175bSopenharmony_ci#endif /* MBEDTLS_PEM_WRITE_C */ 620a8e1175bSopenharmony_ci 621a8e1175bSopenharmony_ci#endif /* MBEDTLS_PK_WRITE_C */ 622