xref: /reactos/dll/3rdparty/mbedtls/pkparse.c (revision 103a79ce)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  *  Public Key layer for parsing key files and structures
3c2c66affSColin Finck  *
4218e2596SThomas Faber  *  Copyright The Mbed TLS Contributors
5e57126f5SThomas Faber  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6e57126f5SThomas Faber  *
7e57126f5SThomas Faber  *  This file is provided under the Apache License 2.0, or the
8e57126f5SThomas Faber  *  GNU General Public License v2.0 or later.
9e57126f5SThomas Faber  *
10e57126f5SThomas Faber  *  **********
11e57126f5SThomas Faber  *  Apache License 2.0:
12e57126f5SThomas Faber  *
13e57126f5SThomas Faber  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
14e57126f5SThomas Faber  *  not use this file except in compliance with the License.
15e57126f5SThomas Faber  *  You may obtain a copy of the License at
16e57126f5SThomas Faber  *
17e57126f5SThomas Faber  *  http://www.apache.org/licenses/LICENSE-2.0
18e57126f5SThomas Faber  *
19e57126f5SThomas Faber  *  Unless required by applicable law or agreed to in writing, software
20e57126f5SThomas Faber  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21e57126f5SThomas Faber  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22e57126f5SThomas Faber  *  See the License for the specific language governing permissions and
23e57126f5SThomas Faber  *  limitations under the License.
24e57126f5SThomas Faber  *
25e57126f5SThomas Faber  *  **********
26e57126f5SThomas Faber  *
27e57126f5SThomas Faber  *  **********
28e57126f5SThomas Faber  *  GNU General Public License v2.0 or later:
29c2c66affSColin Finck  *
30c2c66affSColin Finck  *  This program is free software; you can redistribute it and/or modify
31c2c66affSColin Finck  *  it under the terms of the GNU General Public License as published by
32c2c66affSColin Finck  *  the Free Software Foundation; either version 2 of the License, or
33c2c66affSColin Finck  *  (at your option) any later version.
34c2c66affSColin Finck  *
35c2c66affSColin Finck  *  This program is distributed in the hope that it will be useful,
36c2c66affSColin Finck  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
37c2c66affSColin Finck  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38c2c66affSColin Finck  *  GNU General Public License for more details.
39c2c66affSColin Finck  *
40c2c66affSColin Finck  *  You should have received a copy of the GNU General Public License along
41c2c66affSColin Finck  *  with this program; if not, write to the Free Software Foundation, Inc.,
42c2c66affSColin Finck  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43c2c66affSColin Finck  *
44e57126f5SThomas Faber  *  **********
45c2c66affSColin Finck  */
46c2c66affSColin Finck 
47c2c66affSColin Finck #if !defined(MBEDTLS_CONFIG_FILE)
48c2c66affSColin Finck #include "mbedtls/config.h"
49c2c66affSColin Finck #else
50c2c66affSColin Finck #include MBEDTLS_CONFIG_FILE
51c2c66affSColin Finck #endif
52c2c66affSColin Finck 
53c2c66affSColin Finck #if defined(MBEDTLS_PK_PARSE_C)
54c2c66affSColin Finck 
55c2c66affSColin Finck #include "mbedtls/pk.h"
56c2c66affSColin Finck #include "mbedtls/asn1.h"
57c2c66affSColin Finck #include "mbedtls/oid.h"
58cbda039fSThomas Faber #include "mbedtls/platform_util.h"
59c2c66affSColin Finck 
60c2c66affSColin Finck #include <string.h>
61c2c66affSColin Finck 
62c2c66affSColin Finck #if defined(MBEDTLS_RSA_C)
63c2c66affSColin Finck #include "mbedtls/rsa.h"
64c2c66affSColin Finck #endif
65c2c66affSColin Finck #if defined(MBEDTLS_ECP_C)
66c2c66affSColin Finck #include "mbedtls/ecp.h"
67c2c66affSColin Finck #endif
68c2c66affSColin Finck #if defined(MBEDTLS_ECDSA_C)
69c2c66affSColin Finck #include "mbedtls/ecdsa.h"
70c2c66affSColin Finck #endif
71c2c66affSColin Finck #if defined(MBEDTLS_PEM_PARSE_C)
72c2c66affSColin Finck #include "mbedtls/pem.h"
73c2c66affSColin Finck #endif
74c2c66affSColin Finck #if defined(MBEDTLS_PKCS5_C)
75c2c66affSColin Finck #include "mbedtls/pkcs5.h"
76c2c66affSColin Finck #endif
77c2c66affSColin Finck #if defined(MBEDTLS_PKCS12_C)
78c2c66affSColin Finck #include "mbedtls/pkcs12.h"
79c2c66affSColin Finck #endif
80c2c66affSColin Finck 
81c2c66affSColin Finck #if defined(MBEDTLS_PLATFORM_C)
82c2c66affSColin Finck #include "mbedtls/platform.h"
83c2c66affSColin Finck #else
84c2c66affSColin Finck #include <stdlib.h>
85c2c66affSColin Finck #define mbedtls_calloc    calloc
86c2c66affSColin Finck #define mbedtls_free       free
87c2c66affSColin Finck #endif
88c2c66affSColin Finck 
89cbda039fSThomas Faber /* Parameter validation macros based on platform_util.h */
90cbda039fSThomas Faber #define PK_VALIDATE_RET( cond )    \
91cbda039fSThomas Faber     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA )
92cbda039fSThomas Faber #define PK_VALIDATE( cond )        \
93cbda039fSThomas Faber     MBEDTLS_INTERNAL_VALIDATE( cond )
94c2c66affSColin Finck 
95d9e6c9b5SThomas Faber #if defined(MBEDTLS_FS_IO)
96c2c66affSColin Finck /*
97c2c66affSColin Finck  * Load all data from a file into a given buffer.
98c2c66affSColin Finck  *
99c2c66affSColin Finck  * The file is expected to contain either PEM or DER encoded data.
100c2c66affSColin Finck  * A terminating null byte is always appended. It is included in the announced
101c2c66affSColin Finck  * length only if the data looks like it is PEM encoded.
102c2c66affSColin Finck  */
mbedtls_pk_load_file(const char * path,unsigned char ** buf,size_t * n)103c2c66affSColin Finck int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n )
104c2c66affSColin Finck {
105c2c66affSColin Finck     FILE *f;
106c2c66affSColin Finck     long size;
107c2c66affSColin Finck 
108cbda039fSThomas Faber     PK_VALIDATE_RET( path != NULL );
109cbda039fSThomas Faber     PK_VALIDATE_RET( buf != NULL );
110cbda039fSThomas Faber     PK_VALIDATE_RET( n != NULL );
111cbda039fSThomas Faber 
112c2c66affSColin Finck     if( ( f = fopen( path, "rb" ) ) == NULL )
113c2c66affSColin Finck         return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
114c2c66affSColin Finck 
115c2c66affSColin Finck     fseek( f, 0, SEEK_END );
116c2c66affSColin Finck     if( ( size = ftell( f ) ) == -1 )
117c2c66affSColin Finck     {
118c2c66affSColin Finck         fclose( f );
119c2c66affSColin Finck         return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
120c2c66affSColin Finck     }
121c2c66affSColin Finck     fseek( f, 0, SEEK_SET );
122c2c66affSColin Finck 
123c2c66affSColin Finck     *n = (size_t) size;
124c2c66affSColin Finck 
125c2c66affSColin Finck     if( *n + 1 == 0 ||
126c2c66affSColin Finck         ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
127c2c66affSColin Finck     {
128c2c66affSColin Finck         fclose( f );
129c2c66affSColin Finck         return( MBEDTLS_ERR_PK_ALLOC_FAILED );
130c2c66affSColin Finck     }
131c2c66affSColin Finck 
132c2c66affSColin Finck     if( fread( *buf, 1, *n, f ) != *n )
133c2c66affSColin Finck     {
134c2c66affSColin Finck         fclose( f );
135d9e6c9b5SThomas Faber 
136cbda039fSThomas Faber         mbedtls_platform_zeroize( *buf, *n );
137c2c66affSColin Finck         mbedtls_free( *buf );
138d9e6c9b5SThomas Faber 
139c2c66affSColin Finck         return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
140c2c66affSColin Finck     }
141c2c66affSColin Finck 
142c2c66affSColin Finck     fclose( f );
143c2c66affSColin Finck 
144c2c66affSColin Finck     (*buf)[*n] = '\0';
145c2c66affSColin Finck 
146c2c66affSColin Finck     if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
147c2c66affSColin Finck         ++*n;
148c2c66affSColin Finck 
149c2c66affSColin Finck     return( 0 );
150c2c66affSColin Finck }
151c2c66affSColin Finck 
152c2c66affSColin Finck /*
153c2c66affSColin Finck  * Load and parse a private key
154c2c66affSColin Finck  */
mbedtls_pk_parse_keyfile(mbedtls_pk_context * ctx,const char * path,const char * pwd)155c2c66affSColin Finck int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx,
156c2c66affSColin Finck                       const char *path, const char *pwd )
157c2c66affSColin Finck {
158c2c66affSColin Finck     int ret;
159c2c66affSColin Finck     size_t n;
160c2c66affSColin Finck     unsigned char *buf;
161c2c66affSColin Finck 
162cbda039fSThomas Faber     PK_VALIDATE_RET( ctx != NULL );
163cbda039fSThomas Faber     PK_VALIDATE_RET( path != NULL );
164cbda039fSThomas Faber 
165c2c66affSColin Finck     if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
166c2c66affSColin Finck         return( ret );
167c2c66affSColin Finck 
168c2c66affSColin Finck     if( pwd == NULL )
169c2c66affSColin Finck         ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 );
170c2c66affSColin Finck     else
171c2c66affSColin Finck         ret = mbedtls_pk_parse_key( ctx, buf, n,
172c2c66affSColin Finck                 (const unsigned char *) pwd, strlen( pwd ) );
173c2c66affSColin Finck 
174cbda039fSThomas Faber     mbedtls_platform_zeroize( buf, n );
175c2c66affSColin Finck     mbedtls_free( buf );
176c2c66affSColin Finck 
177c2c66affSColin Finck     return( ret );
178c2c66affSColin Finck }
179c2c66affSColin Finck 
180c2c66affSColin Finck /*
181c2c66affSColin Finck  * Load and parse a public key
182c2c66affSColin Finck  */
mbedtls_pk_parse_public_keyfile(mbedtls_pk_context * ctx,const char * path)183c2c66affSColin Finck int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path )
184c2c66affSColin Finck {
185c2c66affSColin Finck     int ret;
186c2c66affSColin Finck     size_t n;
187c2c66affSColin Finck     unsigned char *buf;
188c2c66affSColin Finck 
189cbda039fSThomas Faber     PK_VALIDATE_RET( ctx != NULL );
190cbda039fSThomas Faber     PK_VALIDATE_RET( path != NULL );
191cbda039fSThomas Faber 
192c2c66affSColin Finck     if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
193c2c66affSColin Finck         return( ret );
194c2c66affSColin Finck 
195c2c66affSColin Finck     ret = mbedtls_pk_parse_public_key( ctx, buf, n );
196c2c66affSColin Finck 
197cbda039fSThomas Faber     mbedtls_platform_zeroize( buf, n );
198c2c66affSColin Finck     mbedtls_free( buf );
199c2c66affSColin Finck 
200c2c66affSColin Finck     return( ret );
201c2c66affSColin Finck }
202c2c66affSColin Finck #endif /* MBEDTLS_FS_IO */
203c2c66affSColin Finck 
204c2c66affSColin Finck #if defined(MBEDTLS_ECP_C)
205c2c66affSColin Finck /* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf
206c2c66affSColin Finck  *
207c2c66affSColin Finck  * ECParameters ::= CHOICE {
208c2c66affSColin Finck  *   namedCurve         OBJECT IDENTIFIER
209c2c66affSColin Finck  *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
210c2c66affSColin Finck  *   -- implicitCurve   NULL
211c2c66affSColin Finck  * }
212c2c66affSColin Finck  */
pk_get_ecparams(unsigned char ** p,const unsigned char * end,mbedtls_asn1_buf * params)213c2c66affSColin Finck static int pk_get_ecparams( unsigned char **p, const unsigned char *end,
214c2c66affSColin Finck                             mbedtls_asn1_buf *params )
215c2c66affSColin Finck {
216c2c66affSColin Finck     int ret;
217c2c66affSColin Finck 
218d9e6c9b5SThomas Faber     if ( end - *p < 1 )
219d9e6c9b5SThomas Faber         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
220d9e6c9b5SThomas Faber                 MBEDTLS_ERR_ASN1_OUT_OF_DATA );
221d9e6c9b5SThomas Faber 
222c2c66affSColin Finck     /* Tag may be either OID or SEQUENCE */
223c2c66affSColin Finck     params->tag = **p;
224c2c66affSColin Finck     if( params->tag != MBEDTLS_ASN1_OID
225c2c66affSColin Finck #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
226c2c66affSColin Finck             && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE )
227c2c66affSColin Finck #endif
228c2c66affSColin Finck             )
229c2c66affSColin Finck     {
230c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
231c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
232c2c66affSColin Finck     }
233c2c66affSColin Finck 
234c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( p, end, &params->len, params->tag ) ) != 0 )
235c2c66affSColin Finck     {
236c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
237c2c66affSColin Finck     }
238c2c66affSColin Finck 
239c2c66affSColin Finck     params->p = *p;
240c2c66affSColin Finck     *p += params->len;
241c2c66affSColin Finck 
242c2c66affSColin Finck     if( *p != end )
243c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
244c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
245c2c66affSColin Finck 
246c2c66affSColin Finck     return( 0 );
247c2c66affSColin Finck }
248c2c66affSColin Finck 
249c2c66affSColin Finck #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
250c2c66affSColin Finck /*
251c2c66affSColin Finck  * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it.
252c2c66affSColin Finck  * WARNING: the resulting group should only be used with
253c2c66affSColin Finck  * pk_group_id_from_specified(), since its base point may not be set correctly
254c2c66affSColin Finck  * if it was encoded compressed.
255c2c66affSColin Finck  *
256c2c66affSColin Finck  *  SpecifiedECDomain ::= SEQUENCE {
257c2c66affSColin Finck  *      version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
258c2c66affSColin Finck  *      fieldID FieldID {{FieldTypes}},
259c2c66affSColin Finck  *      curve Curve,
260c2c66affSColin Finck  *      base ECPoint,
261c2c66affSColin Finck  *      order INTEGER,
262c2c66affSColin Finck  *      cofactor INTEGER OPTIONAL,
263c2c66affSColin Finck  *      hash HashAlgorithm OPTIONAL,
264c2c66affSColin Finck  *      ...
265c2c66affSColin Finck  *  }
266c2c66affSColin Finck  *
267c2c66affSColin Finck  * We only support prime-field as field type, and ignore hash and cofactor.
268c2c66affSColin Finck  */
pk_group_from_specified(const mbedtls_asn1_buf * params,mbedtls_ecp_group * grp)269c2c66affSColin Finck static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp )
270c2c66affSColin Finck {
271c2c66affSColin Finck     int ret;
272c2c66affSColin Finck     unsigned char *p = params->p;
273c2c66affSColin Finck     const unsigned char * const end = params->p + params->len;
274c2c66affSColin Finck     const unsigned char *end_field, *end_curve;
275c2c66affSColin Finck     size_t len;
276c2c66affSColin Finck     int ver;
277c2c66affSColin Finck 
278c2c66affSColin Finck     /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */
279c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 )
280c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
281c2c66affSColin Finck 
282c2c66affSColin Finck     if( ver < 1 || ver > 3 )
283c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
284c2c66affSColin Finck 
285c2c66affSColin Finck     /*
286c2c66affSColin Finck      * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field
287c2c66affSColin Finck      *       fieldType FIELD-ID.&id({IOSet}),
288c2c66affSColin Finck      *       parameters FIELD-ID.&Type({IOSet}{@fieldType})
289c2c66affSColin Finck      * }
290c2c66affSColin Finck      */
291c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
292c2c66affSColin Finck             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
293c2c66affSColin Finck         return( ret );
294c2c66affSColin Finck 
295c2c66affSColin Finck     end_field = p + len;
296c2c66affSColin Finck 
297c2c66affSColin Finck     /*
298c2c66affSColin Finck      * FIELD-ID ::= TYPE-IDENTIFIER
299c2c66affSColin Finck      * FieldTypes FIELD-ID ::= {
300c2c66affSColin Finck      *       { Prime-p IDENTIFIED BY prime-field } |
301c2c66affSColin Finck      *       { Characteristic-two IDENTIFIED BY characteristic-two-field }
302c2c66affSColin Finck      * }
303c2c66affSColin Finck      * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
304c2c66affSColin Finck      */
305c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 )
306c2c66affSColin Finck         return( ret );
307c2c66affSColin Finck 
308c2c66affSColin Finck     if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) ||
309c2c66affSColin Finck         memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 )
310c2c66affSColin Finck     {
311c2c66affSColin Finck         return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
312c2c66affSColin Finck     }
313c2c66affSColin Finck 
314c2c66affSColin Finck     p += len;
315c2c66affSColin Finck 
316c2c66affSColin Finck     /* Prime-p ::= INTEGER -- Field of size p. */
317c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 )
318c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
319c2c66affSColin Finck 
320c2c66affSColin Finck     grp->pbits = mbedtls_mpi_bitlen( &grp->P );
321c2c66affSColin Finck 
322c2c66affSColin Finck     if( p != end_field )
323c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
324c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
325c2c66affSColin Finck 
326c2c66affSColin Finck     /*
327c2c66affSColin Finck      * Curve ::= SEQUENCE {
328c2c66affSColin Finck      *       a FieldElement,
329c2c66affSColin Finck      *       b FieldElement,
330c2c66affSColin Finck      *       seed BIT STRING OPTIONAL
331c2c66affSColin Finck      *       -- Shall be present if used in SpecifiedECDomain
332c2c66affSColin Finck      *       -- with version equal to ecdpVer2 or ecdpVer3
333c2c66affSColin Finck      * }
334c2c66affSColin Finck      */
335c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
336c2c66affSColin Finck             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
337c2c66affSColin Finck         return( ret );
338c2c66affSColin Finck 
339c2c66affSColin Finck     end_curve = p + len;
340c2c66affSColin Finck 
341c2c66affSColin Finck     /*
342c2c66affSColin Finck      * FieldElement ::= OCTET STRING
343c2c66affSColin Finck      * containing an integer in the case of a prime field
344c2c66affSColin Finck      */
345c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ||
346c2c66affSColin Finck         ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 )
347c2c66affSColin Finck     {
348c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
349c2c66affSColin Finck     }
350c2c66affSColin Finck 
351c2c66affSColin Finck     p += len;
352c2c66affSColin Finck 
353c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ||
354c2c66affSColin Finck         ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 )
355c2c66affSColin Finck     {
356c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
357c2c66affSColin Finck     }
358c2c66affSColin Finck 
359c2c66affSColin Finck     p += len;
360c2c66affSColin Finck 
361c2c66affSColin Finck     /* Ignore seed BIT STRING OPTIONAL */
362c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 )
363c2c66affSColin Finck         p += len;
364c2c66affSColin Finck 
365c2c66affSColin Finck     if( p != end_curve )
366c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
367c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
368c2c66affSColin Finck 
369c2c66affSColin Finck     /*
370c2c66affSColin Finck      * ECPoint ::= OCTET STRING
371c2c66affSColin Finck      */
372c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
373c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
374c2c66affSColin Finck 
375c2c66affSColin Finck     if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G,
376c2c66affSColin Finck                                       ( const unsigned char *) p, len ) ) != 0 )
377c2c66affSColin Finck     {
378c2c66affSColin Finck         /*
379c2c66affSColin Finck          * If we can't read the point because it's compressed, cheat by
380c2c66affSColin Finck          * reading only the X coordinate and the parity bit of Y.
381c2c66affSColin Finck          */
382c2c66affSColin Finck         if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ||
383c2c66affSColin Finck             ( p[0] != 0x02 && p[0] != 0x03 ) ||
384c2c66affSColin Finck             len != mbedtls_mpi_size( &grp->P ) + 1 ||
385c2c66affSColin Finck             mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 ||
386c2c66affSColin Finck             mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 ||
387c2c66affSColin Finck             mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 )
388c2c66affSColin Finck         {
389c2c66affSColin Finck             return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
390c2c66affSColin Finck         }
391c2c66affSColin Finck     }
392c2c66affSColin Finck 
393c2c66affSColin Finck     p += len;
394c2c66affSColin Finck 
395c2c66affSColin Finck     /*
396c2c66affSColin Finck      * order INTEGER
397c2c66affSColin Finck      */
398c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 )
399c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
400c2c66affSColin Finck 
401c2c66affSColin Finck     grp->nbits = mbedtls_mpi_bitlen( &grp->N );
402c2c66affSColin Finck 
403c2c66affSColin Finck     /*
404c2c66affSColin Finck      * Allow optional elements by purposefully not enforcing p == end here.
405c2c66affSColin Finck      */
406c2c66affSColin Finck 
407c2c66affSColin Finck     return( 0 );
408c2c66affSColin Finck }
409c2c66affSColin Finck 
410c2c66affSColin Finck /*
411c2c66affSColin Finck  * Find the group id associated with an (almost filled) group as generated by
412c2c66affSColin Finck  * pk_group_from_specified(), or return an error if unknown.
413c2c66affSColin Finck  */
pk_group_id_from_group(const mbedtls_ecp_group * grp,mbedtls_ecp_group_id * grp_id)414c2c66affSColin Finck static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id )
415c2c66affSColin Finck {
416c2c66affSColin Finck     int ret = 0;
417c2c66affSColin Finck     mbedtls_ecp_group ref;
418c2c66affSColin Finck     const mbedtls_ecp_group_id *id;
419c2c66affSColin Finck 
420c2c66affSColin Finck     mbedtls_ecp_group_init( &ref );
421c2c66affSColin Finck 
422c2c66affSColin Finck     for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ )
423c2c66affSColin Finck     {
424c2c66affSColin Finck         /* Load the group associated to that id */
425c2c66affSColin Finck         mbedtls_ecp_group_free( &ref );
426c2c66affSColin Finck         MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) );
427c2c66affSColin Finck 
428c2c66affSColin Finck         /* Compare to the group we were given, starting with easy tests */
429c2c66affSColin Finck         if( grp->pbits == ref.pbits && grp->nbits == ref.nbits &&
430c2c66affSColin Finck             mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 &&
431c2c66affSColin Finck             mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 &&
432c2c66affSColin Finck             mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 &&
433c2c66affSColin Finck             mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 &&
434c2c66affSColin Finck             mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 &&
435c2c66affSColin Finck             mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 &&
436c2c66affSColin Finck             /* For Y we may only know the parity bit, so compare only that */
437c2c66affSColin Finck             mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) )
438c2c66affSColin Finck         {
439c2c66affSColin Finck             break;
440c2c66affSColin Finck         }
441c2c66affSColin Finck 
442c2c66affSColin Finck     }
443c2c66affSColin Finck 
444c2c66affSColin Finck cleanup:
445c2c66affSColin Finck     mbedtls_ecp_group_free( &ref );
446c2c66affSColin Finck 
447c2c66affSColin Finck     *grp_id = *id;
448c2c66affSColin Finck 
449c2c66affSColin Finck     if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE )
450c2c66affSColin Finck         ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
451c2c66affSColin Finck 
452c2c66affSColin Finck     return( ret );
453c2c66affSColin Finck }
454c2c66affSColin Finck 
455c2c66affSColin Finck /*
456c2c66affSColin Finck  * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID
457c2c66affSColin Finck  */
pk_group_id_from_specified(const mbedtls_asn1_buf * params,mbedtls_ecp_group_id * grp_id)458c2c66affSColin Finck static int pk_group_id_from_specified( const mbedtls_asn1_buf *params,
459c2c66affSColin Finck                                        mbedtls_ecp_group_id *grp_id )
460c2c66affSColin Finck {
461c2c66affSColin Finck     int ret;
462c2c66affSColin Finck     mbedtls_ecp_group grp;
463c2c66affSColin Finck 
464c2c66affSColin Finck     mbedtls_ecp_group_init( &grp );
465c2c66affSColin Finck 
466c2c66affSColin Finck     if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 )
467c2c66affSColin Finck         goto cleanup;
468c2c66affSColin Finck 
469c2c66affSColin Finck     ret = pk_group_id_from_group( &grp, grp_id );
470c2c66affSColin Finck 
471c2c66affSColin Finck cleanup:
472c2c66affSColin Finck     mbedtls_ecp_group_free( &grp );
473c2c66affSColin Finck 
474c2c66affSColin Finck     return( ret );
475c2c66affSColin Finck }
476c2c66affSColin Finck #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */
477c2c66affSColin Finck 
478c2c66affSColin Finck /*
479c2c66affSColin Finck  * Use EC parameters to initialise an EC group
480c2c66affSColin Finck  *
481c2c66affSColin Finck  * ECParameters ::= CHOICE {
482c2c66affSColin Finck  *   namedCurve         OBJECT IDENTIFIER
483c2c66affSColin Finck  *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
484c2c66affSColin Finck  *   -- implicitCurve   NULL
485c2c66affSColin Finck  */
pk_use_ecparams(const mbedtls_asn1_buf * params,mbedtls_ecp_group * grp)486c2c66affSColin Finck static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp )
487c2c66affSColin Finck {
488c2c66affSColin Finck     int ret;
489c2c66affSColin Finck     mbedtls_ecp_group_id grp_id;
490c2c66affSColin Finck 
491c2c66affSColin Finck     if( params->tag == MBEDTLS_ASN1_OID )
492c2c66affSColin Finck     {
493c2c66affSColin Finck         if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 )
494c2c66affSColin Finck             return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE );
495c2c66affSColin Finck     }
496c2c66affSColin Finck     else
497c2c66affSColin Finck     {
498c2c66affSColin Finck #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
499c2c66affSColin Finck         if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 )
500c2c66affSColin Finck             return( ret );
501c2c66affSColin Finck #else
502c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
503c2c66affSColin Finck #endif
504c2c66affSColin Finck     }
505c2c66affSColin Finck 
506c2c66affSColin Finck     /*
507c2c66affSColin Finck      * grp may already be initilialized; if so, make sure IDs match
508c2c66affSColin Finck      */
509c2c66affSColin Finck     if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id )
510c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
511c2c66affSColin Finck 
512c2c66affSColin Finck     if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 )
513c2c66affSColin Finck         return( ret );
514c2c66affSColin Finck 
515c2c66affSColin Finck     return( 0 );
516c2c66affSColin Finck }
517c2c66affSColin Finck 
518c2c66affSColin Finck /*
519c2c66affSColin Finck  * EC public key is an EC point
520c2c66affSColin Finck  *
521c2c66affSColin Finck  * The caller is responsible for clearing the structure upon failure if
522c2c66affSColin Finck  * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE
523c2c66affSColin Finck  * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state.
524c2c66affSColin Finck  */
pk_get_ecpubkey(unsigned char ** p,const unsigned char * end,mbedtls_ecp_keypair * key)525c2c66affSColin Finck static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end,
526c2c66affSColin Finck                             mbedtls_ecp_keypair *key )
527c2c66affSColin Finck {
528c2c66affSColin Finck     int ret;
529c2c66affSColin Finck 
530c2c66affSColin Finck     if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q,
531c2c66affSColin Finck                     (const unsigned char *) *p, end - *p ) ) == 0 )
532c2c66affSColin Finck     {
533c2c66affSColin Finck         ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q );
534c2c66affSColin Finck     }
535c2c66affSColin Finck 
536c2c66affSColin Finck     /*
537c2c66affSColin Finck      * We know mbedtls_ecp_point_read_binary consumed all bytes or failed
538c2c66affSColin Finck      */
539c2c66affSColin Finck     *p = (unsigned char *) end;
540c2c66affSColin Finck 
541c2c66affSColin Finck     return( ret );
542c2c66affSColin Finck }
543c2c66affSColin Finck #endif /* MBEDTLS_ECP_C */
544c2c66affSColin Finck 
545c2c66affSColin Finck #if defined(MBEDTLS_RSA_C)
546c2c66affSColin Finck /*
547c2c66affSColin Finck  *  RSAPublicKey ::= SEQUENCE {
548c2c66affSColin Finck  *      modulus           INTEGER,  -- n
549c2c66affSColin Finck  *      publicExponent    INTEGER   -- e
550c2c66affSColin Finck  *  }
551c2c66affSColin Finck  */
pk_get_rsapubkey(unsigned char ** p,const unsigned char * end,mbedtls_rsa_context * rsa)552c2c66affSColin Finck static int pk_get_rsapubkey( unsigned char **p,
553c2c66affSColin Finck                              const unsigned char *end,
554c2c66affSColin Finck                              mbedtls_rsa_context *rsa )
555c2c66affSColin Finck {
556c2c66affSColin Finck     int ret;
557c2c66affSColin Finck     size_t len;
558c2c66affSColin Finck 
559c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
560c2c66affSColin Finck             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
561c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret );
562c2c66affSColin Finck 
563c2c66affSColin Finck     if( *p + len != end )
564c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_PUBKEY +
565c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
566c2c66affSColin Finck 
567d9e6c9b5SThomas Faber     /* Import N */
568d9e6c9b5SThomas Faber     if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
569c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret );
570c2c66affSColin Finck 
571d9e6c9b5SThomas Faber     if( ( ret = mbedtls_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0,
572d9e6c9b5SThomas Faber                                         NULL, 0, NULL, 0 ) ) != 0 )
573d9e6c9b5SThomas Faber         return( MBEDTLS_ERR_PK_INVALID_PUBKEY );
574d9e6c9b5SThomas Faber 
575d9e6c9b5SThomas Faber     *p += len;
576d9e6c9b5SThomas Faber 
577d9e6c9b5SThomas Faber     /* Import E */
578d9e6c9b5SThomas Faber     if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
579d9e6c9b5SThomas Faber         return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret );
580d9e6c9b5SThomas Faber 
581d9e6c9b5SThomas Faber     if( ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0,
582d9e6c9b5SThomas Faber                                         NULL, 0, *p, len ) ) != 0 )
583d9e6c9b5SThomas Faber         return( MBEDTLS_ERR_PK_INVALID_PUBKEY );
584d9e6c9b5SThomas Faber 
585d9e6c9b5SThomas Faber     *p += len;
586d9e6c9b5SThomas Faber 
587d9e6c9b5SThomas Faber     if( mbedtls_rsa_complete( rsa ) != 0 ||
588d9e6c9b5SThomas Faber         mbedtls_rsa_check_pubkey( rsa ) != 0 )
589d9e6c9b5SThomas Faber     {
590d9e6c9b5SThomas Faber         return( MBEDTLS_ERR_PK_INVALID_PUBKEY );
591d9e6c9b5SThomas Faber     }
592d9e6c9b5SThomas Faber 
593c2c66affSColin Finck     if( *p != end )
594c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_PUBKEY +
595c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
596c2c66affSColin Finck 
597c2c66affSColin Finck     return( 0 );
598c2c66affSColin Finck }
599c2c66affSColin Finck #endif /* MBEDTLS_RSA_C */
600c2c66affSColin Finck 
601c2c66affSColin Finck /* Get a PK algorithm identifier
602c2c66affSColin Finck  *
603c2c66affSColin Finck  *  AlgorithmIdentifier  ::=  SEQUENCE  {
604c2c66affSColin Finck  *       algorithm               OBJECT IDENTIFIER,
605c2c66affSColin Finck  *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
606c2c66affSColin Finck  */
pk_get_pk_alg(unsigned char ** p,const unsigned char * end,mbedtls_pk_type_t * pk_alg,mbedtls_asn1_buf * params)607c2c66affSColin Finck static int pk_get_pk_alg( unsigned char **p,
608c2c66affSColin Finck                           const unsigned char *end,
609c2c66affSColin Finck                           mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params )
610c2c66affSColin Finck {
611c2c66affSColin Finck     int ret;
612c2c66affSColin Finck     mbedtls_asn1_buf alg_oid;
613c2c66affSColin Finck 
614c2c66affSColin Finck     memset( params, 0, sizeof(mbedtls_asn1_buf) );
615c2c66affSColin Finck 
616c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 )
617c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_ALG + ret );
618c2c66affSColin Finck 
619c2c66affSColin Finck     if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 )
620c2c66affSColin Finck         return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
621c2c66affSColin Finck 
622c2c66affSColin Finck     /*
623c2c66affSColin Finck      * No parameters with RSA (only for EC)
624c2c66affSColin Finck      */
625c2c66affSColin Finck     if( *pk_alg == MBEDTLS_PK_RSA &&
626c2c66affSColin Finck             ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) ||
627c2c66affSColin Finck                 params->len != 0 ) )
628c2c66affSColin Finck     {
629c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_ALG );
630c2c66affSColin Finck     }
631c2c66affSColin Finck 
632c2c66affSColin Finck     return( 0 );
633c2c66affSColin Finck }
634c2c66affSColin Finck 
635c2c66affSColin Finck /*
636c2c66affSColin Finck  *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
637c2c66affSColin Finck  *       algorithm            AlgorithmIdentifier,
638c2c66affSColin Finck  *       subjectPublicKey     BIT STRING }
639c2c66affSColin Finck  */
mbedtls_pk_parse_subpubkey(unsigned char ** p,const unsigned char * end,mbedtls_pk_context * pk)640c2c66affSColin Finck int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end,
641c2c66affSColin Finck                         mbedtls_pk_context *pk )
642c2c66affSColin Finck {
643c2c66affSColin Finck     int ret;
644c2c66affSColin Finck     size_t len;
645c2c66affSColin Finck     mbedtls_asn1_buf alg_params;
646c2c66affSColin Finck     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
647c2c66affSColin Finck     const mbedtls_pk_info_t *pk_info;
648c2c66affSColin Finck 
649cbda039fSThomas Faber     PK_VALIDATE_RET( p != NULL );
650cbda039fSThomas Faber     PK_VALIDATE_RET( *p != NULL );
651cbda039fSThomas Faber     PK_VALIDATE_RET( end != NULL );
652cbda039fSThomas Faber     PK_VALIDATE_RET( pk != NULL );
653cbda039fSThomas Faber 
654c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
655c2c66affSColin Finck                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
656c2c66affSColin Finck     {
657c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
658c2c66affSColin Finck     }
659c2c66affSColin Finck 
660c2c66affSColin Finck     end = *p + len;
661c2c66affSColin Finck 
662c2c66affSColin Finck     if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 )
663c2c66affSColin Finck         return( ret );
664c2c66affSColin Finck 
665c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 )
666c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret );
667c2c66affSColin Finck 
668c2c66affSColin Finck     if( *p + len != end )
669c2c66affSColin Finck         return( MBEDTLS_ERR_PK_INVALID_PUBKEY +
670c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
671c2c66affSColin Finck 
672c2c66affSColin Finck     if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL )
673c2c66affSColin Finck         return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
674c2c66affSColin Finck 
675c2c66affSColin Finck     if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 )
676c2c66affSColin Finck         return( ret );
677c2c66affSColin Finck 
678c2c66affSColin Finck #if defined(MBEDTLS_RSA_C)
679c2c66affSColin Finck     if( pk_alg == MBEDTLS_PK_RSA )
680c2c66affSColin Finck     {
681c2c66affSColin Finck         ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) );
682c2c66affSColin Finck     } else
683c2c66affSColin Finck #endif /* MBEDTLS_RSA_C */
684c2c66affSColin Finck #if defined(MBEDTLS_ECP_C)
685c2c66affSColin Finck     if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY )
686c2c66affSColin Finck     {
687c2c66affSColin Finck         ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp );
688c2c66affSColin Finck         if( ret == 0 )
689c2c66affSColin Finck             ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) );
690c2c66affSColin Finck     } else
691c2c66affSColin Finck #endif /* MBEDTLS_ECP_C */
692c2c66affSColin Finck         ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
693c2c66affSColin Finck 
694c2c66affSColin Finck     if( ret == 0 && *p != end )
6952e53fc8eSThomas Faber         ret = MBEDTLS_ERR_PK_INVALID_PUBKEY +
696c2c66affSColin Finck               MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
697c2c66affSColin Finck 
698c2c66affSColin Finck     if( ret != 0 )
699c2c66affSColin Finck         mbedtls_pk_free( pk );
700c2c66affSColin Finck 
701c2c66affSColin Finck     return( ret );
702c2c66affSColin Finck }
703c2c66affSColin Finck 
704c2c66affSColin Finck #if defined(MBEDTLS_RSA_C)
705c2c66affSColin Finck /*
7061b00a1f5SThomas Faber  * Wrapper around mbedtls_asn1_get_mpi() that rejects zero.
7071b00a1f5SThomas Faber  *
7081b00a1f5SThomas Faber  * The value zero is:
7091b00a1f5SThomas Faber  * - never a valid value for an RSA parameter
7101b00a1f5SThomas Faber  * - interpreted as "omitted, please reconstruct" by mbedtls_rsa_complete().
7111b00a1f5SThomas Faber  *
7121b00a1f5SThomas Faber  * Since values can't be omitted in PKCS#1, passing a zero value to
7131b00a1f5SThomas Faber  * rsa_complete() would be incorrect, so reject zero values early.
7141b00a1f5SThomas Faber  */
asn1_get_nonzero_mpi(unsigned char ** p,const unsigned char * end,mbedtls_mpi * X)7151b00a1f5SThomas Faber static int asn1_get_nonzero_mpi( unsigned char **p,
7161b00a1f5SThomas Faber                                  const unsigned char *end,
7171b00a1f5SThomas Faber                                  mbedtls_mpi *X )
7181b00a1f5SThomas Faber {
7191b00a1f5SThomas Faber     int ret;
7201b00a1f5SThomas Faber 
7211b00a1f5SThomas Faber     ret = mbedtls_asn1_get_mpi( p, end, X );
7221b00a1f5SThomas Faber     if( ret != 0 )
7231b00a1f5SThomas Faber         return( ret );
7241b00a1f5SThomas Faber 
7251b00a1f5SThomas Faber     if( mbedtls_mpi_cmp_int( X, 0 ) == 0 )
7261b00a1f5SThomas Faber         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
7271b00a1f5SThomas Faber 
7281b00a1f5SThomas Faber     return( 0 );
7291b00a1f5SThomas Faber }
7301b00a1f5SThomas Faber 
7311b00a1f5SThomas Faber /*
732c2c66affSColin Finck  * Parse a PKCS#1 encoded private RSA key
733c2c66affSColin Finck  */
pk_parse_key_pkcs1_der(mbedtls_rsa_context * rsa,const unsigned char * key,size_t keylen)734c2c66affSColin Finck static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa,
735c2c66affSColin Finck                                    const unsigned char *key,
736c2c66affSColin Finck                                    size_t keylen )
737c2c66affSColin Finck {
738d9e6c9b5SThomas Faber     int ret, version;
739c2c66affSColin Finck     size_t len;
740c2c66affSColin Finck     unsigned char *p, *end;
741c2c66affSColin Finck 
742d9e6c9b5SThomas Faber     mbedtls_mpi T;
743d9e6c9b5SThomas Faber     mbedtls_mpi_init( &T );
744d9e6c9b5SThomas Faber 
745c2c66affSColin Finck     p = (unsigned char *) key;
746c2c66affSColin Finck     end = p + keylen;
747c2c66affSColin Finck 
748c2c66affSColin Finck     /*
749c2c66affSColin Finck      * This function parses the RSAPrivateKey (PKCS#1)
750c2c66affSColin Finck      *
751c2c66affSColin Finck      *  RSAPrivateKey ::= SEQUENCE {
752c2c66affSColin Finck      *      version           Version,
753c2c66affSColin Finck      *      modulus           INTEGER,  -- n
754c2c66affSColin Finck      *      publicExponent    INTEGER,  -- e
755c2c66affSColin Finck      *      privateExponent   INTEGER,  -- d
756c2c66affSColin Finck      *      prime1            INTEGER,  -- p
757c2c66affSColin Finck      *      prime2            INTEGER,  -- q
758c2c66affSColin Finck      *      exponent1         INTEGER,  -- d mod (p-1)
759c2c66affSColin Finck      *      exponent2         INTEGER,  -- d mod (q-1)
760c2c66affSColin Finck      *      coefficient       INTEGER,  -- (inverse of q) mod p
761c2c66affSColin Finck      *      otherPrimeInfos   OtherPrimeInfos OPTIONAL
762c2c66affSColin Finck      *  }
763c2c66affSColin Finck      */
764c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
765c2c66affSColin Finck             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
766c2c66affSColin Finck     {
767c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
768c2c66affSColin Finck     }
769c2c66affSColin Finck 
770c2c66affSColin Finck     end = p + len;
771c2c66affSColin Finck 
772d9e6c9b5SThomas Faber     if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 )
773c2c66affSColin Finck     {
774c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
775c2c66affSColin Finck     }
776c2c66affSColin Finck 
777d9e6c9b5SThomas Faber     if( version != 0 )
778c2c66affSColin Finck     {
779c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION );
780c2c66affSColin Finck     }
781c2c66affSColin Finck 
782d9e6c9b5SThomas Faber     /* Import N */
7831b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
7841b00a1f5SThomas Faber         ( ret = mbedtls_rsa_import( rsa, &T, NULL, NULL,
7851b00a1f5SThomas Faber                                         NULL, NULL ) ) != 0 )
786d9e6c9b5SThomas Faber         goto cleanup;
787c2c66affSColin Finck 
788d9e6c9b5SThomas Faber     /* Import E */
7891b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
7901b00a1f5SThomas Faber         ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL,
7911b00a1f5SThomas Faber                                         NULL, &T ) ) != 0 )
792d9e6c9b5SThomas Faber         goto cleanup;
793d9e6c9b5SThomas Faber 
794d9e6c9b5SThomas Faber     /* Import D */
7951b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
7961b00a1f5SThomas Faber         ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL,
7971b00a1f5SThomas Faber                                         &T, NULL ) ) != 0 )
798d9e6c9b5SThomas Faber         goto cleanup;
799d9e6c9b5SThomas Faber 
800d9e6c9b5SThomas Faber     /* Import P */
8011b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
8021b00a1f5SThomas Faber         ( ret = mbedtls_rsa_import( rsa, NULL, &T, NULL,
8031b00a1f5SThomas Faber                                         NULL, NULL ) ) != 0 )
804d9e6c9b5SThomas Faber         goto cleanup;
805d9e6c9b5SThomas Faber 
806d9e6c9b5SThomas Faber     /* Import Q */
8071b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
8081b00a1f5SThomas Faber         ( ret = mbedtls_rsa_import( rsa, NULL, NULL, &T,
8091b00a1f5SThomas Faber                                         NULL, NULL ) ) != 0 )
810d9e6c9b5SThomas Faber         goto cleanup;
811d9e6c9b5SThomas Faber 
8121b00a1f5SThomas Faber #if !defined(MBEDTLS_RSA_NO_CRT) && !defined(MBEDTLS_RSA_ALT)
8131b00a1f5SThomas Faber     /*
8141b00a1f5SThomas Faber     * The RSA CRT parameters DP, DQ and QP are nominally redundant, in
8151b00a1f5SThomas Faber     * that they can be easily recomputed from D, P and Q. However by
8161b00a1f5SThomas Faber     * parsing them from the PKCS1 structure it is possible to avoid
8171b00a1f5SThomas Faber     * recalculating them which both reduces the overhead of loading
8181b00a1f5SThomas Faber     * RSA private keys into memory and also avoids side channels which
8191b00a1f5SThomas Faber     * can arise when computing those values, since all of D, P, and Q
8201b00a1f5SThomas Faber     * are secret. See https://eprint.iacr.org/2020/055 for a
8211b00a1f5SThomas Faber     * description of one such attack.
8221b00a1f5SThomas Faber     */
8231b00a1f5SThomas Faber 
8241b00a1f5SThomas Faber     /* Import DP */
8251b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
8261b00a1f5SThomas Faber         ( ret = mbedtls_mpi_copy( &rsa->DP, &T ) ) != 0 )
827d9e6c9b5SThomas Faber        goto cleanup;
828c2c66affSColin Finck 
8291b00a1f5SThomas Faber     /* Import DQ */
8301b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
8311b00a1f5SThomas Faber         ( ret = mbedtls_mpi_copy( &rsa->DQ, &T ) ) != 0 )
8321b00a1f5SThomas Faber        goto cleanup;
8331b00a1f5SThomas Faber 
8341b00a1f5SThomas Faber     /* Import QP */
8351b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
8361b00a1f5SThomas Faber         ( ret = mbedtls_mpi_copy( &rsa->QP, &T ) ) != 0 )
8371b00a1f5SThomas Faber        goto cleanup;
8381b00a1f5SThomas Faber 
8391b00a1f5SThomas Faber #else
8401b00a1f5SThomas Faber     /* Verify existance of the CRT params */
8411b00a1f5SThomas Faber     if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
8421b00a1f5SThomas Faber         ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
8431b00a1f5SThomas Faber         ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 )
8441b00a1f5SThomas Faber        goto cleanup;
8451b00a1f5SThomas Faber #endif
8461b00a1f5SThomas Faber 
8471b00a1f5SThomas Faber     /* rsa_complete() doesn't complete anything with the default
8481b00a1f5SThomas Faber      * implementation but is still called:
8491b00a1f5SThomas Faber      * - for the benefit of alternative implementation that may want to
8501b00a1f5SThomas Faber      *   pre-compute stuff beyond what's provided (eg Montgomery factors)
8511b00a1f5SThomas Faber      * - as is also sanity-checks the key
8521b00a1f5SThomas Faber      *
8531b00a1f5SThomas Faber      * Furthermore, we also check the public part for consistency with
8541b00a1f5SThomas Faber      * mbedtls_pk_parse_pubkey(), as it includes size minima for example.
8551b00a1f5SThomas Faber      */
8561b00a1f5SThomas Faber     if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 ||
8571b00a1f5SThomas Faber         ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 )
8581b00a1f5SThomas Faber     {
8591b00a1f5SThomas Faber         goto cleanup;
8601b00a1f5SThomas Faber     }
8611b00a1f5SThomas Faber 
862c2c66affSColin Finck     if( p != end )
863c2c66affSColin Finck     {
864d9e6c9b5SThomas Faber         ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
865d9e6c9b5SThomas Faber               MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ;
866c2c66affSColin Finck     }
867c2c66affSColin Finck 
868d9e6c9b5SThomas Faber cleanup:
869d9e6c9b5SThomas Faber 
870d9e6c9b5SThomas Faber     mbedtls_mpi_free( &T );
871d9e6c9b5SThomas Faber 
872d9e6c9b5SThomas Faber     if( ret != 0 )
873c2c66affSColin Finck     {
874d9e6c9b5SThomas Faber         /* Wrap error code if it's coming from a lower level */
875d9e6c9b5SThomas Faber         if( ( ret & 0xff80 ) == 0 )
876d9e6c9b5SThomas Faber             ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret;
877d9e6c9b5SThomas Faber         else
878d9e6c9b5SThomas Faber             ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
879d9e6c9b5SThomas Faber 
880c2c66affSColin Finck         mbedtls_rsa_free( rsa );
881c2c66affSColin Finck     }
882c2c66affSColin Finck 
883d9e6c9b5SThomas Faber     return( ret );
884c2c66affSColin Finck }
885c2c66affSColin Finck #endif /* MBEDTLS_RSA_C */
886c2c66affSColin Finck 
887c2c66affSColin Finck #if defined(MBEDTLS_ECP_C)
888c2c66affSColin Finck /*
889c2c66affSColin Finck  * Parse a SEC1 encoded private EC key
890c2c66affSColin Finck  */
pk_parse_key_sec1_der(mbedtls_ecp_keypair * eck,const unsigned char * key,size_t keylen)891c2c66affSColin Finck static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck,
892c2c66affSColin Finck                                   const unsigned char *key,
893c2c66affSColin Finck                                   size_t keylen )
894c2c66affSColin Finck {
895c2c66affSColin Finck     int ret;
896c2c66affSColin Finck     int version, pubkey_done;
897c2c66affSColin Finck     size_t len;
898c2c66affSColin Finck     mbedtls_asn1_buf params;
899c2c66affSColin Finck     unsigned char *p = (unsigned char *) key;
900c2c66affSColin Finck     unsigned char *end = p + keylen;
901c2c66affSColin Finck     unsigned char *end2;
902c2c66affSColin Finck 
903c2c66affSColin Finck     /*
904c2c66affSColin Finck      * RFC 5915, or SEC1 Appendix C.4
905c2c66affSColin Finck      *
906c2c66affSColin Finck      * ECPrivateKey ::= SEQUENCE {
907c2c66affSColin Finck      *      version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
908c2c66affSColin Finck      *      privateKey     OCTET STRING,
909c2c66affSColin Finck      *      parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
910c2c66affSColin Finck      *      publicKey  [1] BIT STRING OPTIONAL
911c2c66affSColin Finck      *    }
912c2c66affSColin Finck      */
913c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
914c2c66affSColin Finck             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
915c2c66affSColin Finck     {
916c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
917c2c66affSColin Finck     }
918c2c66affSColin Finck 
919c2c66affSColin Finck     end = p + len;
920c2c66affSColin Finck 
921c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 )
922c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
923c2c66affSColin Finck 
924c2c66affSColin Finck     if( version != 1 )
925c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION );
926c2c66affSColin Finck 
927c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
928c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
929c2c66affSColin Finck 
930c2c66affSColin Finck     if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 )
931c2c66affSColin Finck     {
932c2c66affSColin Finck         mbedtls_ecp_keypair_free( eck );
933c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
934c2c66affSColin Finck     }
935c2c66affSColin Finck 
936c2c66affSColin Finck     p += len;
937c2c66affSColin Finck 
938c2c66affSColin Finck     pubkey_done = 0;
939c2c66affSColin Finck     if( p != end )
940c2c66affSColin Finck     {
941c2c66affSColin Finck         /*
942c2c66affSColin Finck          * Is 'parameters' present?
943c2c66affSColin Finck          */
944c2c66affSColin Finck         if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
945c2c66affSColin Finck                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 )
946c2c66affSColin Finck         {
947c2c66affSColin Finck             if( ( ret = pk_get_ecparams( &p, p + len, &params) ) != 0 ||
948c2c66affSColin Finck                 ( ret = pk_use_ecparams( &params, &eck->grp )  ) != 0 )
949c2c66affSColin Finck             {
950c2c66affSColin Finck                 mbedtls_ecp_keypair_free( eck );
951c2c66affSColin Finck                 return( ret );
952c2c66affSColin Finck             }
953c2c66affSColin Finck         }
954c2c66affSColin Finck         else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
955c2c66affSColin Finck         {
956c2c66affSColin Finck             mbedtls_ecp_keypair_free( eck );
957c2c66affSColin Finck             return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
958c2c66affSColin Finck         }
959d9e6c9b5SThomas Faber     }
960c2c66affSColin Finck 
961d9e6c9b5SThomas Faber     if( p != end )
962d9e6c9b5SThomas Faber     {
963c2c66affSColin Finck         /*
964c2c66affSColin Finck          * Is 'publickey' present? If not, or if we can't read it (eg because it
965c2c66affSColin Finck          * is compressed), create it from the private key.
966c2c66affSColin Finck          */
967c2c66affSColin Finck         if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
968c2c66affSColin Finck                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 )
969c2c66affSColin Finck         {
970c2c66affSColin Finck             end2 = p + len;
971c2c66affSColin Finck 
972c2c66affSColin Finck             if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 )
973c2c66affSColin Finck                 return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
974c2c66affSColin Finck 
975c2c66affSColin Finck             if( p + len != end2 )
976c2c66affSColin Finck                 return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
977c2c66affSColin Finck                         MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
978c2c66affSColin Finck 
979c2c66affSColin Finck             if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 )
980c2c66affSColin Finck                 pubkey_done = 1;
981c2c66affSColin Finck             else
982c2c66affSColin Finck             {
983c2c66affSColin Finck                 /*
984c2c66affSColin Finck                  * The only acceptable failure mode of pk_get_ecpubkey() above
985c2c66affSColin Finck                  * is if the point format is not recognized.
986c2c66affSColin Finck                  */
987c2c66affSColin Finck                 if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE )
988c2c66affSColin Finck                     return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
989c2c66affSColin Finck             }
990c2c66affSColin Finck         }
991c2c66affSColin Finck         else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
992c2c66affSColin Finck         {
993c2c66affSColin Finck             mbedtls_ecp_keypair_free( eck );
994c2c66affSColin Finck             return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
995c2c66affSColin Finck         }
996c2c66affSColin Finck     }
997c2c66affSColin Finck 
998c2c66affSColin Finck     if( ! pubkey_done &&
999c2c66affSColin Finck         ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G,
1000c2c66affSColin Finck                                                       NULL, NULL ) ) != 0 )
1001c2c66affSColin Finck     {
1002c2c66affSColin Finck         mbedtls_ecp_keypair_free( eck );
1003c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
1004c2c66affSColin Finck     }
1005c2c66affSColin Finck 
1006c2c66affSColin Finck     if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 )
1007c2c66affSColin Finck     {
1008c2c66affSColin Finck         mbedtls_ecp_keypair_free( eck );
1009c2c66affSColin Finck         return( ret );
1010c2c66affSColin Finck     }
1011c2c66affSColin Finck 
1012c2c66affSColin Finck     return( 0 );
1013c2c66affSColin Finck }
1014c2c66affSColin Finck #endif /* MBEDTLS_ECP_C */
1015c2c66affSColin Finck 
1016c2c66affSColin Finck /*
1017c2c66affSColin Finck  * Parse an unencrypted PKCS#8 encoded private key
1018d9e6c9b5SThomas Faber  *
1019d9e6c9b5SThomas Faber  * Notes:
1020d9e6c9b5SThomas Faber  *
1021d9e6c9b5SThomas Faber  * - This function does not own the key buffer. It is the
1022d9e6c9b5SThomas Faber  *   responsibility of the caller to take care of zeroizing
1023d9e6c9b5SThomas Faber  *   and freeing it after use.
1024d9e6c9b5SThomas Faber  *
1025d9e6c9b5SThomas Faber  * - The function is responsible for freeing the provided
1026d9e6c9b5SThomas Faber  *   PK context on failure.
1027d9e6c9b5SThomas Faber  *
1028c2c66affSColin Finck  */
pk_parse_key_pkcs8_unencrypted_der(mbedtls_pk_context * pk,const unsigned char * key,size_t keylen)1029c2c66affSColin Finck static int pk_parse_key_pkcs8_unencrypted_der(
1030c2c66affSColin Finck                                     mbedtls_pk_context *pk,
1031c2c66affSColin Finck                                     const unsigned char* key,
1032c2c66affSColin Finck                                     size_t keylen )
1033c2c66affSColin Finck {
1034c2c66affSColin Finck     int ret, version;
1035c2c66affSColin Finck     size_t len;
1036c2c66affSColin Finck     mbedtls_asn1_buf params;
1037c2c66affSColin Finck     unsigned char *p = (unsigned char *) key;
1038c2c66affSColin Finck     unsigned char *end = p + keylen;
1039c2c66affSColin Finck     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
1040c2c66affSColin Finck     const mbedtls_pk_info_t *pk_info;
1041c2c66affSColin Finck 
1042c2c66affSColin Finck     /*
1043d9e6c9b5SThomas Faber      * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208)
1044c2c66affSColin Finck      *
1045c2c66affSColin Finck      *    PrivateKeyInfo ::= SEQUENCE {
1046c2c66affSColin Finck      *      version                   Version,
1047c2c66affSColin Finck      *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
1048c2c66affSColin Finck      *      privateKey                PrivateKey,
1049c2c66affSColin Finck      *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
1050c2c66affSColin Finck      *
1051c2c66affSColin Finck      *    Version ::= INTEGER
1052c2c66affSColin Finck      *    PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
1053c2c66affSColin Finck      *    PrivateKey ::= OCTET STRING
1054c2c66affSColin Finck      *
1055c2c66affSColin Finck      *  The PrivateKey OCTET STRING is a SEC1 ECPrivateKey
1056c2c66affSColin Finck      */
1057c2c66affSColin Finck 
1058c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
1059c2c66affSColin Finck             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
1060c2c66affSColin Finck     {
1061c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
1062c2c66affSColin Finck     }
1063c2c66affSColin Finck 
1064c2c66affSColin Finck     end = p + len;
1065c2c66affSColin Finck 
1066c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 )
1067c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
1068c2c66affSColin Finck 
1069c2c66affSColin Finck     if( version != 0 )
1070c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret );
1071c2c66affSColin Finck 
1072c2c66affSColin Finck     if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, &params ) ) != 0 )
1073*103a79ceSThomas Faber         return( ret );
1074c2c66affSColin Finck 
1075c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
1076c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
1077c2c66affSColin Finck 
1078c2c66affSColin Finck     if( len < 1 )
1079c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +
1080c2c66affSColin Finck                 MBEDTLS_ERR_ASN1_OUT_OF_DATA );
1081c2c66affSColin Finck 
1082c2c66affSColin Finck     if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL )
1083c2c66affSColin Finck         return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
1084c2c66affSColin Finck 
1085c2c66affSColin Finck     if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 )
1086c2c66affSColin Finck         return( ret );
1087c2c66affSColin Finck 
1088c2c66affSColin Finck #if defined(MBEDTLS_RSA_C)
1089c2c66affSColin Finck     if( pk_alg == MBEDTLS_PK_RSA )
1090c2c66affSColin Finck     {
1091c2c66affSColin Finck         if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 )
1092c2c66affSColin Finck         {
1093c2c66affSColin Finck             mbedtls_pk_free( pk );
1094c2c66affSColin Finck             return( ret );
1095c2c66affSColin Finck         }
1096c2c66affSColin Finck     } else
1097c2c66affSColin Finck #endif /* MBEDTLS_RSA_C */
1098c2c66affSColin Finck #if defined(MBEDTLS_ECP_C)
1099c2c66affSColin Finck     if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH )
1100c2c66affSColin Finck     {
1101c2c66affSColin Finck         if( ( ret = pk_use_ecparams( &params, &mbedtls_pk_ec( *pk )->grp ) ) != 0 ||
1102c2c66affSColin Finck             ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len )  ) != 0 )
1103c2c66affSColin Finck         {
1104c2c66affSColin Finck             mbedtls_pk_free( pk );
1105c2c66affSColin Finck             return( ret );
1106c2c66affSColin Finck         }
1107c2c66affSColin Finck     } else
1108c2c66affSColin Finck #endif /* MBEDTLS_ECP_C */
1109c2c66affSColin Finck         return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
1110c2c66affSColin Finck 
1111c2c66affSColin Finck     return( 0 );
1112c2c66affSColin Finck }
1113c2c66affSColin Finck 
1114c2c66affSColin Finck /*
1115c2c66affSColin Finck  * Parse an encrypted PKCS#8 encoded private key
1116d9e6c9b5SThomas Faber  *
1117d9e6c9b5SThomas Faber  * To save space, the decryption happens in-place on the given key buffer.
1118d9e6c9b5SThomas Faber  * Also, while this function may modify the keybuffer, it doesn't own it,
1119d9e6c9b5SThomas Faber  * and instead it is the responsibility of the caller to zeroize and properly
1120d9e6c9b5SThomas Faber  * free it after use.
1121d9e6c9b5SThomas Faber  *
1122c2c66affSColin Finck  */
1123c2c66affSColin Finck #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
pk_parse_key_pkcs8_encrypted_der(mbedtls_pk_context * pk,unsigned char * key,size_t keylen,const unsigned char * pwd,size_t pwdlen)1124c2c66affSColin Finck static int pk_parse_key_pkcs8_encrypted_der(
1125c2c66affSColin Finck                                     mbedtls_pk_context *pk,
1126d9e6c9b5SThomas Faber                                     unsigned char *key, size_t keylen,
1127c2c66affSColin Finck                                     const unsigned char *pwd, size_t pwdlen )
1128c2c66affSColin Finck {
1129c2c66affSColin Finck     int ret, decrypted = 0;
1130c2c66affSColin Finck     size_t len;
1131d9e6c9b5SThomas Faber     unsigned char *buf;
1132c2c66affSColin Finck     unsigned char *p, *end;
1133c2c66affSColin Finck     mbedtls_asn1_buf pbe_alg_oid, pbe_params;
1134c2c66affSColin Finck #if defined(MBEDTLS_PKCS12_C)
1135c2c66affSColin Finck     mbedtls_cipher_type_t cipher_alg;
1136c2c66affSColin Finck     mbedtls_md_type_t md_alg;
1137c2c66affSColin Finck #endif
1138c2c66affSColin Finck 
1139d9e6c9b5SThomas Faber     p = key;
1140c2c66affSColin Finck     end = p + keylen;
1141c2c66affSColin Finck 
1142c2c66affSColin Finck     if( pwdlen == 0 )
1143c2c66affSColin Finck         return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED );
1144c2c66affSColin Finck 
1145c2c66affSColin Finck     /*
1146d9e6c9b5SThomas Faber      * This function parses the EncryptedPrivateKeyInfo object (PKCS#8)
1147c2c66affSColin Finck      *
1148c2c66affSColin Finck      *  EncryptedPrivateKeyInfo ::= SEQUENCE {
1149c2c66affSColin Finck      *    encryptionAlgorithm  EncryptionAlgorithmIdentifier,
1150c2c66affSColin Finck      *    encryptedData        EncryptedData
1151c2c66affSColin Finck      *  }
1152c2c66affSColin Finck      *
1153c2c66affSColin Finck      *  EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
1154c2c66affSColin Finck      *
1155c2c66affSColin Finck      *  EncryptedData ::= OCTET STRING
1156c2c66affSColin Finck      *
1157c2c66affSColin Finck      *  The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo
1158d9e6c9b5SThomas Faber      *
1159c2c66affSColin Finck      */
1160c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
1161c2c66affSColin Finck             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
1162c2c66affSColin Finck     {
1163c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
1164c2c66affSColin Finck     }
1165c2c66affSColin Finck 
1166c2c66affSColin Finck     end = p + len;
1167c2c66affSColin Finck 
1168c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 )
1169c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
1170c2c66affSColin Finck 
1171c2c66affSColin Finck     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
1172c2c66affSColin Finck         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret );
1173c2c66affSColin Finck 
1174d9e6c9b5SThomas Faber     buf = p;
1175c2c66affSColin Finck 
1176c2c66affSColin Finck     /*
1177d9e6c9b5SThomas Faber      * Decrypt EncryptedData with appropriate PBE
1178c2c66affSColin Finck      */
1179c2c66affSColin Finck #if defined(MBEDTLS_PKCS12_C)
1180c2c66affSColin Finck     if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 )
1181c2c66affSColin Finck     {
1182c2c66affSColin Finck         if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
1183c2c66affSColin Finck                                 cipher_alg, md_alg,
1184c2c66affSColin Finck                                 pwd, pwdlen, p, len, buf ) ) != 0 )
1185c2c66affSColin Finck         {
1186c2c66affSColin Finck             if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH )
1187c2c66affSColin Finck                 return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );
1188c2c66affSColin Finck 
1189c2c66affSColin Finck             return( ret );
1190c2c66affSColin Finck         }
1191c2c66affSColin Finck 
1192c2c66affSColin Finck         decrypted = 1;
1193c2c66affSColin Finck     }
1194c2c66affSColin Finck     else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 )
1195c2c66affSColin Finck     {
1196c2c66affSColin Finck         if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params,
1197c2c66affSColin Finck                                              MBEDTLS_PKCS12_PBE_DECRYPT,
1198c2c66affSColin Finck                                              pwd, pwdlen,
1199c2c66affSColin Finck                                              p, len, buf ) ) != 0 )
1200c2c66affSColin Finck         {
1201c2c66affSColin Finck             return( ret );
1202c2c66affSColin Finck         }
1203c2c66affSColin Finck 
1204c2c66affSColin Finck         // Best guess for password mismatch when using RC4. If first tag is
1205c2c66affSColin Finck         // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
1206c2c66affSColin Finck         //
1207c2c66affSColin Finck         if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) )
1208c2c66affSColin Finck             return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );
1209c2c66affSColin Finck 
1210c2c66affSColin Finck         decrypted = 1;
1211c2c66affSColin Finck     }
1212c2c66affSColin Finck     else
1213c2c66affSColin Finck #endif /* MBEDTLS_PKCS12_C */
1214c2c66affSColin Finck #if defined(MBEDTLS_PKCS5_C)
1215c2c66affSColin Finck     if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 )
1216c2c66affSColin Finck     {
1217c2c66affSColin Finck         if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
1218c2c66affSColin Finck                                   p, len, buf ) ) != 0 )
1219c2c66affSColin Finck         {
1220c2c66affSColin Finck             if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH )
1221c2c66affSColin Finck                 return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );
1222c2c66affSColin Finck 
1223c2c66affSColin Finck             return( ret );
1224c2c66affSColin Finck         }
1225c2c66affSColin Finck 
1226c2c66affSColin Finck         decrypted = 1;
1227c2c66affSColin Finck     }
1228c2c66affSColin Finck     else
1229c2c66affSColin Finck #endif /* MBEDTLS_PKCS5_C */
1230c2c66affSColin Finck     {
1231c2c66affSColin Finck         ((void) pwd);
1232c2c66affSColin Finck     }
1233c2c66affSColin Finck 
1234c2c66affSColin Finck     if( decrypted == 0 )
1235c2c66affSColin Finck         return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
1236c2c66affSColin Finck 
1237c2c66affSColin Finck     return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) );
1238c2c66affSColin Finck }
1239c2c66affSColin Finck #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1240c2c66affSColin Finck 
1241c2c66affSColin Finck /*
1242c2c66affSColin Finck  * Parse a private key
1243c2c66affSColin Finck  */
mbedtls_pk_parse_key(mbedtls_pk_context * pk,const unsigned char * key,size_t keylen,const unsigned char * pwd,size_t pwdlen)1244c2c66affSColin Finck int mbedtls_pk_parse_key( mbedtls_pk_context *pk,
1245c2c66affSColin Finck                   const unsigned char *key, size_t keylen,
1246c2c66affSColin Finck                   const unsigned char *pwd, size_t pwdlen )
1247c2c66affSColin Finck {
1248c2c66affSColin Finck     int ret;
1249c2c66affSColin Finck     const mbedtls_pk_info_t *pk_info;
1250c2c66affSColin Finck #if defined(MBEDTLS_PEM_PARSE_C)
1251c2c66affSColin Finck     size_t len;
1252c2c66affSColin Finck     mbedtls_pem_context pem;
1253cbda039fSThomas Faber #endif
1254c2c66affSColin Finck 
1255cbda039fSThomas Faber     PK_VALIDATE_RET( pk != NULL );
1256cbda039fSThomas Faber     if( keylen == 0 )
1257cbda039fSThomas Faber         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
1258cbda039fSThomas Faber     PK_VALIDATE_RET( key != NULL );
1259cbda039fSThomas Faber 
1260cbda039fSThomas Faber #if defined(MBEDTLS_PEM_PARSE_C)
1261c2c66affSColin Finck    mbedtls_pem_init( &pem );
1262c2c66affSColin Finck 
1263c2c66affSColin Finck #if defined(MBEDTLS_RSA_C)
1264c2c66affSColin Finck     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1265cbda039fSThomas Faber     if( key[keylen - 1] != '\0' )
1266c2c66affSColin Finck         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1267c2c66affSColin Finck     else
1268c2c66affSColin Finck         ret = mbedtls_pem_read_buffer( &pem,
1269c2c66affSColin Finck                                "-----BEGIN RSA PRIVATE KEY-----",
1270c2c66affSColin Finck                                "-----END RSA PRIVATE KEY-----",
1271c2c66affSColin Finck                                key, pwd, pwdlen, &len );
1272c2c66affSColin Finck 
1273c2c66affSColin Finck     if( ret == 0 )
1274c2c66affSColin Finck     {
1275d9e6c9b5SThomas Faber         pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA );
1276c2c66affSColin Finck         if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ||
1277c2c66affSColin Finck             ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ),
1278c2c66affSColin Finck                                             pem.buf, pem.buflen ) ) != 0 )
1279c2c66affSColin Finck         {
1280c2c66affSColin Finck             mbedtls_pk_free( pk );
1281c2c66affSColin Finck         }
1282c2c66affSColin Finck 
1283c2c66affSColin Finck         mbedtls_pem_free( &pem );
1284c2c66affSColin Finck         return( ret );
1285c2c66affSColin Finck     }
1286c2c66affSColin Finck     else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH )
1287c2c66affSColin Finck         return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );
1288c2c66affSColin Finck     else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED )
1289c2c66affSColin Finck         return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED );
1290c2c66affSColin Finck     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
1291c2c66affSColin Finck         return( ret );
1292c2c66affSColin Finck #endif /* MBEDTLS_RSA_C */
1293c2c66affSColin Finck 
1294c2c66affSColin Finck #if defined(MBEDTLS_ECP_C)
1295c2c66affSColin Finck     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1296cbda039fSThomas Faber     if( key[keylen - 1] != '\0' )
1297c2c66affSColin Finck         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1298c2c66affSColin Finck     else
1299c2c66affSColin Finck         ret = mbedtls_pem_read_buffer( &pem,
1300c2c66affSColin Finck                                "-----BEGIN EC PRIVATE KEY-----",
1301c2c66affSColin Finck                                "-----END EC PRIVATE KEY-----",
1302c2c66affSColin Finck                                key, pwd, pwdlen, &len );
1303c2c66affSColin Finck     if( ret == 0 )
1304c2c66affSColin Finck     {
1305d9e6c9b5SThomas Faber         pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY );
1306c2c66affSColin Finck 
1307c2c66affSColin Finck         if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ||
1308c2c66affSColin Finck             ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ),
1309c2c66affSColin Finck                                            pem.buf, pem.buflen ) ) != 0 )
1310c2c66affSColin Finck         {
1311c2c66affSColin Finck             mbedtls_pk_free( pk );
1312c2c66affSColin Finck         }
1313c2c66affSColin Finck 
1314c2c66affSColin Finck         mbedtls_pem_free( &pem );
1315c2c66affSColin Finck         return( ret );
1316c2c66affSColin Finck     }
1317c2c66affSColin Finck     else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH )
1318c2c66affSColin Finck         return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );
1319c2c66affSColin Finck     else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED )
1320c2c66affSColin Finck         return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED );
1321c2c66affSColin Finck     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
1322c2c66affSColin Finck         return( ret );
1323c2c66affSColin Finck #endif /* MBEDTLS_ECP_C */
1324c2c66affSColin Finck 
1325c2c66affSColin Finck     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1326cbda039fSThomas Faber     if( key[keylen - 1] != '\0' )
1327c2c66affSColin Finck         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1328c2c66affSColin Finck     else
1329c2c66affSColin Finck         ret = mbedtls_pem_read_buffer( &pem,
1330c2c66affSColin Finck                                "-----BEGIN PRIVATE KEY-----",
1331c2c66affSColin Finck                                "-----END PRIVATE KEY-----",
1332c2c66affSColin Finck                                key, NULL, 0, &len );
1333c2c66affSColin Finck     if( ret == 0 )
1334c2c66affSColin Finck     {
1335c2c66affSColin Finck         if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk,
1336c2c66affSColin Finck                                                 pem.buf, pem.buflen ) ) != 0 )
1337c2c66affSColin Finck         {
1338c2c66affSColin Finck             mbedtls_pk_free( pk );
1339c2c66affSColin Finck         }
1340c2c66affSColin Finck 
1341c2c66affSColin Finck         mbedtls_pem_free( &pem );
1342c2c66affSColin Finck         return( ret );
1343c2c66affSColin Finck     }
1344c2c66affSColin Finck     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
1345c2c66affSColin Finck         return( ret );
1346c2c66affSColin Finck 
1347c2c66affSColin Finck #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
1348c2c66affSColin Finck     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1349cbda039fSThomas Faber     if( key[keylen - 1] != '\0' )
1350c2c66affSColin Finck         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1351c2c66affSColin Finck     else
1352c2c66affSColin Finck         ret = mbedtls_pem_read_buffer( &pem,
1353c2c66affSColin Finck                                "-----BEGIN ENCRYPTED PRIVATE KEY-----",
1354c2c66affSColin Finck                                "-----END ENCRYPTED PRIVATE KEY-----",
1355c2c66affSColin Finck                                key, NULL, 0, &len );
1356c2c66affSColin Finck     if( ret == 0 )
1357c2c66affSColin Finck     {
1358c2c66affSColin Finck         if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk,
1359c2c66affSColin Finck                                                       pem.buf, pem.buflen,
1360c2c66affSColin Finck                                                       pwd, pwdlen ) ) != 0 )
1361c2c66affSColin Finck         {
1362c2c66affSColin Finck             mbedtls_pk_free( pk );
1363c2c66affSColin Finck         }
1364c2c66affSColin Finck 
1365c2c66affSColin Finck         mbedtls_pem_free( &pem );
1366c2c66affSColin Finck         return( ret );
1367c2c66affSColin Finck     }
1368c2c66affSColin Finck     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
1369c2c66affSColin Finck         return( ret );
1370c2c66affSColin Finck #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1371c2c66affSColin Finck #else
1372c2c66affSColin Finck     ((void) pwd);
1373c2c66affSColin Finck     ((void) pwdlen);
1374c2c66affSColin Finck #endif /* MBEDTLS_PEM_PARSE_C */
1375c2c66affSColin Finck 
1376c2c66affSColin Finck     /*
1377c2c66affSColin Finck      * At this point we only know it's not a PEM formatted key. Could be any
1378c2c66affSColin Finck      * of the known DER encoded private key formats
1379c2c66affSColin Finck      *
1380c2c66affSColin Finck      * We try the different DER format parsers to see if one passes without
1381c2c66affSColin Finck      * error
1382c2c66affSColin Finck      */
1383c2c66affSColin Finck #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
1384c2c66affSColin Finck     {
1385d9e6c9b5SThomas Faber         unsigned char *key_copy;
1386d9e6c9b5SThomas Faber 
1387d9e6c9b5SThomas Faber         if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL )
1388d9e6c9b5SThomas Faber             return( MBEDTLS_ERR_PK_ALLOC_FAILED );
1389d9e6c9b5SThomas Faber 
1390d9e6c9b5SThomas Faber         memcpy( key_copy, key, keylen );
1391d9e6c9b5SThomas Faber 
1392d9e6c9b5SThomas Faber         ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen,
1393d9e6c9b5SThomas Faber                                                 pwd, pwdlen );
1394d9e6c9b5SThomas Faber 
1395cbda039fSThomas Faber         mbedtls_platform_zeroize( key_copy, keylen );
1396d9e6c9b5SThomas Faber         mbedtls_free( key_copy );
1397c2c66affSColin Finck     }
1398c2c66affSColin Finck 
1399d9e6c9b5SThomas Faber     if( ret == 0 )
1400d9e6c9b5SThomas Faber         return( 0 );
1401d9e6c9b5SThomas Faber 
1402c2c66affSColin Finck     mbedtls_pk_free( pk );
14030ba5bc40SThomas Faber     mbedtls_pk_init( pk );
1404c2c66affSColin Finck 
1405c2c66affSColin Finck     if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH )
1406c2c66affSColin Finck     {
1407c2c66affSColin Finck         return( ret );
1408c2c66affSColin Finck     }
1409c2c66affSColin Finck #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
1410c2c66affSColin Finck 
1411c2c66affSColin Finck     if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 )
1412c2c66affSColin Finck         return( 0 );
1413c2c66affSColin Finck 
1414c2c66affSColin Finck     mbedtls_pk_free( pk );
14150ba5bc40SThomas Faber     mbedtls_pk_init( pk );
1416c2c66affSColin Finck 
1417c2c66affSColin Finck #if defined(MBEDTLS_RSA_C)
1418c2c66affSColin Finck 
1419d9e6c9b5SThomas Faber     pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA );
14200ba5bc40SThomas Faber     if( mbedtls_pk_setup( pk, pk_info ) == 0 &&
14210ba5bc40SThomas Faber         pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) == 0 )
1422c2c66affSColin Finck     {
1423c2c66affSColin Finck         return( 0 );
1424c2c66affSColin Finck     }
1425c2c66affSColin Finck 
14260ba5bc40SThomas Faber     mbedtls_pk_free( pk );
14270ba5bc40SThomas Faber     mbedtls_pk_init( pk );
1428c2c66affSColin Finck #endif /* MBEDTLS_RSA_C */
1429c2c66affSColin Finck 
1430c2c66affSColin Finck #if defined(MBEDTLS_ECP_C)
1431d9e6c9b5SThomas Faber     pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY );
14320ba5bc40SThomas Faber     if( mbedtls_pk_setup( pk, pk_info ) == 0 &&
14330ba5bc40SThomas Faber         pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ),
14340ba5bc40SThomas Faber                                key, keylen ) == 0 )
1435c2c66affSColin Finck     {
1436c2c66affSColin Finck         return( 0 );
1437c2c66affSColin Finck     }
14380ba5bc40SThomas Faber     mbedtls_pk_free( pk );
1439c2c66affSColin Finck #endif /* MBEDTLS_ECP_C */
1440c2c66affSColin Finck 
14410ba5bc40SThomas Faber     /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't,
14420ba5bc40SThomas Faber      * it is ok to leave the PK context initialized but not
14430ba5bc40SThomas Faber      * freed: It is the caller's responsibility to call pk_init()
14440ba5bc40SThomas Faber      * before calling this function, and to call pk_free()
14450ba5bc40SThomas Faber      * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C
14460ba5bc40SThomas Faber      * isn't, this leads to mbedtls_pk_free() being called
14470ba5bc40SThomas Faber      * twice, once here and once by the caller, but this is
14480ba5bc40SThomas Faber      * also ok and in line with the mbedtls_pk_free() calls
14490ba5bc40SThomas Faber      * on failed PEM parsing attempts. */
14500ba5bc40SThomas Faber 
1451c2c66affSColin Finck     return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
1452c2c66affSColin Finck }
1453c2c66affSColin Finck 
1454c2c66affSColin Finck /*
1455c2c66affSColin Finck  * Parse a public key
1456c2c66affSColin Finck  */
mbedtls_pk_parse_public_key(mbedtls_pk_context * ctx,const unsigned char * key,size_t keylen)1457c2c66affSColin Finck int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx,
1458c2c66affSColin Finck                          const unsigned char *key, size_t keylen )
1459c2c66affSColin Finck {
1460c2c66affSColin Finck     int ret;
1461c2c66affSColin Finck     unsigned char *p;
1462cbda039fSThomas Faber #if defined(MBEDTLS_RSA_C)
1463cbda039fSThomas Faber     const mbedtls_pk_info_t *pk_info;
1464cbda039fSThomas Faber #endif
1465c2c66affSColin Finck #if defined(MBEDTLS_PEM_PARSE_C)
1466c2c66affSColin Finck     size_t len;
1467c2c66affSColin Finck     mbedtls_pem_context pem;
1468cbda039fSThomas Faber #endif
1469c2c66affSColin Finck 
1470cbda039fSThomas Faber     PK_VALIDATE_RET( ctx != NULL );
1471cbda039fSThomas Faber     if( keylen == 0 )
1472cbda039fSThomas Faber         return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
1473cbda039fSThomas Faber     PK_VALIDATE_RET( key != NULL || keylen == 0 );
1474cbda039fSThomas Faber 
1475cbda039fSThomas Faber #if defined(MBEDTLS_PEM_PARSE_C)
1476c2c66affSColin Finck     mbedtls_pem_init( &pem );
1477cbda039fSThomas Faber #if defined(MBEDTLS_RSA_C)
1478cbda039fSThomas Faber     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1479cbda039fSThomas Faber     if( key[keylen - 1] != '\0' )
1480cbda039fSThomas Faber         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1481cbda039fSThomas Faber     else
1482cbda039fSThomas Faber         ret = mbedtls_pem_read_buffer( &pem,
1483cbda039fSThomas Faber                                "-----BEGIN RSA PUBLIC KEY-----",
1484cbda039fSThomas Faber                                "-----END RSA PUBLIC KEY-----",
1485cbda039fSThomas Faber                                key, NULL, 0, &len );
1486cbda039fSThomas Faber 
1487cbda039fSThomas Faber     if( ret == 0 )
1488cbda039fSThomas Faber     {
1489cbda039fSThomas Faber         p = pem.buf;
1490cbda039fSThomas Faber         if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL )
1491cbda039fSThomas Faber             return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
1492cbda039fSThomas Faber 
1493cbda039fSThomas Faber         if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 )
1494cbda039fSThomas Faber             return( ret );
1495cbda039fSThomas Faber 
1496cbda039fSThomas Faber         if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 )
1497cbda039fSThomas Faber             mbedtls_pk_free( ctx );
1498cbda039fSThomas Faber 
1499cbda039fSThomas Faber         mbedtls_pem_free( &pem );
1500cbda039fSThomas Faber         return( ret );
1501cbda039fSThomas Faber     }
1502cbda039fSThomas Faber     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
1503cbda039fSThomas Faber     {
1504cbda039fSThomas Faber         mbedtls_pem_free( &pem );
1505cbda039fSThomas Faber         return( ret );
1506cbda039fSThomas Faber     }
1507cbda039fSThomas Faber #endif /* MBEDTLS_RSA_C */
1508c2c66affSColin Finck 
1509c2c66affSColin Finck     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
1510cbda039fSThomas Faber     if( key[keylen - 1] != '\0' )
1511c2c66affSColin Finck         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
1512c2c66affSColin Finck     else
1513c2c66affSColin Finck         ret = mbedtls_pem_read_buffer( &pem,
1514c2c66affSColin Finck                 "-----BEGIN PUBLIC KEY-----",
1515c2c66affSColin Finck                 "-----END PUBLIC KEY-----",
1516c2c66affSColin Finck                 key, NULL, 0, &len );
1517c2c66affSColin Finck 
1518c2c66affSColin Finck     if( ret == 0 )
1519c2c66affSColin Finck     {
1520c2c66affSColin Finck         /*
1521c2c66affSColin Finck          * Was PEM encoded
1522c2c66affSColin Finck          */
1523cbda039fSThomas Faber         p = pem.buf;
1524cbda039fSThomas Faber 
1525cbda039fSThomas Faber         ret = mbedtls_pk_parse_subpubkey( &p,  p + pem.buflen, ctx );
1526cbda039fSThomas Faber         mbedtls_pem_free( &pem );
1527cbda039fSThomas Faber         return( ret );
1528c2c66affSColin Finck     }
1529c2c66affSColin Finck     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
1530c2c66affSColin Finck     {
1531c2c66affSColin Finck         mbedtls_pem_free( &pem );
1532c2c66affSColin Finck         return( ret );
1533c2c66affSColin Finck     }
1534cbda039fSThomas Faber     mbedtls_pem_free( &pem );
1535c2c66affSColin Finck #endif /* MBEDTLS_PEM_PARSE_C */
1536cbda039fSThomas Faber 
1537cbda039fSThomas Faber #if defined(MBEDTLS_RSA_C)
1538cbda039fSThomas Faber     if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL )
1539cbda039fSThomas Faber         return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
1540cbda039fSThomas Faber 
1541cbda039fSThomas Faber     if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 )
1542cbda039fSThomas Faber         return( ret );
1543cbda039fSThomas Faber 
1544cbda039fSThomas Faber     p = (unsigned char *)key;
1545cbda039fSThomas Faber     ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) );
1546cbda039fSThomas Faber     if( ret == 0 )
1547cbda039fSThomas Faber     {
1548cbda039fSThomas Faber         return( ret );
1549cbda039fSThomas Faber     }
1550cbda039fSThomas Faber     mbedtls_pk_free( ctx );
1551cbda039fSThomas Faber     if( ret != ( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) )
1552cbda039fSThomas Faber     {
1553cbda039fSThomas Faber         return( ret );
1554cbda039fSThomas Faber     }
1555cbda039fSThomas Faber #endif /* MBEDTLS_RSA_C */
1556c2c66affSColin Finck     p = (unsigned char *) key;
1557c2c66affSColin Finck 
1558c2c66affSColin Finck     ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx );
1559c2c66affSColin Finck 
1560c2c66affSColin Finck     return( ret );
1561c2c66affSColin Finck }
1562c2c66affSColin Finck 
1563c2c66affSColin Finck #endif /* MBEDTLS_PK_PARSE_C */
1564