xref: /optee_os/lib/libmbedtls/mbedtls/library/pkparse.c (revision b0563631928755fe864b97785160fb3088e9efdc)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  Public Key layer for parsing key files and structures
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5*b0563631STom Van Eyck  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6817466cbSJens Wiklander  */
7817466cbSJens Wiklander 
87901324dSJerome Forissier #include "common.h"
9817466cbSJens Wiklander 
10817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_C)
11817466cbSJens Wiklander 
12817466cbSJens Wiklander #include "mbedtls/pk.h"
13817466cbSJens Wiklander #include "mbedtls/asn1.h"
14817466cbSJens Wiklander #include "mbedtls/oid.h"
153d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
16*b0563631STom Van Eyck #include "mbedtls/platform.h"
1711fa71b9SJerome Forissier #include "mbedtls/error.h"
18*b0563631STom Van Eyck #include "mbedtls/ecp.h"
19*b0563631STom Van Eyck #include "pk_internal.h"
20817466cbSJens Wiklander 
21817466cbSJens Wiklander #include <string.h>
22817466cbSJens Wiklander 
23*b0563631STom Van Eyck #if defined(MBEDTLS_USE_PSA_CRYPTO)
24*b0563631STom Van Eyck #include "mbedtls/psa_util.h"
25*b0563631STom Van Eyck #include "psa/crypto.h"
26*b0563631STom Van Eyck #endif
27*b0563631STom Van Eyck 
28*b0563631STom Van Eyck /* Key types */
29817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
30817466cbSJens Wiklander #include "mbedtls/rsa.h"
31*b0563631STom Van Eyck #include "rsa_internal.h"
32817466cbSJens Wiklander #endif
33*b0563631STom Van Eyck 
34*b0563631STom Van Eyck /* Extended formats */
35817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
36817466cbSJens Wiklander #include "mbedtls/pem.h"
37817466cbSJens Wiklander #endif
38817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C)
39817466cbSJens Wiklander #include "mbedtls/pkcs5.h"
40817466cbSJens Wiklander #endif
41817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C)
42817466cbSJens Wiklander #include "mbedtls/pkcs12.h"
43817466cbSJens Wiklander #endif
44817466cbSJens Wiklander 
45*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
46817466cbSJens Wiklander 
47*b0563631STom Van Eyck /***********************************************************************
48817466cbSJens Wiklander  *
49*b0563631STom Van Eyck  *      Low-level ECC parsing: optional support for SpecifiedECDomain
50*b0563631STom Van Eyck  *
51*b0563631STom Van Eyck  * There are two functions here that are used by the rest of the code:
52*b0563631STom Van Eyck  * - pk_ecc_tag_is_speficied_ec_domain()
53*b0563631STom Van Eyck  * - pk_ecc_group_id_from_specified()
54*b0563631STom Van Eyck  *
55*b0563631STom Van Eyck  * All the other functions are internal to this section.
56*b0563631STom Van Eyck  *
57*b0563631STom Van Eyck  * The two "public" functions have a dummy variant provided
58*b0563631STom Van Eyck  * in configs without MBEDTLS_PK_PARSE_EC_EXTENDED. This acts as an
59*b0563631STom Van Eyck  * abstraction layer for this macro, which should not appear outside
60*b0563631STom Van Eyck  * this section.
61*b0563631STom Van Eyck  *
62*b0563631STom Van Eyck  **********************************************************************/
63*b0563631STom Van Eyck 
64*b0563631STom Van Eyck #if !defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
65*b0563631STom Van Eyck /* See the "real" version for documentation */
pk_ecc_tag_is_specified_ec_domain(int tag)66*b0563631STom Van Eyck static int pk_ecc_tag_is_specified_ec_domain(int tag)
67817466cbSJens Wiklander {
68*b0563631STom Van Eyck     (void) tag;
6932b31808SJens Wiklander     return 0;
70817466cbSJens Wiklander }
71817466cbSJens Wiklander 
72*b0563631STom Van Eyck /* See the "real" version for documentation */
pk_ecc_group_id_from_specified(const mbedtls_asn1_buf * params,mbedtls_ecp_group_id * grp_id)73*b0563631STom Van Eyck static int pk_ecc_group_id_from_specified(const mbedtls_asn1_buf *params,
74*b0563631STom Van Eyck                                           mbedtls_ecp_group_id *grp_id)
75*b0563631STom Van Eyck {
76*b0563631STom Van Eyck     (void) params;
77*b0563631STom Van Eyck     (void) grp_id;
78*b0563631STom Van Eyck     return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
79*b0563631STom Van Eyck }
80*b0563631STom Van Eyck #else /* MBEDTLS_PK_PARSE_EC_EXTENDED */
81817466cbSJens Wiklander /*
82*b0563631STom Van Eyck  * Tell if the passed tag might be the start of SpecifiedECDomain
83*b0563631STom Van Eyck  * (that is, a sequence).
84817466cbSJens Wiklander  */
pk_ecc_tag_is_specified_ec_domain(int tag)85*b0563631STom Van Eyck static int pk_ecc_tag_is_specified_ec_domain(int tag)
86817466cbSJens Wiklander {
87*b0563631STom Van Eyck     return tag == (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
8832b31808SJens Wiklander }
893d3b0591SJens Wiklander 
90817466cbSJens Wiklander /*
91817466cbSJens Wiklander  * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it.
92817466cbSJens Wiklander  * WARNING: the resulting group should only be used with
93*b0563631STom Van Eyck  * pk_ecc_group_id_from_specified(), since its base point may not be set correctly
94817466cbSJens Wiklander  * if it was encoded compressed.
95817466cbSJens Wiklander  *
96817466cbSJens Wiklander  *  SpecifiedECDomain ::= SEQUENCE {
97817466cbSJens Wiklander  *      version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
98817466cbSJens Wiklander  *      fieldID FieldID {{FieldTypes}},
99817466cbSJens Wiklander  *      curve Curve,
100817466cbSJens Wiklander  *      base ECPoint,
101817466cbSJens Wiklander  *      order INTEGER,
102817466cbSJens Wiklander  *      cofactor INTEGER OPTIONAL,
103817466cbSJens Wiklander  *      hash HashAlgorithm OPTIONAL,
104817466cbSJens Wiklander  *      ...
105817466cbSJens Wiklander  *  }
106817466cbSJens Wiklander  *
107817466cbSJens Wiklander  * We only support prime-field as field type, and ignore hash and cofactor.
108817466cbSJens Wiklander  */
pk_group_from_specified(const mbedtls_asn1_buf * params,mbedtls_ecp_group * grp)109817466cbSJens Wiklander static int pk_group_from_specified(const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp)
110817466cbSJens Wiklander {
11111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
112817466cbSJens Wiklander     unsigned char *p = params->p;
113817466cbSJens Wiklander     const unsigned char *const end = params->p + params->len;
114817466cbSJens Wiklander     const unsigned char *end_field, *end_curve;
115817466cbSJens Wiklander     size_t len;
116817466cbSJens Wiklander     int ver;
117817466cbSJens Wiklander 
118817466cbSJens Wiklander     /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */
11932b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, &ver)) != 0) {
12032b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
12132b31808SJens Wiklander     }
122817466cbSJens Wiklander 
12332b31808SJens Wiklander     if (ver < 1 || ver > 3) {
12432b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
12532b31808SJens Wiklander     }
126817466cbSJens Wiklander 
127817466cbSJens Wiklander     /*
128817466cbSJens Wiklander      * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field
129817466cbSJens Wiklander      *       fieldType FIELD-ID.&id({IOSet}),
130817466cbSJens Wiklander      *       parameters FIELD-ID.&Type({IOSet}{@fieldType})
131817466cbSJens Wiklander      * }
132817466cbSJens Wiklander      */
133817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
13432b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
13532b31808SJens Wiklander         return ret;
13632b31808SJens Wiklander     }
137817466cbSJens Wiklander 
138817466cbSJens Wiklander     end_field = p + len;
139817466cbSJens Wiklander 
140817466cbSJens Wiklander     /*
141817466cbSJens Wiklander      * FIELD-ID ::= TYPE-IDENTIFIER
142817466cbSJens Wiklander      * FieldTypes FIELD-ID ::= {
143817466cbSJens Wiklander      *       { Prime-p IDENTIFIED BY prime-field } |
144817466cbSJens Wiklander      *       { Characteristic-two IDENTIFIED BY characteristic-two-field }
145817466cbSJens Wiklander      * }
146817466cbSJens Wiklander      * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
147817466cbSJens Wiklander      */
14832b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_field, &len, MBEDTLS_ASN1_OID)) != 0) {
14932b31808SJens Wiklander         return ret;
15032b31808SJens Wiklander     }
151817466cbSJens Wiklander 
152817466cbSJens Wiklander     if (len != MBEDTLS_OID_SIZE(MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD) ||
15332b31808SJens Wiklander         memcmp(p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len) != 0) {
15432b31808SJens Wiklander         return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
155817466cbSJens Wiklander     }
156817466cbSJens Wiklander 
157817466cbSJens Wiklander     p += len;
158817466cbSJens Wiklander 
159817466cbSJens Wiklander     /* Prime-p ::= INTEGER -- Field of size p. */
16032b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_mpi(&p, end_field, &grp->P)) != 0) {
16132b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
16232b31808SJens Wiklander     }
163817466cbSJens Wiklander 
164817466cbSJens Wiklander     grp->pbits = mbedtls_mpi_bitlen(&grp->P);
165817466cbSJens Wiklander 
16632b31808SJens Wiklander     if (p != end_field) {
16732b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
16832b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
16932b31808SJens Wiklander     }
170817466cbSJens Wiklander 
171817466cbSJens Wiklander     /*
172817466cbSJens Wiklander      * Curve ::= SEQUENCE {
173817466cbSJens Wiklander      *       a FieldElement,
174817466cbSJens Wiklander      *       b FieldElement,
175817466cbSJens Wiklander      *       seed BIT STRING OPTIONAL
176817466cbSJens Wiklander      *       -- Shall be present if used in SpecifiedECDomain
177817466cbSJens Wiklander      *       -- with version equal to ecdpVer2 or ecdpVer3
178817466cbSJens Wiklander      * }
179817466cbSJens Wiklander      */
180817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
18132b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
18232b31808SJens Wiklander         return ret;
18332b31808SJens Wiklander     }
184817466cbSJens Wiklander 
185817466cbSJens Wiklander     end_curve = p + len;
186817466cbSJens Wiklander 
187817466cbSJens Wiklander     /*
188817466cbSJens Wiklander      * FieldElement ::= OCTET STRING
189817466cbSJens Wiklander      * containing an integer in the case of a prime field
190817466cbSJens Wiklander      */
191817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0 ||
19232b31808SJens Wiklander         (ret = mbedtls_mpi_read_binary(&grp->A, p, len)) != 0) {
19332b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
194817466cbSJens Wiklander     }
195817466cbSJens Wiklander 
196817466cbSJens Wiklander     p += len;
197817466cbSJens Wiklander 
198817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0 ||
19932b31808SJens Wiklander         (ret = mbedtls_mpi_read_binary(&grp->B, p, len)) != 0) {
20032b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
201817466cbSJens Wiklander     }
202817466cbSJens Wiklander 
203817466cbSJens Wiklander     p += len;
204817466cbSJens Wiklander 
205817466cbSJens Wiklander     /* Ignore seed BIT STRING OPTIONAL */
20632b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING)) == 0) {
207817466cbSJens Wiklander         p += len;
20832b31808SJens Wiklander     }
209817466cbSJens Wiklander 
21032b31808SJens Wiklander     if (p != end_curve) {
21132b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
21232b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
21332b31808SJens Wiklander     }
214817466cbSJens Wiklander 
215817466cbSJens Wiklander     /*
216817466cbSJens Wiklander      * ECPoint ::= OCTET STRING
217817466cbSJens Wiklander      */
21832b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
21932b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
22032b31808SJens Wiklander     }
221817466cbSJens Wiklander 
222817466cbSJens Wiklander     if ((ret = mbedtls_ecp_point_read_binary(grp, &grp->G,
22332b31808SJens Wiklander                                              (const unsigned char *) p, len)) != 0) {
224817466cbSJens Wiklander         /*
225817466cbSJens Wiklander          * If we can't read the point because it's compressed, cheat by
226817466cbSJens Wiklander          * reading only the X coordinate and the parity bit of Y.
227817466cbSJens Wiklander          */
228817466cbSJens Wiklander         if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ||
229817466cbSJens Wiklander             (p[0] != 0x02 && p[0] != 0x03) ||
230817466cbSJens Wiklander             len != mbedtls_mpi_size(&grp->P) + 1 ||
231817466cbSJens Wiklander             mbedtls_mpi_read_binary(&grp->G.X, p + 1, len - 1) != 0 ||
232817466cbSJens Wiklander             mbedtls_mpi_lset(&grp->G.Y, p[0] - 2) != 0 ||
23332b31808SJens Wiklander             mbedtls_mpi_lset(&grp->G.Z, 1) != 0) {
23432b31808SJens Wiklander             return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
235817466cbSJens Wiklander         }
236817466cbSJens Wiklander     }
237817466cbSJens Wiklander 
238817466cbSJens Wiklander     p += len;
239817466cbSJens Wiklander 
240817466cbSJens Wiklander     /*
241817466cbSJens Wiklander      * order INTEGER
242817466cbSJens Wiklander      */
24332b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_mpi(&p, end, &grp->N)) != 0) {
24432b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
24532b31808SJens Wiklander     }
246817466cbSJens Wiklander 
247817466cbSJens Wiklander     grp->nbits = mbedtls_mpi_bitlen(&grp->N);
248817466cbSJens Wiklander 
249817466cbSJens Wiklander     /*
250817466cbSJens Wiklander      * Allow optional elements by purposefully not enforcing p == end here.
251817466cbSJens Wiklander      */
252817466cbSJens Wiklander 
25332b31808SJens Wiklander     return 0;
254817466cbSJens Wiklander }
255817466cbSJens Wiklander 
256817466cbSJens Wiklander /*
257817466cbSJens Wiklander  * Find the group id associated with an (almost filled) group as generated by
258817466cbSJens Wiklander  * pk_group_from_specified(), or return an error if unknown.
259817466cbSJens Wiklander  */
pk_group_id_from_group(const mbedtls_ecp_group * grp,mbedtls_ecp_group_id * grp_id)260817466cbSJens Wiklander static int pk_group_id_from_group(const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id)
261817466cbSJens Wiklander {
262817466cbSJens Wiklander     int ret = 0;
263817466cbSJens Wiklander     mbedtls_ecp_group ref;
264817466cbSJens Wiklander     const mbedtls_ecp_group_id *id;
265817466cbSJens Wiklander 
266817466cbSJens Wiklander     mbedtls_ecp_group_init(&ref);
267817466cbSJens Wiklander 
26832b31808SJens Wiklander     for (id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++) {
269817466cbSJens Wiklander         /* Load the group associated to that id */
270817466cbSJens Wiklander         mbedtls_ecp_group_free(&ref);
271817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ref, *id));
272817466cbSJens Wiklander 
273817466cbSJens Wiklander         /* Compare to the group we were given, starting with easy tests */
274817466cbSJens Wiklander         if (grp->pbits == ref.pbits && grp->nbits == ref.nbits &&
275817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->P, &ref.P) == 0 &&
276817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->A, &ref.A) == 0 &&
277817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->B, &ref.B) == 0 &&
278817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->N, &ref.N) == 0 &&
279817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->G.X, &ref.G.X) == 0 &&
280817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->G.Z, &ref.G.Z) == 0 &&
281817466cbSJens Wiklander             /* For Y we may only know the parity bit, so compare only that */
28232b31808SJens Wiklander             mbedtls_mpi_get_bit(&grp->G.Y, 0) == mbedtls_mpi_get_bit(&ref.G.Y, 0)) {
283817466cbSJens Wiklander             break;
284817466cbSJens Wiklander         }
285817466cbSJens Wiklander     }
286817466cbSJens Wiklander 
287817466cbSJens Wiklander cleanup:
288817466cbSJens Wiklander     mbedtls_ecp_group_free(&ref);
289817466cbSJens Wiklander 
290817466cbSJens Wiklander     *grp_id = *id;
291817466cbSJens Wiklander 
29232b31808SJens Wiklander     if (ret == 0 && *id == MBEDTLS_ECP_DP_NONE) {
293817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
29432b31808SJens Wiklander     }
295817466cbSJens Wiklander 
29632b31808SJens Wiklander     return ret;
297817466cbSJens Wiklander }
298817466cbSJens Wiklander 
299817466cbSJens Wiklander /*
300817466cbSJens Wiklander  * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID
301817466cbSJens Wiklander  */
pk_ecc_group_id_from_specified(const mbedtls_asn1_buf * params,mbedtls_ecp_group_id * grp_id)302*b0563631STom Van Eyck static int pk_ecc_group_id_from_specified(const mbedtls_asn1_buf *params,
303817466cbSJens Wiklander                                           mbedtls_ecp_group_id *grp_id)
304817466cbSJens Wiklander {
30511fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
306817466cbSJens Wiklander     mbedtls_ecp_group grp;
307817466cbSJens Wiklander 
308817466cbSJens Wiklander     mbedtls_ecp_group_init(&grp);
309817466cbSJens Wiklander 
31032b31808SJens Wiklander     if ((ret = pk_group_from_specified(params, &grp)) != 0) {
311817466cbSJens Wiklander         goto cleanup;
31232b31808SJens Wiklander     }
313817466cbSJens Wiklander 
314817466cbSJens Wiklander     ret = pk_group_id_from_group(&grp, grp_id);
315817466cbSJens Wiklander 
316817466cbSJens Wiklander cleanup:
31732b31808SJens Wiklander     /* The API respecting lifecycle for mbedtls_ecp_group struct is
318*b0563631STom Van Eyck      * _init(), _load() and _free(). In pk_ecc_group_id_from_specified() the
31932b31808SJens Wiklander      * temporary grp breaks that flow and it's members are populated
32032b31808SJens Wiklander      * by pk_group_id_from_group(). As such mbedtls_ecp_group_free()
32132b31808SJens Wiklander      * which is assuming a group populated by _setup() may not clean-up
32232b31808SJens Wiklander      * properly -> Manually free it's members.
32332b31808SJens Wiklander      */
32432b31808SJens Wiklander     mbedtls_mpi_free(&grp.N);
32532b31808SJens Wiklander     mbedtls_mpi_free(&grp.P);
32632b31808SJens Wiklander     mbedtls_mpi_free(&grp.A);
32732b31808SJens Wiklander     mbedtls_mpi_free(&grp.B);
32832b31808SJens Wiklander     mbedtls_ecp_point_free(&grp.G);
329817466cbSJens Wiklander 
33032b31808SJens Wiklander     return ret;
331817466cbSJens Wiklander }
332817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */
333817466cbSJens Wiklander 
334*b0563631STom Van Eyck /***********************************************************************
335*b0563631STom Van Eyck  *
336*b0563631STom Van Eyck  * Unsorted (yet!) from this point on until the next section header
337*b0563631STom Van Eyck  *
338*b0563631STom Van Eyck  **********************************************************************/
339*b0563631STom Van Eyck 
340*b0563631STom Van Eyck /* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf
341*b0563631STom Van Eyck  *
342*b0563631STom Van Eyck  * ECParameters ::= CHOICE {
343*b0563631STom Van Eyck  *   namedCurve         OBJECT IDENTIFIER
344*b0563631STom Van Eyck  *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
345*b0563631STom Van Eyck  *   -- implicitCurve   NULL
346*b0563631STom Van Eyck  * }
347*b0563631STom Van Eyck  */
pk_get_ecparams(unsigned char ** p,const unsigned char * end,mbedtls_asn1_buf * params)348*b0563631STom Van Eyck static int pk_get_ecparams(unsigned char **p, const unsigned char *end,
349*b0563631STom Van Eyck                            mbedtls_asn1_buf *params)
350*b0563631STom Van Eyck {
351*b0563631STom Van Eyck     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
352*b0563631STom Van Eyck 
353*b0563631STom Van Eyck     if (end - *p < 1) {
354*b0563631STom Van Eyck         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
355*b0563631STom Van Eyck                                  MBEDTLS_ERR_ASN1_OUT_OF_DATA);
356*b0563631STom Van Eyck     }
357*b0563631STom Van Eyck 
358*b0563631STom Van Eyck     /* Acceptable tags: OID for namedCurve, or specifiedECDomain */
359*b0563631STom Van Eyck     params->tag = **p;
360*b0563631STom Van Eyck     if (params->tag != MBEDTLS_ASN1_OID &&
361*b0563631STom Van Eyck         !pk_ecc_tag_is_specified_ec_domain(params->tag)) {
362*b0563631STom Van Eyck         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
363*b0563631STom Van Eyck                                  MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
364*b0563631STom Van Eyck     }
365*b0563631STom Van Eyck 
366*b0563631STom Van Eyck     if ((ret = mbedtls_asn1_get_tag(p, end, &params->len, params->tag)) != 0) {
367*b0563631STom Van Eyck         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
368*b0563631STom Van Eyck     }
369*b0563631STom Van Eyck 
370*b0563631STom Van Eyck     params->p = *p;
371*b0563631STom Van Eyck     *p += params->len;
372*b0563631STom Van Eyck 
373*b0563631STom Van Eyck     if (*p != end) {
374*b0563631STom Van Eyck         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
375*b0563631STom Van Eyck                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
376*b0563631STom Van Eyck     }
377*b0563631STom Van Eyck 
378*b0563631STom Van Eyck     return 0;
379*b0563631STom Van Eyck }
380*b0563631STom Van Eyck 
381817466cbSJens Wiklander /*
382817466cbSJens Wiklander  * Use EC parameters to initialise an EC group
383817466cbSJens Wiklander  *
384817466cbSJens Wiklander  * ECParameters ::= CHOICE {
385817466cbSJens Wiklander  *   namedCurve         OBJECT IDENTIFIER
386817466cbSJens Wiklander  *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
387817466cbSJens Wiklander  *   -- implicitCurve   NULL
388817466cbSJens Wiklander  */
pk_use_ecparams(const mbedtls_asn1_buf * params,mbedtls_pk_context * pk)389*b0563631STom Van Eyck static int pk_use_ecparams(const mbedtls_asn1_buf *params, mbedtls_pk_context *pk)
390817466cbSJens Wiklander {
39111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
392817466cbSJens Wiklander     mbedtls_ecp_group_id grp_id;
393817466cbSJens Wiklander 
39432b31808SJens Wiklander     if (params->tag == MBEDTLS_ASN1_OID) {
39532b31808SJens Wiklander         if (mbedtls_oid_get_ec_grp(params, &grp_id) != 0) {
39632b31808SJens Wiklander             return MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE;
397817466cbSJens Wiklander         }
39832b31808SJens Wiklander     } else {
399*b0563631STom Van Eyck         ret = pk_ecc_group_id_from_specified(params, &grp_id);
400*b0563631STom Van Eyck         if (ret != 0) {
40132b31808SJens Wiklander             return ret;
40232b31808SJens Wiklander         }
403817466cbSJens Wiklander     }
404817466cbSJens Wiklander 
405*b0563631STom Van Eyck     return mbedtls_pk_ecc_set_group(pk, grp_id);
406*b0563631STom Van Eyck }
407*b0563631STom Van Eyck 
408*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
409*b0563631STom Van Eyck 
410817466cbSJens Wiklander /*
411*b0563631STom Van Eyck  * Load an RFC8410 EC key, which doesn't have any parameters
412817466cbSJens Wiklander  */
pk_use_ecparams_rfc8410(const mbedtls_asn1_buf * params,mbedtls_ecp_group_id grp_id,mbedtls_pk_context * pk)413*b0563631STom Van Eyck static int pk_use_ecparams_rfc8410(const mbedtls_asn1_buf *params,
414*b0563631STom Van Eyck                                    mbedtls_ecp_group_id grp_id,
415*b0563631STom Van Eyck                                    mbedtls_pk_context *pk)
416817466cbSJens Wiklander {
417*b0563631STom Van Eyck     if (params->tag != 0 || params->len != 0) {
418*b0563631STom Van Eyck         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
419*b0563631STom Van Eyck     }
420817466cbSJens Wiklander 
421*b0563631STom Van Eyck     return mbedtls_pk_ecc_set_group(pk, grp_id);
422817466cbSJens Wiklander }
423817466cbSJens Wiklander 
424817466cbSJens Wiklander /*
425*b0563631STom Van Eyck  * Parse an RFC 8410 encoded private EC key
426*b0563631STom Van Eyck  *
427*b0563631STom Van Eyck  * CurvePrivateKey ::= OCTET STRING
428817466cbSJens Wiklander  */
pk_parse_key_rfc8410_der(mbedtls_pk_context * pk,unsigned char * key,size_t keylen,const unsigned char * end,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)429*b0563631STom Van Eyck static int pk_parse_key_rfc8410_der(mbedtls_pk_context *pk,
430*b0563631STom Van Eyck                                     unsigned char *key, size_t keylen, const unsigned char *end,
431*b0563631STom Van Eyck                                     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
432817466cbSJens Wiklander {
43311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
434817466cbSJens Wiklander     size_t len;
435817466cbSJens Wiklander 
436*b0563631STom Van Eyck     if ((ret = mbedtls_asn1_get_tag(&key, (key + keylen), &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
437*b0563631STom Van Eyck         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
43832b31808SJens Wiklander     }
439817466cbSJens Wiklander 
440*b0563631STom Van Eyck     if (key + len != end) {
441*b0563631STom Van Eyck         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
44232b31808SJens Wiklander     }
443817466cbSJens Wiklander 
444*b0563631STom Van Eyck     /*
445*b0563631STom Van Eyck      * Load the private key
446*b0563631STom Van Eyck      */
447*b0563631STom Van Eyck     ret = mbedtls_pk_ecc_set_key(pk, key, len);
448*b0563631STom Van Eyck     if (ret != 0) {
449*b0563631STom Van Eyck         return ret;
45032b31808SJens Wiklander     }
451817466cbSJens Wiklander 
452*b0563631STom Van Eyck     /* pk_parse_key_pkcs8_unencrypted_der() only supports version 1 PKCS8 keys,
453*b0563631STom Van Eyck      * which never contain a public key. As such, derive the public key
454*b0563631STom Van Eyck      * unconditionally. */
455*b0563631STom Van Eyck     if ((ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, key, len, f_rng, p_rng)) != 0) {
456*b0563631STom Van Eyck         return ret;
45732b31808SJens Wiklander     }
458817466cbSJens Wiklander 
45932b31808SJens Wiklander     return 0;
460817466cbSJens Wiklander }
461*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
462*b0563631STom Van Eyck 
463*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
464817466cbSJens Wiklander 
465817466cbSJens Wiklander /* Get a PK algorithm identifier
466817466cbSJens Wiklander  *
467817466cbSJens Wiklander  *  AlgorithmIdentifier  ::=  SEQUENCE  {
468817466cbSJens Wiklander  *       algorithm               OBJECT IDENTIFIER,
469817466cbSJens Wiklander  *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
470817466cbSJens Wiklander  */
pk_get_pk_alg(unsigned char ** p,const unsigned char * end,mbedtls_pk_type_t * pk_alg,mbedtls_asn1_buf * params,mbedtls_ecp_group_id * ec_grp_id)471817466cbSJens Wiklander static int pk_get_pk_alg(unsigned char **p,
472817466cbSJens Wiklander                          const unsigned char *end,
473*b0563631STom Van Eyck                          mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params,
474*b0563631STom Van Eyck                          mbedtls_ecp_group_id *ec_grp_id)
475817466cbSJens Wiklander {
47611fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
477817466cbSJens Wiklander     mbedtls_asn1_buf alg_oid;
478817466cbSJens Wiklander 
479817466cbSJens Wiklander     memset(params, 0, sizeof(mbedtls_asn1_buf));
480817466cbSJens Wiklander 
48132b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_alg(p, end, &alg_oid, params)) != 0) {
48232b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_ALG, ret);
48332b31808SJens Wiklander     }
484817466cbSJens Wiklander 
485*b0563631STom Van Eyck     ret = mbedtls_oid_get_pk_alg(&alg_oid, pk_alg);
486*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
487*b0563631STom Van Eyck     if (ret == MBEDTLS_ERR_OID_NOT_FOUND) {
488*b0563631STom Van Eyck         ret = mbedtls_oid_get_ec_grp_algid(&alg_oid, ec_grp_id);
489*b0563631STom Van Eyck         if (ret == 0) {
490*b0563631STom Van Eyck             *pk_alg = MBEDTLS_PK_ECKEY;
491*b0563631STom Van Eyck         }
492*b0563631STom Van Eyck     }
493*b0563631STom Van Eyck #else
494*b0563631STom Van Eyck     (void) ec_grp_id;
495*b0563631STom Van Eyck #endif
496*b0563631STom Van Eyck     if (ret != 0) {
49732b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
49832b31808SJens Wiklander     }
499817466cbSJens Wiklander 
500817466cbSJens Wiklander     /*
501817466cbSJens Wiklander      * No parameters with RSA (only for EC)
502817466cbSJens Wiklander      */
503817466cbSJens Wiklander     if (*pk_alg == MBEDTLS_PK_RSA &&
504817466cbSJens Wiklander         ((params->tag != MBEDTLS_ASN1_NULL && params->tag != 0) ||
50532b31808SJens Wiklander          params->len != 0)) {
50632b31808SJens Wiklander         return MBEDTLS_ERR_PK_INVALID_ALG;
507817466cbSJens Wiklander     }
508817466cbSJens Wiklander 
50932b31808SJens Wiklander     return 0;
510817466cbSJens Wiklander }
511817466cbSJens Wiklander 
512817466cbSJens Wiklander /*
513817466cbSJens Wiklander  *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
514817466cbSJens Wiklander  *       algorithm            AlgorithmIdentifier,
515817466cbSJens Wiklander  *       subjectPublicKey     BIT STRING }
516817466cbSJens Wiklander  */
mbedtls_pk_parse_subpubkey(unsigned char ** p,const unsigned char * end,mbedtls_pk_context * pk)517817466cbSJens Wiklander int mbedtls_pk_parse_subpubkey(unsigned char **p, const unsigned char *end,
518817466cbSJens Wiklander                                mbedtls_pk_context *pk)
519817466cbSJens Wiklander {
52011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
521817466cbSJens Wiklander     size_t len;
522817466cbSJens Wiklander     mbedtls_asn1_buf alg_params;
523817466cbSJens Wiklander     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
524*b0563631STom Van Eyck     mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE;
525817466cbSJens Wiklander     const mbedtls_pk_info_t *pk_info;
526817466cbSJens Wiklander 
527817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(p, end, &len,
52832b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
52932b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
530817466cbSJens Wiklander     }
531817466cbSJens Wiklander 
532817466cbSJens Wiklander     end = *p + len;
533817466cbSJens Wiklander 
534*b0563631STom Van Eyck     if ((ret = pk_get_pk_alg(p, end, &pk_alg, &alg_params, &ec_grp_id)) != 0) {
53532b31808SJens Wiklander         return ret;
53632b31808SJens Wiklander     }
537817466cbSJens Wiklander 
53832b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_bitstring_null(p, end, &len)) != 0) {
53932b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
54032b31808SJens Wiklander     }
541817466cbSJens Wiklander 
54232b31808SJens Wiklander     if (*p + len != end) {
54332b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
54432b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
54532b31808SJens Wiklander     }
546817466cbSJens Wiklander 
54732b31808SJens Wiklander     if ((pk_info = mbedtls_pk_info_from_type(pk_alg)) == NULL) {
54832b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
54932b31808SJens Wiklander     }
550817466cbSJens Wiklander 
55132b31808SJens Wiklander     if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0) {
55232b31808SJens Wiklander         return ret;
55332b31808SJens Wiklander     }
554817466cbSJens Wiklander 
555817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
55632b31808SJens Wiklander     if (pk_alg == MBEDTLS_PK_RSA) {
557*b0563631STom Van Eyck         ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*pk), *p, (size_t) (end - *p));
55832b31808SJens Wiklander         if (ret == 0) {
559*b0563631STom Van Eyck             /* On success all the input has been consumed by the parsing function. */
560*b0563631STom Van Eyck             *p += end - *p;
561*b0563631STom Van Eyck         } else if ((ret <= MBEDTLS_ERR_ASN1_OUT_OF_DATA) &&
562*b0563631STom Van Eyck                    (ret >= MBEDTLS_ERR_ASN1_BUF_TOO_SMALL)) {
563*b0563631STom Van Eyck             /* In case of ASN1 error codes add MBEDTLS_ERR_PK_INVALID_PUBKEY. */
564*b0563631STom Van Eyck             ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
565*b0563631STom Van Eyck         } else {
566*b0563631STom Van Eyck             ret = MBEDTLS_ERR_PK_INVALID_PUBKEY;
56732b31808SJens Wiklander         }
568817466cbSJens Wiklander     } else
569*b0563631STom Van Eyck #endif /* MBEDTLS_RSA_C */
570*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
571*b0563631STom Van Eyck     if (pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY) {
572*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
573*b0563631STom Van Eyck         if (MBEDTLS_PK_IS_RFC8410_GROUP_ID(ec_grp_id)) {
574*b0563631STom Van Eyck             ret = pk_use_ecparams_rfc8410(&alg_params, ec_grp_id, pk);
575*b0563631STom Van Eyck         } else
576*b0563631STom Van Eyck #endif
577*b0563631STom Van Eyck         {
578*b0563631STom Van Eyck             ret = pk_use_ecparams(&alg_params, pk);
579*b0563631STom Van Eyck         }
580*b0563631STom Van Eyck         if (ret == 0) {
581*b0563631STom Van Eyck             ret = mbedtls_pk_ecc_set_pubkey(pk, *p, (size_t) (end - *p));
582*b0563631STom Van Eyck             *p += end - *p;
583*b0563631STom Van Eyck         }
584*b0563631STom Van Eyck     } else
585*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
586817466cbSJens Wiklander     ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
587817466cbSJens Wiklander 
58832b31808SJens Wiklander     if (ret == 0 && *p != end) {
5897901324dSJerome Forissier         ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
5907901324dSJerome Forissier                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
59132b31808SJens Wiklander     }
592817466cbSJens Wiklander 
59332b31808SJens Wiklander     if (ret != 0) {
594817466cbSJens Wiklander         mbedtls_pk_free(pk);
59532b31808SJens Wiklander     }
596817466cbSJens Wiklander 
59732b31808SJens Wiklander     return ret;
598817466cbSJens Wiklander }
599817466cbSJens Wiklander 
600*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
601817466cbSJens Wiklander /*
602817466cbSJens Wiklander  * Parse a SEC1 encoded private EC key
603817466cbSJens Wiklander  */
pk_parse_key_sec1_der(mbedtls_pk_context * pk,const unsigned char * key,size_t keylen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)604*b0563631STom Van Eyck static int pk_parse_key_sec1_der(mbedtls_pk_context *pk,
60532b31808SJens Wiklander                                  const unsigned char *key, size_t keylen,
60632b31808SJens Wiklander                                  int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
607817466cbSJens Wiklander {
60811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
609817466cbSJens Wiklander     int version, pubkey_done;
610*b0563631STom Van Eyck     size_t len, d_len;
61132b31808SJens Wiklander     mbedtls_asn1_buf params = { 0, 0, NULL };
612817466cbSJens Wiklander     unsigned char *p = (unsigned char *) key;
613*b0563631STom Van Eyck     unsigned char *d;
614817466cbSJens Wiklander     unsigned char *end = p + keylen;
615817466cbSJens Wiklander     unsigned char *end2;
616817466cbSJens Wiklander 
617817466cbSJens Wiklander     /*
618817466cbSJens Wiklander      * RFC 5915, or SEC1 Appendix C.4
619817466cbSJens Wiklander      *
620817466cbSJens Wiklander      * ECPrivateKey ::= SEQUENCE {
621817466cbSJens Wiklander      *      version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
622817466cbSJens Wiklander      *      privateKey     OCTET STRING,
623817466cbSJens Wiklander      *      parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
624817466cbSJens Wiklander      *      publicKey  [1] BIT STRING OPTIONAL
625817466cbSJens Wiklander      *    }
626817466cbSJens Wiklander      */
627817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
62832b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
62932b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
630817466cbSJens Wiklander     }
631817466cbSJens Wiklander 
632817466cbSJens Wiklander     end = p + len;
633817466cbSJens Wiklander 
63432b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
63532b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
63632b31808SJens Wiklander     }
637817466cbSJens Wiklander 
63832b31808SJens Wiklander     if (version != 1) {
63932b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_VERSION;
64032b31808SJens Wiklander     }
641817466cbSJens Wiklander 
64232b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
64332b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
64432b31808SJens Wiklander     }
645817466cbSJens Wiklander 
646*b0563631STom Van Eyck     /* Keep a reference to the position fo the private key. It will be used
647*b0563631STom Van Eyck      * later in this function. */
648*b0563631STom Van Eyck     d = p;
649*b0563631STom Van Eyck     d_len = len;
650817466cbSJens Wiklander 
651817466cbSJens Wiklander     p += len;
652817466cbSJens Wiklander 
653817466cbSJens Wiklander     pubkey_done = 0;
65432b31808SJens Wiklander     if (p != end) {
655817466cbSJens Wiklander         /*
656817466cbSJens Wiklander          * Is 'parameters' present?
657817466cbSJens Wiklander          */
658817466cbSJens Wiklander         if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
65932b31808SJens Wiklander                                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
66032b31808SJens Wiklander                                         0)) == 0) {
661817466cbSJens Wiklander             if ((ret = pk_get_ecparams(&p, p + len, &params)) != 0 ||
662*b0563631STom Van Eyck                 (ret = pk_use_ecparams(&params, pk)) != 0) {
66332b31808SJens Wiklander                 return ret;
664817466cbSJens Wiklander             }
66532b31808SJens Wiklander         } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
66632b31808SJens Wiklander             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
667817466cbSJens Wiklander         }
6683d3b0591SJens Wiklander     }
669817466cbSJens Wiklander 
670*b0563631STom Van Eyck     /*
671*b0563631STom Van Eyck      * Load the private key
672*b0563631STom Van Eyck      */
673*b0563631STom Van Eyck     ret = mbedtls_pk_ecc_set_key(pk, d, d_len);
674*b0563631STom Van Eyck     if (ret != 0) {
675*b0563631STom Van Eyck         return ret;
676*b0563631STom Van Eyck     }
677*b0563631STom Van Eyck 
67832b31808SJens Wiklander     if (p != end) {
679817466cbSJens Wiklander         /*
680817466cbSJens Wiklander          * Is 'publickey' present? If not, or if we can't read it (eg because it
681817466cbSJens Wiklander          * is compressed), create it from the private key.
682817466cbSJens Wiklander          */
683817466cbSJens Wiklander         if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
68432b31808SJens Wiklander                                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
68532b31808SJens Wiklander                                         1)) == 0) {
686817466cbSJens Wiklander             end2 = p + len;
687817466cbSJens Wiklander 
68832b31808SJens Wiklander             if ((ret = mbedtls_asn1_get_bitstring_null(&p, end2, &len)) != 0) {
68932b31808SJens Wiklander                 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
69032b31808SJens Wiklander             }
691817466cbSJens Wiklander 
69232b31808SJens Wiklander             if (p + len != end2) {
69332b31808SJens Wiklander                 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
69432b31808SJens Wiklander                                          MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
69532b31808SJens Wiklander             }
696817466cbSJens Wiklander 
697*b0563631STom Van Eyck             if ((ret = mbedtls_pk_ecc_set_pubkey(pk, p, (size_t) (end2 - p))) == 0) {
698817466cbSJens Wiklander                 pubkey_done = 1;
69932b31808SJens Wiklander             } else {
700817466cbSJens Wiklander                 /*
701*b0563631STom Van Eyck                  * The only acceptable failure mode of mbedtls_pk_ecc_set_pubkey() above
702817466cbSJens Wiklander                  * is if the point format is not recognized.
703817466cbSJens Wiklander                  */
70432b31808SJens Wiklander                 if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) {
70532b31808SJens Wiklander                     return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
706817466cbSJens Wiklander                 }
707817466cbSJens Wiklander             }
70832b31808SJens Wiklander         } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
70932b31808SJens Wiklander             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
710817466cbSJens Wiklander         }
711817466cbSJens Wiklander     }
712817466cbSJens Wiklander 
713*b0563631STom Van Eyck     if (!pubkey_done) {
714*b0563631STom Van Eyck         if ((ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, d, d_len, f_rng, p_rng)) != 0) {
71532b31808SJens Wiklander             return ret;
716817466cbSJens Wiklander         }
717*b0563631STom Van Eyck     }
718817466cbSJens Wiklander 
71932b31808SJens Wiklander     return 0;
720817466cbSJens Wiklander }
721*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
722*b0563631STom Van Eyck 
723*b0563631STom Van Eyck /***********************************************************************
724*b0563631STom Van Eyck  *
725*b0563631STom Van Eyck  *      PKCS#8 parsing functions
726*b0563631STom Van Eyck  *
727*b0563631STom Van Eyck  **********************************************************************/
728817466cbSJens Wiklander 
729817466cbSJens Wiklander /*
730817466cbSJens Wiklander  * Parse an unencrypted PKCS#8 encoded private key
7313d3b0591SJens Wiklander  *
7323d3b0591SJens Wiklander  * Notes:
7333d3b0591SJens Wiklander  *
7343d3b0591SJens Wiklander  * - This function does not own the key buffer. It is the
7353d3b0591SJens Wiklander  *   responsibility of the caller to take care of zeroizing
7363d3b0591SJens Wiklander  *   and freeing it after use.
7373d3b0591SJens Wiklander  *
7383d3b0591SJens Wiklander  * - The function is responsible for freeing the provided
7393d3b0591SJens Wiklander  *   PK context on failure.
7403d3b0591SJens Wiklander  *
741817466cbSJens Wiklander  */
pk_parse_key_pkcs8_unencrypted_der(mbedtls_pk_context * pk,const unsigned char * key,size_t keylen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)742817466cbSJens Wiklander static int pk_parse_key_pkcs8_unencrypted_der(
743817466cbSJens Wiklander     mbedtls_pk_context *pk,
74432b31808SJens Wiklander     const unsigned char *key, size_t keylen,
74532b31808SJens Wiklander     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
746817466cbSJens Wiklander {
747817466cbSJens Wiklander     int ret, version;
748817466cbSJens Wiklander     size_t len;
749817466cbSJens Wiklander     mbedtls_asn1_buf params;
750817466cbSJens Wiklander     unsigned char *p = (unsigned char *) key;
751817466cbSJens Wiklander     unsigned char *end = p + keylen;
752817466cbSJens Wiklander     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
753*b0563631STom Van Eyck     mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE;
754817466cbSJens Wiklander     const mbedtls_pk_info_t *pk_info;
755817466cbSJens Wiklander 
756*b0563631STom Van Eyck #if !defined(MBEDTLS_PK_HAVE_ECC_KEYS)
75732b31808SJens Wiklander     (void) f_rng;
75832b31808SJens Wiklander     (void) p_rng;
75932b31808SJens Wiklander #endif
76032b31808SJens Wiklander 
761817466cbSJens Wiklander     /*
7623d3b0591SJens Wiklander      * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208)
763817466cbSJens Wiklander      *
764817466cbSJens Wiklander      *    PrivateKeyInfo ::= SEQUENCE {
765817466cbSJens Wiklander      *      version                   Version,
766817466cbSJens Wiklander      *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
767817466cbSJens Wiklander      *      privateKey                PrivateKey,
768817466cbSJens Wiklander      *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
769817466cbSJens Wiklander      *
770817466cbSJens Wiklander      *    Version ::= INTEGER
771817466cbSJens Wiklander      *    PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
772817466cbSJens Wiklander      *    PrivateKey ::= OCTET STRING
773817466cbSJens Wiklander      *
774817466cbSJens Wiklander      *  The PrivateKey OCTET STRING is a SEC1 ECPrivateKey
775817466cbSJens Wiklander      */
776817466cbSJens Wiklander 
777817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
77832b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
77932b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
780817466cbSJens Wiklander     }
781817466cbSJens Wiklander 
782817466cbSJens Wiklander     end = p + len;
783817466cbSJens Wiklander 
78432b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
78532b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
7867901324dSJerome Forissier     }
787817466cbSJens Wiklander 
78832b31808SJens Wiklander     if (version != 0) {
78932b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_VERSION, ret);
79032b31808SJens Wiklander     }
791817466cbSJens Wiklander 
792*b0563631STom Van Eyck     if ((ret = pk_get_pk_alg(&p, end, &pk_alg, &params, &ec_grp_id)) != 0) {
79332b31808SJens Wiklander         return ret;
79432b31808SJens Wiklander     }
795817466cbSJens Wiklander 
79632b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
79732b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
79832b31808SJens Wiklander     }
799817466cbSJens Wiklander 
80032b31808SJens Wiklander     if (len < 1) {
80132b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
80232b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_OUT_OF_DATA);
80332b31808SJens Wiklander     }
80432b31808SJens Wiklander 
80532b31808SJens Wiklander     if ((pk_info = mbedtls_pk_info_from_type(pk_alg)) == NULL) {
80632b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
80732b31808SJens Wiklander     }
80832b31808SJens Wiklander 
80932b31808SJens Wiklander     if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0) {
81032b31808SJens Wiklander         return ret;
81132b31808SJens Wiklander     }
812817466cbSJens Wiklander 
813817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
81432b31808SJens Wiklander     if (pk_alg == MBEDTLS_PK_RSA) {
815*b0563631STom Van Eyck         if ((ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), p, len)) != 0) {
816817466cbSJens Wiklander             mbedtls_pk_free(pk);
81732b31808SJens Wiklander             return ret;
818817466cbSJens Wiklander         }
819817466cbSJens Wiklander     } else
820817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
821*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
82232b31808SJens Wiklander     if (pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH) {
823*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
824*b0563631STom Van Eyck         if (MBEDTLS_PK_IS_RFC8410_GROUP_ID(ec_grp_id)) {
825*b0563631STom Van Eyck             if ((ret =
826*b0563631STom Van Eyck                      pk_use_ecparams_rfc8410(&params, ec_grp_id, pk)) != 0 ||
827*b0563631STom Van Eyck                 (ret =
828*b0563631STom Van Eyck                      pk_parse_key_rfc8410_der(pk, p, len, end, f_rng,
829*b0563631STom Van Eyck                                               p_rng)) != 0) {
830817466cbSJens Wiklander                 mbedtls_pk_free(pk);
83132b31808SJens Wiklander                 return ret;
832817466cbSJens Wiklander             }
833817466cbSJens Wiklander         } else
834*b0563631STom Van Eyck #endif
835*b0563631STom Van Eyck         {
836*b0563631STom Van Eyck             if ((ret = pk_use_ecparams(&params, pk)) != 0 ||
837*b0563631STom Van Eyck                 (ret = pk_parse_key_sec1_der(pk, p, len, f_rng, p_rng)) != 0) {
838*b0563631STom Van Eyck                 mbedtls_pk_free(pk);
839*b0563631STom Van Eyck                 return ret;
840*b0563631STom Van Eyck             }
841*b0563631STom Van Eyck         }
842*b0563631STom Van Eyck     } else
843*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
84432b31808SJens Wiklander     return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
845817466cbSJens Wiklander 
846*b0563631STom Van Eyck     end = p + len;
847*b0563631STom Van Eyck     if (end != (key + keylen)) {
848*b0563631STom Van Eyck         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
849*b0563631STom Van Eyck                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
850*b0563631STom Van Eyck     }
851*b0563631STom Van Eyck 
85232b31808SJens Wiklander     return 0;
853817466cbSJens Wiklander }
854817466cbSJens Wiklander 
855817466cbSJens Wiklander /*
856817466cbSJens Wiklander  * Parse an encrypted PKCS#8 encoded private key
8573d3b0591SJens Wiklander  *
8583d3b0591SJens Wiklander  * To save space, the decryption happens in-place on the given key buffer.
8593d3b0591SJens Wiklander  * Also, while this function may modify the keybuffer, it doesn't own it,
8603d3b0591SJens Wiklander  * and instead it is the responsibility of the caller to zeroize and properly
8613d3b0591SJens Wiklander  * free it after use.
8623d3b0591SJens Wiklander  *
863817466cbSJens Wiklander  */
864817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
mbedtls_pk_parse_key_pkcs8_encrypted_der(mbedtls_pk_context * pk,unsigned char * key,size_t keylen,const unsigned char * pwd,size_t pwdlen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)865*b0563631STom Van Eyck MBEDTLS_STATIC_TESTABLE int mbedtls_pk_parse_key_pkcs8_encrypted_der(
866817466cbSJens Wiklander     mbedtls_pk_context *pk,
8673d3b0591SJens Wiklander     unsigned char *key, size_t keylen,
86832b31808SJens Wiklander     const unsigned char *pwd, size_t pwdlen,
86932b31808SJens Wiklander     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
870817466cbSJens Wiklander {
871817466cbSJens Wiklander     int ret, decrypted = 0;
872817466cbSJens Wiklander     size_t len;
8733d3b0591SJens Wiklander     unsigned char *buf;
874817466cbSJens Wiklander     unsigned char *p, *end;
875817466cbSJens Wiklander     mbedtls_asn1_buf pbe_alg_oid, pbe_params;
876*b0563631STom Van Eyck #if defined(MBEDTLS_PKCS12_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C)
877817466cbSJens Wiklander     mbedtls_cipher_type_t cipher_alg;
878817466cbSJens Wiklander     mbedtls_md_type_t md_alg;
879817466cbSJens Wiklander #endif
880*b0563631STom Van Eyck     size_t outlen = 0;
881817466cbSJens Wiklander 
8823d3b0591SJens Wiklander     p = key;
883817466cbSJens Wiklander     end = p + keylen;
884817466cbSJens Wiklander 
88532b31808SJens Wiklander     if (pwdlen == 0) {
88632b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
88732b31808SJens Wiklander     }
888817466cbSJens Wiklander 
889817466cbSJens Wiklander     /*
8903d3b0591SJens Wiklander      * This function parses the EncryptedPrivateKeyInfo object (PKCS#8)
891817466cbSJens Wiklander      *
892817466cbSJens Wiklander      *  EncryptedPrivateKeyInfo ::= SEQUENCE {
893817466cbSJens Wiklander      *    encryptionAlgorithm  EncryptionAlgorithmIdentifier,
894817466cbSJens Wiklander      *    encryptedData        EncryptedData
895817466cbSJens Wiklander      *  }
896817466cbSJens Wiklander      *
897817466cbSJens Wiklander      *  EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
898817466cbSJens Wiklander      *
899817466cbSJens Wiklander      *  EncryptedData ::= OCTET STRING
900817466cbSJens Wiklander      *
901817466cbSJens Wiklander      *  The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo
9023d3b0591SJens Wiklander      *
903817466cbSJens Wiklander      */
904817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
90532b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
90632b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
907817466cbSJens Wiklander     }
908817466cbSJens Wiklander 
909817466cbSJens Wiklander     end = p + len;
910817466cbSJens Wiklander 
91132b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_alg(&p, end, &pbe_alg_oid, &pbe_params)) != 0) {
91232b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
91332b31808SJens Wiklander     }
914817466cbSJens Wiklander 
91532b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
91632b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
91732b31808SJens Wiklander     }
918817466cbSJens Wiklander 
9193d3b0591SJens Wiklander     buf = p;
920817466cbSJens Wiklander 
921817466cbSJens Wiklander     /*
9223d3b0591SJens Wiklander      * Decrypt EncryptedData with appropriate PBE
923817466cbSJens Wiklander      */
924*b0563631STom Van Eyck #if defined(MBEDTLS_PKCS12_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C)
92532b31808SJens Wiklander     if (mbedtls_oid_get_pkcs12_pbe_alg(&pbe_alg_oid, &md_alg, &cipher_alg) == 0) {
926*b0563631STom Van Eyck         if ((ret = mbedtls_pkcs12_pbe_ext(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
927817466cbSJens Wiklander                                           cipher_alg, md_alg,
928*b0563631STom Van Eyck                                           pwd, pwdlen, p, len, buf, len, &outlen)) != 0) {
92932b31808SJens Wiklander             if (ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) {
93032b31808SJens Wiklander                 return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
93132b31808SJens Wiklander             }
932817466cbSJens Wiklander 
93332b31808SJens Wiklander             return ret;
934817466cbSJens Wiklander         }
935817466cbSJens Wiklander 
936817466cbSJens Wiklander         decrypted = 1;
93732b31808SJens Wiklander     } else
938*b0563631STom Van Eyck #endif /* MBEDTLS_PKCS12_C && MBEDTLS_CIPHER_PADDING_PKCS7 && MBEDTLS_CIPHER_C */
939*b0563631STom Van Eyck #if defined(MBEDTLS_PKCS5_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C)
94032b31808SJens Wiklander     if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid) == 0) {
941*b0563631STom Van Eyck         if ((ret = mbedtls_pkcs5_pbes2_ext(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
942*b0563631STom Van Eyck                                            p, len, buf, len, &outlen)) != 0) {
94332b31808SJens Wiklander             if (ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) {
94432b31808SJens Wiklander                 return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
94532b31808SJens Wiklander             }
946817466cbSJens Wiklander 
94732b31808SJens Wiklander             return ret;
948817466cbSJens Wiklander         }
949817466cbSJens Wiklander 
950817466cbSJens Wiklander         decrypted = 1;
95132b31808SJens Wiklander     } else
952*b0563631STom Van Eyck #endif /* MBEDTLS_PKCS5_C && MBEDTLS_CIPHER_PADDING_PKCS7 && MBEDTLS_CIPHER_C */
953817466cbSJens Wiklander     {
954817466cbSJens Wiklander         ((void) pwd);
955817466cbSJens Wiklander     }
956817466cbSJens Wiklander 
95732b31808SJens Wiklander     if (decrypted == 0) {
95832b31808SJens Wiklander         return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
95932b31808SJens Wiklander     }
960*b0563631STom Van Eyck     return pk_parse_key_pkcs8_unencrypted_der(pk, buf, outlen, f_rng, p_rng);
961817466cbSJens Wiklander }
962817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
963817466cbSJens Wiklander 
964*b0563631STom Van Eyck /***********************************************************************
965*b0563631STom Van Eyck  *
966*b0563631STom Van Eyck  *      Top-level functions, with format auto-discovery
967*b0563631STom Van Eyck  *
968*b0563631STom Van Eyck  **********************************************************************/
969*b0563631STom Van Eyck 
970817466cbSJens Wiklander /*
971817466cbSJens Wiklander  * Parse a private key
972817466cbSJens Wiklander  */
mbedtls_pk_parse_key(mbedtls_pk_context * pk,const unsigned char * key,size_t keylen,const unsigned char * pwd,size_t pwdlen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)973817466cbSJens Wiklander int mbedtls_pk_parse_key(mbedtls_pk_context *pk,
974817466cbSJens Wiklander                          const unsigned char *key, size_t keylen,
97532b31808SJens Wiklander                          const unsigned char *pwd, size_t pwdlen,
97632b31808SJens Wiklander                          int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
977817466cbSJens Wiklander {
97811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
979817466cbSJens Wiklander     const mbedtls_pk_info_t *pk_info;
980817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
981817466cbSJens Wiklander     size_t len;
982817466cbSJens Wiklander     mbedtls_pem_context pem;
9833d3b0591SJens Wiklander #endif
984817466cbSJens Wiklander 
98532b31808SJens Wiklander     if (keylen == 0) {
98632b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
98732b31808SJens Wiklander     }
9883d3b0591SJens Wiklander 
9893d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
990817466cbSJens Wiklander     mbedtls_pem_init(&pem);
991817466cbSJens Wiklander 
992817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
993817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
99432b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
995817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
99632b31808SJens Wiklander     } else {
997817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
998*b0563631STom Van Eyck                                       PEM_BEGIN_PRIVATE_KEY_RSA, PEM_END_PRIVATE_KEY_RSA,
999817466cbSJens Wiklander                                       key, pwd, pwdlen, &len);
100032b31808SJens Wiklander     }
1001817466cbSJens Wiklander 
100232b31808SJens Wiklander     if (ret == 0) {
10033d3b0591SJens Wiklander         pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
1004817466cbSJens Wiklander         if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 ||
1005*b0563631STom Van Eyck             (ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk),
100632b31808SJens Wiklander                                          pem.buf, pem.buflen)) != 0) {
1007817466cbSJens Wiklander             mbedtls_pk_free(pk);
1008817466cbSJens Wiklander         }
1009817466cbSJens Wiklander 
1010817466cbSJens Wiklander         mbedtls_pem_free(&pem);
101132b31808SJens Wiklander         return ret;
101232b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
101332b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
101432b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
101532b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
101632b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
101732b31808SJens Wiklander         return ret;
1018817466cbSJens Wiklander     }
1019817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
1020817466cbSJens Wiklander 
1021*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
1022817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
102332b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1024817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
102532b31808SJens Wiklander     } else {
1026817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1027*b0563631STom Van Eyck                                       PEM_BEGIN_PRIVATE_KEY_EC,
1028*b0563631STom Van Eyck                                       PEM_END_PRIVATE_KEY_EC,
1029817466cbSJens Wiklander                                       key, pwd, pwdlen, &len);
103032b31808SJens Wiklander     }
103132b31808SJens Wiklander     if (ret == 0) {
10323d3b0591SJens Wiklander         pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
1033817466cbSJens Wiklander 
1034817466cbSJens Wiklander         if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 ||
1035*b0563631STom Van Eyck             (ret = pk_parse_key_sec1_der(pk,
103632b31808SJens Wiklander                                          pem.buf, pem.buflen,
103732b31808SJens Wiklander                                          f_rng, p_rng)) != 0) {
1038817466cbSJens Wiklander             mbedtls_pk_free(pk);
1039817466cbSJens Wiklander         }
1040817466cbSJens Wiklander 
1041817466cbSJens Wiklander         mbedtls_pem_free(&pem);
104232b31808SJens Wiklander         return ret;
104332b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
104432b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
104532b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
104632b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
104732b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
104832b31808SJens Wiklander         return ret;
1049817466cbSJens Wiklander     }
1050*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
1051817466cbSJens Wiklander 
1052817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
105332b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1054817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
105532b31808SJens Wiklander     } else {
1056817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1057*b0563631STom Van Eyck                                       PEM_BEGIN_PRIVATE_KEY_PKCS8, PEM_END_PRIVATE_KEY_PKCS8,
1058817466cbSJens Wiklander                                       key, NULL, 0, &len);
105932b31808SJens Wiklander     }
106032b31808SJens Wiklander     if (ret == 0) {
1061817466cbSJens Wiklander         if ((ret = pk_parse_key_pkcs8_unencrypted_der(pk,
106232b31808SJens Wiklander                                                       pem.buf, pem.buflen, f_rng, p_rng)) != 0) {
1063817466cbSJens Wiklander             mbedtls_pk_free(pk);
1064817466cbSJens Wiklander         }
1065817466cbSJens Wiklander 
1066817466cbSJens Wiklander         mbedtls_pem_free(&pem);
106732b31808SJens Wiklander         return ret;
106832b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
106932b31808SJens Wiklander         return ret;
1070817466cbSJens Wiklander     }
1071817466cbSJens Wiklander 
1072817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
1073817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
107432b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1075817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
107632b31808SJens Wiklander     } else {
1077817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1078*b0563631STom Van Eyck                                       PEM_BEGIN_ENCRYPTED_PRIVATE_KEY_PKCS8,
1079*b0563631STom Van Eyck                                       PEM_END_ENCRYPTED_PRIVATE_KEY_PKCS8,
1080817466cbSJens Wiklander                                       key, NULL, 0, &len);
108132b31808SJens Wiklander     }
108232b31808SJens Wiklander     if (ret == 0) {
1083*b0563631STom Van Eyck         if ((ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, pem.buf, pem.buflen,
108432b31808SJens Wiklander                                                             pwd, pwdlen, f_rng, p_rng)) != 0) {
1085817466cbSJens Wiklander             mbedtls_pk_free(pk);
1086817466cbSJens Wiklander         }
1087817466cbSJens Wiklander 
1088817466cbSJens Wiklander         mbedtls_pem_free(&pem);
108932b31808SJens Wiklander         return ret;
109032b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
109132b31808SJens Wiklander         return ret;
1092817466cbSJens Wiklander     }
1093817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1094817466cbSJens Wiklander #else
1095817466cbSJens Wiklander     ((void) pwd);
1096817466cbSJens Wiklander     ((void) pwdlen);
1097817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
1098817466cbSJens Wiklander 
1099817466cbSJens Wiklander     /*
1100817466cbSJens Wiklander      * At this point we only know it's not a PEM formatted key. Could be any
1101817466cbSJens Wiklander      * of the known DER encoded private key formats
1102817466cbSJens Wiklander      *
1103817466cbSJens Wiklander      * We try the different DER format parsers to see if one passes without
1104817466cbSJens Wiklander      * error
1105817466cbSJens Wiklander      */
1106817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
110732b31808SJens Wiklander     if (pwdlen != 0) {
11083d3b0591SJens Wiklander         unsigned char *key_copy;
11093d3b0591SJens Wiklander 
111032b31808SJens Wiklander         if ((key_copy = mbedtls_calloc(1, keylen)) == NULL) {
111132b31808SJens Wiklander             return MBEDTLS_ERR_PK_ALLOC_FAILED;
111232b31808SJens Wiklander         }
11133d3b0591SJens Wiklander 
11143d3b0591SJens Wiklander         memcpy(key_copy, key, keylen);
11153d3b0591SJens Wiklander 
1116*b0563631STom Van Eyck         ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen,
111732b31808SJens Wiklander                                                        pwd, pwdlen, f_rng, p_rng);
11183d3b0591SJens Wiklander 
1119*b0563631STom Van Eyck         mbedtls_zeroize_and_free(key_copy, keylen);
1120817466cbSJens Wiklander     }
1121817466cbSJens Wiklander 
112232b31808SJens Wiklander     if (ret == 0) {
112332b31808SJens Wiklander         return 0;
112432b31808SJens Wiklander     }
11253d3b0591SJens Wiklander 
1126817466cbSJens Wiklander     mbedtls_pk_free(pk);
11273d3b0591SJens Wiklander     mbedtls_pk_init(pk);
1128817466cbSJens Wiklander 
112932b31808SJens Wiklander     if (ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH) {
113032b31808SJens Wiklander         return ret;
1131817466cbSJens Wiklander     }
1132817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1133817466cbSJens Wiklander 
113432b31808SJens Wiklander     ret = pk_parse_key_pkcs8_unencrypted_der(pk, key, keylen, f_rng, p_rng);
113532b31808SJens Wiklander     if (ret == 0) {
113632b31808SJens Wiklander         return 0;
1137039e02dfSJerome Forissier     }
1138817466cbSJens Wiklander 
1139817466cbSJens Wiklander     mbedtls_pk_free(pk);
11403d3b0591SJens Wiklander     mbedtls_pk_init(pk);
1141817466cbSJens Wiklander 
1142817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
1143817466cbSJens Wiklander 
11443d3b0591SJens Wiklander     pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
11453d3b0591SJens Wiklander     if (mbedtls_pk_setup(pk, pk_info) == 0 &&
1146*b0563631STom Van Eyck         mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), key, keylen) == 0) {
114732b31808SJens Wiklander         return 0;
1148817466cbSJens Wiklander     }
1149817466cbSJens Wiklander 
1150817466cbSJens Wiklander     mbedtls_pk_free(pk);
11513d3b0591SJens Wiklander     mbedtls_pk_init(pk);
1152817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
1153817466cbSJens Wiklander 
1154*b0563631STom Van Eyck #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
11553d3b0591SJens Wiklander     pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
11563d3b0591SJens Wiklander     if (mbedtls_pk_setup(pk, pk_info) == 0 &&
1157*b0563631STom Van Eyck         pk_parse_key_sec1_der(pk,
115832b31808SJens Wiklander                               key, keylen, f_rng, p_rng) == 0) {
115932b31808SJens Wiklander         return 0;
1160817466cbSJens Wiklander     }
1161817466cbSJens Wiklander     mbedtls_pk_free(pk);
1162*b0563631STom Van Eyck #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
1163817466cbSJens Wiklander 
1164*b0563631STom Van Eyck     /* If MBEDTLS_RSA_C is defined but MBEDTLS_PK_HAVE_ECC_KEYS isn't,
11653d3b0591SJens Wiklander      * it is ok to leave the PK context initialized but not
11663d3b0591SJens Wiklander      * freed: It is the caller's responsibility to call pk_init()
11673d3b0591SJens Wiklander      * before calling this function, and to call pk_free()
1168*b0563631STom Van Eyck      * when it fails. If MBEDTLS_PK_HAVE_ECC_KEYS is defined but MBEDTLS_RSA_C
11693d3b0591SJens Wiklander      * isn't, this leads to mbedtls_pk_free() being called
11703d3b0591SJens Wiklander      * twice, once here and once by the caller, but this is
11713d3b0591SJens Wiklander      * also ok and in line with the mbedtls_pk_free() calls
11723d3b0591SJens Wiklander      * on failed PEM parsing attempts. */
11733d3b0591SJens Wiklander 
117432b31808SJens Wiklander     return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
1175817466cbSJens Wiklander }
1176817466cbSJens Wiklander 
1177817466cbSJens Wiklander /*
1178817466cbSJens Wiklander  * Parse a public key
1179817466cbSJens Wiklander  */
mbedtls_pk_parse_public_key(mbedtls_pk_context * ctx,const unsigned char * key,size_t keylen)1180817466cbSJens Wiklander int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx,
1181817466cbSJens Wiklander                                 const unsigned char *key, size_t keylen)
1182817466cbSJens Wiklander {
118311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1184817466cbSJens Wiklander     unsigned char *p;
11853d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C)
11863d3b0591SJens Wiklander     const mbedtls_pk_info_t *pk_info;
11873d3b0591SJens Wiklander #endif
1188817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1189817466cbSJens Wiklander     size_t len;
1190817466cbSJens Wiklander     mbedtls_pem_context pem;
11913d3b0591SJens Wiklander #endif
1192817466cbSJens Wiklander 
119332b31808SJens Wiklander     if (keylen == 0) {
119432b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
119532b31808SJens Wiklander     }
11963d3b0591SJens Wiklander 
11973d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1198817466cbSJens Wiklander     mbedtls_pem_init(&pem);
11993d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C)
12003d3b0591SJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
120132b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
12023d3b0591SJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
120332b31808SJens Wiklander     } else {
12043d3b0591SJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1205*b0563631STom Van Eyck                                       PEM_BEGIN_PUBLIC_KEY_RSA, PEM_END_PUBLIC_KEY_RSA,
12063d3b0591SJens Wiklander                                       key, NULL, 0, &len);
120732b31808SJens Wiklander     }
12083d3b0591SJens Wiklander 
120932b31808SJens Wiklander     if (ret == 0) {
12103d3b0591SJens Wiklander         p = pem.buf;
121132b31808SJens Wiklander         if ((pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) == NULL) {
1212039e02dfSJerome Forissier             mbedtls_pem_free(&pem);
121332b31808SJens Wiklander             return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
1214039e02dfSJerome Forissier         }
12153d3b0591SJens Wiklander 
121632b31808SJens Wiklander         if ((ret = mbedtls_pk_setup(ctx, pk_info)) != 0) {
1217039e02dfSJerome Forissier             mbedtls_pem_free(&pem);
121832b31808SJens Wiklander             return ret;
1219039e02dfSJerome Forissier         }
12203d3b0591SJens Wiklander 
1221*b0563631STom Van Eyck         if ((ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*ctx), p, pem.buflen)) != 0) {
12223d3b0591SJens Wiklander             mbedtls_pk_free(ctx);
122332b31808SJens Wiklander         }
12243d3b0591SJens Wiklander 
12253d3b0591SJens Wiklander         mbedtls_pem_free(&pem);
122632b31808SJens Wiklander         return ret;
122732b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
12283d3b0591SJens Wiklander         mbedtls_pem_free(&pem);
122932b31808SJens Wiklander         return ret;
12303d3b0591SJens Wiklander     }
12313d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */
1232817466cbSJens Wiklander 
1233817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
123432b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1235817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
123632b31808SJens Wiklander     } else {
1237817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1238*b0563631STom Van Eyck                                       PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
1239817466cbSJens Wiklander                                       key, NULL, 0, &len);
124032b31808SJens Wiklander     }
1241817466cbSJens Wiklander 
124232b31808SJens Wiklander     if (ret == 0) {
1243817466cbSJens Wiklander         /*
1244817466cbSJens Wiklander          * Was PEM encoded
1245817466cbSJens Wiklander          */
12463d3b0591SJens Wiklander         p = pem.buf;
12473d3b0591SJens Wiklander 
12483d3b0591SJens Wiklander         ret = mbedtls_pk_parse_subpubkey(&p, p + pem.buflen, ctx);
12493d3b0591SJens Wiklander         mbedtls_pem_free(&pem);
125032b31808SJens Wiklander         return ret;
125132b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
1252817466cbSJens Wiklander         mbedtls_pem_free(&pem);
125332b31808SJens Wiklander         return ret;
1254817466cbSJens Wiklander     }
12553d3b0591SJens Wiklander     mbedtls_pem_free(&pem);
1256817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
12573d3b0591SJens Wiklander 
12583d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C)
125932b31808SJens Wiklander     if ((pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) == NULL) {
126032b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
126132b31808SJens Wiklander     }
12623d3b0591SJens Wiklander 
126332b31808SJens Wiklander     if ((ret = mbedtls_pk_setup(ctx, pk_info)) != 0) {
126432b31808SJens Wiklander         return ret;
126532b31808SJens Wiklander     }
12663d3b0591SJens Wiklander 
12673d3b0591SJens Wiklander     p = (unsigned char *) key;
1268*b0563631STom Van Eyck     ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*ctx), p, keylen);
126932b31808SJens Wiklander     if (ret == 0) {
127032b31808SJens Wiklander         return ret;
12713d3b0591SJens Wiklander     }
12723d3b0591SJens Wiklander     mbedtls_pk_free(ctx);
1273*b0563631STom Van Eyck     if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
127432b31808SJens Wiklander         return ret;
12753d3b0591SJens Wiklander     }
12763d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */
1277817466cbSJens Wiklander     p = (unsigned char *) key;
1278817466cbSJens Wiklander 
1279817466cbSJens Wiklander     ret = mbedtls_pk_parse_subpubkey(&p, p + keylen, ctx);
1280817466cbSJens Wiklander 
128132b31808SJens Wiklander     return ret;
1282817466cbSJens Wiklander }
1283817466cbSJens Wiklander 
1284*b0563631STom Van Eyck /***********************************************************************
1285*b0563631STom Van Eyck  *
1286*b0563631STom Van Eyck  *      Top-level functions, with filesystem support
1287*b0563631STom Van Eyck  *
1288*b0563631STom Van Eyck  **********************************************************************/
1289*b0563631STom Van Eyck 
1290*b0563631STom Van Eyck #if defined(MBEDTLS_FS_IO)
1291*b0563631STom Van Eyck /*
1292*b0563631STom Van Eyck  * Load all data from a file into a given buffer.
1293*b0563631STom Van Eyck  *
1294*b0563631STom Van Eyck  * The file is expected to contain either PEM or DER encoded data.
1295*b0563631STom Van Eyck  * A terminating null byte is always appended. It is included in the announced
1296*b0563631STom Van Eyck  * length only if the data looks like it is PEM encoded.
1297*b0563631STom Van Eyck  */
mbedtls_pk_load_file(const char * path,unsigned char ** buf,size_t * n)1298*b0563631STom Van Eyck int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n)
1299*b0563631STom Van Eyck {
1300*b0563631STom Van Eyck     FILE *f;
1301*b0563631STom Van Eyck     long size;
1302*b0563631STom Van Eyck 
1303*b0563631STom Van Eyck     if ((f = fopen(path, "rb")) == NULL) {
1304*b0563631STom Van Eyck         return MBEDTLS_ERR_PK_FILE_IO_ERROR;
1305*b0563631STom Van Eyck     }
1306*b0563631STom Van Eyck 
1307*b0563631STom Van Eyck     /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
1308*b0563631STom Van Eyck     mbedtls_setbuf(f, NULL);
1309*b0563631STom Van Eyck 
1310*b0563631STom Van Eyck     fseek(f, 0, SEEK_END);
1311*b0563631STom Van Eyck     if ((size = ftell(f)) == -1) {
1312*b0563631STom Van Eyck         fclose(f);
1313*b0563631STom Van Eyck         return MBEDTLS_ERR_PK_FILE_IO_ERROR;
1314*b0563631STom Van Eyck     }
1315*b0563631STom Van Eyck     fseek(f, 0, SEEK_SET);
1316*b0563631STom Van Eyck 
1317*b0563631STom Van Eyck     *n = (size_t) size;
1318*b0563631STom Van Eyck 
1319*b0563631STom Van Eyck     if (*n + 1 == 0 ||
1320*b0563631STom Van Eyck         (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
1321*b0563631STom Van Eyck         fclose(f);
1322*b0563631STom Van Eyck         return MBEDTLS_ERR_PK_ALLOC_FAILED;
1323*b0563631STom Van Eyck     }
1324*b0563631STom Van Eyck 
1325*b0563631STom Van Eyck     if (fread(*buf, 1, *n, f) != *n) {
1326*b0563631STom Van Eyck         fclose(f);
1327*b0563631STom Van Eyck 
1328*b0563631STom Van Eyck         mbedtls_zeroize_and_free(*buf, *n);
1329*b0563631STom Van Eyck 
1330*b0563631STom Van Eyck         return MBEDTLS_ERR_PK_FILE_IO_ERROR;
1331*b0563631STom Van Eyck     }
1332*b0563631STom Van Eyck 
1333*b0563631STom Van Eyck     fclose(f);
1334*b0563631STom Van Eyck 
1335*b0563631STom Van Eyck     (*buf)[*n] = '\0';
1336*b0563631STom Van Eyck 
1337*b0563631STom Van Eyck     if (strstr((const char *) *buf, "-----BEGIN ") != NULL) {
1338*b0563631STom Van Eyck         ++*n;
1339*b0563631STom Van Eyck     }
1340*b0563631STom Van Eyck 
1341*b0563631STom Van Eyck     return 0;
1342*b0563631STom Van Eyck }
1343*b0563631STom Van Eyck 
1344*b0563631STom Van Eyck /*
1345*b0563631STom Van Eyck  * Load and parse a private key
1346*b0563631STom Van Eyck  */
mbedtls_pk_parse_keyfile(mbedtls_pk_context * ctx,const char * path,const char * pwd,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)1347*b0563631STom Van Eyck int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx,
1348*b0563631STom Van Eyck                              const char *path, const char *pwd,
1349*b0563631STom Van Eyck                              int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
1350*b0563631STom Van Eyck {
1351*b0563631STom Van Eyck     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1352*b0563631STom Van Eyck     size_t n;
1353*b0563631STom Van Eyck     unsigned char *buf;
1354*b0563631STom Van Eyck 
1355*b0563631STom Van Eyck     if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
1356*b0563631STom Van Eyck         return ret;
1357*b0563631STom Van Eyck     }
1358*b0563631STom Van Eyck 
1359*b0563631STom Van Eyck     if (pwd == NULL) {
1360*b0563631STom Van Eyck         ret = mbedtls_pk_parse_key(ctx, buf, n, NULL, 0, f_rng, p_rng);
1361*b0563631STom Van Eyck     } else {
1362*b0563631STom Van Eyck         ret = mbedtls_pk_parse_key(ctx, buf, n,
1363*b0563631STom Van Eyck                                    (const unsigned char *) pwd, strlen(pwd), f_rng, p_rng);
1364*b0563631STom Van Eyck     }
1365*b0563631STom Van Eyck 
1366*b0563631STom Van Eyck     mbedtls_zeroize_and_free(buf, n);
1367*b0563631STom Van Eyck 
1368*b0563631STom Van Eyck     return ret;
1369*b0563631STom Van Eyck }
1370*b0563631STom Van Eyck 
1371*b0563631STom Van Eyck /*
1372*b0563631STom Van Eyck  * Load and parse a public key
1373*b0563631STom Van Eyck  */
mbedtls_pk_parse_public_keyfile(mbedtls_pk_context * ctx,const char * path)1374*b0563631STom Van Eyck int mbedtls_pk_parse_public_keyfile(mbedtls_pk_context *ctx, const char *path)
1375*b0563631STom Van Eyck {
1376*b0563631STom Van Eyck     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1377*b0563631STom Van Eyck     size_t n;
1378*b0563631STom Van Eyck     unsigned char *buf;
1379*b0563631STom Van Eyck 
1380*b0563631STom Van Eyck     if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
1381*b0563631STom Van Eyck         return ret;
1382*b0563631STom Van Eyck     }
1383*b0563631STom Van Eyck 
1384*b0563631STom Van Eyck     ret = mbedtls_pk_parse_public_key(ctx, buf, n);
1385*b0563631STom Van Eyck 
1386*b0563631STom Van Eyck     mbedtls_zeroize_and_free(buf, n);
1387*b0563631STom Van Eyck 
1388*b0563631STom Van Eyck     return ret;
1389*b0563631STom Van Eyck }
1390*b0563631STom Van Eyck #endif /* MBEDTLS_FS_IO */
1391*b0563631STom Van Eyck 
1392817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_C */
1393