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