xref: /optee_os/lib/libmbedtls/mbedtls/library/pkparse.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  Public Key layer for parsing key files and structures
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
57901324dSJerome Forissier  *  SPDX-License-Identifier: Apache-2.0
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  */
19817466cbSJens Wiklander 
207901324dSJerome Forissier #include "common.h"
21817466cbSJens Wiklander 
22817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_C)
23817466cbSJens Wiklander 
24817466cbSJens Wiklander #include "mbedtls/pk.h"
25817466cbSJens Wiklander #include "mbedtls/asn1.h"
26817466cbSJens Wiklander #include "mbedtls/oid.h"
273d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
2811fa71b9SJerome Forissier #include "mbedtls/error.h"
29817466cbSJens Wiklander 
30817466cbSJens Wiklander #include <string.h>
31817466cbSJens Wiklander 
32817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
33817466cbSJens Wiklander #include "mbedtls/rsa.h"
34817466cbSJens Wiklander #endif
35817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
36817466cbSJens Wiklander #include "mbedtls/ecp.h"
37817466cbSJens Wiklander #endif
38817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_C)
39817466cbSJens Wiklander #include "mbedtls/ecdsa.h"
40817466cbSJens Wiklander #endif
41817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
42817466cbSJens Wiklander #include "mbedtls/pem.h"
43817466cbSJens Wiklander #endif
44817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C)
45817466cbSJens Wiklander #include "mbedtls/pkcs5.h"
46817466cbSJens Wiklander #endif
47817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C)
48817466cbSJens Wiklander #include "mbedtls/pkcs12.h"
49817466cbSJens Wiklander #endif
50817466cbSJens Wiklander 
51817466cbSJens Wiklander #include "mbedtls/platform.h"
52817466cbSJens Wiklander 
533d3b0591SJens Wiklander #if defined(MBEDTLS_FS_IO)
54817466cbSJens Wiklander /*
55817466cbSJens Wiklander  * Load all data from a file into a given buffer.
56817466cbSJens Wiklander  *
57817466cbSJens Wiklander  * The file is expected to contain either PEM or DER encoded data.
58817466cbSJens Wiklander  * A terminating null byte is always appended. It is included in the announced
59817466cbSJens Wiklander  * length only if the data looks like it is PEM encoded.
60817466cbSJens Wiklander  */
61817466cbSJens Wiklander int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n)
62817466cbSJens Wiklander {
63817466cbSJens Wiklander     FILE *f;
64817466cbSJens Wiklander     long size;
65817466cbSJens Wiklander 
66*32b31808SJens Wiklander     if ((f = fopen(path, "rb")) == NULL) {
67*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_FILE_IO_ERROR;
68*32b31808SJens Wiklander     }
693d3b0591SJens Wiklander 
70*32b31808SJens Wiklander     /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
71*32b31808SJens Wiklander     mbedtls_setbuf(f, NULL);
72817466cbSJens Wiklander 
73817466cbSJens Wiklander     fseek(f, 0, SEEK_END);
74*32b31808SJens Wiklander     if ((size = ftell(f)) == -1) {
75817466cbSJens Wiklander         fclose(f);
76*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_FILE_IO_ERROR;
77817466cbSJens Wiklander     }
78817466cbSJens Wiklander     fseek(f, 0, SEEK_SET);
79817466cbSJens Wiklander 
80817466cbSJens Wiklander     *n = (size_t) size;
81817466cbSJens Wiklander 
82817466cbSJens Wiklander     if (*n + 1 == 0 ||
83*32b31808SJens Wiklander         (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
84817466cbSJens Wiklander         fclose(f);
85*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_ALLOC_FAILED;
86817466cbSJens Wiklander     }
87817466cbSJens Wiklander 
88*32b31808SJens Wiklander     if (fread(*buf, 1, *n, f) != *n) {
89817466cbSJens Wiklander         fclose(f);
903d3b0591SJens Wiklander 
913d3b0591SJens Wiklander         mbedtls_platform_zeroize(*buf, *n);
92817466cbSJens Wiklander         mbedtls_free(*buf);
933d3b0591SJens Wiklander 
94*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_FILE_IO_ERROR;
95817466cbSJens Wiklander     }
96817466cbSJens Wiklander 
97817466cbSJens Wiklander     fclose(f);
98817466cbSJens Wiklander 
99817466cbSJens Wiklander     (*buf)[*n] = '\0';
100817466cbSJens Wiklander 
101*32b31808SJens Wiklander     if (strstr((const char *) *buf, "-----BEGIN ") != NULL) {
102817466cbSJens Wiklander         ++*n;
103*32b31808SJens Wiklander     }
104817466cbSJens Wiklander 
105*32b31808SJens Wiklander     return 0;
106817466cbSJens Wiklander }
107817466cbSJens Wiklander 
108817466cbSJens Wiklander /*
109817466cbSJens Wiklander  * Load and parse a private key
110817466cbSJens Wiklander  */
111817466cbSJens Wiklander int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx,
112*32b31808SJens Wiklander                              const char *path, const char *pwd,
113*32b31808SJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
114817466cbSJens Wiklander {
11511fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
116817466cbSJens Wiklander     size_t n;
117817466cbSJens Wiklander     unsigned char *buf;
118817466cbSJens Wiklander 
119*32b31808SJens Wiklander     if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
120*32b31808SJens Wiklander         return ret;
121*32b31808SJens Wiklander     }
1223d3b0591SJens Wiklander 
123*32b31808SJens Wiklander     if (pwd == NULL) {
124*32b31808SJens Wiklander         ret = mbedtls_pk_parse_key(ctx, buf, n, NULL, 0, f_rng, p_rng);
125*32b31808SJens Wiklander     } else {
126817466cbSJens Wiklander         ret = mbedtls_pk_parse_key(ctx, buf, n,
127*32b31808SJens Wiklander                                    (const unsigned char *) pwd, strlen(pwd), f_rng, p_rng);
128*32b31808SJens Wiklander     }
129817466cbSJens Wiklander 
1303d3b0591SJens Wiklander     mbedtls_platform_zeroize(buf, n);
131817466cbSJens Wiklander     mbedtls_free(buf);
132817466cbSJens Wiklander 
133*32b31808SJens Wiklander     return ret;
134817466cbSJens Wiklander }
135817466cbSJens Wiklander 
136817466cbSJens Wiklander /*
137817466cbSJens Wiklander  * Load and parse a public key
138817466cbSJens Wiklander  */
139817466cbSJens Wiklander int mbedtls_pk_parse_public_keyfile(mbedtls_pk_context *ctx, const char *path)
140817466cbSJens Wiklander {
14111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
142817466cbSJens Wiklander     size_t n;
143817466cbSJens Wiklander     unsigned char *buf;
144817466cbSJens Wiklander 
145*32b31808SJens Wiklander     if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
146*32b31808SJens Wiklander         return ret;
147*32b31808SJens Wiklander     }
148817466cbSJens Wiklander 
149817466cbSJens Wiklander     ret = mbedtls_pk_parse_public_key(ctx, buf, n);
150817466cbSJens Wiklander 
1513d3b0591SJens Wiklander     mbedtls_platform_zeroize(buf, n);
152817466cbSJens Wiklander     mbedtls_free(buf);
153817466cbSJens Wiklander 
154*32b31808SJens Wiklander     return ret;
155817466cbSJens Wiklander }
156817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
157817466cbSJens Wiklander 
158817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
159817466cbSJens Wiklander /* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf
160817466cbSJens Wiklander  *
161817466cbSJens Wiklander  * ECParameters ::= CHOICE {
162817466cbSJens Wiklander  *   namedCurve         OBJECT IDENTIFIER
163817466cbSJens Wiklander  *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
164817466cbSJens Wiklander  *   -- implicitCurve   NULL
165817466cbSJens Wiklander  * }
166817466cbSJens Wiklander  */
167817466cbSJens Wiklander static int pk_get_ecparams(unsigned char **p, const unsigned char *end,
168817466cbSJens Wiklander                            mbedtls_asn1_buf *params)
169817466cbSJens Wiklander {
17011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
171817466cbSJens Wiklander 
172*32b31808SJens Wiklander     if (end - *p < 1) {
173*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
174*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_OUT_OF_DATA);
175*32b31808SJens Wiklander     }
1763d3b0591SJens Wiklander 
177817466cbSJens Wiklander     /* Tag may be either OID or SEQUENCE */
178817466cbSJens Wiklander     params->tag = **p;
179817466cbSJens Wiklander     if (params->tag != MBEDTLS_ASN1_OID
180817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
181817466cbSJens Wiklander         && params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
182817466cbSJens Wiklander #endif
183*32b31808SJens Wiklander         ) {
184*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
185*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
186817466cbSJens Wiklander     }
187817466cbSJens Wiklander 
188*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(p, end, &params->len, params->tag)) != 0) {
189*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
190817466cbSJens Wiklander     }
191817466cbSJens Wiklander 
192817466cbSJens Wiklander     params->p = *p;
193817466cbSJens Wiklander     *p += params->len;
194817466cbSJens Wiklander 
195*32b31808SJens Wiklander     if (*p != end) {
196*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
197*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
198*32b31808SJens Wiklander     }
199817466cbSJens Wiklander 
200*32b31808SJens Wiklander     return 0;
201817466cbSJens Wiklander }
202817466cbSJens Wiklander 
203817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
204817466cbSJens Wiklander /*
205817466cbSJens Wiklander  * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it.
206817466cbSJens Wiklander  * WARNING: the resulting group should only be used with
207817466cbSJens Wiklander  * pk_group_id_from_specified(), since its base point may not be set correctly
208817466cbSJens Wiklander  * if it was encoded compressed.
209817466cbSJens Wiklander  *
210817466cbSJens Wiklander  *  SpecifiedECDomain ::= SEQUENCE {
211817466cbSJens Wiklander  *      version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
212817466cbSJens Wiklander  *      fieldID FieldID {{FieldTypes}},
213817466cbSJens Wiklander  *      curve Curve,
214817466cbSJens Wiklander  *      base ECPoint,
215817466cbSJens Wiklander  *      order INTEGER,
216817466cbSJens Wiklander  *      cofactor INTEGER OPTIONAL,
217817466cbSJens Wiklander  *      hash HashAlgorithm OPTIONAL,
218817466cbSJens Wiklander  *      ...
219817466cbSJens Wiklander  *  }
220817466cbSJens Wiklander  *
221817466cbSJens Wiklander  * We only support prime-field as field type, and ignore hash and cofactor.
222817466cbSJens Wiklander  */
223817466cbSJens Wiklander static int pk_group_from_specified(const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp)
224817466cbSJens Wiklander {
22511fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
226817466cbSJens Wiklander     unsigned char *p = params->p;
227817466cbSJens Wiklander     const unsigned char * const end = params->p + params->len;
228817466cbSJens Wiklander     const unsigned char *end_field, *end_curve;
229817466cbSJens Wiklander     size_t len;
230817466cbSJens Wiklander     int ver;
231817466cbSJens Wiklander 
232817466cbSJens Wiklander     /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */
233*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, &ver)) != 0) {
234*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
235*32b31808SJens Wiklander     }
236817466cbSJens Wiklander 
237*32b31808SJens Wiklander     if (ver < 1 || ver > 3) {
238*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
239*32b31808SJens Wiklander     }
240817466cbSJens Wiklander 
241817466cbSJens Wiklander     /*
242817466cbSJens Wiklander      * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field
243817466cbSJens Wiklander      *       fieldType FIELD-ID.&id({IOSet}),
244817466cbSJens Wiklander      *       parameters FIELD-ID.&Type({IOSet}{@fieldType})
245817466cbSJens Wiklander      * }
246817466cbSJens Wiklander      */
247817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
248*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
249*32b31808SJens Wiklander         return ret;
250*32b31808SJens Wiklander     }
251817466cbSJens Wiklander 
252817466cbSJens Wiklander     end_field = p + len;
253817466cbSJens Wiklander 
254817466cbSJens Wiklander     /*
255817466cbSJens Wiklander      * FIELD-ID ::= TYPE-IDENTIFIER
256817466cbSJens Wiklander      * FieldTypes FIELD-ID ::= {
257817466cbSJens Wiklander      *       { Prime-p IDENTIFIED BY prime-field } |
258817466cbSJens Wiklander      *       { Characteristic-two IDENTIFIED BY characteristic-two-field }
259817466cbSJens Wiklander      * }
260817466cbSJens Wiklander      * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
261817466cbSJens Wiklander      */
262*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_field, &len, MBEDTLS_ASN1_OID)) != 0) {
263*32b31808SJens Wiklander         return ret;
264*32b31808SJens Wiklander     }
265817466cbSJens Wiklander 
266817466cbSJens Wiklander     if (len != MBEDTLS_OID_SIZE(MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD) ||
267*32b31808SJens Wiklander         memcmp(p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len) != 0) {
268*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
269817466cbSJens Wiklander     }
270817466cbSJens Wiklander 
271817466cbSJens Wiklander     p += len;
272817466cbSJens Wiklander 
273817466cbSJens Wiklander     /* Prime-p ::= INTEGER -- Field of size p. */
274*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_mpi(&p, end_field, &grp->P)) != 0) {
275*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
276*32b31808SJens Wiklander     }
277817466cbSJens Wiklander 
278817466cbSJens Wiklander     grp->pbits = mbedtls_mpi_bitlen(&grp->P);
279817466cbSJens Wiklander 
280*32b31808SJens Wiklander     if (p != end_field) {
281*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
282*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
283*32b31808SJens Wiklander     }
284817466cbSJens Wiklander 
285817466cbSJens Wiklander     /*
286817466cbSJens Wiklander      * Curve ::= SEQUENCE {
287817466cbSJens Wiklander      *       a FieldElement,
288817466cbSJens Wiklander      *       b FieldElement,
289817466cbSJens Wiklander      *       seed BIT STRING OPTIONAL
290817466cbSJens Wiklander      *       -- Shall be present if used in SpecifiedECDomain
291817466cbSJens Wiklander      *       -- with version equal to ecdpVer2 or ecdpVer3
292817466cbSJens Wiklander      * }
293817466cbSJens Wiklander      */
294817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
295*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
296*32b31808SJens Wiklander         return ret;
297*32b31808SJens Wiklander     }
298817466cbSJens Wiklander 
299817466cbSJens Wiklander     end_curve = p + len;
300817466cbSJens Wiklander 
301817466cbSJens Wiklander     /*
302817466cbSJens Wiklander      * FieldElement ::= OCTET STRING
303817466cbSJens Wiklander      * containing an integer in the case of a prime field
304817466cbSJens Wiklander      */
305817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0 ||
306*32b31808SJens Wiklander         (ret = mbedtls_mpi_read_binary(&grp->A, p, len)) != 0) {
307*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
308817466cbSJens Wiklander     }
309817466cbSJens Wiklander 
310817466cbSJens Wiklander     p += len;
311817466cbSJens Wiklander 
312817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0 ||
313*32b31808SJens Wiklander         (ret = mbedtls_mpi_read_binary(&grp->B, p, len)) != 0) {
314*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
315817466cbSJens Wiklander     }
316817466cbSJens Wiklander 
317817466cbSJens Wiklander     p += len;
318817466cbSJens Wiklander 
319817466cbSJens Wiklander     /* Ignore seed BIT STRING OPTIONAL */
320*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING)) == 0) {
321817466cbSJens Wiklander         p += len;
322*32b31808SJens Wiklander     }
323817466cbSJens Wiklander 
324*32b31808SJens Wiklander     if (p != end_curve) {
325*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
326*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
327*32b31808SJens Wiklander     }
328817466cbSJens Wiklander 
329817466cbSJens Wiklander     /*
330817466cbSJens Wiklander      * ECPoint ::= OCTET STRING
331817466cbSJens Wiklander      */
332*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
333*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
334*32b31808SJens Wiklander     }
335817466cbSJens Wiklander 
336817466cbSJens Wiklander     if ((ret = mbedtls_ecp_point_read_binary(grp, &grp->G,
337*32b31808SJens Wiklander                                              (const unsigned char *) p, len)) != 0) {
338817466cbSJens Wiklander         /*
339817466cbSJens Wiklander          * If we can't read the point because it's compressed, cheat by
340817466cbSJens Wiklander          * reading only the X coordinate and the parity bit of Y.
341817466cbSJens Wiklander          */
342817466cbSJens Wiklander         if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ||
343817466cbSJens Wiklander             (p[0] != 0x02 && p[0] != 0x03) ||
344817466cbSJens Wiklander             len != mbedtls_mpi_size(&grp->P) + 1 ||
345817466cbSJens Wiklander             mbedtls_mpi_read_binary(&grp->G.X, p + 1, len - 1) != 0 ||
346817466cbSJens Wiklander             mbedtls_mpi_lset(&grp->G.Y, p[0] - 2) != 0 ||
347*32b31808SJens Wiklander             mbedtls_mpi_lset(&grp->G.Z, 1) != 0) {
348*32b31808SJens Wiklander             return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
349817466cbSJens Wiklander         }
350817466cbSJens Wiklander     }
351817466cbSJens Wiklander 
352817466cbSJens Wiklander     p += len;
353817466cbSJens Wiklander 
354817466cbSJens Wiklander     /*
355817466cbSJens Wiklander      * order INTEGER
356817466cbSJens Wiklander      */
357*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_mpi(&p, end, &grp->N)) != 0) {
358*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
359*32b31808SJens Wiklander     }
360817466cbSJens Wiklander 
361817466cbSJens Wiklander     grp->nbits = mbedtls_mpi_bitlen(&grp->N);
362817466cbSJens Wiklander 
363817466cbSJens Wiklander     /*
364817466cbSJens Wiklander      * Allow optional elements by purposefully not enforcing p == end here.
365817466cbSJens Wiklander      */
366817466cbSJens Wiklander 
367*32b31808SJens Wiklander     return 0;
368817466cbSJens Wiklander }
369817466cbSJens Wiklander 
370817466cbSJens Wiklander /*
371817466cbSJens Wiklander  * Find the group id associated with an (almost filled) group as generated by
372817466cbSJens Wiklander  * pk_group_from_specified(), or return an error if unknown.
373817466cbSJens Wiklander  */
374817466cbSJens Wiklander static int pk_group_id_from_group(const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id)
375817466cbSJens Wiklander {
376817466cbSJens Wiklander     int ret = 0;
377817466cbSJens Wiklander     mbedtls_ecp_group ref;
378817466cbSJens Wiklander     const mbedtls_ecp_group_id *id;
379817466cbSJens Wiklander 
380817466cbSJens Wiklander     mbedtls_ecp_group_init(&ref);
381817466cbSJens Wiklander 
382*32b31808SJens Wiklander     for (id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++) {
383817466cbSJens Wiklander         /* Load the group associated to that id */
384817466cbSJens Wiklander         mbedtls_ecp_group_free(&ref);
385817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ref, *id));
386817466cbSJens Wiklander 
387817466cbSJens Wiklander         /* Compare to the group we were given, starting with easy tests */
388817466cbSJens Wiklander         if (grp->pbits == ref.pbits && grp->nbits == ref.nbits &&
389817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->P, &ref.P) == 0 &&
390817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->A, &ref.A) == 0 &&
391817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->B, &ref.B) == 0 &&
392817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->N, &ref.N) == 0 &&
393817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->G.X, &ref.G.X) == 0 &&
394817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi(&grp->G.Z, &ref.G.Z) == 0 &&
395817466cbSJens Wiklander             /* For Y we may only know the parity bit, so compare only that */
396*32b31808SJens Wiklander             mbedtls_mpi_get_bit(&grp->G.Y, 0) == mbedtls_mpi_get_bit(&ref.G.Y, 0)) {
397817466cbSJens Wiklander             break;
398817466cbSJens Wiklander         }
399817466cbSJens Wiklander 
400817466cbSJens Wiklander     }
401817466cbSJens Wiklander 
402817466cbSJens Wiklander cleanup:
403817466cbSJens Wiklander     mbedtls_ecp_group_free(&ref);
404817466cbSJens Wiklander 
405817466cbSJens Wiklander     *grp_id = *id;
406817466cbSJens Wiklander 
407*32b31808SJens Wiklander     if (ret == 0 && *id == MBEDTLS_ECP_DP_NONE) {
408817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
409*32b31808SJens Wiklander     }
410817466cbSJens Wiklander 
411*32b31808SJens Wiklander     return ret;
412817466cbSJens Wiklander }
413817466cbSJens Wiklander 
414817466cbSJens Wiklander /*
415817466cbSJens Wiklander  * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID
416817466cbSJens Wiklander  */
417817466cbSJens Wiklander static int pk_group_id_from_specified(const mbedtls_asn1_buf *params,
418817466cbSJens Wiklander                                       mbedtls_ecp_group_id *grp_id)
419817466cbSJens Wiklander {
42011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
421817466cbSJens Wiklander     mbedtls_ecp_group grp;
422817466cbSJens Wiklander 
423817466cbSJens Wiklander     mbedtls_ecp_group_init(&grp);
424817466cbSJens Wiklander 
425*32b31808SJens Wiklander     if ((ret = pk_group_from_specified(params, &grp)) != 0) {
426817466cbSJens Wiklander         goto cleanup;
427*32b31808SJens Wiklander     }
428817466cbSJens Wiklander 
429817466cbSJens Wiklander     ret = pk_group_id_from_group(&grp, grp_id);
430817466cbSJens Wiklander 
431817466cbSJens Wiklander cleanup:
432*32b31808SJens Wiklander     /* The API respecting lifecycle for mbedtls_ecp_group struct is
433*32b31808SJens Wiklander      * _init(), _load() and _free(). In pk_group_id_from_specified() the
434*32b31808SJens Wiklander      * temporary grp breaks that flow and it's members are populated
435*32b31808SJens Wiklander      * by pk_group_id_from_group(). As such mbedtls_ecp_group_free()
436*32b31808SJens Wiklander      * which is assuming a group populated by _setup() may not clean-up
437*32b31808SJens Wiklander      * properly -> Manually free it's members.
438*32b31808SJens Wiklander      */
439*32b31808SJens Wiklander     mbedtls_mpi_free(&grp.N);
440*32b31808SJens Wiklander     mbedtls_mpi_free(&grp.P);
441*32b31808SJens Wiklander     mbedtls_mpi_free(&grp.A);
442*32b31808SJens Wiklander     mbedtls_mpi_free(&grp.B);
443*32b31808SJens Wiklander     mbedtls_ecp_point_free(&grp.G);
444817466cbSJens Wiklander 
445*32b31808SJens Wiklander     return ret;
446817466cbSJens Wiklander }
447817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */
448817466cbSJens Wiklander 
449817466cbSJens Wiklander /*
450817466cbSJens Wiklander  * Use EC parameters to initialise an EC group
451817466cbSJens Wiklander  *
452817466cbSJens Wiklander  * ECParameters ::= CHOICE {
453817466cbSJens Wiklander  *   namedCurve         OBJECT IDENTIFIER
454817466cbSJens Wiklander  *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
455817466cbSJens Wiklander  *   -- implicitCurve   NULL
456817466cbSJens Wiklander  */
457817466cbSJens Wiklander static int pk_use_ecparams(const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp)
458817466cbSJens Wiklander {
45911fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
460817466cbSJens Wiklander     mbedtls_ecp_group_id grp_id;
461817466cbSJens Wiklander 
462*32b31808SJens Wiklander     if (params->tag == MBEDTLS_ASN1_OID) {
463*32b31808SJens Wiklander         if (mbedtls_oid_get_ec_grp(params, &grp_id) != 0) {
464*32b31808SJens Wiklander             return MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE;
465817466cbSJens Wiklander         }
466*32b31808SJens Wiklander     } else {
467817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
468*32b31808SJens Wiklander         if ((ret = pk_group_id_from_specified(params, &grp_id)) != 0) {
469*32b31808SJens Wiklander             return ret;
470*32b31808SJens Wiklander         }
471817466cbSJens Wiklander #else
472*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
473817466cbSJens Wiklander #endif
474817466cbSJens Wiklander     }
475817466cbSJens Wiklander 
476817466cbSJens Wiklander     /*
477039e02dfSJerome Forissier      * grp may already be initialized; if so, make sure IDs match
478817466cbSJens Wiklander      */
479*32b31808SJens Wiklander     if (grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id) {
480*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
481*32b31808SJens Wiklander     }
482817466cbSJens Wiklander 
483*32b31808SJens Wiklander     if ((ret = mbedtls_ecp_group_load(grp, grp_id)) != 0) {
484*32b31808SJens Wiklander         return ret;
485*32b31808SJens Wiklander     }
486817466cbSJens Wiklander 
487*32b31808SJens Wiklander     return 0;
488817466cbSJens Wiklander }
489817466cbSJens Wiklander 
490817466cbSJens Wiklander /*
491817466cbSJens Wiklander  * EC public key is an EC point
492817466cbSJens Wiklander  *
493817466cbSJens Wiklander  * The caller is responsible for clearing the structure upon failure if
494817466cbSJens Wiklander  * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE
495817466cbSJens Wiklander  * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state.
496817466cbSJens Wiklander  */
497817466cbSJens Wiklander static int pk_get_ecpubkey(unsigned char **p, const unsigned char *end,
498817466cbSJens Wiklander                            mbedtls_ecp_keypair *key)
499817466cbSJens Wiklander {
50011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
501817466cbSJens Wiklander 
502817466cbSJens Wiklander     if ((ret = mbedtls_ecp_point_read_binary(&key->grp, &key->Q,
503*32b31808SJens Wiklander                                              (const unsigned char *) *p, end - *p)) == 0) {
504817466cbSJens Wiklander         ret = mbedtls_ecp_check_pubkey(&key->grp, &key->Q);
505817466cbSJens Wiklander     }
506817466cbSJens Wiklander 
507817466cbSJens Wiklander     /*
508817466cbSJens Wiklander      * We know mbedtls_ecp_point_read_binary consumed all bytes or failed
509817466cbSJens Wiklander      */
510817466cbSJens Wiklander     *p = (unsigned char *) end;
511817466cbSJens Wiklander 
512*32b31808SJens Wiklander     return ret;
513817466cbSJens Wiklander }
514817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */
515817466cbSJens Wiklander 
516817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
517817466cbSJens Wiklander /*
518817466cbSJens Wiklander  *  RSAPublicKey ::= SEQUENCE {
519817466cbSJens Wiklander  *      modulus           INTEGER,  -- n
520817466cbSJens Wiklander  *      publicExponent    INTEGER   -- e
521817466cbSJens Wiklander  *  }
522817466cbSJens Wiklander  */
523817466cbSJens Wiklander static int pk_get_rsapubkey(unsigned char **p,
524817466cbSJens Wiklander                             const unsigned char *end,
525817466cbSJens Wiklander                             mbedtls_rsa_context *rsa)
526817466cbSJens Wiklander {
52711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
528817466cbSJens Wiklander     size_t len;
529817466cbSJens Wiklander 
530817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(p, end, &len,
531*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
532*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
533*32b31808SJens Wiklander     }
534817466cbSJens Wiklander 
535*32b31808SJens Wiklander     if (*p + len != end) {
536*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
537*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
538*32b31808SJens Wiklander     }
539817466cbSJens Wiklander 
5403d3b0591SJens Wiklander     /* Import N */
541*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) {
542*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
543*32b31808SJens Wiklander     }
544817466cbSJens Wiklander 
5453d3b0591SJens Wiklander     if ((ret = mbedtls_rsa_import_raw(rsa, *p, len, NULL, 0, NULL, 0,
546*32b31808SJens Wiklander                                       NULL, 0, NULL, 0)) != 0) {
547*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_INVALID_PUBKEY;
548*32b31808SJens Wiklander     }
5493d3b0591SJens Wiklander 
5503d3b0591SJens Wiklander     *p += len;
5513d3b0591SJens Wiklander 
5523d3b0591SJens Wiklander     /* Import E */
553*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) {
554*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
555*32b31808SJens Wiklander     }
5563d3b0591SJens Wiklander 
5573d3b0591SJens Wiklander     if ((ret = mbedtls_rsa_import_raw(rsa, NULL, 0, NULL, 0, NULL, 0,
558*32b31808SJens Wiklander                                       NULL, 0, *p, len)) != 0) {
559*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_INVALID_PUBKEY;
560*32b31808SJens Wiklander     }
5613d3b0591SJens Wiklander 
5623d3b0591SJens Wiklander     *p += len;
5633d3b0591SJens Wiklander 
5643d3b0591SJens Wiklander     if (mbedtls_rsa_complete(rsa) != 0 ||
565*32b31808SJens Wiklander         mbedtls_rsa_check_pubkey(rsa) != 0) {
566*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_INVALID_PUBKEY;
5673d3b0591SJens Wiklander     }
5683d3b0591SJens Wiklander 
569*32b31808SJens Wiklander     if (*p != end) {
570*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
571*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
572*32b31808SJens Wiklander     }
573817466cbSJens Wiklander 
574*32b31808SJens Wiklander     return 0;
575817466cbSJens Wiklander }
576817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
577817466cbSJens Wiklander 
578817466cbSJens Wiklander /* Get a PK algorithm identifier
579817466cbSJens Wiklander  *
580817466cbSJens Wiklander  *  AlgorithmIdentifier  ::=  SEQUENCE  {
581817466cbSJens Wiklander  *       algorithm               OBJECT IDENTIFIER,
582817466cbSJens Wiklander  *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
583817466cbSJens Wiklander  */
584817466cbSJens Wiklander static int pk_get_pk_alg(unsigned char **p,
585817466cbSJens Wiklander                          const unsigned char *end,
586817466cbSJens Wiklander                          mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params)
587817466cbSJens Wiklander {
58811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
589817466cbSJens Wiklander     mbedtls_asn1_buf alg_oid;
590817466cbSJens Wiklander 
591817466cbSJens Wiklander     memset(params, 0, sizeof(mbedtls_asn1_buf));
592817466cbSJens Wiklander 
593*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_alg(p, end, &alg_oid, params)) != 0) {
594*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_ALG, ret);
595*32b31808SJens Wiklander     }
596817466cbSJens Wiklander 
597*32b31808SJens Wiklander     if (mbedtls_oid_get_pk_alg(&alg_oid, pk_alg) != 0) {
598*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
599*32b31808SJens Wiklander     }
600817466cbSJens Wiklander 
601817466cbSJens Wiklander     /*
602817466cbSJens Wiklander      * No parameters with RSA (only for EC)
603817466cbSJens Wiklander      */
604817466cbSJens Wiklander     if (*pk_alg == MBEDTLS_PK_RSA &&
605817466cbSJens Wiklander         ((params->tag != MBEDTLS_ASN1_NULL && params->tag != 0) ||
606*32b31808SJens Wiklander          params->len != 0)) {
607*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_INVALID_ALG;
608817466cbSJens Wiklander     }
609817466cbSJens Wiklander 
610*32b31808SJens Wiklander     return 0;
611817466cbSJens Wiklander }
612817466cbSJens Wiklander 
613817466cbSJens Wiklander /*
614817466cbSJens Wiklander  *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
615817466cbSJens Wiklander  *       algorithm            AlgorithmIdentifier,
616817466cbSJens Wiklander  *       subjectPublicKey     BIT STRING }
617817466cbSJens Wiklander  */
618817466cbSJens Wiklander int mbedtls_pk_parse_subpubkey(unsigned char **p, const unsigned char *end,
619817466cbSJens Wiklander                                mbedtls_pk_context *pk)
620817466cbSJens Wiklander {
62111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
622817466cbSJens Wiklander     size_t len;
623817466cbSJens Wiklander     mbedtls_asn1_buf alg_params;
624817466cbSJens Wiklander     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
625817466cbSJens Wiklander     const mbedtls_pk_info_t *pk_info;
626817466cbSJens Wiklander 
627817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(p, end, &len,
628*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
629*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
630817466cbSJens Wiklander     }
631817466cbSJens Wiklander 
632817466cbSJens Wiklander     end = *p + len;
633817466cbSJens Wiklander 
634*32b31808SJens Wiklander     if ((ret = pk_get_pk_alg(p, end, &pk_alg, &alg_params)) != 0) {
635*32b31808SJens Wiklander         return ret;
636*32b31808SJens Wiklander     }
637817466cbSJens Wiklander 
638*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_bitstring_null(p, end, &len)) != 0) {
639*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
640*32b31808SJens Wiklander     }
641817466cbSJens Wiklander 
642*32b31808SJens Wiklander     if (*p + len != end) {
643*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
644*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
645*32b31808SJens Wiklander     }
646817466cbSJens Wiklander 
647*32b31808SJens Wiklander     if ((pk_info = mbedtls_pk_info_from_type(pk_alg)) == NULL) {
648*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
649*32b31808SJens Wiklander     }
650817466cbSJens Wiklander 
651*32b31808SJens Wiklander     if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0) {
652*32b31808SJens Wiklander         return ret;
653*32b31808SJens Wiklander     }
654817466cbSJens Wiklander 
655817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
656*32b31808SJens Wiklander     if (pk_alg == MBEDTLS_PK_RSA) {
657817466cbSJens Wiklander         ret = pk_get_rsapubkey(p, end, mbedtls_pk_rsa(*pk));
658817466cbSJens Wiklander     } else
659817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
660817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
661*32b31808SJens Wiklander     if (pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY) {
662817466cbSJens Wiklander         ret = pk_use_ecparams(&alg_params, &mbedtls_pk_ec(*pk)->grp);
663*32b31808SJens Wiklander         if (ret == 0) {
664817466cbSJens Wiklander             ret = pk_get_ecpubkey(p, end, mbedtls_pk_ec(*pk));
665*32b31808SJens Wiklander         }
666817466cbSJens Wiklander     } else
667817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */
668817466cbSJens Wiklander     ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
669817466cbSJens Wiklander 
670*32b31808SJens Wiklander     if (ret == 0 && *p != end) {
6717901324dSJerome Forissier         ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
6727901324dSJerome Forissier                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
673*32b31808SJens Wiklander     }
674817466cbSJens Wiklander 
675*32b31808SJens Wiklander     if (ret != 0) {
676817466cbSJens Wiklander         mbedtls_pk_free(pk);
677*32b31808SJens Wiklander     }
678817466cbSJens Wiklander 
679*32b31808SJens Wiklander     return ret;
680817466cbSJens Wiklander }
681817466cbSJens Wiklander 
682817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
683817466cbSJens Wiklander /*
6845b25c76aSJerome Forissier  * Wrapper around mbedtls_asn1_get_mpi() that rejects zero.
6855b25c76aSJerome Forissier  *
6865b25c76aSJerome Forissier  * The value zero is:
6875b25c76aSJerome Forissier  * - never a valid value for an RSA parameter
6885b25c76aSJerome Forissier  * - interpreted as "omitted, please reconstruct" by mbedtls_rsa_complete().
6895b25c76aSJerome Forissier  *
6905b25c76aSJerome Forissier  * Since values can't be omitted in PKCS#1, passing a zero value to
6915b25c76aSJerome Forissier  * rsa_complete() would be incorrect, so reject zero values early.
6925b25c76aSJerome Forissier  */
6935b25c76aSJerome Forissier static int asn1_get_nonzero_mpi(unsigned char **p,
6945b25c76aSJerome Forissier                                 const unsigned char *end,
6955b25c76aSJerome Forissier                                 mbedtls_mpi *X)
6965b25c76aSJerome Forissier {
6975b25c76aSJerome Forissier     int ret;
6985b25c76aSJerome Forissier 
6995b25c76aSJerome Forissier     ret = mbedtls_asn1_get_mpi(p, end, X);
700*32b31808SJens Wiklander     if (ret != 0) {
701*32b31808SJens Wiklander         return ret;
702*32b31808SJens Wiklander     }
7035b25c76aSJerome Forissier 
704*32b31808SJens Wiklander     if (mbedtls_mpi_cmp_int(X, 0) == 0) {
705*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
706*32b31808SJens Wiklander     }
7075b25c76aSJerome Forissier 
708*32b31808SJens Wiklander     return 0;
7095b25c76aSJerome Forissier }
7105b25c76aSJerome Forissier 
7115b25c76aSJerome Forissier /*
712817466cbSJens Wiklander  * Parse a PKCS#1 encoded private RSA key
713817466cbSJens Wiklander  */
714817466cbSJens Wiklander static int pk_parse_key_pkcs1_der(mbedtls_rsa_context *rsa,
715817466cbSJens Wiklander                                   const unsigned char *key,
716817466cbSJens Wiklander                                   size_t keylen)
717817466cbSJens Wiklander {
7183d3b0591SJens Wiklander     int ret, version;
719817466cbSJens Wiklander     size_t len;
720817466cbSJens Wiklander     unsigned char *p, *end;
721817466cbSJens Wiklander 
7223d3b0591SJens Wiklander     mbedtls_mpi T;
7233d3b0591SJens Wiklander     mbedtls_mpi_init(&T);
7243d3b0591SJens Wiklander 
725817466cbSJens Wiklander     p = (unsigned char *) key;
726817466cbSJens Wiklander     end = p + keylen;
727817466cbSJens Wiklander 
728817466cbSJens Wiklander     /*
729817466cbSJens Wiklander      * This function parses the RSAPrivateKey (PKCS#1)
730817466cbSJens Wiklander      *
731817466cbSJens Wiklander      *  RSAPrivateKey ::= SEQUENCE {
732817466cbSJens Wiklander      *      version           Version,
733817466cbSJens Wiklander      *      modulus           INTEGER,  -- n
734817466cbSJens Wiklander      *      publicExponent    INTEGER,  -- e
735817466cbSJens Wiklander      *      privateExponent   INTEGER,  -- d
736817466cbSJens Wiklander      *      prime1            INTEGER,  -- p
737817466cbSJens Wiklander      *      prime2            INTEGER,  -- q
738817466cbSJens Wiklander      *      exponent1         INTEGER,  -- d mod (p-1)
739817466cbSJens Wiklander      *      exponent2         INTEGER,  -- d mod (q-1)
740817466cbSJens Wiklander      *      coefficient       INTEGER,  -- (inverse of q) mod p
741817466cbSJens Wiklander      *      otherPrimeInfos   OtherPrimeInfos OPTIONAL
742817466cbSJens Wiklander      *  }
743817466cbSJens Wiklander      */
744817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
745*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
746*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
747817466cbSJens Wiklander     }
748817466cbSJens Wiklander 
749817466cbSJens Wiklander     end = p + len;
750817466cbSJens Wiklander 
751*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
752*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
753817466cbSJens Wiklander     }
754817466cbSJens Wiklander 
755*32b31808SJens Wiklander     if (version != 0) {
756*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_VERSION;
757817466cbSJens Wiklander     }
758817466cbSJens Wiklander 
7593d3b0591SJens Wiklander     /* Import N */
7605b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
7615b25c76aSJerome Forissier         (ret = mbedtls_rsa_import(rsa, &T, NULL, NULL,
762*32b31808SJens Wiklander                                   NULL, NULL)) != 0) {
7633d3b0591SJens Wiklander         goto cleanup;
764*32b31808SJens Wiklander     }
765817466cbSJens Wiklander 
7663d3b0591SJens Wiklander     /* Import E */
7675b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
7685b25c76aSJerome Forissier         (ret = mbedtls_rsa_import(rsa, NULL, NULL, NULL,
769*32b31808SJens Wiklander                                   NULL, &T)) != 0) {
7703d3b0591SJens Wiklander         goto cleanup;
771*32b31808SJens Wiklander     }
7723d3b0591SJens Wiklander 
7733d3b0591SJens Wiklander     /* Import D */
7745b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
7755b25c76aSJerome Forissier         (ret = mbedtls_rsa_import(rsa, NULL, NULL, NULL,
776*32b31808SJens Wiklander                                   &T, NULL)) != 0) {
7773d3b0591SJens Wiklander         goto cleanup;
778*32b31808SJens Wiklander     }
7793d3b0591SJens Wiklander 
7803d3b0591SJens Wiklander     /* Import P */
7815b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
7825b25c76aSJerome Forissier         (ret = mbedtls_rsa_import(rsa, NULL, &T, NULL,
783*32b31808SJens Wiklander                                   NULL, NULL)) != 0) {
7843d3b0591SJens Wiklander         goto cleanup;
785*32b31808SJens Wiklander     }
7863d3b0591SJens Wiklander 
7873d3b0591SJens Wiklander     /* Import Q */
7885b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
7895b25c76aSJerome Forissier         (ret = mbedtls_rsa_import(rsa, NULL, NULL, &T,
790*32b31808SJens Wiklander                                   NULL, NULL)) != 0) {
7913d3b0591SJens Wiklander         goto cleanup;
792*32b31808SJens Wiklander     }
7933d3b0591SJens Wiklander 
7945b25c76aSJerome Forissier #if !defined(MBEDTLS_RSA_NO_CRT) && !defined(MBEDTLS_RSA_ALT)
7955b25c76aSJerome Forissier     /*
7965b25c76aSJerome Forissier      * The RSA CRT parameters DP, DQ and QP are nominally redundant, in
7975b25c76aSJerome Forissier      * that they can be easily recomputed from D, P and Q. However by
7985b25c76aSJerome Forissier      * parsing them from the PKCS1 structure it is possible to avoid
7995b25c76aSJerome Forissier      * recalculating them which both reduces the overhead of loading
8005b25c76aSJerome Forissier      * RSA private keys into memory and also avoids side channels which
8015b25c76aSJerome Forissier      * can arise when computing those values, since all of D, P, and Q
8025b25c76aSJerome Forissier      * are secret. See https://eprint.iacr.org/2020/055 for a
8035b25c76aSJerome Forissier      * description of one such attack.
8045b25c76aSJerome Forissier      */
8055b25c76aSJerome Forissier 
8065b25c76aSJerome Forissier     /* Import DP */
8075b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
808*32b31808SJens Wiklander         (ret = mbedtls_mpi_copy(&rsa->DP, &T)) != 0) {
8093d3b0591SJens Wiklander         goto cleanup;
810*32b31808SJens Wiklander     }
811817466cbSJens Wiklander 
8125b25c76aSJerome Forissier     /* Import DQ */
8135b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
814*32b31808SJens Wiklander         (ret = mbedtls_mpi_copy(&rsa->DQ, &T)) != 0) {
8155b25c76aSJerome Forissier         goto cleanup;
816*32b31808SJens Wiklander     }
8175b25c76aSJerome Forissier 
8185b25c76aSJerome Forissier     /* Import QP */
8195b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
820*32b31808SJens Wiklander         (ret = mbedtls_mpi_copy(&rsa->QP, &T)) != 0) {
8215b25c76aSJerome Forissier         goto cleanup;
822*32b31808SJens Wiklander     }
8235b25c76aSJerome Forissier 
8245b25c76aSJerome Forissier #else
825039e02dfSJerome Forissier     /* Verify existence of the CRT params */
8265b25c76aSJerome Forissier     if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
8275b25c76aSJerome Forissier         (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
828*32b31808SJens Wiklander         (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0) {
8295b25c76aSJerome Forissier         goto cleanup;
830*32b31808SJens Wiklander     }
8315b25c76aSJerome Forissier #endif
8325b25c76aSJerome Forissier 
8335b25c76aSJerome Forissier     /* rsa_complete() doesn't complete anything with the default
8345b25c76aSJerome Forissier      * implementation but is still called:
8355b25c76aSJerome Forissier      * - for the benefit of alternative implementation that may want to
8365b25c76aSJerome Forissier      *   pre-compute stuff beyond what's provided (eg Montgomery factors)
8375b25c76aSJerome Forissier      * - as is also sanity-checks the key
8385b25c76aSJerome Forissier      *
8395b25c76aSJerome Forissier      * Furthermore, we also check the public part for consistency with
8405b25c76aSJerome Forissier      * mbedtls_pk_parse_pubkey(), as it includes size minima for example.
8415b25c76aSJerome Forissier      */
8425b25c76aSJerome Forissier     if ((ret = mbedtls_rsa_complete(rsa)) != 0 ||
843*32b31808SJens Wiklander         (ret = mbedtls_rsa_check_pubkey(rsa)) != 0) {
8445b25c76aSJerome Forissier         goto cleanup;
8455b25c76aSJerome Forissier     }
8465b25c76aSJerome Forissier 
847*32b31808SJens Wiklander     if (p != end) {
8487901324dSJerome Forissier         ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
8497901324dSJerome Forissier                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
850817466cbSJens Wiklander     }
851817466cbSJens Wiklander 
8523d3b0591SJens Wiklander cleanup:
8533d3b0591SJens Wiklander 
8543d3b0591SJens Wiklander     mbedtls_mpi_free(&T);
8553d3b0591SJens Wiklander 
856*32b31808SJens Wiklander     if (ret != 0) {
8573d3b0591SJens Wiklander         /* Wrap error code if it's coming from a lower level */
858*32b31808SJens Wiklander         if ((ret & 0xff80) == 0) {
8597901324dSJerome Forissier             ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
860*32b31808SJens Wiklander         } else {
8613d3b0591SJens Wiklander             ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
862*32b31808SJens Wiklander         }
8633d3b0591SJens Wiklander 
864817466cbSJens Wiklander         mbedtls_rsa_free(rsa);
865817466cbSJens Wiklander     }
866817466cbSJens Wiklander 
867*32b31808SJens Wiklander     return ret;
868817466cbSJens Wiklander }
869817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
870817466cbSJens Wiklander 
871817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
872817466cbSJens Wiklander /*
873817466cbSJens Wiklander  * Parse a SEC1 encoded private EC key
874817466cbSJens Wiklander  */
875817466cbSJens Wiklander static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck,
876*32b31808SJens Wiklander                                  const unsigned char *key, size_t keylen,
877*32b31808SJens Wiklander                                  int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
878817466cbSJens Wiklander {
87911fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
880817466cbSJens Wiklander     int version, pubkey_done;
881817466cbSJens Wiklander     size_t len;
882*32b31808SJens Wiklander     mbedtls_asn1_buf params = { 0, 0, NULL };
883817466cbSJens Wiklander     unsigned char *p = (unsigned char *) key;
884817466cbSJens Wiklander     unsigned char *end = p + keylen;
885817466cbSJens Wiklander     unsigned char *end2;
886817466cbSJens Wiklander 
887817466cbSJens Wiklander     /*
888817466cbSJens Wiklander      * RFC 5915, or SEC1 Appendix C.4
889817466cbSJens Wiklander      *
890817466cbSJens Wiklander      * ECPrivateKey ::= SEQUENCE {
891817466cbSJens Wiklander      *      version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
892817466cbSJens Wiklander      *      privateKey     OCTET STRING,
893817466cbSJens Wiklander      *      parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
894817466cbSJens Wiklander      *      publicKey  [1] BIT STRING OPTIONAL
895817466cbSJens Wiklander      *    }
896817466cbSJens Wiklander      */
897817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
898*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
899*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
900817466cbSJens Wiklander     }
901817466cbSJens Wiklander 
902817466cbSJens Wiklander     end = p + len;
903817466cbSJens Wiklander 
904*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
905*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
906*32b31808SJens Wiklander     }
907817466cbSJens Wiklander 
908*32b31808SJens Wiklander     if (version != 1) {
909*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_VERSION;
910*32b31808SJens Wiklander     }
911817466cbSJens Wiklander 
912*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
913*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
914*32b31808SJens Wiklander     }
915817466cbSJens Wiklander 
916*32b31808SJens Wiklander     if ((ret = mbedtls_mpi_read_binary(&eck->d, p, len)) != 0) {
917817466cbSJens Wiklander         mbedtls_ecp_keypair_free(eck);
918*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
919817466cbSJens Wiklander     }
920817466cbSJens Wiklander 
921817466cbSJens Wiklander     p += len;
922817466cbSJens Wiklander 
923817466cbSJens Wiklander     pubkey_done = 0;
924*32b31808SJens Wiklander     if (p != end) {
925817466cbSJens Wiklander         /*
926817466cbSJens Wiklander          * Is 'parameters' present?
927817466cbSJens Wiklander          */
928817466cbSJens Wiklander         if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
929*32b31808SJens Wiklander                                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
930*32b31808SJens Wiklander                                         0)) == 0) {
931817466cbSJens Wiklander             if ((ret = pk_get_ecparams(&p, p + len, &params)) != 0 ||
932*32b31808SJens Wiklander                 (ret = pk_use_ecparams(&params, &eck->grp)) != 0) {
933817466cbSJens Wiklander                 mbedtls_ecp_keypair_free(eck);
934*32b31808SJens Wiklander                 return ret;
935817466cbSJens Wiklander             }
936*32b31808SJens Wiklander         } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
937817466cbSJens Wiklander             mbedtls_ecp_keypair_free(eck);
938*32b31808SJens Wiklander             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
939817466cbSJens Wiklander         }
9403d3b0591SJens Wiklander     }
941817466cbSJens Wiklander 
942*32b31808SJens Wiklander     if (p != end) {
943817466cbSJens Wiklander         /*
944817466cbSJens Wiklander          * Is 'publickey' present? If not, or if we can't read it (eg because it
945817466cbSJens Wiklander          * is compressed), create it from the private key.
946817466cbSJens Wiklander          */
947817466cbSJens Wiklander         if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
948*32b31808SJens Wiklander                                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
949*32b31808SJens Wiklander                                         1)) == 0) {
950817466cbSJens Wiklander             end2 = p + len;
951817466cbSJens Wiklander 
952*32b31808SJens Wiklander             if ((ret = mbedtls_asn1_get_bitstring_null(&p, end2, &len)) != 0) {
953*32b31808SJens Wiklander                 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
954*32b31808SJens Wiklander             }
955817466cbSJens Wiklander 
956*32b31808SJens Wiklander             if (p + len != end2) {
957*32b31808SJens Wiklander                 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
958*32b31808SJens Wiklander                                          MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
959*32b31808SJens Wiklander             }
960817466cbSJens Wiklander 
961*32b31808SJens Wiklander             if ((ret = pk_get_ecpubkey(&p, end2, eck)) == 0) {
962817466cbSJens Wiklander                 pubkey_done = 1;
963*32b31808SJens Wiklander             } else {
964817466cbSJens Wiklander                 /*
965817466cbSJens Wiklander                  * The only acceptable failure mode of pk_get_ecpubkey() above
966817466cbSJens Wiklander                  * is if the point format is not recognized.
967817466cbSJens Wiklander                  */
968*32b31808SJens Wiklander                 if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) {
969*32b31808SJens Wiklander                     return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
970817466cbSJens Wiklander                 }
971817466cbSJens Wiklander             }
972*32b31808SJens Wiklander         } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
973817466cbSJens Wiklander             mbedtls_ecp_keypair_free(eck);
974*32b31808SJens Wiklander             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
975817466cbSJens Wiklander         }
976817466cbSJens Wiklander     }
977817466cbSJens Wiklander 
978817466cbSJens Wiklander     if (!pubkey_done &&
979817466cbSJens Wiklander         (ret = mbedtls_ecp_mul(&eck->grp, &eck->Q, &eck->d, &eck->grp.G,
980*32b31808SJens Wiklander                                f_rng, p_rng)) != 0) {
981817466cbSJens Wiklander         mbedtls_ecp_keypair_free(eck);
982*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
983817466cbSJens Wiklander     }
984817466cbSJens Wiklander 
985*32b31808SJens Wiklander     if ((ret = mbedtls_ecp_check_privkey(&eck->grp, &eck->d)) != 0) {
986817466cbSJens Wiklander         mbedtls_ecp_keypair_free(eck);
987*32b31808SJens Wiklander         return ret;
988817466cbSJens Wiklander     }
989817466cbSJens Wiklander 
990*32b31808SJens Wiklander     return 0;
991817466cbSJens Wiklander }
992817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */
993817466cbSJens Wiklander 
994817466cbSJens Wiklander /*
995817466cbSJens Wiklander  * Parse an unencrypted PKCS#8 encoded private key
9963d3b0591SJens Wiklander  *
9973d3b0591SJens Wiklander  * Notes:
9983d3b0591SJens Wiklander  *
9993d3b0591SJens Wiklander  * - This function does not own the key buffer. It is the
10003d3b0591SJens Wiklander  *   responsibility of the caller to take care of zeroizing
10013d3b0591SJens Wiklander  *   and freeing it after use.
10023d3b0591SJens Wiklander  *
10033d3b0591SJens Wiklander  * - The function is responsible for freeing the provided
10043d3b0591SJens Wiklander  *   PK context on failure.
10053d3b0591SJens Wiklander  *
1006817466cbSJens Wiklander  */
1007817466cbSJens Wiklander static int pk_parse_key_pkcs8_unencrypted_der(
1008817466cbSJens Wiklander     mbedtls_pk_context *pk,
1009*32b31808SJens Wiklander     const unsigned char *key, size_t keylen,
1010*32b31808SJens Wiklander     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
1011817466cbSJens Wiklander {
1012817466cbSJens Wiklander     int ret, version;
1013817466cbSJens Wiklander     size_t len;
1014817466cbSJens Wiklander     mbedtls_asn1_buf params;
1015817466cbSJens Wiklander     unsigned char *p = (unsigned char *) key;
1016817466cbSJens Wiklander     unsigned char *end = p + keylen;
1017817466cbSJens Wiklander     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
1018817466cbSJens Wiklander     const mbedtls_pk_info_t *pk_info;
1019817466cbSJens Wiklander 
1020*32b31808SJens Wiklander #if !defined(MBEDTLS_ECP_C)
1021*32b31808SJens Wiklander     (void) f_rng;
1022*32b31808SJens Wiklander     (void) p_rng;
1023*32b31808SJens Wiklander #endif
1024*32b31808SJens Wiklander 
1025817466cbSJens Wiklander     /*
10263d3b0591SJens Wiklander      * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208)
1027817466cbSJens Wiklander      *
1028817466cbSJens Wiklander      *    PrivateKeyInfo ::= SEQUENCE {
1029817466cbSJens Wiklander      *      version                   Version,
1030817466cbSJens Wiklander      *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
1031817466cbSJens Wiklander      *      privateKey                PrivateKey,
1032817466cbSJens Wiklander      *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
1033817466cbSJens Wiklander      *
1034817466cbSJens Wiklander      *    Version ::= INTEGER
1035817466cbSJens Wiklander      *    PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
1036817466cbSJens Wiklander      *    PrivateKey ::= OCTET STRING
1037817466cbSJens Wiklander      *
1038817466cbSJens Wiklander      *  The PrivateKey OCTET STRING is a SEC1 ECPrivateKey
1039817466cbSJens Wiklander      */
1040817466cbSJens Wiklander 
1041817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
1042*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
1043*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
1044817466cbSJens Wiklander     }
1045817466cbSJens Wiklander 
1046817466cbSJens Wiklander     end = p + len;
1047817466cbSJens Wiklander 
1048*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
1049*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
10507901324dSJerome Forissier     }
1051817466cbSJens Wiklander 
1052*32b31808SJens Wiklander     if (version != 0) {
1053*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_VERSION, ret);
1054*32b31808SJens Wiklander     }
1055817466cbSJens Wiklander 
1056*32b31808SJens Wiklander     if ((ret = pk_get_pk_alg(&p, end, &pk_alg, &params)) != 0) {
1057*32b31808SJens Wiklander         return ret;
1058*32b31808SJens Wiklander     }
1059817466cbSJens Wiklander 
1060*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
1061*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
1062*32b31808SJens Wiklander     }
1063817466cbSJens Wiklander 
1064*32b31808SJens Wiklander     if (len < 1) {
1065*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
1066*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_OUT_OF_DATA);
1067*32b31808SJens Wiklander     }
1068*32b31808SJens Wiklander 
1069*32b31808SJens Wiklander     if ((pk_info = mbedtls_pk_info_from_type(pk_alg)) == NULL) {
1070*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
1071*32b31808SJens Wiklander     }
1072*32b31808SJens Wiklander 
1073*32b31808SJens Wiklander     if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0) {
1074*32b31808SJens Wiklander         return ret;
1075*32b31808SJens Wiklander     }
1076817466cbSJens Wiklander 
1077817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
1078*32b31808SJens Wiklander     if (pk_alg == MBEDTLS_PK_RSA) {
1079*32b31808SJens Wiklander         if ((ret = pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk), p, len)) != 0) {
1080817466cbSJens Wiklander             mbedtls_pk_free(pk);
1081*32b31808SJens Wiklander             return ret;
1082817466cbSJens Wiklander         }
1083817466cbSJens Wiklander     } else
1084817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
1085817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
1086*32b31808SJens Wiklander     if (pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH) {
1087817466cbSJens Wiklander         if ((ret = pk_use_ecparams(&params, &mbedtls_pk_ec(*pk)->grp)) != 0 ||
1088*32b31808SJens Wiklander             (ret = pk_parse_key_sec1_der(mbedtls_pk_ec(*pk), p, len, f_rng, p_rng)) != 0) {
1089817466cbSJens Wiklander             mbedtls_pk_free(pk);
1090*32b31808SJens Wiklander             return ret;
1091817466cbSJens Wiklander         }
1092817466cbSJens Wiklander     } else
1093817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */
1094*32b31808SJens Wiklander     return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
1095817466cbSJens Wiklander 
1096*32b31808SJens Wiklander     return 0;
1097817466cbSJens Wiklander }
1098817466cbSJens Wiklander 
1099817466cbSJens Wiklander /*
1100817466cbSJens Wiklander  * Parse an encrypted PKCS#8 encoded private key
11013d3b0591SJens Wiklander  *
11023d3b0591SJens Wiklander  * To save space, the decryption happens in-place on the given key buffer.
11033d3b0591SJens Wiklander  * Also, while this function may modify the keybuffer, it doesn't own it,
11043d3b0591SJens Wiklander  * and instead it is the responsibility of the caller to zeroize and properly
11053d3b0591SJens Wiklander  * free it after use.
11063d3b0591SJens Wiklander  *
1107817466cbSJens Wiklander  */
1108817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
1109817466cbSJens Wiklander static int pk_parse_key_pkcs8_encrypted_der(
1110817466cbSJens Wiklander     mbedtls_pk_context *pk,
11113d3b0591SJens Wiklander     unsigned char *key, size_t keylen,
1112*32b31808SJens Wiklander     const unsigned char *pwd, size_t pwdlen,
1113*32b31808SJens Wiklander     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
1114817466cbSJens Wiklander {
1115817466cbSJens Wiklander     int ret, decrypted = 0;
1116817466cbSJens Wiklander     size_t len;
11173d3b0591SJens Wiklander     unsigned char *buf;
1118817466cbSJens Wiklander     unsigned char *p, *end;
1119817466cbSJens Wiklander     mbedtls_asn1_buf pbe_alg_oid, pbe_params;
1120817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C)
1121817466cbSJens Wiklander     mbedtls_cipher_type_t cipher_alg;
1122817466cbSJens Wiklander     mbedtls_md_type_t md_alg;
1123817466cbSJens Wiklander #endif
1124817466cbSJens Wiklander 
11253d3b0591SJens Wiklander     p = key;
1126817466cbSJens Wiklander     end = p + keylen;
1127817466cbSJens Wiklander 
1128*32b31808SJens Wiklander     if (pwdlen == 0) {
1129*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
1130*32b31808SJens Wiklander     }
1131817466cbSJens Wiklander 
1132817466cbSJens Wiklander     /*
11333d3b0591SJens Wiklander      * This function parses the EncryptedPrivateKeyInfo object (PKCS#8)
1134817466cbSJens Wiklander      *
1135817466cbSJens Wiklander      *  EncryptedPrivateKeyInfo ::= SEQUENCE {
1136817466cbSJens Wiklander      *    encryptionAlgorithm  EncryptionAlgorithmIdentifier,
1137817466cbSJens Wiklander      *    encryptedData        EncryptedData
1138817466cbSJens Wiklander      *  }
1139817466cbSJens Wiklander      *
1140817466cbSJens Wiklander      *  EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
1141817466cbSJens Wiklander      *
1142817466cbSJens Wiklander      *  EncryptedData ::= OCTET STRING
1143817466cbSJens Wiklander      *
1144817466cbSJens Wiklander      *  The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo
11453d3b0591SJens Wiklander      *
1146817466cbSJens Wiklander      */
1147817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
1148*32b31808SJens Wiklander                                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
1149*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
1150817466cbSJens Wiklander     }
1151817466cbSJens Wiklander 
1152817466cbSJens Wiklander     end = p + len;
1153817466cbSJens Wiklander 
1154*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_alg(&p, end, &pbe_alg_oid, &pbe_params)) != 0) {
1155*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
1156*32b31808SJens Wiklander     }
1157817466cbSJens Wiklander 
1158*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
1159*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
1160*32b31808SJens Wiklander     }
1161817466cbSJens Wiklander 
11623d3b0591SJens Wiklander     buf = p;
1163817466cbSJens Wiklander 
1164817466cbSJens Wiklander     /*
11653d3b0591SJens Wiklander      * Decrypt EncryptedData with appropriate PBE
1166817466cbSJens Wiklander      */
1167817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C)
1168*32b31808SJens Wiklander     if (mbedtls_oid_get_pkcs12_pbe_alg(&pbe_alg_oid, &md_alg, &cipher_alg) == 0) {
1169817466cbSJens Wiklander         if ((ret = mbedtls_pkcs12_pbe(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
1170817466cbSJens Wiklander                                       cipher_alg, md_alg,
1171*32b31808SJens Wiklander                                       pwd, pwdlen, p, len, buf)) != 0) {
1172*32b31808SJens Wiklander             if (ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) {
1173*32b31808SJens Wiklander                 return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
1174*32b31808SJens Wiklander             }
1175817466cbSJens Wiklander 
1176*32b31808SJens Wiklander             return ret;
1177817466cbSJens Wiklander         }
1178817466cbSJens Wiklander 
1179817466cbSJens Wiklander         decrypted = 1;
1180*32b31808SJens Wiklander     } else
1181817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C */
1182817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C)
1183*32b31808SJens Wiklander     if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid) == 0) {
1184817466cbSJens Wiklander         if ((ret = mbedtls_pkcs5_pbes2(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
1185*32b31808SJens Wiklander                                        p, len, buf)) != 0) {
1186*32b31808SJens Wiklander             if (ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) {
1187*32b31808SJens Wiklander                 return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
1188*32b31808SJens Wiklander             }
1189817466cbSJens Wiklander 
1190*32b31808SJens Wiklander             return ret;
1191817466cbSJens Wiklander         }
1192817466cbSJens Wiklander 
1193817466cbSJens Wiklander         decrypted = 1;
1194*32b31808SJens Wiklander     } else
1195817466cbSJens Wiklander #endif /* MBEDTLS_PKCS5_C */
1196817466cbSJens Wiklander     {
1197817466cbSJens Wiklander         ((void) pwd);
1198817466cbSJens Wiklander     }
1199817466cbSJens Wiklander 
1200*32b31808SJens Wiklander     if (decrypted == 0) {
1201*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
1202*32b31808SJens Wiklander     }
1203817466cbSJens Wiklander 
1204*32b31808SJens Wiklander     return pk_parse_key_pkcs8_unencrypted_der(pk, buf, len, f_rng, p_rng);
1205817466cbSJens Wiklander }
1206817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1207817466cbSJens Wiklander 
1208817466cbSJens Wiklander /*
1209817466cbSJens Wiklander  * Parse a private key
1210817466cbSJens Wiklander  */
1211817466cbSJens Wiklander int mbedtls_pk_parse_key(mbedtls_pk_context *pk,
1212817466cbSJens Wiklander                          const unsigned char *key, size_t keylen,
1213*32b31808SJens Wiklander                          const unsigned char *pwd, size_t pwdlen,
1214*32b31808SJens Wiklander                          int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
1215817466cbSJens Wiklander {
121611fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1217817466cbSJens Wiklander     const mbedtls_pk_info_t *pk_info;
1218817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1219817466cbSJens Wiklander     size_t len;
1220817466cbSJens Wiklander     mbedtls_pem_context pem;
12213d3b0591SJens Wiklander #endif
1222817466cbSJens Wiklander 
1223*32b31808SJens Wiklander     if (keylen == 0) {
1224*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
1225*32b31808SJens Wiklander     }
12263d3b0591SJens Wiklander 
12273d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1228817466cbSJens Wiklander     mbedtls_pem_init(&pem);
1229817466cbSJens Wiklander 
1230817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
1231817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1232*32b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1233817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1234*32b31808SJens Wiklander     } else {
1235817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1236817466cbSJens Wiklander                                       "-----BEGIN RSA PRIVATE KEY-----",
1237817466cbSJens Wiklander                                       "-----END RSA PRIVATE KEY-----",
1238817466cbSJens Wiklander                                       key, pwd, pwdlen, &len);
1239*32b31808SJens Wiklander     }
1240817466cbSJens Wiklander 
1241*32b31808SJens Wiklander     if (ret == 0) {
12423d3b0591SJens Wiklander         pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
1243817466cbSJens Wiklander         if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 ||
1244817466cbSJens Wiklander             (ret = pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk),
1245*32b31808SJens Wiklander                                           pem.buf, pem.buflen)) != 0) {
1246817466cbSJens Wiklander             mbedtls_pk_free(pk);
1247817466cbSJens Wiklander         }
1248817466cbSJens Wiklander 
1249817466cbSJens Wiklander         mbedtls_pem_free(&pem);
1250*32b31808SJens Wiklander         return ret;
1251*32b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
1252*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
1253*32b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
1254*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
1255*32b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
1256*32b31808SJens Wiklander         return ret;
1257817466cbSJens Wiklander     }
1258817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
1259817466cbSJens Wiklander 
1260817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
1261817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1262*32b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1263817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1264*32b31808SJens Wiklander     } else {
1265817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1266817466cbSJens Wiklander                                       "-----BEGIN EC PRIVATE KEY-----",
1267817466cbSJens Wiklander                                       "-----END EC PRIVATE KEY-----",
1268817466cbSJens Wiklander                                       key, pwd, pwdlen, &len);
1269*32b31808SJens Wiklander     }
1270*32b31808SJens Wiklander     if (ret == 0) {
12713d3b0591SJens Wiklander         pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
1272817466cbSJens Wiklander 
1273817466cbSJens Wiklander         if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 ||
1274817466cbSJens Wiklander             (ret = pk_parse_key_sec1_der(mbedtls_pk_ec(*pk),
1275*32b31808SJens Wiklander                                          pem.buf, pem.buflen,
1276*32b31808SJens Wiklander                                          f_rng, p_rng)) != 0) {
1277817466cbSJens Wiklander             mbedtls_pk_free(pk);
1278817466cbSJens Wiklander         }
1279817466cbSJens Wiklander 
1280817466cbSJens Wiklander         mbedtls_pem_free(&pem);
1281*32b31808SJens Wiklander         return ret;
1282*32b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
1283*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
1284*32b31808SJens Wiklander     } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
1285*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
1286*32b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
1287*32b31808SJens Wiklander         return ret;
1288817466cbSJens Wiklander     }
1289817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */
1290817466cbSJens Wiklander 
1291817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1292*32b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1293817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1294*32b31808SJens Wiklander     } else {
1295817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1296817466cbSJens Wiklander                                       "-----BEGIN PRIVATE KEY-----",
1297817466cbSJens Wiklander                                       "-----END PRIVATE KEY-----",
1298817466cbSJens Wiklander                                       key, NULL, 0, &len);
1299*32b31808SJens Wiklander     }
1300*32b31808SJens Wiklander     if (ret == 0) {
1301817466cbSJens Wiklander         if ((ret = pk_parse_key_pkcs8_unencrypted_der(pk,
1302*32b31808SJens Wiklander                                                       pem.buf, pem.buflen, f_rng, p_rng)) != 0) {
1303817466cbSJens Wiklander             mbedtls_pk_free(pk);
1304817466cbSJens Wiklander         }
1305817466cbSJens Wiklander 
1306817466cbSJens Wiklander         mbedtls_pem_free(&pem);
1307*32b31808SJens Wiklander         return ret;
1308*32b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
1309*32b31808SJens Wiklander         return ret;
1310817466cbSJens Wiklander     }
1311817466cbSJens Wiklander 
1312817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
1313817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1314*32b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1315817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1316*32b31808SJens Wiklander     } else {
1317817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1318817466cbSJens Wiklander                                       "-----BEGIN ENCRYPTED PRIVATE KEY-----",
1319817466cbSJens Wiklander                                       "-----END ENCRYPTED PRIVATE KEY-----",
1320817466cbSJens Wiklander                                       key, NULL, 0, &len);
1321*32b31808SJens Wiklander     }
1322*32b31808SJens Wiklander     if (ret == 0) {
1323*32b31808SJens Wiklander         if ((ret = pk_parse_key_pkcs8_encrypted_der(pk, pem.buf, pem.buflen,
1324*32b31808SJens Wiklander                                                     pwd, pwdlen, f_rng, p_rng)) != 0) {
1325817466cbSJens Wiklander             mbedtls_pk_free(pk);
1326817466cbSJens Wiklander         }
1327817466cbSJens Wiklander 
1328817466cbSJens Wiklander         mbedtls_pem_free(&pem);
1329*32b31808SJens Wiklander         return ret;
1330*32b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
1331*32b31808SJens Wiklander         return ret;
1332817466cbSJens Wiklander     }
1333817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1334817466cbSJens Wiklander #else
1335817466cbSJens Wiklander     ((void) pwd);
1336817466cbSJens Wiklander     ((void) pwdlen);
1337817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
1338817466cbSJens Wiklander 
1339817466cbSJens Wiklander     /*
1340817466cbSJens Wiklander      * At this point we only know it's not a PEM formatted key. Could be any
1341817466cbSJens Wiklander      * of the known DER encoded private key formats
1342817466cbSJens Wiklander      *
1343817466cbSJens Wiklander      * We try the different DER format parsers to see if one passes without
1344817466cbSJens Wiklander      * error
1345817466cbSJens Wiklander      */
1346817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
1347*32b31808SJens Wiklander     if (pwdlen != 0) {
13483d3b0591SJens Wiklander         unsigned char *key_copy;
13493d3b0591SJens Wiklander 
1350*32b31808SJens Wiklander         if ((key_copy = mbedtls_calloc(1, keylen)) == NULL) {
1351*32b31808SJens Wiklander             return MBEDTLS_ERR_PK_ALLOC_FAILED;
1352*32b31808SJens Wiklander         }
13533d3b0591SJens Wiklander 
13543d3b0591SJens Wiklander         memcpy(key_copy, key, keylen);
13553d3b0591SJens Wiklander 
13563d3b0591SJens Wiklander         ret = pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen,
1357*32b31808SJens Wiklander                                                pwd, pwdlen, f_rng, p_rng);
13583d3b0591SJens Wiklander 
13593d3b0591SJens Wiklander         mbedtls_platform_zeroize(key_copy, keylen);
13603d3b0591SJens Wiklander         mbedtls_free(key_copy);
1361817466cbSJens Wiklander     }
1362817466cbSJens Wiklander 
1363*32b31808SJens Wiklander     if (ret == 0) {
1364*32b31808SJens Wiklander         return 0;
1365*32b31808SJens Wiklander     }
13663d3b0591SJens Wiklander 
1367817466cbSJens Wiklander     mbedtls_pk_free(pk);
13683d3b0591SJens Wiklander     mbedtls_pk_init(pk);
1369817466cbSJens Wiklander 
1370*32b31808SJens Wiklander     if (ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH) {
1371*32b31808SJens Wiklander         return ret;
1372817466cbSJens Wiklander     }
1373817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1374817466cbSJens Wiklander 
1375*32b31808SJens Wiklander     ret = pk_parse_key_pkcs8_unencrypted_der(pk, key, keylen, f_rng, p_rng);
1376*32b31808SJens Wiklander     if (ret == 0) {
1377*32b31808SJens Wiklander         return 0;
1378039e02dfSJerome Forissier     }
1379817466cbSJens Wiklander 
1380817466cbSJens Wiklander     mbedtls_pk_free(pk);
13813d3b0591SJens Wiklander     mbedtls_pk_init(pk);
1382817466cbSJens Wiklander 
1383817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C)
1384817466cbSJens Wiklander 
13853d3b0591SJens Wiklander     pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
13863d3b0591SJens Wiklander     if (mbedtls_pk_setup(pk, pk_info) == 0 &&
1387*32b31808SJens Wiklander         pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk), key, keylen) == 0) {
1388*32b31808SJens Wiklander         return 0;
1389817466cbSJens Wiklander     }
1390817466cbSJens Wiklander 
1391817466cbSJens Wiklander     mbedtls_pk_free(pk);
13923d3b0591SJens Wiklander     mbedtls_pk_init(pk);
1393817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */
1394817466cbSJens Wiklander 
1395817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
13963d3b0591SJens Wiklander     pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
13973d3b0591SJens Wiklander     if (mbedtls_pk_setup(pk, pk_info) == 0 &&
13983d3b0591SJens Wiklander         pk_parse_key_sec1_der(mbedtls_pk_ec(*pk),
1399*32b31808SJens Wiklander                               key, keylen, f_rng, p_rng) == 0) {
1400*32b31808SJens Wiklander         return 0;
1401817466cbSJens Wiklander     }
1402817466cbSJens Wiklander     mbedtls_pk_free(pk);
1403817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */
1404817466cbSJens Wiklander 
14053d3b0591SJens Wiklander     /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't,
14063d3b0591SJens Wiklander      * it is ok to leave the PK context initialized but not
14073d3b0591SJens Wiklander      * freed: It is the caller's responsibility to call pk_init()
14083d3b0591SJens Wiklander      * before calling this function, and to call pk_free()
14093d3b0591SJens Wiklander      * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C
14103d3b0591SJens Wiklander      * isn't, this leads to mbedtls_pk_free() being called
14113d3b0591SJens Wiklander      * twice, once here and once by the caller, but this is
14123d3b0591SJens Wiklander      * also ok and in line with the mbedtls_pk_free() calls
14133d3b0591SJens Wiklander      * on failed PEM parsing attempts. */
14143d3b0591SJens Wiklander 
1415*32b31808SJens Wiklander     return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
1416817466cbSJens Wiklander }
1417817466cbSJens Wiklander 
1418817466cbSJens Wiklander /*
1419817466cbSJens Wiklander  * Parse a public key
1420817466cbSJens Wiklander  */
1421817466cbSJens Wiklander int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx,
1422817466cbSJens Wiklander                                 const unsigned char *key, size_t keylen)
1423817466cbSJens Wiklander {
142411fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1425817466cbSJens Wiklander     unsigned char *p;
14263d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C)
14273d3b0591SJens Wiklander     const mbedtls_pk_info_t *pk_info;
14283d3b0591SJens Wiklander #endif
1429817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1430817466cbSJens Wiklander     size_t len;
1431817466cbSJens Wiklander     mbedtls_pem_context pem;
14323d3b0591SJens Wiklander #endif
1433817466cbSJens Wiklander 
1434*32b31808SJens Wiklander     if (keylen == 0) {
1435*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
1436*32b31808SJens Wiklander     }
14373d3b0591SJens Wiklander 
14383d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
1439817466cbSJens Wiklander     mbedtls_pem_init(&pem);
14403d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C)
14413d3b0591SJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1442*32b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
14433d3b0591SJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1444*32b31808SJens Wiklander     } else {
14453d3b0591SJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
14463d3b0591SJens Wiklander                                       "-----BEGIN RSA PUBLIC KEY-----",
14473d3b0591SJens Wiklander                                       "-----END RSA PUBLIC KEY-----",
14483d3b0591SJens Wiklander                                       key, NULL, 0, &len);
1449*32b31808SJens Wiklander     }
14503d3b0591SJens Wiklander 
1451*32b31808SJens Wiklander     if (ret == 0) {
14523d3b0591SJens Wiklander         p = pem.buf;
1453*32b31808SJens Wiklander         if ((pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) == NULL) {
1454039e02dfSJerome Forissier             mbedtls_pem_free(&pem);
1455*32b31808SJens Wiklander             return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
1456039e02dfSJerome Forissier         }
14573d3b0591SJens Wiklander 
1458*32b31808SJens Wiklander         if ((ret = mbedtls_pk_setup(ctx, pk_info)) != 0) {
1459039e02dfSJerome Forissier             mbedtls_pem_free(&pem);
1460*32b31808SJens Wiklander             return ret;
1461039e02dfSJerome Forissier         }
14623d3b0591SJens Wiklander 
1463*32b31808SJens Wiklander         if ((ret = pk_get_rsapubkey(&p, p + pem.buflen, mbedtls_pk_rsa(*ctx))) != 0) {
14643d3b0591SJens Wiklander             mbedtls_pk_free(ctx);
1465*32b31808SJens Wiklander         }
14663d3b0591SJens Wiklander 
14673d3b0591SJens Wiklander         mbedtls_pem_free(&pem);
1468*32b31808SJens Wiklander         return ret;
1469*32b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
14703d3b0591SJens Wiklander         mbedtls_pem_free(&pem);
1471*32b31808SJens Wiklander         return ret;
14723d3b0591SJens Wiklander     }
14733d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */
1474817466cbSJens Wiklander 
1475817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1476*32b31808SJens Wiklander     if (key[keylen - 1] != '\0') {
1477817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1478*32b31808SJens Wiklander     } else {
1479817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer(&pem,
1480817466cbSJens Wiklander                                       "-----BEGIN PUBLIC KEY-----",
1481817466cbSJens Wiklander                                       "-----END PUBLIC KEY-----",
1482817466cbSJens Wiklander                                       key, NULL, 0, &len);
1483*32b31808SJens Wiklander     }
1484817466cbSJens Wiklander 
1485*32b31808SJens Wiklander     if (ret == 0) {
1486817466cbSJens Wiklander         /*
1487817466cbSJens Wiklander          * Was PEM encoded
1488817466cbSJens Wiklander          */
14893d3b0591SJens Wiklander         p = pem.buf;
14903d3b0591SJens Wiklander 
14913d3b0591SJens Wiklander         ret = mbedtls_pk_parse_subpubkey(&p,  p + pem.buflen, ctx);
14923d3b0591SJens Wiklander         mbedtls_pem_free(&pem);
1493*32b31808SJens Wiklander         return ret;
1494*32b31808SJens Wiklander     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
1495817466cbSJens Wiklander         mbedtls_pem_free(&pem);
1496*32b31808SJens Wiklander         return ret;
1497817466cbSJens Wiklander     }
14983d3b0591SJens Wiklander     mbedtls_pem_free(&pem);
1499817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
15003d3b0591SJens Wiklander 
15013d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C)
1502*32b31808SJens Wiklander     if ((pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) == NULL) {
1503*32b31808SJens Wiklander         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
1504*32b31808SJens Wiklander     }
15053d3b0591SJens Wiklander 
1506*32b31808SJens Wiklander     if ((ret = mbedtls_pk_setup(ctx, pk_info)) != 0) {
1507*32b31808SJens Wiklander         return ret;
1508*32b31808SJens Wiklander     }
15093d3b0591SJens Wiklander 
15103d3b0591SJens Wiklander     p = (unsigned char *) key;
15113d3b0591SJens Wiklander     ret = pk_get_rsapubkey(&p, p + keylen, mbedtls_pk_rsa(*ctx));
1512*32b31808SJens Wiklander     if (ret == 0) {
1513*32b31808SJens Wiklander         return ret;
15143d3b0591SJens Wiklander     }
15153d3b0591SJens Wiklander     mbedtls_pk_free(ctx);
15167901324dSJerome Forissier     if (ret != (MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
1517*32b31808SJens Wiklander                                   MBEDTLS_ERR_ASN1_UNEXPECTED_TAG))) {
1518*32b31808SJens Wiklander         return ret;
15193d3b0591SJens Wiklander     }
15203d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */
1521817466cbSJens Wiklander     p = (unsigned char *) key;
1522817466cbSJens Wiklander 
1523817466cbSJens Wiklander     ret = mbedtls_pk_parse_subpubkey(&p, p + keylen, ctx);
1524817466cbSJens Wiklander 
1525*32b31808SJens Wiklander     return ret;
1526817466cbSJens Wiklander }
1527817466cbSJens Wiklander 
1528817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_C */
1529