blob: e38bc27debcc5e1cd7ba6bed5358bef924489f4c [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
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020018 */
19
Gilles Peskinedb09ef62020-06-03 01:43:33 +020020#include "common.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020021
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020022#if defined(MBEDTLS_PK_WRITE_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020023
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/pk.h"
25#include "mbedtls/asn1write.h"
26#include "mbedtls/oid.h"
Andrzej Kurekc470b6b2019-01-31 08:20:20 -050027#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000028#include "mbedtls/error.h"
Valerio Setti77a75682023-05-15 11:18:46 +020029#include "pk_internal.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020030
Rich Evans00ab4702015-02-06 13:43:58 +000031#include <string.h>
32
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020033#if defined(MBEDTLS_RSA_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000034#include "mbedtls/rsa.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020035#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020036#if defined(MBEDTLS_ECP_C)
Gilles Peskine2700cfb2018-08-11 00:48:44 +020037#include "mbedtls/bignum.h"
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000038#include "mbedtls/ecp.h"
Gilles Peskine2700cfb2018-08-11 00:48:44 +020039#include "mbedtls/platform_util.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020040#endif
Valerio Setti81d75122023-06-14 14:49:33 +020041#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Valerio Setti4064dbb2023-05-17 15:33:07 +020042#include "pk_internal.h"
43#endif
Valerio Setti81d75122023-06-14 14:49:33 +020044#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Neil Armstronge0326a62022-02-25 08:57:19 +010045#include "pkwrite.h"
46#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020047#if defined(MBEDTLS_ECDSA_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000048#include "mbedtls/ecdsa.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020049#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020050#if defined(MBEDTLS_PEM_WRITE_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000051#include "mbedtls/pem.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020052#endif
53
Andrzej Kurek5fec0862018-11-19 10:07:36 -050054#if defined(MBEDTLS_USE_PSA_CRYPTO)
55#include "psa/crypto.h"
Manuel Pégourié-Gonnard2be8c632023-06-07 13:07:21 +020056#include "psa_util_internal.h"
Andrzej Kurek5fec0862018-11-19 10:07:36 -050057#endif
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000058#include "mbedtls/platform.h"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +020059
Valerio Settie0e63112023-05-18 18:48:07 +020060/* Helper for Montgomery curves */
Valerio Setti81d75122023-06-14 14:49:33 +020061#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valeriob7273142023-05-31 12:07:18 +020062#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
Valerio Settie0e63112023-05-18 18:48:07 +020063static inline int mbedtls_pk_is_rfc8410(const mbedtls_pk_context *pk)
64{
65 mbedtls_ecp_group_id id = mbedtls_pk_get_group_id(pk);
66
Valerio Settidb6b4db2023-09-01 09:20:51 +020067#if defined(MBEDTLS_ECP_HAVE_CURVE25519)
Valerio Settie0e63112023-05-18 18:48:07 +020068 if (id == MBEDTLS_ECP_DP_CURVE25519) {
69 return 1;
70 }
71#endif
Valerio Settidb6b4db2023-09-01 09:20:51 +020072#if defined(MBEDTLS_ECP_HAVE_CURVE448)
Valerio Settie0e63112023-05-18 18:48:07 +020073 if (id == MBEDTLS_ECP_DP_CURVE448) {
74 return 1;
75 }
76#endif
77 return 0;
78}
Valerio Setti81d75122023-06-14 14:49:33 +020079
Ronald Cronb9c79532023-09-07 14:20:49 +020080#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PEM_WRITE_C)
valeriob7273142023-05-31 12:07:18 +020081/* It is assumed that the input key is opaque */
82static psa_ecc_family_t pk_get_opaque_ec_family(const mbedtls_pk_context *pk)
83{
84 psa_ecc_family_t ec_family = 0;
85 psa_key_attributes_t key_attrs = PSA_KEY_ATTRIBUTES_INIT;
86
87 if (psa_get_key_attributes(pk->priv_id, &key_attrs) != PSA_SUCCESS) {
88 return 0;
89 }
90 ec_family = PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(&key_attrs));
91 psa_reset_key_attributes(&key_attrs);
92
93 return ec_family;
94}
Ronald Cronb9c79532023-09-07 14:20:49 +020095#endif /* MBETLS_USE_PSA_CRYPTO && MBEDTLS_PEM_WRITE_C */
Valerio Settie1651362023-06-19 14:19:44 +020096#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
97#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valeriob7273142023-05-31 12:07:18 +020098
Valerio Settie1651362023-06-19 14:19:44 +020099#if defined(MBEDTLS_USE_PSA_CRYPTO)
valeriob7273142023-05-31 12:07:18 +0200100/* It is assumed that the input key is opaque */
101static psa_key_type_t pk_get_opaque_key_type(const mbedtls_pk_context *pk)
102{
103 psa_key_attributes_t opaque_attrs = PSA_KEY_ATTRIBUTES_INIT;
104 psa_key_type_t opaque_key_type;
105
106 if (psa_get_key_attributes(pk->priv_id, &opaque_attrs) != PSA_SUCCESS) {
107 return 0;
108 }
109 opaque_key_type = psa_get_key_type(&opaque_attrs);
110 psa_reset_key_attributes(&opaque_attrs);
111
112 return opaque_key_type;
113}
114#endif /* MBETLS_USE_PSA_CRYPTO */
Valerio Settie0e63112023-05-18 18:48:07 +0200115
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200116#if defined(MBEDTLS_RSA_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200117/*
118 * RSAPublicKey ::= SEQUENCE {
119 * modulus INTEGER, -- n
120 * publicExponent INTEGER -- e
121 * }
122 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100123static int pk_write_rsa_pubkey(unsigned char **p, unsigned char *start,
valerio9ea26172023-05-31 12:10:23 +0200124 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200125{
Janos Follath24eed8d2019-11-22 13:21:35 +0000126 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200127 size_t len = 0;
Hanno Becker15f81fa2017-08-23 12:38:27 +0100128 mbedtls_mpi T;
valerio9ea26172023-05-31 12:10:23 +0200129 mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200130
Gilles Peskine449bd832023-01-11 14:50:10 +0100131 mbedtls_mpi_init(&T);
Hanno Becker15f81fa2017-08-23 12:38:27 +0100132
133 /* Export E */
Gilles Peskine449bd832023-01-11 14:50:10 +0100134 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, NULL, &T)) != 0 ||
135 (ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100136 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100137 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100138 len += ret;
139
140 /* Export N */
Gilles Peskine449bd832023-01-11 14:50:10 +0100141 if ((ret = mbedtls_rsa_export(rsa, &T, NULL, NULL, NULL, NULL)) != 0 ||
142 (ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100143 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100144 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100145 len += ret;
146
147end_of_export:
148
Gilles Peskine449bd832023-01-11 14:50:10 +0100149 mbedtls_mpi_free(&T);
150 if (ret < 0) {
151 return ret;
152 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200153
Gilles Peskine449bd832023-01-11 14:50:10 +0100154 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
155 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED |
156 MBEDTLS_ASN1_SEQUENCE));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200157
Gilles Peskine449bd832023-01-11 14:50:10 +0100158 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200159}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200160#endif /* MBEDTLS_RSA_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200161
Valerio Setti81d75122023-06-14 14:49:33 +0200162#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerio9ea26172023-05-31 12:10:23 +0200163#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
Gilles Peskine449bd832023-01-11 14:50:10 +0100164static int pk_write_ec_pubkey(unsigned char **p, unsigned char *start,
Valerio Setti4064dbb2023-05-17 15:33:07 +0200165 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200166{
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200167 size_t len = 0;
Valerio Settie1d7c9d2023-08-10 07:40:18 +0200168 uint8_t buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
Valerio Setti4064dbb2023-05-17 15:33:07 +0200169
valerio9ea26172023-05-31 12:10:23 +0200170 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
171 if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) {
172 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
173 }
174 } else {
175 len = pk->pub_raw_len;
valeriof9139e52023-05-31 18:01:33 +0200176 memcpy(buf, pk->pub_raw, len);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200177 }
178
Gilles Peskine449bd832023-01-11 14:50:10 +0100179 if (*p < start || (size_t) (*p - start) < len) {
180 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
181 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200182
183 *p -= len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100184 memcpy(*p, buf, len);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200185
Gilles Peskine449bd832023-01-11 14:50:10 +0100186 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200187}
valerio9ea26172023-05-31 12:10:23 +0200188#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
189static int pk_write_ec_pubkey(unsigned char **p, unsigned char *start,
190 const mbedtls_pk_context *pk)
191{
192 size_t len = 0;
193#if defined(MBEDTLS_USE_PSA_CRYPTO)
194 uint8_t buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
195#else
196 unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN];
197#endif /* MBEDTLS_USE_PSA_CRYPTO */
198 mbedtls_ecp_keypair *ec = mbedtls_pk_ec(*pk);
199 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
200
201#if defined(MBEDTLS_USE_PSA_CRYPTO)
202 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
203 if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) {
204 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
205 }
206 *p -= len;
207 memcpy(*p, buf, len);
208 return (int) len;
209 } else
210#endif /* MBEDTLS_USE_PSA_CRYPTO */
211 {
212 if ((ret = mbedtls_ecp_point_write_binary(&ec->grp, &ec->Q,
213 MBEDTLS_ECP_PF_UNCOMPRESSED,
214 &len, buf, sizeof(buf))) != 0) {
215 return ret;
216 }
217 }
218
219 if (*p < start || (size_t) (*p - start) < len) {
220 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
221 }
222
223 *p -= len;
224 memcpy(*p, buf, len);
225
226 return (int) len;
227}
228#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200229
230/*
231 * ECParameters ::= CHOICE {
232 * namedCurve OBJECT IDENTIFIER
233 * }
234 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100235static int pk_write_ec_param(unsigned char **p, unsigned char *start,
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200236 mbedtls_ecp_group_id grp_id)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200237{
Janos Follath24eed8d2019-11-22 13:21:35 +0000238 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200239 size_t len = 0;
240 const char *oid;
241 size_t oid_len;
242
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200243 if ((ret = mbedtls_oid_get_oid_by_ec_grp(grp_id, &oid, &oid_len)) != 0) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100244 return ret;
245 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200246
Gilles Peskine449bd832023-01-11 14:50:10 +0100247 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200248
Gilles Peskine449bd832023-01-11 14:50:10 +0100249 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200250}
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200251
252/*
253 * privateKey OCTET STRING -- always of length ceil(log2(n)/8)
254 */
valerio52b675f2023-05-31 12:14:37 +0200255#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
Gilles Peskine449bd832023-01-11 14:50:10 +0100256static int pk_write_ec_private(unsigned char **p, unsigned char *start,
Valerio Setti00e8dd12023-05-18 18:56:59 +0200257 const mbedtls_pk_context *pk)
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200258{
Valerio Setti00e8dd12023-05-18 18:56:59 +0200259 size_t byte_length;
Janos Follath24eed8d2019-11-22 13:21:35 +0000260 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Valerio Setti00e8dd12023-05-18 18:56:59 +0200261 unsigned char tmp[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
262 psa_status_t status;
263
valerio52b675f2023-05-31 12:14:37 +0200264 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
265 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
266 if (status != PSA_SUCCESS) {
267 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
268 return ret;
269 }
270 } else {
271 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
272 if (status != PSA_SUCCESS) {
273 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
274 goto exit;
275 }
Valerio Setti00e8dd12023-05-18 18:56:59 +0200276 }
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200277
Gilles Peskine449bd832023-01-11 14:50:10 +0100278 ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length);
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200279exit:
Valerio Setti00e8dd12023-05-18 18:56:59 +0200280 mbedtls_platform_zeroize(tmp, sizeof(tmp));
Gilles Peskine449bd832023-01-11 14:50:10 +0100281 return ret;
Gilles Peskine2700cfb2018-08-11 00:48:44 +0200282}
valerio52b675f2023-05-31 12:14:37 +0200283#else /* MBEDTLS_PK_USE_PSA_EC_DATA */
284static int pk_write_ec_private(unsigned char **p, unsigned char *start,
285 const mbedtls_pk_context *pk)
286{
287 size_t byte_length;
288 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
289#if defined(MBEDTLS_USE_PSA_CRYPTO)
290 unsigned char tmp[MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH];
291 psa_status_t status;
292#else
293 unsigned char tmp[MBEDTLS_ECP_MAX_BYTES];
294#endif /* MBEDTLS_USE_PSA_CRYPTO */
295
296#if defined(MBEDTLS_USE_PSA_CRYPTO)
297 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
298 status = psa_export_key(pk->priv_id, tmp, sizeof(tmp), &byte_length);
299 if (status != PSA_SUCCESS) {
300 ret = PSA_PK_ECDSA_TO_MBEDTLS_ERR(status);
301 return ret;
302 }
303 } else
304#endif /* MBEDTLS_USE_PSA_CRYPTO */
305 {
306 mbedtls_ecp_keypair *ec = mbedtls_pk_ec_rw(*pk);
307 byte_length = (ec->grp.pbits + 7) / 8;
308
309 ret = mbedtls_ecp_write_key(ec, tmp, byte_length);
310 if (ret != 0) {
311 goto exit;
312 }
313 }
314 ret = mbedtls_asn1_write_octet_string(p, start, tmp, byte_length);
315exit:
316 mbedtls_platform_zeroize(tmp, sizeof(tmp));
317 return ret;
318}
319#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
Valerio Setti81d75122023-06-14 14:49:33 +0200320#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200321
valerio9ea26172023-05-31 12:10:23 +0200322#if defined(MBEDTLS_USE_PSA_CRYPTO)
323static int pk_write_opaque_pubkey(unsigned char **p, unsigned char *start,
324 const mbedtls_pk_context *pk)
325{
326 size_t buffer_size;
327 size_t len = 0;
328
329 if (*p < start) {
330 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
331 }
332
333 buffer_size = (size_t) (*p - start);
334 if (psa_export_public_key(pk->priv_id, start, buffer_size,
335 &len) != PSA_SUCCESS) {
336 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
337 }
338
339 *p -= len;
340 memmove(*p, start, len);
341
342 return (int) len;
343}
344#endif /* MBEDTLS_USE_PSA_CRYPTO */
345
Gilles Peskine449bd832023-01-11 14:50:10 +0100346int mbedtls_pk_write_pubkey(unsigned char **p, unsigned char *start,
347 const mbedtls_pk_context *key)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200348{
Janos Follath24eed8d2019-11-22 13:21:35 +0000349 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200350 size_t len = 0;
351
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200352#if defined(MBEDTLS_RSA_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100353 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) {
valerio9ea26172023-05-31 12:10:23 +0200354 MBEDTLS_ASN1_CHK_ADD(len, pk_write_rsa_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100355 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200356#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200357#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Gilles Peskine449bd832023-01-11 14:50:10 +0100358 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) {
Valerio Setti4064dbb2023-05-17 15:33:07 +0200359 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100360 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200361#endif
Andrzej Kurek5fec0862018-11-19 10:07:36 -0500362#if defined(MBEDTLS_USE_PSA_CRYPTO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100363 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
valerio9ea26172023-05-31 12:10:23 +0200364 MBEDTLS_ASN1_CHK_ADD(len, pk_write_opaque_pubkey(p, start, key));
Gilles Peskine449bd832023-01-11 14:50:10 +0100365 } else
Andrzej Kurek5fec0862018-11-19 10:07:36 -0500366#endif /* MBEDTLS_USE_PSA_CRYPTO */
Gilles Peskine449bd832023-01-11 14:50:10 +0100367 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200368
Gilles Peskine449bd832023-01-11 14:50:10 +0100369 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200370}
371
Gilles Peskine449bd832023-01-11 14:50:10 +0100372int mbedtls_pk_write_pubkey_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200373{
Janos Follath24eed8d2019-11-22 13:21:35 +0000374 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200375 unsigned char *c;
Jethro Beekman01672442023-04-19 14:08:14 +0200376 int has_par = 1;
377 size_t len = 0, par_len = 0, oid_len = 0;
Hanno Becker493c1712019-02-01 10:07:07 +0000378 mbedtls_pk_type_t pk_type;
Valerio Setti81d75122023-06-14 14:49:33 +0200379#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekmancb706ea2023-05-04 12:28:49 +0200380 mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE;
Jethro Beekman13d415c2023-05-04 10:11:58 +0200381#endif
correya15b4852023-09-21 16:19:11 +0800382 const char *oid = NULL;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200383
Gilles Peskine449bd832023-01-11 14:50:10 +0100384 if (size == 0) {
385 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
386 }
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500387
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200388 c = buf + size;
389
Gilles Peskine449bd832023-01-11 14:50:10 +0100390 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_pk_write_pubkey(&c, buf, key));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200391
Gilles Peskine449bd832023-01-11 14:50:10 +0100392 if (c - buf < 1) {
393 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
394 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200395
396 /*
397 * SubjectPublicKeyInfo ::= SEQUENCE {
398 * algorithm AlgorithmIdentifier,
399 * subjectPublicKey BIT STRING }
400 */
401 *--c = 0;
402 len += 1;
403
Gilles Peskine449bd832023-01-11 14:50:10 +0100404 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
405 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_BIT_STRING));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200406
Gilles Peskine449bd832023-01-11 14:50:10 +0100407 pk_type = mbedtls_pk_get_type(key);
Valerio Setti81d75122023-06-14 14:49:33 +0200408#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Gilles Peskine449bd832023-01-11 14:50:10 +0100409 if (pk_type == MBEDTLS_PK_ECKEY) {
valerioba1fd322023-05-31 12:13:17 +0200410 ec_grp_id = mbedtls_pk_get_group_id(key);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200411 }
Valerio Setti81d75122023-06-14 14:49:33 +0200412#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Hanno Becker493c1712019-02-01 10:07:07 +0000413#if defined(MBEDTLS_USE_PSA_CRYPTO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100414 if (pk_type == MBEDTLS_PK_OPAQUE) {
valerioba1fd322023-05-31 12:13:17 +0200415 psa_key_type_t opaque_key_type = pk_get_opaque_key_type(key);
Valerio Setti81d75122023-06-14 14:49:33 +0200416#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioba1fd322023-05-31 12:13:17 +0200417 if (PSA_KEY_TYPE_IS_ECC(opaque_key_type)) {
valerio52b675f2023-05-31 12:14:37 +0200418 pk_type = MBEDTLS_PK_ECKEY;
valerioba1fd322023-05-31 12:13:17 +0200419 ec_grp_id = mbedtls_pk_get_group_id(key);
420 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200421#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioba1fd322023-05-31 12:13:17 +0200422 if (PSA_KEY_TYPE_IS_RSA(opaque_key_type)) {
Neil Armstrong295aeb12022-03-15 16:25:41 +0100423 /* The rest of the function works as for legacy RSA contexts. */
424 pk_type = MBEDTLS_PK_RSA;
Neil Armstrong295aeb12022-03-15 16:25:41 +0100425 }
Jethro Beekmancf4545e2023-05-04 12:05:55 +0200426 }
427 /* `pk_type` will have been changed to non-opaque by here if this function can handle it */
428 if (pk_type == MBEDTLS_PK_OPAQUE) {
429 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Hanno Becker493c1712019-02-01 10:07:07 +0000430 }
431#endif /* MBEDTLS_USE_PSA_CRYPTO */
432
Valerio Setti81d75122023-06-14 14:49:33 +0200433#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200434 if (pk_type == MBEDTLS_PK_ECKEY) {
valerioba1fd322023-05-31 12:13:17 +0200435 /* Some groups have their own AlgorithmIdentifier OID, others are handled
436 * by mbedtls_oid_get_oid_by_pk_alg() below */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200437 ret = mbedtls_oid_get_oid_by_ec_grp_algid(ec_grp_id, &oid, &oid_len);
438
439 if (ret == 0) {
valerioba1fd322023-05-31 12:13:17 +0200440 /* Currently, none of the supported algorithms that have their own
441 * AlgorithmIdentifier OID have any parameters */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200442 has_par = 0;
443 } else if (ret == MBEDTLS_ERR_OID_NOT_FOUND) {
444 MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(&c, buf, ec_grp_id));
445 } else {
446 return ret;
447 }
448 }
Valerio Setti81d75122023-06-14 14:49:33 +0200449#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Jethro Beekman8e59ebb2023-05-03 13:05:33 +0200450
Jethro Beekman01672442023-04-19 14:08:14 +0200451 if (oid_len == 0) {
452 if ((ret = mbedtls_oid_get_oid_by_pk_alg(pk_type, &oid,
453 &oid_len)) != 0) {
454 return ret;
455 }
Hanno Becker493c1712019-02-01 10:07:07 +0000456 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200457
Jethro Beekman01672442023-04-19 14:08:14 +0200458 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_algorithm_identifier_ext(&c, buf, oid, oid_len,
459 par_len, has_par));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200460
Gilles Peskine449bd832023-01-11 14:50:10 +0100461 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
462 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED |
463 MBEDTLS_ASN1_SEQUENCE));
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200464
Gilles Peskine449bd832023-01-11 14:50:10 +0100465 return (int) len;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200466}
467
Valerio Setti81d75122023-06-14 14:49:33 +0200468#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
Jethro Beekman01672442023-04-19 14:08:14 +0200469#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
470/*
Valerio Setti4064dbb2023-05-17 15:33:07 +0200471 * RFC8410 section 7
Jethro Beekman01672442023-04-19 14:08:14 +0200472 *
473 * OneAsymmetricKey ::= SEQUENCE {
474 * version Version,
475 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
476 * privateKey PrivateKey,
477 * attributes [0] IMPLICIT Attributes OPTIONAL,
478 * ...,
479 * [[2: publicKey [1] IMPLICIT PublicKey OPTIONAL ]],
480 * ...
481 * }
Valerio Setti4064dbb2023-05-17 15:33:07 +0200482 * ...
Jethro Beekman01672442023-04-19 14:08:14 +0200483 * CurvePrivateKey ::= OCTET STRING
484 */
485static int pk_write_ec_rfc8410_der(unsigned char **p, unsigned char *buf,
Valerio Setti00e8dd12023-05-18 18:56:59 +0200486 const mbedtls_pk_context *pk)
Jethro Beekman01672442023-04-19 14:08:14 +0200487{
488 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
489 size_t len = 0;
490 size_t oid_len = 0;
491 const char *oid;
Valerio Setti1194ffa2023-05-24 13:15:58 +0200492 mbedtls_ecp_group_id grp_id;
Jethro Beekman01672442023-04-19 14:08:14 +0200493
494 /* privateKey */
Valerio Setti00e8dd12023-05-18 18:56:59 +0200495 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk));
Jethro Beekman01672442023-04-19 14:08:14 +0200496 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
497 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_OCTET_STRING));
498
Valerio Setti1194ffa2023-05-24 13:15:58 +0200499 grp_id = mbedtls_pk_get_group_id(pk);
Jethro Beekman01672442023-04-19 14:08:14 +0200500 /* privateKeyAlgorithm */
Valerio Setti00e8dd12023-05-18 18:56:59 +0200501 if ((ret = mbedtls_oid_get_oid_by_ec_grp_algid(grp_id, &oid, &oid_len)) != 0) {
502 return ret;
503 }
Jethro Beekman01672442023-04-19 14:08:14 +0200504 MBEDTLS_ASN1_CHK_ADD(len,
505 mbedtls_asn1_write_algorithm_identifier_ext(p, buf, oid, oid_len, 0, 0));
506
507 /* version */
508 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0));
509
510 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
511 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED |
512 MBEDTLS_ASN1_SEQUENCE));
513
514 return (int) len;
515}
516#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Jethro Beekman01672442023-04-19 14:08:14 +0200517
valerioc0bac572023-05-31 12:15:41 +0200518/*
519 * RFC 5915, or SEC1 Appendix C.4
520 *
521 * ECPrivateKey ::= SEQUENCE {
522 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
523 * privateKey OCTET STRING,
524 * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
525 * publicKey [1] BIT STRING OPTIONAL
526 * }
527 */
528static int pk_write_ec_der(unsigned char **p, unsigned char *buf,
529 const mbedtls_pk_context *pk)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200530{
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200531 size_t len = 0;
valerioc0bac572023-05-31 12:15:41 +0200532 int ret;
533 size_t pub_len = 0, par_len = 0;
Valerio Setti00e8dd12023-05-18 18:56:59 +0200534 mbedtls_ecp_group_id grp_id;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200535
valerioc0bac572023-05-31 12:15:41 +0200536 /* publicKey */
537 MBEDTLS_ASN1_CHK_ADD(pub_len, pk_write_ec_pubkey(p, buf, pk));
538
539 if (*p - buf < 1) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100540 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
541 }
valerioc0bac572023-05-31 12:15:41 +0200542 (*p)--;
543 **p = 0;
544 pub_len += 1;
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500545
valerioc0bac572023-05-31 12:15:41 +0200546 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len));
547 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_BIT_STRING));
548
549 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_len(p, buf, pub_len));
550 MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_asn1_write_tag(p, buf,
551 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
552 MBEDTLS_ASN1_CONSTRUCTED | 1));
553 len += pub_len;
554
555 /* parameters */
556 grp_id = mbedtls_pk_get_group_id(pk);
557 MBEDTLS_ASN1_CHK_ADD(par_len, pk_write_ec_param(p, buf, grp_id));
558 MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_len(p, buf, par_len));
559 MBEDTLS_ASN1_CHK_ADD(par_len, mbedtls_asn1_write_tag(p, buf,
560 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
561 MBEDTLS_ASN1_CONSTRUCTED | 0));
562 len += par_len;
563
564 /* privateKey */
565 MBEDTLS_ASN1_CHK_ADD(len, pk_write_ec_private(p, buf, pk));
566
567 /* version */
568 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 1));
569
570 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
571 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, buf, MBEDTLS_ASN1_CONSTRUCTED |
572 MBEDTLS_ASN1_SEQUENCE));
573
574 return (int) len;
575}
Valerio Setti81d75122023-06-14 14:49:33 +0200576#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500577
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200578#if defined(MBEDTLS_RSA_C)
valerioc0bac572023-05-31 12:15:41 +0200579static int pk_write_rsa_der(unsigned char **p, unsigned char *buf,
580 const mbedtls_pk_context *pk)
581{
582 size_t len = 0;
583 int ret;
584
585#if defined(MBEDTLS_USE_PSA_CRYPTO)
586 if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
587 uint8_t tmp[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
588 size_t tmp_len = 0;
589
590 if (psa_export_key(pk->priv_id, tmp, sizeof(tmp), &tmp_len) != PSA_SUCCESS) {
591 return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
592 }
593 *p -= tmp_len;
594 memcpy(*p, tmp, tmp_len);
595 len += tmp_len;
596 mbedtls_platform_zeroize(tmp, sizeof(tmp));
597 } else
598#endif /* MBEDTLS_USE_PSA_CRYPTO */
599 {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100600 mbedtls_mpi T; /* Temporary holding the exported parameters */
valerioc0bac572023-05-31 12:15:41 +0200601 mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200602
Hanno Becker15f81fa2017-08-23 12:38:27 +0100603 /*
604 * Export the parameters one after another to avoid simultaneous copies.
605 */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200606
Gilles Peskine449bd832023-01-11 14:50:10 +0100607 mbedtls_mpi_init(&T);
Hanno Becker15f81fa2017-08-23 12:38:27 +0100608
609 /* Export QP */
Gilles Peskine449bd832023-01-11 14:50:10 +0100610 if ((ret = mbedtls_rsa_export_crt(rsa, NULL, NULL, &T)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200611 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100612 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100613 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100614 len += ret;
615
616 /* Export DQ */
Gilles Peskine449bd832023-01-11 14:50:10 +0100617 if ((ret = mbedtls_rsa_export_crt(rsa, NULL, &T, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200618 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100619 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100620 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100621 len += ret;
622
623 /* Export DP */
Gilles Peskine449bd832023-01-11 14:50:10 +0100624 if ((ret = mbedtls_rsa_export_crt(rsa, &T, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200625 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100626 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100627 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100628 len += ret;
629
630 /* Export Q */
Gilles Peskine449bd832023-01-11 14:50:10 +0100631 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
632 &T, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200633 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100634 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100635 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100636 len += ret;
637
638 /* Export P */
Gilles Peskine449bd832023-01-11 14:50:10 +0100639 if ((ret = mbedtls_rsa_export(rsa, NULL, &T,
640 NULL, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200641 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100642 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100643 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100644 len += ret;
645
646 /* Export D */
Gilles Peskine449bd832023-01-11 14:50:10 +0100647 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
648 NULL, &T, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200649 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100650 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100651 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100652 len += ret;
653
654 /* Export E */
Gilles Peskine449bd832023-01-11 14:50:10 +0100655 if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
656 NULL, NULL, &T)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200657 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100658 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100659 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100660 len += ret;
661
662 /* Export N */
Gilles Peskine449bd832023-01-11 14:50:10 +0100663 if ((ret = mbedtls_rsa_export(rsa, &T, NULL,
664 NULL, NULL, NULL)) != 0 ||
valerioc0bac572023-05-31 12:15:41 +0200665 (ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
Hanno Becker15f81fa2017-08-23 12:38:27 +0100666 goto end_of_export;
Gilles Peskine449bd832023-01-11 14:50:10 +0100667 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100668 len += ret;
669
Gilles Peskine449bd832023-01-11 14:50:10 +0100670end_of_export:
Hanno Becker15f81fa2017-08-23 12:38:27 +0100671
Gilles Peskine449bd832023-01-11 14:50:10 +0100672 mbedtls_mpi_free(&T);
673 if (ret < 0) {
674 return ret;
675 }
Hanno Becker15f81fa2017-08-23 12:38:27 +0100676
valerioc0bac572023-05-31 12:15:41 +0200677 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0));
678 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
679 MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p,
Gilles Peskine449bd832023-01-11 14:50:10 +0100680 buf, MBEDTLS_ASN1_CONSTRUCTED |
681 MBEDTLS_ASN1_SEQUENCE));
valerioc0bac572023-05-31 12:15:41 +0200682 }
683
684 return (int) len;
685}
686#endif /* MBEDTLS_RSA_C */
687
688int mbedtls_pk_write_key_der(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
689{
690 unsigned char *c;
valerioc0bac572023-05-31 12:15:41 +0200691#if defined(MBEDTLS_RSA_C)
692 int is_rsa_opaque = 0;
693#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200694#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200695 int is_ec_opaque = 0;
Valerio Setti81d75122023-06-14 14:49:33 +0200696#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioc0bac572023-05-31 12:15:41 +0200697#if defined(MBEDTLS_USE_PSA_CRYPTO)
valeriof9139e52023-05-31 18:01:33 +0200698 psa_key_type_t opaque_key_type;
valerioc0bac572023-05-31 12:15:41 +0200699#endif /* MBEDTLS_USE_PSA_CRYPTO */
700
701 if (size == 0) {
702 return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
703 }
704
705 c = buf + size;
706
707#if defined(MBEDTLS_USE_PSA_CRYPTO)
708 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
valeriof9139e52023-05-31 18:01:33 +0200709 opaque_key_type = pk_get_opaque_key_type(key);
valerioc0bac572023-05-31 12:15:41 +0200710#if defined(MBEDTLS_RSA_C)
711 is_rsa_opaque = PSA_KEY_TYPE_IS_RSA(opaque_key_type);
712#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200713#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200714 is_ec_opaque = PSA_KEY_TYPE_IS_ECC(opaque_key_type);
Valerio Setti81d75122023-06-14 14:49:33 +0200715#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioc0bac572023-05-31 12:15:41 +0200716 }
717#endif /* MBEDTLS_USE_PSA_CRYPTO */
718
719#if defined(MBEDTLS_RSA_C)
720 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) || is_rsa_opaque) {
721 return pk_write_rsa_der(&c, buf, key);
Gilles Peskine449bd832023-01-11 14:50:10 +0100722 } else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200723#endif /* MBEDTLS_RSA_C */
Valerio Setti81d75122023-06-14 14:49:33 +0200724#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioc0bac572023-05-31 12:15:41 +0200725 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) || is_ec_opaque) {
Jethro Beekman01672442023-04-19 14:08:14 +0200726#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
Valerio Setti00e8dd12023-05-18 18:56:59 +0200727 if (mbedtls_pk_is_rfc8410(key)) {
728 return pk_write_ec_rfc8410_der(&c, buf, key);
Jethro Beekman01672442023-04-19 14:08:14 +0200729 }
valerioc0bac572023-05-31 12:15:41 +0200730#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
731 return pk_write_ec_der(&c, buf, key);
Gilles Peskine449bd832023-01-11 14:50:10 +0100732 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200733#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Gilles Peskine449bd832023-01-11 14:50:10 +0100734 return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200735}
736
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200737#if defined(MBEDTLS_PEM_WRITE_C)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200738
739#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n"
740#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n"
741
742#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n"
743#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n"
744#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n"
745#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n"
Jethro Beekman01672442023-04-19 14:08:14 +0200746#define PEM_BEGIN_PRIVATE_KEY_PKCS8 "-----BEGIN PRIVATE KEY-----\n"
747#define PEM_END_PRIVATE_KEY_PKCS8 "-----END PRIVATE KEY-----\n"
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200748
Neil Armstronge9ecd272022-03-01 10:03:21 +0100749#define PUB_DER_MAX_BYTES \
Gilles Peskine449bd832023-01-11 14:50:10 +0100750 (MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES > MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES ? \
751 MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES : MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES)
Neil Armstronge9ecd272022-03-01 10:03:21 +0100752#define PRV_DER_MAX_BYTES \
Gilles Peskine449bd832023-01-11 14:50:10 +0100753 (MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES > MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES ? \
754 MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES : MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES)
Manuel Pégourié-Gonnard192253a2014-07-21 16:37:15 +0200755
Gilles Peskine449bd832023-01-11 14:50:10 +0100756int mbedtls_pk_write_pubkey_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200757{
Janos Follath24eed8d2019-11-22 13:21:35 +0000758 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Yanray Wang45ad3062023-08-11 15:03:51 +0800759 unsigned char *output_buf = NULL;
Yanray Wang08d5f462023-08-21 15:15:19 +0800760 output_buf = mbedtls_calloc(1, PUB_DER_MAX_BYTES);
Yanray Wang45ad3062023-08-11 15:03:51 +0800761 if (output_buf == NULL) {
762 return MBEDTLS_ERR_PK_ALLOC_FAILED;
763 }
Paul Bakker77e23fb2013-09-15 20:03:26 +0200764 size_t olen = 0;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200765
Gilles Peskine449bd832023-01-11 14:50:10 +0100766 if ((ret = mbedtls_pk_write_pubkey_der(key, output_buf,
Yanray Wang45ad3062023-08-11 15:03:51 +0800767 PUB_DER_MAX_BYTES)) < 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800768 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200769 }
770
Gilles Peskine449bd832023-01-11 14:50:10 +0100771 if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
Yanray Wang45ad3062023-08-11 15:03:51 +0800772 output_buf + PUB_DER_MAX_BYTES - ret,
Gilles Peskine449bd832023-01-11 14:50:10 +0100773 ret, buf, size, &olen)) != 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800774 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200775 }
776
Yanray Wang7226df02023-08-11 15:52:09 +0800777 ret = 0;
778cleanup:
Yanray Wang08d5f462023-08-21 15:15:19 +0800779 mbedtls_free(output_buf);
Yanray Wang7226df02023-08-11 15:52:09 +0800780 return ret;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200781}
782
Gilles Peskine449bd832023-01-11 14:50:10 +0100783int mbedtls_pk_write_key_pem(const mbedtls_pk_context *key, unsigned char *buf, size_t size)
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200784{
Janos Follath24eed8d2019-11-22 13:21:35 +0000785 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Yanray Wangc84086e2023-08-11 15:33:07 +0800786 unsigned char *output_buf = NULL;
Yanray Wang08d5f462023-08-21 15:15:19 +0800787 output_buf = mbedtls_calloc(1, PRV_DER_MAX_BYTES);
Yanray Wangc84086e2023-08-11 15:33:07 +0800788 if (output_buf == NULL) {
789 return MBEDTLS_ERR_PK_ALLOC_FAILED;
790 }
Paul Bakkerfcc17212013-10-11 09:36:52 +0200791 const char *begin, *end;
Paul Bakker77e23fb2013-09-15 20:03:26 +0200792 size_t olen = 0;
Valerio Setti81d75122023-06-14 14:49:33 +0200793#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200794 int is_ec_opaque = 0;
795#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
796 int is_montgomery_opaque = 0;
797#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Valerio Setti81d75122023-06-14 14:49:33 +0200798#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioe279e502023-05-31 12:16:12 +0200799#if defined(MBEDTLS_RSA_C)
800 int is_rsa_opaque = 0;
801#endif
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200802
Yanray Wangc84086e2023-08-11 15:33:07 +0800803 if ((ret = mbedtls_pk_write_key_der(key, output_buf, PRV_DER_MAX_BYTES)) < 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800804 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +0100805 }
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200806
valerioe279e502023-05-31 12:16:12 +0200807#if defined(MBEDTLS_USE_PSA_CRYPTO)
808 if (mbedtls_pk_get_type(key) == MBEDTLS_PK_OPAQUE) {
809 psa_key_type_t opaque_key_type = pk_get_opaque_key_type(key);
810
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200811#if defined(MBEDTLS_RSA_C)
valerioe279e502023-05-31 12:16:12 +0200812 is_rsa_opaque = PSA_KEY_TYPE_IS_RSA(opaque_key_type);
813#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200814#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200815 is_ec_opaque = PSA_KEY_TYPE_IS_ECC(opaque_key_type);
816#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
817 if (pk_get_opaque_ec_family(key) == PSA_ECC_FAMILY_MONTGOMERY) {
818 is_montgomery_opaque = 1;
819 }
820#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Valerio Setti81d75122023-06-14 14:49:33 +0200821#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
valerioe279e502023-05-31 12:16:12 +0200822 }
823#endif /* MBEDTLS_USE_PSA_CRYPTO */
824
825#if defined(MBEDTLS_RSA_C)
826 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) || is_rsa_opaque) {
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200827 begin = PEM_BEGIN_PRIVATE_KEY_RSA;
828 end = PEM_END_PRIVATE_KEY_RSA;
Gilles Peskine449bd832023-01-11 14:50:10 +0100829 } else
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200830#endif
Valerio Setti81d75122023-06-14 14:49:33 +0200831#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
valerioe279e502023-05-31 12:16:12 +0200832 if ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) || is_ec_opaque) {
Jethro Beekman01672442023-04-19 14:08:14 +0200833#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
valerioe279e502023-05-31 12:16:12 +0200834 if (is_montgomery_opaque ||
835 ((mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) &&
836 (mbedtls_pk_is_rfc8410(key)))) {
Jethro Beekman01672442023-04-19 14:08:14 +0200837 begin = PEM_BEGIN_PRIVATE_KEY_PKCS8;
838 end = PEM_END_PRIVATE_KEY_PKCS8;
839 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200840#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
Jethro Beekman01672442023-04-19 14:08:14 +0200841 {
842 begin = PEM_BEGIN_PRIVATE_KEY_EC;
843 end = PEM_END_PRIVATE_KEY_EC;
844 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100845 } else
Valerio Setti81d75122023-06-14 14:49:33 +0200846#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
Yanray Wangc84086e2023-08-11 15:33:07 +0800847 {
Yanray Wang7226df02023-08-11 15:52:09 +0800848 ret = MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
849 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200850 }
851
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200852 if ((ret = mbedtls_pem_write_buffer(begin, end,
Yanray Wangc84086e2023-08-11 15:33:07 +0800853 output_buf + PRV_DER_MAX_BYTES - ret,
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200854 ret, buf, size, &olen)) != 0) {
Yanray Wang7226df02023-08-11 15:52:09 +0800855 goto cleanup;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200856 }
857
Yanray Wang7226df02023-08-11 15:52:09 +0800858 ret = 0;
859cleanup:
Yanray Wang044eb162023-08-28 10:35:39 +0800860 mbedtls_zeroize_and_free(output_buf, PRV_DER_MAX_BYTES);
Yanray Wang7226df02023-08-11 15:52:09 +0800861 return ret;
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200862}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200863#endif /* MBEDTLS_PEM_WRITE_C */
Paul Bakkerc7bb02b2013-09-15 14:54:56 +0200864
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200865#endif /* MBEDTLS_PK_WRITE_C */