blob: 11c020473e8b267a7021119fcf01f133c19722a4 [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_RSA_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000022#include "mbedtls/rsa.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020023#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020024#if defined(MBEDTLS_ECP_C)
Gilles Peskine2700cfb2018-08-11 00:48:44 +020025#include "mbedtls/bignum.h"
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000026#include "mbedtls/ecp.h"
Gilles Peskine2700cfb2018-08-11 00:48:44 +020027#include "mbedtls/platform_util.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020028#endif
Valerio Setti81d75122023-06-14 14:49:33 +020029#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Valerio Setti4064dbb2023-05-17 15:33:07 +020030#include "pk_internal.h"
31#endif
Valerio Setti81d75122023-06-14 14:49:33 +020032#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Neil Armstronge0326a62022-02-25 08:57:19 +010033#include "pkwrite.h"
34#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020035#if defined(MBEDTLS_ECDSA_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000036#include "mbedtls/ecdsa.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020037#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020038#if defined(MBEDTLS_PEM_WRITE_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000039#include "mbedtls/pem.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020040#endif
41
Andrzej Kurek5fec0862018-11-19 10:07:36 -050042#if defined(MBEDTLS_USE_PSA_CRYPTO)
43#include "psa/crypto.h"
Manuel Pégourié-Gonnard2be8c632023-06-07 13:07:21 +020044#include "psa_util_internal.h"
Andrzej Kurek5fec0862018-11-19 10:07:36 -050045#endif
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000046#include "mbedtls/platform.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020047
Valerio Settie0e63112023-05-18 18:48:07 +020048/* Helper for Montgomery curves */
Valerio Setti81d75122023-06-14 14:49:33 +020049#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valeriob7273142023-05-31 12:07:18 +020050#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
Valerio Settie0e63112023-05-18 18:48:07 +020051static inline int mbedtls_pk_is_rfc8410(const mbedtls_pk_context *pk)
52{
53 mbedtls_ecp_group_id id = mbedtls_pk_get_group_id(pk);
54
Valerio Settidb6b4db2023-09-01 09:20:51 +020055#if defined(MBEDTLS_ECP_HAVE_CURVE25519)
Valerio Settie0e63112023-05-18 18:48:07 +020056 if (id == MBEDTLS_ECP_DP_CURVE25519) {
57 return 1;
58 }
59#endif
Valerio Settidb6b4db2023-09-01 09:20:51 +020060#if defined(MBEDTLS_ECP_HAVE_CURVE448)
Valerio Settie0e63112023-05-18 18:48:07 +020061 if (id == MBEDTLS_ECP_DP_CURVE448) {
62 return 1;
63 }
64#endif
65 return 0;
66}
Valerio Setti81d75122023-06-14 14:49:33 +020067
Ronald Cronb9c79532023-09-07 14:20:49 +020068#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PEM_WRITE_C)
valeriob7273142023-05-31 12:07:18 +020069/* It is assumed that the input key is opaque */
70static psa_ecc_family_t pk_get_opaque_ec_family(const mbedtls_pk_context *pk)
71{
72 psa_ecc_family_t ec_family = 0;
73 psa_key_attributes_t key_attrs = PSA_KEY_ATTRIBUTES_INIT;
74
75 if (psa_get_key_attributes(pk->priv_id, &key_attrs) != PSA_SUCCESS) {
76 return 0;
77 }
78 ec_family = PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(&key_attrs));
79 psa_reset_key_attributes(&key_attrs);
80
81 return ec_family;
82}
Ronald Cronb9c79532023-09-07 14:20:49 +020083#endif /* MBETLS_USE_PSA_CRYPTO && MBEDTLS_PEM_WRITE_C */
Valerio Settie1651362023-06-19 14:19:44 +020084#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
85#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valeriob7273142023-05-31 12:07:18 +020086
Valerio Settie1651362023-06-19 14:19:44 +020087#if defined(MBEDTLS_USE_PSA_CRYPTO)
valeriob7273142023-05-31 12:07:18 +020088/* It is assumed that the input key is opaque */
89static psa_key_type_t pk_get_opaque_key_type(const mbedtls_pk_context *pk)
90{
91 psa_key_attributes_t opaque_attrs = PSA_KEY_ATTRIBUTES_INIT;
92 psa_key_type_t opaque_key_type;
93
94 if (psa_get_key_attributes(pk->priv_id, &opaque_attrs) != PSA_SUCCESS) {
95 return 0;
96 }
97 opaque_key_type = psa_get_key_type(&opaque_attrs);
98 psa_reset_key_attributes(&opaque_attrs);
99
100 return opaque_key_type;
101}
102#endif /* MBETLS_USE_PSA_CRYPTO */
Valerio Settie0e63112023-05-18 18:48:07 +0200103
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200104#if defined(MBEDTLS_RSA_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200105/*
106 * RSAPublicKey ::= SEQUENCE {
107 * modulus INTEGER, -- n
108 * publicExponent INTEGER -- e
109 * }
110 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100111static int pk_write_rsa_pubkey(unsigned char **p, unsigned char *start,
valerio9ea26172023-05-31 12:10:23 +0200112 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200113{
Janos Follath24eed8d2019-11-22 13:21:35 +0000114 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200115 size_t len = 0;
Hanno Becker15f81fa2017-08-23 12:38:27 +0100116 mbedtls_mpi T;
valerio9ea26172023-05-31 12:10:23 +0200117 mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200118
Gilles Peskine449bd832023-01-11 14:50:10 +0100119 mbedtls_mpi_init(&T);
Hanno Becker15f81fa2017-08-23 12:38:27 +0100120
121 /* Export E */
Gilles Peskine449bd832023-01-11 14:50:10 +0100122 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, NULL, &T)) != 0 ||
123 (ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100124 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100125 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100126 len += ret;
127
128 /* Export N */
Gilles Peskine449bd832023-01-11 14:50:10 +0100129 if ((ret = mbedtls_rsa_export(rsa, &T, NULL, NULL, NULL, NULL)) != 0 ||
130 (ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100131 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100132 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100133 len += ret;
134
135end_of_export:
136
Gilles Peskine449bd832023-01-11 14:50:10 +0100137 mbedtls_mpi_free(&T);
138 if (ret < 0) {
139 return ret;
140 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200141
Gilles Peskine449bd832023-01-11 14:50:10 +0100142 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
143 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED |
144 MBEDTLS_ASN1_SEQUENCE));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200145
Gilles Peskine449bd832023-01-11 14:50:10 +0100146 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200147}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200148#endif /* MBEDTLS_RSA_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200149
Valerio Setti81d75122023-06-14 14:49:33 +0200150#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerio9ea26172023-05-31 12:10:23 +0200151#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
Gilles Peskine449bd832023-01-11 14:50:10 +0100152static int pk_write_ec_pubkey(unsigned char **p, unsigned char *start,
Valerio Setti4064dbb2023-05-17 15:33:07 +0200153 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200154{
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200155 size_t len = 0;
Valerio Settie1d7c9d2023-08-10 07:40:18 +0200156 uint8_t buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
Valerio Setti4064dbb2023-05-17 15:33:07 +0200157
valerio9ea26172023-05-31 12:10:23 +0200158 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
159 if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) {
160 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
161 }
162 } else {
163 len = pk->pub_raw_len;
valeriof9139e52023-05-31 18:01:33 +0200164 memcpy(buf, pk->pub_raw, len);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200165 }
166
Gilles Peskine449bd832023-01-11 14:50:10 +0100167 if (*p < start || (size_t) (*p - start) < len) {
168 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
169 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200170
171 *p -= len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100172 memcpy(*p, buf, len);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200173
Gilles Peskine449bd832023-01-11 14:50:10 +0100174 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200175}
valerio9ea26172023-05-31 12:10:23 +0200176#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
177static int pk_write_ec_pubkey(unsigned char **p, unsigned char *start,
178 const mbedtls_pk_context *pk)
179{
180 size_t len = 0;
181#if defined(MBEDTLS_USE_PSA_CRYPTO)
182 uint8_t buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
183#else
184 unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN];
185#endif /* MBEDTLS_USE_PSA_CRYPTO */
186 mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*pk);
187 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
188
189#if defined(MBEDTLS_USE_PSA_CRYPTO)
190 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
191 if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) {
192 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
193 }
194 *p -= len;
195 memcpy(*p, buf, len);
196 return (int) len;
197 } else
198#endif /* MBEDTLS_USE_PSA_CRYPTO */
199 {
200 if ((ret = mbedtls_ecp_point_write_binary(&ec->grp, &ec->Q,
201 MBEDTLS_ECP_PF_UNCOMPRESSED,
202 &len, buf, sizeof(buf))) != 0) {
203 return ret;
204 }
205 }
206
207 if (*p < start || (size_t) (*p - start) < len) {
208 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
209 }
210
211 *p -= len;
212 memcpy(*p, buf, len);
213
214 return (int) len;
215}
216#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200217
218/*
219 * ECParameters ::= CHOICE {
220 * namedCurve OBJECT IDENTIFIER
221 * }
222 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100223static int pk_write_ec_param(unsigned char **p, unsigned char *start,
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200224 mbedtls_ecp_group_id grp_id)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200225{
Janos Follath24eed8d2019-11-22 13:21:35 +0000226 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200227 size_t len = 0;
228 const char *oid;
229 size_t oid_len;
230
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200231 if ((ret = mbedtls_oid_get_oid_by_ec_grp(grp_id, &oid, &oid_len)) != 0) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100232 return ret;
233 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200234
Gilles Peskine449bd832023-01-11 14:50:10 +0100235 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200236
Gilles Peskine449bd832023-01-11 14:50:10 +0100237 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200238}
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200239
240/*
241 * privateKey OCTET STRING -- always of length ceil(log2(n)/8)
242 */
valerio52b675f2023-05-31 12:14:37 +0200243#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
Gilles Peskine449bd832023-01-11 14:50:10 +0100244static int pk_write_ec_private(unsigned char **p, unsigned char *start,
Valerio Setti00e8dd12023-05-18 18:56:59 +0200245 const mbedtls_pk_context *pk)
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200246{
Valerio Setti00e8dd12023-05-18 18:56:59 +0200247 size_t byte_length;
Janos Follath24eed8d2019-11-22 13:21:35 +0000248 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Valerio Setti00e8dd12023-05-18 18:56:59 +0200249 unsigned char tmp[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
250 psa_status_t status;
251
valerio52b675f2023-05-31 12:14:37 +0200252 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
253 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
254 if (status != PSA_SUCCESS) {
255 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
256 return ret;
257 }
258 } else {
259 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
260 if (status != PSA_SUCCESS) {
261 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
262 goto exit;
263 }
Valerio Setti00e8dd12023-05-18 18:56:59 +0200264 }
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200265
Gilles Peskine449bd832023-01-11 14:50:10 +0100266 ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length);
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200267exit:
Valerio Setti00e8dd12023-05-18 18:56:59 +0200268 mbedtls_platform_zeroize(tmp, sizeof(tmp));
Gilles Peskine449bd832023-01-11 14:50:10 +0100269 return ret;
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200270}
valerio52b675f2023-05-31 12:14:37 +0200271#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
272static int pk_write_ec_private(unsigned char **p, unsigned char *start,
273 const mbedtls_pk_context *pk)
274{
275 size_t byte_length;
276 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
277#if defined(MBEDTLS_USE_PSA_CRYPTO)
278 unsigned char tmp[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
279 psa_status_t status;
280#else
281 unsigned char tmp[MBEDTLS_ECP_MAX_BYTES];
282#endif /* MBEDTLS_USE_PSA_CRYPTO */
283
284#if defined(MBEDTLS_USE_PSA_CRYPTO)
285 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
286 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
287 if (status != PSA_SUCCESS) {
288 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
289 return ret;
290 }
291 } else
292#endif /* MBEDTLS_USE_PSA_CRYPTO */
293 {
294 mbedtls_ecp_keypair *ec = mbedtls_pk_ec_rw(*pk);
295 byte_length = (ec->grp.pbits + 7) / 8;
296
297 ret = mbedtls_ecp_write_key(ec, tmp, byte_length);
298 if (ret != 0) {
299 goto exit;
300 }
301 }
302 ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length);
303exit:
304 mbedtls_platform_zeroize(tmp, sizeof(tmp));
305 return ret;
306}
307#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
Valerio Setti81d75122023-06-14 14:49:33 +0200308#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200309
valerio9ea26172023-05-31 12:10:23 +0200310#if defined(MBEDTLS_USE_PSA_CRYPTO)
311static int pk_write_opaque_pubkey(unsigned char **p, unsigned char *start,
312 const mbedtls_pk_context *pk)
313{
314 size_t buffer_size;
315 size_t len = 0;
316
317 if (*p < start) {
318 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
319 }
320
321 buffer_size = (size_t) (*p - start);
322 if (psa_export_public_key(pk->priv_id, start, buffer_size,
323 &len) != PSA_SUCCESS) {
324 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
325 }
326
327 *p -= len;
328 memmove(*p, start, len);
329
330 return (int) len;
331}
332#endif /* MBEDTLS_USE_PSA_CRYPTO */
333
Gilles Peskine449bd832023-01-11 14:50:10 +0100334int mbedtls_pk_write_pubkey(unsigned char **p, unsigned char *start,
335 const mbedtls_pk_context *key)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200336{
Janos Follath24eed8d2019-11-22 13:21:35 +0000337 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200338 size_t len = 0;
339
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200340#if defined(MBEDTLS_RSA_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100341 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) {
valerio9ea26172023-05-31 12:10:23 +0200342 MBEDTLS_ASN1_CHK_ADD(len, pk_write_rsa_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100343 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200344#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200345#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Gilles Peskine449bd832023-01-11 14:50:10 +0100346 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) {
Valerio Setti4064dbb2023-05-17 15:33:07 +0200347 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100348 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200349#endif
Andrzej Kurek5fec0862018-11-19 10:07:36 -0500350#if defined(MBEDTLS_USE_PSA_CRYPTO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100351 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
valerio9ea26172023-05-31 12:10:23 +0200352 MBEDTLS_ASN1_CHK_ADD(len, pk_write_opaque_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100353 } else
Andrzej Kurek5fec0862018-11-19 10:07:36 -0500354#endif /* MBEDTLS_USE_PSA_CRYPTO */
Gilles Peskine449bd832023-01-11 14:50:10 +0100355 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200356
Gilles Peskine449bd832023-01-11 14:50:10 +0100357 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200358}
359
Gilles Peskine449bd832023-01-11 14:50:10 +0100360int mbedtls_pk_write_pubkey_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200361{
Janos Follath24eed8d2019-11-22 13:21:35 +0000362 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200363 unsigned char *c;
Jethro Beekman01672442023-04-19 14:08:14 +0200364 int has_par = 1;
365 size_t len = 0, par_len = 0, oid_len = 0;
Hanno Becker493c1712019-02-01 10:07:07 +0000366 mbedtls_pk_type_t pk_type;
Valerio Setti81d75122023-06-14 14:49:33 +0200367#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekmancb706ea2023-05-04 12:28:49 +0200368 mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE;
Jethro Beekman13d415c2023-05-04 10:11:58 +0200369#endif
correya15b4852023-09-21 16:19:11 +0800370 const char *oid = NULL;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200371
Gilles Peskine449bd832023-01-11 14:50:10 +0100372 if (size == 0) {
373 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
374 }
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500375
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200376 c = buf + size;
377
Gilles Peskine449bd832023-01-11 14:50:10 +0100378 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_pk_write_pubkey(&c, buf, key));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200379
Gilles Peskine449bd832023-01-11 14:50:10 +0100380 if (c - buf < 1) {
381 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
382 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200383
384 /*
385 * SubjectPublicKeyInfo ::= SEQUENCE {
386 * algorithm AlgorithmIdentifier,
387 * subjectPublicKey BIT STRING }
388 */
389 *--c = 0;
390 len += 1;
391
Gilles Peskine449bd832023-01-11 14:50:10 +0100392 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
393 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_BIT_STRING));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200394
Gilles Peskine449bd832023-01-11 14:50:10 +0100395 pk_type = mbedtls_pk_get_type(key);
Valerio Setti81d75122023-06-14 14:49:33 +0200396#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Gilles Peskine449bd832023-01-11 14:50:10 +0100397 if (pk_type == MBEDTLS_PK_ECKEY) {
valerioba1fd322023-05-31 12:13:17 +0200398 ec_grp_id = mbedtls_pk_get_group_id(key);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200399 }
Valerio Setti81d75122023-06-14 14:49:33 +0200400#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Hanno Becker493c1712019-02-01 10:07:07 +0000401#if defined(MBEDTLS_USE_PSA_CRYPTO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100402 if (pk_type == MBEDTLS_PK_OPAQUE) {
valerioba1fd322023-05-31 12:13:17 +0200403 psa_key_type_t opaque_key_type = pk_get_opaque_key_type(key);
Valerio Setti81d75122023-06-14 14:49:33 +0200404#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioba1fd322023-05-31 12:13:17 +0200405 if (PSA_KEY_TYPE_IS_ECC(opaque_key_type)) {
valerio52b675f2023-05-31 12:14:37 +0200406 pk_type = MBEDTLS_PK_ECKEY;
valerioba1fd322023-05-31 12:13:17 +0200407 ec_grp_id = mbedtls_pk_get_group_id(key);
408 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200409#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioba1fd322023-05-31 12:13:17 +0200410 if (PSA_KEY_TYPE_IS_RSA(opaque_key_type)) {
Neil Armstrong295aeb12022-03-15 16:25:41 +0100411 /* The rest of the function works as for legacy RSA contexts. */
412 pk_type = MBEDTLS_PK_RSA;
Neil Armstrong295aeb12022-03-15 16:25:41 +0100413 }
Jethro Beekmancf4545e2023-05-04 12:05:55 +0200414 }
415 /* `pk_type` will have been changed to non-opaque by here if this function can handle it */
416 if (pk_type == MBEDTLS_PK_OPAQUE) {
417 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Hanno Becker493c1712019-02-01 10:07:07 +0000418 }
419#endif /* MBEDTLS_USE_PSA_CRYPTO */
420
Valerio Setti81d75122023-06-14 14:49:33 +0200421#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200422 if (pk_type == MBEDTLS_PK_ECKEY) {
valerioba1fd322023-05-31 12:13:17 +0200423 /* Some groups have their own AlgorithmIdentifier OID, others are handled
424 * by mbedtls_oid_get_oid_by_pk_alg() below */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200425 ret = mbedtls_oid_get_oid_by_ec_grp_algid(ec_grp_id, &oid, &oid_len);
426
427 if (ret == 0) {
valerioba1fd322023-05-31 12:13:17 +0200428 /* Currently, none of the supported algorithms that have their own
429 * AlgorithmIdentifier OID have any parameters */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200430 has_par = 0;
431 } else if (ret == MBEDTLS_ERR_OID_NOT_FOUND) {
432 MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(&c, buf, ec_grp_id));
433 } else {
434 return ret;
435 }
436 }
Valerio Setti81d75122023-06-14 14:49:33 +0200437#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200438
Jethro Beekman01672442023-04-19 14:08:14 +0200439 if (oid_len == 0) {
440 if ((ret = mbedtls_oid_get_oid_by_pk_alg(pk_type, &oid,
441 &oid_len)) != 0) {
442 return ret;
443 }
Hanno Becker493c1712019-02-01 10:07:07 +0000444 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200445
Jethro Beekman01672442023-04-19 14:08:14 +0200446 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_algorithm_identifier_ext(&c, buf, oid, oid_len,
447 par_len, has_par));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200448
Gilles Peskine449bd832023-01-11 14:50:10 +0100449 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
450 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED |
451 MBEDTLS_ASN1_SEQUENCE));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200452
Gilles Peskine449bd832023-01-11 14:50:10 +0100453 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200454}
455
Valerio Setti81d75122023-06-14 14:49:33 +0200456#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekman01672442023-04-19 14:08:14 +0200457#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
458/*
Valerio Setti4064dbb2023-05-17 15:33:07 +0200459 * RFC8410 section 7
Jethro Beekman01672442023-04-19 14:08:14 +0200460 *
461 * OneAsymmetricKey ::= SEQUENCE {
462 * version Version,
463 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
464 * privateKey PrivateKey,
465 * attributes [0] IMPLICIT Attributes OPTIONAL,
466 * ...,
467 * [[2: publicKey [1] IMPLICIT PublicKey OPTIONAL ]],
468 * ...
469 * }
Valerio Setti4064dbb2023-05-17 15:33:07 +0200470 * ...
Jethro Beekman01672442023-04-19 14:08:14 +0200471 * CurvePrivateKey ::= OCTET STRING
472 */
473static int pk_write_ec_rfc8410_der(unsigned char **p, unsigned char *buf,
Valerio Setti00e8dd12023-05-18 18:56:59 +0200474 const mbedtls_pk_context *pk)
Jethro Beekman01672442023-04-19 14:08:14 +0200475{
476 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
477 size_t len = 0;
478 size_t oid_len = 0;
479 const char *oid;
Valerio Setti1194ffa2023-05-24 13:15:58 +0200480 mbedtls_ecp_group_id grp_id;
Jethro Beekman01672442023-04-19 14:08:14 +0200481
482 /* privateKey */
Valerio Setti00e8dd12023-05-18 18:56:59 +0200483 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk));
Jethro Beekman01672442023-04-19 14:08:14 +0200484 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
485 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_OCTET_STRING));
486
Valerio Setti1194ffa2023-05-24 13:15:58 +0200487 grp_id = mbedtls_pk_get_group_id(pk);
Jethro Beekman01672442023-04-19 14:08:14 +0200488 /* privateKeyAlgorithm */
Valerio Setti00e8dd12023-05-18 18:56:59 +0200489 if ((ret = mbedtls_oid_get_oid_by_ec_grp_algid(grp_id, &oid, &oid_len)) != 0) {
490 return ret;
491 }
Jethro Beekman01672442023-04-19 14:08:14 +0200492 MBEDTLS_ASN1_CHK_ADD(len,
493 mbedtls_asn1_write_algorithm_identifier_ext(p, buf, oid, oid_len, 0, 0));
494
495 /* version */
496 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0));
497
498 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
499 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED |
500 MBEDTLS_ASN1_SEQUENCE));
501
502 return (int) len;
503}
504#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Jethro Beekman01672442023-04-19 14:08:14 +0200505
valerioc0bac572023-05-31 12:15:41 +0200506/*
507 * RFC 5915, or SEC1 Appendix C.4
508 *
509 * ECPrivateKey ::= SEQUENCE {
510 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
511 * privateKey OCTET STRING,
512 * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
513 * publicKey [1] BIT STRING OPTIONAL
514 * }
515 */
516static int pk_write_ec_der(unsigned char **p, unsigned char *buf,
517 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200518{
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200519 size_t len = 0;
valerioc0bac572023-05-31 12:15:41 +0200520 int ret;
521 size_t pub_len = 0, par_len = 0;
Valerio Setti00e8dd12023-05-18 18:56:59 +0200522 mbedtls_ecp_group_id grp_id;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200523
valerioc0bac572023-05-31 12:15:41 +0200524 /* publicKey */
525 MBEDTLS_ASN1_CHK_ADD(pub_len, pk_write_ec_pubkey(p, buf, pk));
526
527 if (*p - buf < 1) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100528 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
529 }
valerioc0bac572023-05-31 12:15:41 +0200530 (*p)--;
531 **p = 0;
532 pub_len += 1;
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500533
valerioc0bac572023-05-31 12:15:41 +0200534 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len));
535 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_BIT_STRING));
536
537 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len));
538 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf,
539 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
540 MBEDTLS_ASN1_CONSTRUCTED | 1));
541 len += pub_len;
542
543 /* parameters */
544 grp_id = mbedtls_pk_get_group_id(pk);
545 MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(p, buf, grp_id));
546 MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_len(p, buf, par_len));
547 MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_tag(p, buf,
548 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
549 MBEDTLS_ASN1_CONSTRUCTED | 0));
550 len += par_len;
551
552 /* privateKey */
553 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk));
554
555 /* version */
556 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 1));
557
558 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
559 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED |
560 MBEDTLS_ASN1_SEQUENCE));
561
562 return (int) len;
563}
Valerio Setti81d75122023-06-14 14:49:33 +0200564#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500565
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200566#if defined(MBEDTLS_RSA_C)
valerioc0bac572023-05-31 12:15:41 +0200567static int pk_write_rsa_der(unsigned char **p, unsigned char *buf,
568 const mbedtls_pk_context *pk)
569{
570 size_t len = 0;
571 int ret;
572
573#if defined(MBEDTLS_USE_PSA_CRYPTO)
574 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
575 uint8_t tmp[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
576 size_t tmp_len = 0;
577
578 if (psa_export_key(pk->priv_id, tmp, sizeof(tmp), &tmp_len) != PSA_SUCCESS) {
579 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
580 }
581 *p -= tmp_len;
582 memcpy(*p, tmp, tmp_len);
583 len += tmp_len;
584 mbedtls_platform_zeroize(tmp, sizeof(tmp));
585 } else
586#endif /* MBEDTLS_USE_PSA_CRYPTO */
587 {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100588 mbedtls_mpi T; /* Temporary holding the exported parameters */
valerioc0bac572023-05-31 12:15:41 +0200589 mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200590
Hanno Becker15f81fa2017-08-23 12:38:27 +0100591 /*
592 * Export the parameters one after another to avoid simultaneous copies.
593 */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200594
Gilles Peskine449bd832023-01-11 14:50:10 +0100595 mbedtls_mpi_init(&T);
Hanno Becker15f81fa2017-08-23 12:38:27 +0100596
597 /* Export QP */
Gilles Peskine449bd832023-01-11 14:50:10 +0100598 if ((ret = mbedtls_rsa_export_crt(rsa, NULL, NULL, &T)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200599 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100600 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100601 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100602 len += ret;
603
604 /* Export DQ */
Gilles Peskine449bd832023-01-11 14:50:10 +0100605 if ((ret = mbedtls_rsa_export_crt(rsa, NULL, &T, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200606 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100607 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100608 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100609 len += ret;
610
611 /* Export DP */
Gilles Peskine449bd832023-01-11 14:50:10 +0100612 if ((ret = mbedtls_rsa_export_crt(rsa, &T, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200613 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100614 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100615 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100616 len += ret;
617
618 /* Export Q */
Gilles Peskine449bd832023-01-11 14:50:10 +0100619 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
620 &T, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200621 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100622 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100623 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100624 len += ret;
625
626 /* Export P */
Gilles Peskine449bd832023-01-11 14:50:10 +0100627 if ((ret = mbedtls_rsa_export(rsa, NULL, &T,
628 NULL, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200629 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100630 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100631 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100632 len += ret;
633
634 /* Export D */
Gilles Peskine449bd832023-01-11 14:50:10 +0100635 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
636 NULL, &T, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200637 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100638 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100639 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100640 len += ret;
641
642 /* Export E */
Gilles Peskine449bd832023-01-11 14:50:10 +0100643 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
644 NULL, NULL, &T)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200645 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100646 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100647 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100648 len += ret;
649
650 /* Export N */
Gilles Peskine449bd832023-01-11 14:50:10 +0100651 if ((ret = mbedtls_rsa_export(rsa, &T, NULL,
652 NULL, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200653 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100654 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100655 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100656 len += ret;
657
Gilles Peskine449bd832023-01-11 14:50:10 +0100658end_of_export:
Hanno Becker15f81fa2017-08-23 12:38:27 +0100659
Gilles Peskine449bd832023-01-11 14:50:10 +0100660 mbedtls_mpi_free(&T);
661 if (ret < 0) {
662 return ret;
663 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100664
valerioc0bac572023-05-31 12:15:41 +0200665 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0));
666 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
667 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p,
Gilles Peskine449bd832023-01-11 14:50:10 +0100668 buf, MBEDTLS_ASN1_CONSTRUCTED |
669 MBEDTLS_ASN1_SEQUENCE));
valerioc0bac572023-05-31 12:15:41 +0200670 }
671
672 return (int) len;
673}
674#endif /* MBEDTLS_RSA_C */
675
676int mbedtls_pk_write_key_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
677{
678 unsigned char *c;
valerioc0bac572023-05-31 12:15:41 +0200679#if defined(MBEDTLS_RSA_C)
680 int is_rsa_opaque = 0;
681#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200682#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200683 int is_ec_opaque = 0;
Valerio Setti81d75122023-06-14 14:49:33 +0200684#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioc0bac572023-05-31 12:15:41 +0200685#if defined(MBEDTLS_USE_PSA_CRYPTO)
valeriof9139e52023-05-31 18:01:33 +0200686 psa_key_type_t opaque_key_type;
valerioc0bac572023-05-31 12:15:41 +0200687#endif /* MBEDTLS_USE_PSA_CRYPTO */
688
689 if (size == 0) {
690 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
691 }
692
693 c = buf + size;
694
695#if defined(MBEDTLS_USE_PSA_CRYPTO)
696 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
valeriof9139e52023-05-31 18:01:33 +0200697 opaque_key_type = pk_get_opaque_key_type(key);
valerioc0bac572023-05-31 12:15:41 +0200698#if defined(MBEDTLS_RSA_C)
699 is_rsa_opaque = PSA_KEY_TYPE_IS_RSA(opaque_key_type);
700#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200701#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200702 is_ec_opaque = PSA_KEY_TYPE_IS_ECC(opaque_key_type);
Valerio Setti81d75122023-06-14 14:49:33 +0200703#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioc0bac572023-05-31 12:15:41 +0200704 }
705#endif /* MBEDTLS_USE_PSA_CRYPTO */
706
707#if defined(MBEDTLS_RSA_C)
708 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) || is_rsa_opaque) {
709 return pk_write_rsa_der(&c, buf, key);
Gilles Peskine449bd832023-01-11 14:50:10 +0100710 } else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200711#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200712#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200713 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) || is_ec_opaque) {
Jethro Beekman01672442023-04-19 14:08:14 +0200714#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
Valerio Setti00e8dd12023-05-18 18:56:59 +0200715 if (mbedtls_pk_is_rfc8410(key)) {
716 return pk_write_ec_rfc8410_der(&c, buf, key);
Jethro Beekman01672442023-04-19 14:08:14 +0200717 }
valerioc0bac572023-05-31 12:15:41 +0200718#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
719 return pk_write_ec_der(&c, buf, key);
Gilles Peskine449bd832023-01-11 14:50:10 +0100720 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200721#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Gilles Peskine449bd832023-01-11 14:50:10 +0100722 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200723}
724
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200725#if defined(MBEDTLS_PEM_WRITE_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200726
727#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n"
728#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n"
729
730#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n"
731#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n"
732#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n"
733#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n"
Jethro Beekman01672442023-04-19 14:08:14 +0200734#define PEM_BEGIN_PRIVATE_KEY_PKCS8 "-----BEGIN PRIVATE KEY-----\n"
735#define PEM_END_PRIVATE_KEY_PKCS8 "-----END PRIVATE KEY-----\n"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200736
Neil Armstronge9ecd272022-03-01 10:03:21 +0100737#define PUB_DER_MAX_BYTES \
Gilles Peskine449bd832023-01-11 14:50:10 +0100738 (MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES > MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES ? \
739 MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES : MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES)
Neil Armstronge9ecd272022-03-01 10:03:21 +0100740#define PRV_DER_MAX_BYTES \
Gilles Peskine449bd832023-01-11 14:50:10 +0100741 (MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES > MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES ? \
742 MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES : MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES)
Manuel Pégourié-Gonnard192253a2014-07-21 16:37:15 +0200743
Gilles Peskine449bd832023-01-11 14:50:10 +0100744int mbedtls_pk_write_pubkey_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200745{
Janos Follath24eed8d2019-11-22 13:21:35 +0000746 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Yanray Wang45ad3062023-08-11 15:03:51 +0800747 unsigned char *output_buf = NULL;
Yanray Wang08d5f462023-08-21 15:15:19 +0800748 output_buf = mbedtls_calloc(1, PUB_DER_MAX_BYTES);
Yanray Wang45ad3062023-08-11 15:03:51 +0800749 if (output_buf == NULL) {
750 return MBEDTLS_ERR_PK_ALLOC_FAILED;
751 }
Paul Bakker77e23fb2013-09-15 20:03:26 +0200752 size_t olen = 0;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200753
Gilles Peskine449bd832023-01-11 14:50:10 +0100754 if ((ret = mbedtls_pk_write_pubkey_der(key, output_buf,
Yanray Wang45ad3062023-08-11 15:03:51 +0800755 PUB_DER_MAX_BYTES)) < 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800756 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200757 }
758
Gilles Peskine449bd832023-01-11 14:50:10 +0100759 if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
Yanray Wang45ad3062023-08-11 15:03:51 +0800760 output_buf + PUB_DER_MAX_BYTES - ret,
Gilles Peskine449bd832023-01-11 14:50:10 +0100761 ret, buf, size, &olen)) != 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800762 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200763 }
764
Yanray Wang7226df02023-08-11 15:52:09 +0800765 ret = 0;
766cleanup:
Yanray Wang08d5f462023-08-21 15:15:19 +0800767 mbedtls_free(output_buf);
Yanray Wang7226df02023-08-11 15:52:09 +0800768 return ret;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200769}
770
Gilles Peskine449bd832023-01-11 14:50:10 +0100771int mbedtls_pk_write_key_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200772{
Janos Follath24eed8d2019-11-22 13:21:35 +0000773 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Yanray Wangc84086e2023-08-11 15:33:07 +0800774 unsigned char *output_buf = NULL;
Yanray Wang08d5f462023-08-21 15:15:19 +0800775 output_buf = mbedtls_calloc(1, PRV_DER_MAX_BYTES);
Yanray Wangc84086e2023-08-11 15:33:07 +0800776 if (output_buf == NULL) {
777 return MBEDTLS_ERR_PK_ALLOC_FAILED;
778 }
Paul Bakkerfcc17212013-10-11 09:36:52 +0200779 const char *begin, *end;
Paul Bakker77e23fb2013-09-15 20:03:26 +0200780 size_t olen = 0;
Valerio Setti81d75122023-06-14 14:49:33 +0200781#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200782 int is_ec_opaque = 0;
783#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
784 int is_montgomery_opaque = 0;
785#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Valerio Setti81d75122023-06-14 14:49:33 +0200786#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioe279e502023-05-31 12:16:12 +0200787#if defined(MBEDTLS_RSA_C)
788 int is_rsa_opaque = 0;
789#endif
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200790
Yanray Wangc84086e2023-08-11 15:33:07 +0800791 if ((ret = mbedtls_pk_write_key_der(key, output_buf, PRV_DER_MAX_BYTES)) < 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800792 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +0100793 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200794
valerioe279e502023-05-31 12:16:12 +0200795#if defined(MBEDTLS_USE_PSA_CRYPTO)
796 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
797 psa_key_type_t opaque_key_type = pk_get_opaque_key_type(key);
798
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200799#if defined(MBEDTLS_RSA_C)
valerioe279e502023-05-31 12:16:12 +0200800 is_rsa_opaque = PSA_KEY_TYPE_IS_RSA(opaque_key_type);
801#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200802#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200803 is_ec_opaque = PSA_KEY_TYPE_IS_ECC(opaque_key_type);
804#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
805 if (pk_get_opaque_ec_family(key) == PSA_ECC_FAMILY_MONTGOMERY) {
806 is_montgomery_opaque = 1;
807 }
808#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Valerio Setti81d75122023-06-14 14:49:33 +0200809#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioe279e502023-05-31 12:16:12 +0200810 }
811#endif /* MBEDTLS_USE_PSA_CRYPTO */
812
813#if defined(MBEDTLS_RSA_C)
814 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) || is_rsa_opaque) {
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200815 begin = PEM_BEGIN_PRIVATE_KEY_RSA;
816 end = PEM_END_PRIVATE_KEY_RSA;
Gilles Peskine449bd832023-01-11 14:50:10 +0100817 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200818#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200819#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200820 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) || is_ec_opaque) {
Jethro Beekman01672442023-04-19 14:08:14 +0200821#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
valerioe279e502023-05-31 12:16:12 +0200822 if (is_montgomery_opaque ||
823 ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) &&
824 (mbedtls_pk_is_rfc8410(key)))) {
Jethro Beekman01672442023-04-19 14:08:14 +0200825 begin = PEM_BEGIN_PRIVATE_KEY_PKCS8;
826 end = PEM_END_PRIVATE_KEY_PKCS8;
827 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200828#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Jethro Beekman01672442023-04-19 14:08:14 +0200829 {
830 begin = PEM_BEGIN_PRIVATE_KEY_EC;
831 end = PEM_END_PRIVATE_KEY_EC;
832 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100833 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200834#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Yanray Wangc84086e2023-08-11 15:33:07 +0800835 {
Yanray Wang7226df02023-08-11 15:52:09 +0800836 ret = MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
837 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200838 }
839
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200840 if ((ret = mbedtls_pem_write_buffer(begin, end,
Yanray Wangc84086e2023-08-11 15:33:07 +0800841 output_buf + PRV_DER_MAX_BYTES - ret,
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200842 ret, buf, size, &olen)) != 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800843 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200844 }
845
Yanray Wang7226df02023-08-11 15:52:09 +0800846 ret = 0;
847cleanup:
Yanray Wang044eb162023-08-28 10:35:39 +0800848 mbedtls_zeroize_and_free(output_buf, PRV_DER_MAX_BYTES);
Yanray Wang7226df02023-08-11 15:52:09 +0800849 return ret;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200850}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200851#endif /* MBEDTLS_PEM_WRITE_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200852
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200853#endif /* MBEDTLS_PK_WRITE_C */