blob: 30008b992d5724e42e64be279a21ead4b192a0e4 [file] [log] [blame]
Paul Bakkerc7bb02b2013-09-15 14:54:56 +02001/*
2 * Public Key layer for writing key files and structures
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman16799db2023-11-02 19:47:20 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakkerc7bb02b2013-09-15 14:54:56 +02006 */
7
Gilles Peskinedb09ef62020-06-03 01:43:33 +02008#include "common.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +02009
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020010#if defined(MBEDTLS_PK_WRITE_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020011
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000012#include "mbedtls/pk.h"
13#include "mbedtls/asn1write.h"
14#include "mbedtls/oid.h"
Andrzej Kurekc470b6b2019-01-31 08:20:20 -050015#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000016#include "mbedtls/error.h"
Valerio Setti77a75682023-05-15 11:18:46 +020017#include "pk_internal.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020018
Rich Evans00ab4702015-02-06 13:43:58 +000019#include <string.h>
20
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020021#if defined(MBEDTLS_ECP_C)
Gilles Peskine2700cfb2018-08-11 00:48:44 +020022#include "mbedtls/bignum.h"
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000023#include "mbedtls/ecp.h"
Gilles Peskine2700cfb2018-08-11 00:48:44 +020024#include "mbedtls/platform_util.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020025#endif
Valerio Setti81d75122023-06-14 14:49:33 +020026#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Valerio Setti4064dbb2023-05-17 15:33:07 +020027#include "pk_internal.h"
28#endif
Valerio Setti81d75122023-06-14 14:49:33 +020029#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Neil Armstronge0326a62022-02-25 08:57:19 +010030#include "pkwrite.h"
31#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032#if defined(MBEDTLS_PEM_WRITE_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000033#include "mbedtls/pem.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020034#endif
35
Andrzej Kurek5fec0862018-11-19 10:07:36 -050036#if defined(MBEDTLS_USE_PSA_CRYPTO)
37#include "psa/crypto.h"
Manuel Pégourié-Gonnard2be8c632023-06-07 13:07:21 +020038#include "psa_util_internal.h"
Andrzej Kurek5fec0862018-11-19 10:07:36 -050039#endif
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000040#include "mbedtls/platform.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020041
Valerio Setti605f03c2023-11-28 12:46:39 +010042/******************************************************************************
43 * Internal functions for RSA keys.
44 ******************************************************************************/
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020045#if defined(MBEDTLS_RSA_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020046/*
47 * RSAPublicKey ::= SEQUENCE {
48 * modulus INTEGER, -- n
49 * publicExponent INTEGER -- e
50 * }
51 */
Gilles Peskine449bd832023-01-11 14:50:10 +010052static int pk_write_rsa_pubkey(unsigned char **p, unsigned char *start,
valerio9ea26172023-05-31 12:10:23 +020053 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020054{
Janos Follath24eed8d2019-11-22 13:21:35 +000055 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020056 size_t len = 0;
Hanno Becker15f81fa2017-08-23 12:38:27 +010057 mbedtls_mpi T;
valerio9ea26172023-05-31 12:10:23 +020058 mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020059
Gilles Peskine449bd832023-01-11 14:50:10 +010060 mbedtls_mpi_init(&T);
Hanno Becker15f81fa2017-08-23 12:38:27 +010061
62 /* Export E */
Gilles Peskine449bd832023-01-11 14:50:10 +010063 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, NULL, &T)) != 0 ||
64 (ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +010065 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +010066 }
Hanno Becker15f81fa2017-08-23 12:38:27 +010067 len += ret;
68
69 /* Export N */
Gilles Peskine449bd832023-01-11 14:50:10 +010070 if ((ret = mbedtls_rsa_export(rsa, &T, NULL, NULL, NULL, NULL)) != 0 ||
71 (ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +010072 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +010073 }
Hanno Becker15f81fa2017-08-23 12:38:27 +010074 len += ret;
75
76end_of_export:
77
Gilles Peskine449bd832023-01-11 14:50:10 +010078 mbedtls_mpi_free(&T);
79 if (ret < 0) {
80 return ret;
81 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020082
Gilles Peskine449bd832023-01-11 14:50:10 +010083 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
84 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED |
85 MBEDTLS_ASN1_SEQUENCE));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020086
Gilles Peskine449bd832023-01-11 14:50:10 +010087 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020088}
Valerio Setti605f03c2023-11-28 12:46:39 +010089
90static int pk_write_rsa_der(unsigned char **p, unsigned char *buf,
91 const mbedtls_pk_context *pk)
92{
93 size_t len = 0;
94 int ret;
95
96#if defined(MBEDTLS_USE_PSA_CRYPTO)
97 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
98 uint8_t tmp[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
99 size_t tmp_len = 0;
100
101 if (psa_export_key(pk->priv_id, tmp, sizeof(tmp), &tmp_len) != PSA_SUCCESS) {
102 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
103 }
104 *p -= tmp_len;
105 memcpy(*p, tmp, tmp_len);
106 len += tmp_len;
107 mbedtls_platform_zeroize(tmp, sizeof(tmp));
108 } else
109#endif /* MBEDTLS_USE_PSA_CRYPTO */
110 {
111 mbedtls_mpi T; /* Temporary holding the exported parameters */
112 mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
113
114 /*
115 * Export the parameters one after another to avoid simultaneous copies.
116 */
117
118 mbedtls_mpi_init(&T);
119
120 /* Export QP */
121 if ((ret = mbedtls_rsa_export_crt(rsa, NULL, NULL, &T)) != 0 ||
122 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
123 goto end_of_export;
124 }
125 len += ret;
126
127 /* Export DQ */
128 if ((ret = mbedtls_rsa_export_crt(rsa, NULL, &T, NULL)) != 0 ||
129 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
130 goto end_of_export;
131 }
132 len += ret;
133
134 /* Export DP */
135 if ((ret = mbedtls_rsa_export_crt(rsa, &T, NULL, NULL)) != 0 ||
136 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
137 goto end_of_export;
138 }
139 len += ret;
140
141 /* Export Q */
142 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
143 &T, NULL, NULL)) != 0 ||
144 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
145 goto end_of_export;
146 }
147 len += ret;
148
149 /* Export P */
150 if ((ret = mbedtls_rsa_export(rsa, NULL, &T,
151 NULL, NULL, NULL)) != 0 ||
152 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
153 goto end_of_export;
154 }
155 len += ret;
156
157 /* Export D */
158 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
159 NULL, &T, NULL)) != 0 ||
160 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
161 goto end_of_export;
162 }
163 len += ret;
164
165 /* Export E */
166 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
167 NULL, NULL, &T)) != 0 ||
168 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
169 goto end_of_export;
170 }
171 len += ret;
172
173 /* Export N */
174 if ((ret = mbedtls_rsa_export(rsa, &T, NULL,
175 NULL, NULL, NULL)) != 0 ||
176 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
177 goto end_of_export;
178 }
179 len += ret;
180
181end_of_export:
182
183 mbedtls_mpi_free(&T);
184 if (ret < 0) {
185 return ret;
186 }
187
188 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0));
189 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
190 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p,
191 buf, MBEDTLS_ASN1_CONSTRUCTED |
192 MBEDTLS_ASN1_SEQUENCE));
193 }
194
195 return (int) len;
196}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200197#endif /* MBEDTLS_RSA_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200198
Valerio Setti605f03c2023-11-28 12:46:39 +0100199/******************************************************************************
200 * Internal functions for EC keys.
201 ******************************************************************************/
Valerio Setti81d75122023-06-14 14:49:33 +0200202#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerio9ea26172023-05-31 12:10:23 +0200203#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
Gilles Peskine449bd832023-01-11 14:50:10 +0100204static int pk_write_ec_pubkey(unsigned char **p, unsigned char *start,
Valerio Setti4064dbb2023-05-17 15:33:07 +0200205 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200206{
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200207 size_t len = 0;
Valerio Settie1d7c9d2023-08-10 07:40:18 +0200208 uint8_t buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
Valerio Setti4064dbb2023-05-17 15:33:07 +0200209
valerio9ea26172023-05-31 12:10:23 +0200210 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
211 if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) {
212 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
213 }
214 } else {
215 len = pk->pub_raw_len;
valeriof9139e52023-05-31 18:01:33 +0200216 memcpy(buf, pk->pub_raw, len);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200217 }
218
Gilles Peskine449bd832023-01-11 14:50:10 +0100219 if (*p < start || (size_t) (*p - start) < len) {
220 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
221 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200222
223 *p -= len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100224 memcpy(*p, buf, len);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200225
Gilles Peskine449bd832023-01-11 14:50:10 +0100226 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200227}
valerio9ea26172023-05-31 12:10:23 +0200228#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
229static int pk_write_ec_pubkey(unsigned char **p, unsigned char *start,
230 const mbedtls_pk_context *pk)
231{
232 size_t len = 0;
233#if defined(MBEDTLS_USE_PSA_CRYPTO)
234 uint8_t buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
235#else
236 unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN];
237#endif /* MBEDTLS_USE_PSA_CRYPTO */
238 mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*pk);
239 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
240
241#if defined(MBEDTLS_USE_PSA_CRYPTO)
242 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
243 if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) {
244 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
245 }
246 *p -= len;
247 memcpy(*p, buf, len);
248 return (int) len;
249 } else
250#endif /* MBEDTLS_USE_PSA_CRYPTO */
251 {
252 if ((ret = mbedtls_ecp_point_write_binary(&ec->grp, &ec->Q,
253 MBEDTLS_ECP_PF_UNCOMPRESSED,
254 &len, buf, sizeof(buf))) != 0) {
255 return ret;
256 }
257 }
258
259 if (*p < start || (size_t) (*p - start) < len) {
260 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
261 }
262
263 *p -= len;
264 memcpy(*p, buf, len);
265
266 return (int) len;
267}
268#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200269
270/*
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200271 * privateKey OCTET STRING -- always of length ceil(log2(n)/8)
272 */
valerio52b675f2023-05-31 12:14:37 +0200273#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
Gilles Peskine449bd832023-01-11 14:50:10 +0100274static int pk_write_ec_private(unsigned char **p, unsigned char *start,
Valerio Setti00e8dd12023-05-18 18:56:59 +0200275 const mbedtls_pk_context *pk)
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200276{
Valerio Setti00e8dd12023-05-18 18:56:59 +0200277 size_t byte_length;
Janos Follath24eed8d2019-11-22 13:21:35 +0000278 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Valerio Setti00e8dd12023-05-18 18:56:59 +0200279 unsigned char tmp[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
280 psa_status_t status;
281
valerio52b675f2023-05-31 12:14:37 +0200282 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
283 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
284 if (status != PSA_SUCCESS) {
285 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
286 return ret;
287 }
288 } else {
289 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
290 if (status != PSA_SUCCESS) {
291 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
292 goto exit;
293 }
Valerio Setti00e8dd12023-05-18 18:56:59 +0200294 }
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200295
Gilles Peskine449bd832023-01-11 14:50:10 +0100296 ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length);
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200297exit:
Valerio Setti00e8dd12023-05-18 18:56:59 +0200298 mbedtls_platform_zeroize(tmp, sizeof(tmp));
Gilles Peskine449bd832023-01-11 14:50:10 +0100299 return ret;
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200300}
valerio52b675f2023-05-31 12:14:37 +0200301#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
302static int pk_write_ec_private(unsigned char **p, unsigned char *start,
303 const mbedtls_pk_context *pk)
304{
305 size_t byte_length;
306 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
307#if defined(MBEDTLS_USE_PSA_CRYPTO)
308 unsigned char tmp[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
309 psa_status_t status;
310#else
311 unsigned char tmp[MBEDTLS_ECP_MAX_BYTES];
312#endif /* MBEDTLS_USE_PSA_CRYPTO */
313
314#if defined(MBEDTLS_USE_PSA_CRYPTO)
315 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
316 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
317 if (status != PSA_SUCCESS) {
318 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
319 return ret;
320 }
321 } else
322#endif /* MBEDTLS_USE_PSA_CRYPTO */
323 {
324 mbedtls_ecp_keypair *ec = mbedtls_pk_ec_rw(*pk);
325 byte_length = (ec->grp.pbits + 7) / 8;
326
327 ret = mbedtls_ecp_write_key(ec, tmp, byte_length);
328 if (ret != 0) {
329 goto exit;
330 }
331 }
332 ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length);
333exit:
334 mbedtls_platform_zeroize(tmp, sizeof(tmp));
335 return ret;
336}
337#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
Valerio Setti605f03c2023-11-28 12:46:39 +0100338
339/*
340 * ECParameters ::= CHOICE {
341 * namedCurve OBJECT IDENTIFIER
342 * }
343 */
344static int pk_write_ec_param(unsigned char **p, unsigned char *start,
345 mbedtls_ecp_group_id grp_id)
346{
347 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
348 size_t len = 0;
349 const char *oid;
350 size_t oid_len;
351
352 if ((ret = mbedtls_oid_get_oid_by_ec_grp(grp_id, &oid, &oid_len)) != 0) {
353 return ret;
354 }
355
356 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len));
357
358 return (int) len;
359}
360
361#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
362static inline int mbedtls_pk_is_rfc8410(const mbedtls_pk_context *pk)
363{
364 mbedtls_ecp_group_id id = mbedtls_pk_get_group_id(pk);
365
366#if defined(MBEDTLS_ECP_HAVE_CURVE25519)
367 if (id == MBEDTLS_ECP_DP_CURVE25519) {
368 return 1;
369 }
370#endif
371#if defined(MBEDTLS_ECP_HAVE_CURVE448)
372 if (id == MBEDTLS_ECP_DP_CURVE448) {
373 return 1;
374 }
375#endif
376 return 0;
377}
378
379/*
380 * RFC8410 section 7
381 *
382 * OneAsymmetricKey ::= SEQUENCE {
383 * version Version,
384 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
385 * privateKey PrivateKey,
386 * attributes [0] IMPLICIT Attributes OPTIONAL,
387 * ...,
388 * [[2: publicKey [1] IMPLICIT PublicKey OPTIONAL ]],
389 * ...
390 * }
391 * ...
392 * CurvePrivateKey ::= OCTET STRING
393 */
394static int pk_write_ec_rfc8410_der(unsigned char **p, unsigned char *buf,
395 const mbedtls_pk_context *pk)
396{
397 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
398 size_t len = 0;
399 size_t oid_len = 0;
400 const char *oid;
401 mbedtls_ecp_group_id grp_id;
402
403 /* privateKey */
404 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk));
405 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
406 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_OCTET_STRING));
407
408 grp_id = mbedtls_pk_get_group_id(pk);
409 /* privateKeyAlgorithm */
410 if ((ret = mbedtls_oid_get_oid_by_ec_grp_algid(grp_id, &oid, &oid_len)) != 0) {
411 return ret;
412 }
413 MBEDTLS_ASN1_CHK_ADD(len,
414 mbedtls_asn1_write_algorithm_identifier_ext(p, buf, oid, oid_len, 0, 0));
415
416 /* version */
417 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0));
418
419 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
420 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED |
421 MBEDTLS_ASN1_SEQUENCE));
422
423 return (int) len;
424}
425#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
426
427/*
428 * RFC 5915, or SEC1 Appendix C.4
429 *
430 * ECPrivateKey ::= SEQUENCE {
431 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
432 * privateKey OCTET STRING,
433 * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
434 * publicKey [1] BIT STRING OPTIONAL
435 * }
436 */
437static int pk_write_ec_der(unsigned char **p, unsigned char *buf,
438 const mbedtls_pk_context *pk)
439{
440 size_t len = 0;
441 int ret;
442 size_t pub_len = 0, par_len = 0;
443 mbedtls_ecp_group_id grp_id;
444
445 /* publicKey */
446 MBEDTLS_ASN1_CHK_ADD(pub_len, pk_write_ec_pubkey(p, buf, pk));
447
448 if (*p - buf < 1) {
449 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
450 }
451 (*p)--;
452 **p = 0;
453 pub_len += 1;
454
455 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len));
456 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_BIT_STRING));
457
458 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len));
459 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf,
460 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
461 MBEDTLS_ASN1_CONSTRUCTED | 1));
462 len += pub_len;
463
464 /* parameters */
465 grp_id = mbedtls_pk_get_group_id(pk);
466 MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(p, buf, grp_id));
467 MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_len(p, buf, par_len));
468 MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_tag(p, buf,
469 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
470 MBEDTLS_ASN1_CONSTRUCTED | 0));
471 len += par_len;
472
473 /* privateKey */
474 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk));
475
476 /* version */
477 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 1));
478
479 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
480 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED |
481 MBEDTLS_ASN1_SEQUENCE));
482
483 return (int) len;
484}
Valerio Setti81d75122023-06-14 14:49:33 +0200485#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200486
Valerio Setti605f03c2023-11-28 12:46:39 +0100487/******************************************************************************
488 * Internal functions for Opaque keys.
489 ******************************************************************************/
valerio9ea26172023-05-31 12:10:23 +0200490#if defined(MBEDTLS_USE_PSA_CRYPTO)
Valerio Setti605f03c2023-11-28 12:46:39 +0100491/* It is assumed that the input key is opaque */
492static psa_key_type_t pk_get_opaque_key_type(const mbedtls_pk_context *pk)
493{
494 psa_key_attributes_t opaque_attrs = PSA_KEY_ATTRIBUTES_INIT;
495 psa_key_type_t opaque_key_type;
496
497 if (psa_get_key_attributes(pk->priv_id, &opaque_attrs) != PSA_SUCCESS) {
498 return 0;
499 }
500 opaque_key_type = psa_get_key_type(&opaque_attrs);
501 psa_reset_key_attributes(&opaque_attrs);
502
503 return opaque_key_type;
504}
505
valerio9ea26172023-05-31 12:10:23 +0200506static int pk_write_opaque_pubkey(unsigned char **p, unsigned char *start,
507 const mbedtls_pk_context *pk)
508{
509 size_t buffer_size;
510 size_t len = 0;
511
512 if (*p < start) {
513 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
514 }
515
516 buffer_size = (size_t) (*p - start);
517 if (psa_export_public_key(pk->priv_id, start, buffer_size,
518 &len) != PSA_SUCCESS) {
519 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
520 }
521
522 *p -= len;
523 memmove(*p, start, len);
524
525 return (int) len;
526}
Valerio Setti605f03c2023-11-28 12:46:39 +0100527
528#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && defined(MBEDTLS_PEM_WRITE_C)
529/* It is assumed that the input key is opaque */
530static psa_ecc_family_t pk_get_opaque_ec_family(const mbedtls_pk_context *pk)
531{
532 psa_ecc_family_t ec_family = 0;
533 psa_key_attributes_t key_attrs = PSA_KEY_ATTRIBUTES_INIT;
534
535 if (psa_get_key_attributes(pk->priv_id, &key_attrs) != PSA_SUCCESS) {
536 return 0;
537 }
538 ec_family = PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(&key_attrs));
539 psa_reset_key_attributes(&key_attrs);
540
541 return ec_family;
542}
543#endif /* MBEDTLS_PK_HAVE_ECC_KEYS && MBEDTLS_PEM_WRITE_C */
valerio9ea26172023-05-31 12:10:23 +0200544#endif /* MBEDTLS_USE_PSA_CRYPTO */
545
Valerio Setti605f03c2023-11-28 12:46:39 +0100546/******************************************************************************
547 * Public functions for writing private/public DER keys.
548 ******************************************************************************/
Gilles Peskine449bd832023-01-11 14:50:10 +0100549int mbedtls_pk_write_pubkey(unsigned char **p, unsigned char *start,
550 const mbedtls_pk_context *key)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200551{
Janos Follath24eed8d2019-11-22 13:21:35 +0000552 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200553 size_t len = 0;
554
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200555#if defined(MBEDTLS_RSA_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100556 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) {
valerio9ea26172023-05-31 12:10:23 +0200557 MBEDTLS_ASN1_CHK_ADD(len, pk_write_rsa_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100558 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200559#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200560#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Gilles Peskine449bd832023-01-11 14:50:10 +0100561 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) {
Valerio Setti4064dbb2023-05-17 15:33:07 +0200562 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100563 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200564#endif
Andrzej Kurek5fec0862018-11-19 10:07:36 -0500565#if defined(MBEDTLS_USE_PSA_CRYPTO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100566 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
valerio9ea26172023-05-31 12:10:23 +0200567 MBEDTLS_ASN1_CHK_ADD(len, pk_write_opaque_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100568 } else
Andrzej Kurek5fec0862018-11-19 10:07:36 -0500569#endif /* MBEDTLS_USE_PSA_CRYPTO */
Gilles Peskine449bd832023-01-11 14:50:10 +0100570 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200571
Gilles Peskine449bd832023-01-11 14:50:10 +0100572 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200573}
574
Gilles Peskine449bd832023-01-11 14:50:10 +0100575int mbedtls_pk_write_pubkey_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200576{
Janos Follath24eed8d2019-11-22 13:21:35 +0000577 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200578 unsigned char *c;
Jethro Beekman01672442023-04-19 14:08:14 +0200579 int has_par = 1;
580 size_t len = 0, par_len = 0, oid_len = 0;
Hanno Becker493c1712019-02-01 10:07:07 +0000581 mbedtls_pk_type_t pk_type;
Valerio Setti81d75122023-06-14 14:49:33 +0200582#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekmancb706ea2023-05-04 12:28:49 +0200583 mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE;
Jethro Beekman13d415c2023-05-04 10:11:58 +0200584#endif
correya15b4852023-09-21 16:19:11 +0800585 const char *oid = NULL;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200586
Gilles Peskine449bd832023-01-11 14:50:10 +0100587 if (size == 0) {
588 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
589 }
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500590
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200591 c = buf + size;
592
Gilles Peskine449bd832023-01-11 14:50:10 +0100593 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_pk_write_pubkey(&c, buf, key));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200594
Gilles Peskine449bd832023-01-11 14:50:10 +0100595 if (c - buf < 1) {
596 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
597 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200598
599 /*
600 * SubjectPublicKeyInfo ::= SEQUENCE {
601 * algorithm AlgorithmIdentifier,
602 * subjectPublicKey BIT STRING }
603 */
604 *--c = 0;
605 len += 1;
606
Gilles Peskine449bd832023-01-11 14:50:10 +0100607 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
608 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_BIT_STRING));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200609
Gilles Peskine449bd832023-01-11 14:50:10 +0100610 pk_type = mbedtls_pk_get_type(key);
Valerio Setti81d75122023-06-14 14:49:33 +0200611#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Gilles Peskine449bd832023-01-11 14:50:10 +0100612 if (pk_type == MBEDTLS_PK_ECKEY) {
valerioba1fd322023-05-31 12:13:17 +0200613 ec_grp_id = mbedtls_pk_get_group_id(key);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200614 }
Valerio Setti81d75122023-06-14 14:49:33 +0200615#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Hanno Becker493c1712019-02-01 10:07:07 +0000616#if defined(MBEDTLS_USE_PSA_CRYPTO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100617 if (pk_type == MBEDTLS_PK_OPAQUE) {
valerioba1fd322023-05-31 12:13:17 +0200618 psa_key_type_t opaque_key_type = pk_get_opaque_key_type(key);
Valerio Setti81d75122023-06-14 14:49:33 +0200619#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioba1fd322023-05-31 12:13:17 +0200620 if (PSA_KEY_TYPE_IS_ECC(opaque_key_type)) {
valerio52b675f2023-05-31 12:14:37 +0200621 pk_type = MBEDTLS_PK_ECKEY;
valerioba1fd322023-05-31 12:13:17 +0200622 ec_grp_id = mbedtls_pk_get_group_id(key);
623 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200624#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioba1fd322023-05-31 12:13:17 +0200625 if (PSA_KEY_TYPE_IS_RSA(opaque_key_type)) {
Neil Armstrong295aeb12022-03-15 16:25:41 +0100626 /* The rest of the function works as for legacy RSA contexts. */
627 pk_type = MBEDTLS_PK_RSA;
Neil Armstrong295aeb12022-03-15 16:25:41 +0100628 }
Jethro Beekmancf4545e2023-05-04 12:05:55 +0200629 }
630 /* `pk_type` will have been changed to non-opaque by here if this function can handle it */
631 if (pk_type == MBEDTLS_PK_OPAQUE) {
632 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Hanno Becker493c1712019-02-01 10:07:07 +0000633 }
634#endif /* MBEDTLS_USE_PSA_CRYPTO */
635
Valerio Setti81d75122023-06-14 14:49:33 +0200636#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200637 if (pk_type == MBEDTLS_PK_ECKEY) {
valerioba1fd322023-05-31 12:13:17 +0200638 /* Some groups have their own AlgorithmIdentifier OID, others are handled
639 * by mbedtls_oid_get_oid_by_pk_alg() below */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200640 ret = mbedtls_oid_get_oid_by_ec_grp_algid(ec_grp_id, &oid, &oid_len);
641
642 if (ret == 0) {
valerioba1fd322023-05-31 12:13:17 +0200643 /* Currently, none of the supported algorithms that have their own
644 * AlgorithmIdentifier OID have any parameters */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200645 has_par = 0;
646 } else if (ret == MBEDTLS_ERR_OID_NOT_FOUND) {
647 MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(&c, buf, ec_grp_id));
648 } else {
649 return ret;
650 }
651 }
Valerio Setti81d75122023-06-14 14:49:33 +0200652#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200653
Jethro Beekman01672442023-04-19 14:08:14 +0200654 if (oid_len == 0) {
655 if ((ret = mbedtls_oid_get_oid_by_pk_alg(pk_type, &oid,
656 &oid_len)) != 0) {
657 return ret;
658 }
Hanno Becker493c1712019-02-01 10:07:07 +0000659 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200660
Jethro Beekman01672442023-04-19 14:08:14 +0200661 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_algorithm_identifier_ext(&c, buf, oid, oid_len,
662 par_len, has_par));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200663
Gilles Peskine449bd832023-01-11 14:50:10 +0100664 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
665 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED |
666 MBEDTLS_ASN1_SEQUENCE));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200667
Gilles Peskine449bd832023-01-11 14:50:10 +0100668 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200669}
670
valerioc0bac572023-05-31 12:15:41 +0200671int mbedtls_pk_write_key_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
672{
673 unsigned char *c;
valerioc0bac572023-05-31 12:15:41 +0200674#if defined(MBEDTLS_RSA_C)
675 int is_rsa_opaque = 0;
676#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200677#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200678 int is_ec_opaque = 0;
Valerio Setti81d75122023-06-14 14:49:33 +0200679#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioc0bac572023-05-31 12:15:41 +0200680#if defined(MBEDTLS_USE_PSA_CRYPTO)
valeriof9139e52023-05-31 18:01:33 +0200681 psa_key_type_t opaque_key_type;
valerioc0bac572023-05-31 12:15:41 +0200682#endif /* MBEDTLS_USE_PSA_CRYPTO */
683
684 if (size == 0) {
685 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
686 }
687
688 c = buf + size;
689
690#if defined(MBEDTLS_USE_PSA_CRYPTO)
691 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
valeriof9139e52023-05-31 18:01:33 +0200692 opaque_key_type = pk_get_opaque_key_type(key);
valerioc0bac572023-05-31 12:15:41 +0200693#if defined(MBEDTLS_RSA_C)
694 is_rsa_opaque = PSA_KEY_TYPE_IS_RSA(opaque_key_type);
695#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200696#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200697 is_ec_opaque = PSA_KEY_TYPE_IS_ECC(opaque_key_type);
Valerio Setti81d75122023-06-14 14:49:33 +0200698#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioc0bac572023-05-31 12:15:41 +0200699 }
700#endif /* MBEDTLS_USE_PSA_CRYPTO */
701
702#if defined(MBEDTLS_RSA_C)
703 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) || is_rsa_opaque) {
704 return pk_write_rsa_der(&c, buf, key);
Gilles Peskine449bd832023-01-11 14:50:10 +0100705 } else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200706#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200707#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200708 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) || is_ec_opaque) {
Jethro Beekman01672442023-04-19 14:08:14 +0200709#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
Valerio Setti00e8dd12023-05-18 18:56:59 +0200710 if (mbedtls_pk_is_rfc8410(key)) {
711 return pk_write_ec_rfc8410_der(&c, buf, key);
Jethro Beekman01672442023-04-19 14:08:14 +0200712 }
valerioc0bac572023-05-31 12:15:41 +0200713#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
714 return pk_write_ec_der(&c, buf, key);
Gilles Peskine449bd832023-01-11 14:50:10 +0100715 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200716#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Gilles Peskine449bd832023-01-11 14:50:10 +0100717 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200718}
719
Valerio Setti605f03c2023-11-28 12:46:39 +0100720/******************************************************************************
721 * Public functions for wrinting private/public PEM keys.
722 ******************************************************************************/
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200723#if defined(MBEDTLS_PEM_WRITE_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200724
Neil Armstronge9ecd272022-03-01 10:03:21 +0100725#define PUB_DER_MAX_BYTES \
Gilles Peskine449bd832023-01-11 14:50:10 +0100726 (MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES > MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES ? \
727 MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES : MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES)
Neil Armstronge9ecd272022-03-01 10:03:21 +0100728#define PRV_DER_MAX_BYTES \
Gilles Peskine449bd832023-01-11 14:50:10 +0100729 (MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES > MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES ? \
730 MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES : MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES)
Manuel Pégourié-Gonnard192253a2014-07-21 16:37:15 +0200731
Gilles Peskine449bd832023-01-11 14:50:10 +0100732int mbedtls_pk_write_pubkey_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200733{
Janos Follath24eed8d2019-11-22 13:21:35 +0000734 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Yanray Wang45ad3062023-08-11 15:03:51 +0800735 unsigned char *output_buf = NULL;
Yanray Wang08d5f462023-08-21 15:15:19 +0800736 output_buf = mbedtls_calloc(1, PUB_DER_MAX_BYTES);
Yanray Wang45ad3062023-08-11 15:03:51 +0800737 if (output_buf == NULL) {
738 return MBEDTLS_ERR_PK_ALLOC_FAILED;
739 }
Paul Bakker77e23fb2013-09-15 20:03:26 +0200740 size_t olen = 0;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200741
Gilles Peskine449bd832023-01-11 14:50:10 +0100742 if ((ret = mbedtls_pk_write_pubkey_der(key, output_buf,
Yanray Wang45ad3062023-08-11 15:03:51 +0800743 PUB_DER_MAX_BYTES)) < 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800744 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200745 }
746
Gilles Peskine449bd832023-01-11 14:50:10 +0100747 if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
Yanray Wang45ad3062023-08-11 15:03:51 +0800748 output_buf + PUB_DER_MAX_BYTES - ret,
Gilles Peskine449bd832023-01-11 14:50:10 +0100749 ret, buf, size, &olen)) != 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800750 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200751 }
752
Yanray Wang7226df02023-08-11 15:52:09 +0800753 ret = 0;
754cleanup:
Yanray Wang08d5f462023-08-21 15:15:19 +0800755 mbedtls_free(output_buf);
Yanray Wang7226df02023-08-11 15:52:09 +0800756 return ret;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200757}
758
Gilles Peskine449bd832023-01-11 14:50:10 +0100759int mbedtls_pk_write_key_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200760{
Janos Follath24eed8d2019-11-22 13:21:35 +0000761 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Yanray Wangc84086e2023-08-11 15:33:07 +0800762 unsigned char *output_buf = NULL;
Yanray Wang08d5f462023-08-21 15:15:19 +0800763 output_buf = mbedtls_calloc(1, PRV_DER_MAX_BYTES);
Yanray Wangc84086e2023-08-11 15:33:07 +0800764 if (output_buf == NULL) {
765 return MBEDTLS_ERR_PK_ALLOC_FAILED;
766 }
Paul Bakkerfcc17212013-10-11 09:36:52 +0200767 const char *begin, *end;
Paul Bakker77e23fb2013-09-15 20:03:26 +0200768 size_t olen = 0;
Valerio Setti81d75122023-06-14 14:49:33 +0200769#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200770 int is_ec_opaque = 0;
771#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
772 int is_montgomery_opaque = 0;
773#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Valerio Setti81d75122023-06-14 14:49:33 +0200774#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioe279e502023-05-31 12:16:12 +0200775#if defined(MBEDTLS_RSA_C)
776 int is_rsa_opaque = 0;
777#endif
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200778
Yanray Wangc84086e2023-08-11 15:33:07 +0800779 if ((ret = mbedtls_pk_write_key_der(key, output_buf, PRV_DER_MAX_BYTES)) < 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800780 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +0100781 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200782
valerioe279e502023-05-31 12:16:12 +0200783#if defined(MBEDTLS_USE_PSA_CRYPTO)
784 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
785 psa_key_type_t opaque_key_type = pk_get_opaque_key_type(key);
786
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200787#if defined(MBEDTLS_RSA_C)
valerioe279e502023-05-31 12:16:12 +0200788 is_rsa_opaque = PSA_KEY_TYPE_IS_RSA(opaque_key_type);
789#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200790#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200791 is_ec_opaque = PSA_KEY_TYPE_IS_ECC(opaque_key_type);
792#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
793 if (pk_get_opaque_ec_family(key) == PSA_ECC_FAMILY_MONTGOMERY) {
794 is_montgomery_opaque = 1;
795 }
796#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Valerio Setti81d75122023-06-14 14:49:33 +0200797#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioe279e502023-05-31 12:16:12 +0200798 }
799#endif /* MBEDTLS_USE_PSA_CRYPTO */
800
801#if defined(MBEDTLS_RSA_C)
802 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) || is_rsa_opaque) {
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200803 begin = PEM_BEGIN_PRIVATE_KEY_RSA;
804 end = PEM_END_PRIVATE_KEY_RSA;
Gilles Peskine449bd832023-01-11 14:50:10 +0100805 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200806#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200807#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200808 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) || is_ec_opaque) {
Jethro Beekman01672442023-04-19 14:08:14 +0200809#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
valerioe279e502023-05-31 12:16:12 +0200810 if (is_montgomery_opaque ||
811 ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) &&
812 (mbedtls_pk_is_rfc8410(key)))) {
Jethro Beekman01672442023-04-19 14:08:14 +0200813 begin = PEM_BEGIN_PRIVATE_KEY_PKCS8;
814 end = PEM_END_PRIVATE_KEY_PKCS8;
815 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200816#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Jethro Beekman01672442023-04-19 14:08:14 +0200817 {
818 begin = PEM_BEGIN_PRIVATE_KEY_EC;
819 end = PEM_END_PRIVATE_KEY_EC;
820 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100821 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200822#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Yanray Wangc84086e2023-08-11 15:33:07 +0800823 {
Yanray Wang7226df02023-08-11 15:52:09 +0800824 ret = MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
825 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200826 }
827
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200828 if ((ret = mbedtls_pem_write_buffer(begin, end,
Yanray Wangc84086e2023-08-11 15:33:07 +0800829 output_buf + PRV_DER_MAX_BYTES - ret,
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200830 ret, buf, size, &olen)) != 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800831 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200832 }
833
Yanray Wang7226df02023-08-11 15:52:09 +0800834 ret = 0;
835cleanup:
Yanray Wang044eb162023-08-28 10:35:39 +0800836 mbedtls_zeroize_and_free(output_buf, PRV_DER_MAX_BYTES);
Yanray Wang7226df02023-08-11 15:52:09 +0800837 return ret;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200838}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200839#endif /* MBEDTLS_PEM_WRITE_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200840
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200841#endif /* MBEDTLS_PK_WRITE_C */