pkparse 46.9 KB
Newer Older
ROOL's avatar
ROOL committed
1 2 3
/*
 *  Public Key layer for parsing key files and structures
 *
4
 *  Copyright The Mbed TLS Contributors
ROOL's avatar
ROOL committed
5
 *  SPDX-License-Identifier: Apache-2.0
ROOL's avatar
ROOL committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

ROOL's avatar
ROOL committed
20
#include "common.h"
ROOL's avatar
ROOL committed
21 22 23 24 25 26

#if defined(MBEDTLS_PK_PARSE_C)

#include "mbedtls/pk.h"
#include "mbedtls/asn1.h"
#include "mbedtls/oid.h"
ROOL's avatar
ROOL committed
27
#include "mbedtls/platform_util.h"
ROOL's avatar
ROOL committed
28
#include "mbedtls/error.h"
ROOL's avatar
ROOL committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

#include <string.h>

#if defined(MBEDTLS_RSA_C)
#include "mbedtls/rsa.h"
#endif
#if defined(MBEDTLS_ECP_C)
#include "mbedtls/ecp.h"
#endif
#if defined(MBEDTLS_ECDSA_C)
#include "mbedtls/ecdsa.h"
#endif
#if defined(MBEDTLS_PEM_PARSE_C)
#include "mbedtls/pem.h"
#endif
#if defined(MBEDTLS_PKCS5_C)
#include "mbedtls/pkcs5.h"
#endif
#if defined(MBEDTLS_PKCS12_C)
#include "mbedtls/pkcs12.h"
#endif

#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc    calloc
#define mbedtls_free       free
#endif

ROOL's avatar
ROOL committed
59 60 61 62 63 64
/* Parameter validation macros based on platform_util.h */
#define PK_VALIDATE_RET( cond )    \
    MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA )
#define PK_VALIDATE( cond )        \
    MBEDTLS_INTERNAL_VALIDATE( cond )

ROOL's avatar
ROOL committed
65 66 67 68 69 70 71 72 73 74 75 76 77
#if defined(MBEDTLS_FS_IO)
/*
 * Load all data from a file into a given buffer.
 *
 * The file is expected to contain either PEM or DER encoded data.
 * A terminating null byte is always appended. It is included in the announced
 * length only if the data looks like it is PEM encoded.
 */
int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n )
{
    FILE *f;
    long size;

ROOL's avatar
ROOL committed
78 79 80 81
    PK_VALIDATE_RET( path != NULL );
    PK_VALIDATE_RET( buf != NULL );
    PK_VALIDATE_RET( n != NULL );

ROOL's avatar
ROOL committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    if( ( f = fopen( path, "rb" ) ) == NULL )
        return( MBEDTLS_ERR_PK_FILE_IO_ERROR );

    fseek( f, 0, SEEK_END );
    if( ( size = ftell( f ) ) == -1 )
    {
        fclose( f );
        return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
    }
    fseek( f, 0, SEEK_SET );

    *n = (size_t) size;

    if( *n + 1 == 0 ||
        ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
    {
        fclose( f );
        return( MBEDTLS_ERR_PK_ALLOC_FAILED );
    }

    if( fread( *buf, 1, *n, f ) != *n )
    {
        fclose( f );

ROOL's avatar
ROOL committed
106
        mbedtls_platform_zeroize( *buf, *n );
ROOL's avatar
ROOL committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        mbedtls_free( *buf );

        return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
    }

    fclose( f );

    (*buf)[*n] = '\0';

    if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
        ++*n;

    return( 0 );
}

/*
 * Load and parse a private key
 */
int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx,
                      const char *path, const char *pwd )
{
ROOL's avatar
ROOL committed
128
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
129 130 131
    size_t n;
    unsigned char *buf;

ROOL's avatar
ROOL committed
132 133 134
    PK_VALIDATE_RET( ctx != NULL );
    PK_VALIDATE_RET( path != NULL );

ROOL's avatar
ROOL committed
135 136 137 138 139 140 141 142 143
    if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
        return( ret );

    if( pwd == NULL )
        ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 );
    else
        ret = mbedtls_pk_parse_key( ctx, buf, n,
                (const unsigned char *) pwd, strlen( pwd ) );

ROOL's avatar
ROOL committed
144
    mbedtls_platform_zeroize( buf, n );
ROOL's avatar
ROOL committed
145 146 147 148 149 150 151 152 153 154
    mbedtls_free( buf );

    return( ret );
}

/*
 * Load and parse a public key
 */
int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path )
{
ROOL's avatar
ROOL committed
155
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
156 157 158
    size_t n;
    unsigned char *buf;

ROOL's avatar
ROOL committed
159 160 161
    PK_VALIDATE_RET( ctx != NULL );
    PK_VALIDATE_RET( path != NULL );

ROOL's avatar
ROOL committed
162 163 164 165 166
    if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
        return( ret );

    ret = mbedtls_pk_parse_public_key( ctx, buf, n );

ROOL's avatar
ROOL committed
167
    mbedtls_platform_zeroize( buf, n );
ROOL's avatar
ROOL committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    mbedtls_free( buf );

    return( ret );
}
#endif /* MBEDTLS_FS_IO */

#if defined(MBEDTLS_ECP_C)
/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf
 *
 * ECParameters ::= CHOICE {
 *   namedCurve         OBJECT IDENTIFIER
 *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
 *   -- implicitCurve   NULL
 * }
 */
static int pk_get_ecparams( unsigned char **p, const unsigned char *end,
                            mbedtls_asn1_buf *params )
{
ROOL's avatar
ROOL committed
186
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
187 188

    if ( end - *p < 1 )
ROOL's avatar
ROOL committed
189 190
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
                MBEDTLS_ERR_ASN1_OUT_OF_DATA ) );
ROOL's avatar
ROOL committed
191 192 193 194 195 196 197 198 199

    /* Tag may be either OID or SEQUENCE */
    params->tag = **p;
    if( params->tag != MBEDTLS_ASN1_OID
#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
            && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE )
#endif
            )
    {
ROOL's avatar
ROOL committed
200 201
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
                MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) );
ROOL's avatar
ROOL committed
202 203 204 205
    }

    if( ( ret = mbedtls_asn1_get_tag( p, end, &params->len, params->tag ) ) != 0 )
    {
ROOL's avatar
ROOL committed
206
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
207 208 209 210 211 212
    }

    params->p = *p;
    *p += params->len;

    if( *p != end )
ROOL's avatar
ROOL committed
213 214
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
ROOL's avatar
ROOL committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240

    return( 0 );
}

#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
/*
 * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it.
 * WARNING: the resulting group should only be used with
 * pk_group_id_from_specified(), since its base point may not be set correctly
 * if it was encoded compressed.
 *
 *  SpecifiedECDomain ::= SEQUENCE {
 *      version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...),
 *      fieldID FieldID {{FieldTypes}},
 *      curve Curve,
 *      base ECPoint,
 *      order INTEGER,
 *      cofactor INTEGER OPTIONAL,
 *      hash HashAlgorithm OPTIONAL,
 *      ...
 *  }
 *
 * We only support prime-field as field type, and ignore hash and cofactor.
 */
static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp )
{
ROOL's avatar
ROOL committed
241
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
242 243 244 245 246 247 248 249
    unsigned char *p = params->p;
    const unsigned char * const end = params->p + params->len;
    const unsigned char *end_field, *end_curve;
    size_t len;
    int ver;

    /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */
    if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 )
ROOL's avatar
ROOL committed
250
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287

    if( ver < 1 || ver > 3 )
        return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );

    /*
     * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field
     *       fieldType FIELD-ID.&id({IOSet}),
     *       parameters FIELD-ID.&Type({IOSet}{@fieldType})
     * }
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
        return( ret );

    end_field = p + len;

    /*
     * FIELD-ID ::= TYPE-IDENTIFIER
     * FieldTypes FIELD-ID ::= {
     *       { Prime-p IDENTIFIED BY prime-field } |
     *       { Characteristic-two IDENTIFIED BY characteristic-two-field }
     * }
     * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 )
        return( ret );

    if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) ||
        memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 )
    {
        return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
    }

    p += len;

    /* Prime-p ::= INTEGER -- Field of size p. */
    if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 )
ROOL's avatar
ROOL committed
288
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
289 290 291 292

    grp->pbits = mbedtls_mpi_bitlen( &grp->P );

    if( p != end_field )
ROOL's avatar
ROOL committed
293 294
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
ROOL's avatar
ROOL committed
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

    /*
     * Curve ::= SEQUENCE {
     *       a FieldElement,
     *       b FieldElement,
     *       seed BIT STRING OPTIONAL
     *       -- Shall be present if used in SpecifiedECDomain
     *       -- with version equal to ecdpVer2 or ecdpVer3
     * }
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
        return( ret );

    end_curve = p + len;

    /*
     * FieldElement ::= OCTET STRING
     * containing an integer in the case of a prime field
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ||
        ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 )
    {
ROOL's avatar
ROOL committed
318
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
319 320 321 322 323 324 325
    }

    p += len;

    if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ||
        ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 )
    {
ROOL's avatar
ROOL committed
326
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
327 328 329 330 331 332 333 334 335
    }

    p += len;

    /* Ignore seed BIT STRING OPTIONAL */
    if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 )
        p += len;

    if( p != end_curve )
ROOL's avatar
ROOL committed
336 337
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
ROOL's avatar
ROOL committed
338 339 340 341 342

    /*
     * ECPoint ::= OCTET STRING
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
ROOL's avatar
ROOL committed
343
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

    if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G,
                                      ( const unsigned char *) p, len ) ) != 0 )
    {
        /*
         * If we can't read the point because it's compressed, cheat by
         * reading only the X coordinate and the parity bit of Y.
         */
        if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ||
            ( p[0] != 0x02 && p[0] != 0x03 ) ||
            len != mbedtls_mpi_size( &grp->P ) + 1 ||
            mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 ||
            mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 ||
            mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 )
        {
            return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
        }
    }

    p += len;

    /*
     * order INTEGER
     */
    if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 )
ROOL's avatar
ROOL committed
369
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430

    grp->nbits = mbedtls_mpi_bitlen( &grp->N );

    /*
     * Allow optional elements by purposefully not enforcing p == end here.
     */

    return( 0 );
}

/*
 * Find the group id associated with an (almost filled) group as generated by
 * pk_group_from_specified(), or return an error if unknown.
 */
static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id )
{
    int ret = 0;
    mbedtls_ecp_group ref;
    const mbedtls_ecp_group_id *id;

    mbedtls_ecp_group_init( &ref );

    for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ )
    {
        /* Load the group associated to that id */
        mbedtls_ecp_group_free( &ref );
        MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) );

        /* Compare to the group we were given, starting with easy tests */
        if( grp->pbits == ref.pbits && grp->nbits == ref.nbits &&
            mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 &&
            mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 &&
            mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 &&
            mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 &&
            mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 &&
            mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 &&
            /* For Y we may only know the parity bit, so compare only that */
            mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) )
        {
            break;
        }

    }

cleanup:
    mbedtls_ecp_group_free( &ref );

    *grp_id = *id;

    if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE )
        ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;

    return( ret );
}

/*
 * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID
 */
static int pk_group_id_from_specified( const mbedtls_asn1_buf *params,
                                       mbedtls_ecp_group_id *grp_id )
{
ROOL's avatar
ROOL committed
431
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
    mbedtls_ecp_group grp;

    mbedtls_ecp_group_init( &grp );

    if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 )
        goto cleanup;

    ret = pk_group_id_from_group( &grp, grp_id );

cleanup:
    mbedtls_ecp_group_free( &grp );

    return( ret );
}
#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */

/*
 * Use EC parameters to initialise an EC group
 *
 * ECParameters ::= CHOICE {
 *   namedCurve         OBJECT IDENTIFIER
 *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
 *   -- implicitCurve   NULL
 */
static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp )
{
ROOL's avatar
ROOL committed
458
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    mbedtls_ecp_group_id grp_id;

    if( params->tag == MBEDTLS_ASN1_OID )
    {
        if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 )
            return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE );
    }
    else
    {
#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
        if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 )
            return( ret );
#else
        return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
#endif
    }

    /*
ROOL's avatar
ROOL committed
477
     * grp may already be initialized; if so, make sure IDs match
ROOL's avatar
ROOL committed
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
     */
    if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id )
        return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );

    if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 )
        return( ret );

    return( 0 );
}

/*
 * EC public key is an EC point
 *
 * The caller is responsible for clearing the structure upon failure if
 * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE
 * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state.
 */
static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end,
                            mbedtls_ecp_keypair *key )
{
ROOL's avatar
ROOL committed
498
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525

    if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q,
                    (const unsigned char *) *p, end - *p ) ) == 0 )
    {
        ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q );
    }

    /*
     * We know mbedtls_ecp_point_read_binary consumed all bytes or failed
     */
    *p = (unsigned char *) end;

    return( ret );
}
#endif /* MBEDTLS_ECP_C */

#if defined(MBEDTLS_RSA_C)
/*
 *  RSAPublicKey ::= SEQUENCE {
 *      modulus           INTEGER,  -- n
 *      publicExponent    INTEGER   -- e
 *  }
 */
static int pk_get_rsapubkey( unsigned char **p,
                             const unsigned char *end,
                             mbedtls_rsa_context *rsa )
{
ROOL's avatar
ROOL committed
526
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
527 528 529 530
    size_t len;

    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
ROOL's avatar
ROOL committed
531
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ret ) );
ROOL's avatar
ROOL committed
532 533

    if( *p + len != end )
ROOL's avatar
ROOL committed
534 535
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY,
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
ROOL's avatar
ROOL committed
536 537 538

    /* Import N */
    if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
ROOL's avatar
ROOL committed
539
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ret ) );
ROOL's avatar
ROOL committed
540 541 542 543 544 545 546 547 548

    if( ( ret = mbedtls_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0,
                                        NULL, 0, NULL, 0 ) ) != 0 )
        return( MBEDTLS_ERR_PK_INVALID_PUBKEY );

    *p += len;

    /* Import E */
    if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
ROOL's avatar
ROOL committed
549
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ret ) );
ROOL's avatar
ROOL committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563

    if( ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0,
                                        NULL, 0, *p, len ) ) != 0 )
        return( MBEDTLS_ERR_PK_INVALID_PUBKEY );

    *p += len;

    if( mbedtls_rsa_complete( rsa ) != 0 ||
        mbedtls_rsa_check_pubkey( rsa ) != 0 )
    {
        return( MBEDTLS_ERR_PK_INVALID_PUBKEY );
    }

    if( *p != end )
ROOL's avatar
ROOL committed
564 565
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY,
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
ROOL's avatar
ROOL committed
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580

    return( 0 );
}
#endif /* MBEDTLS_RSA_C */

/* Get a PK algorithm identifier
 *
 *  AlgorithmIdentifier  ::=  SEQUENCE  {
 *       algorithm               OBJECT IDENTIFIER,
 *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
 */
static int pk_get_pk_alg( unsigned char **p,
                          const unsigned char *end,
                          mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params )
{
ROOL's avatar
ROOL committed
581
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
582 583 584 585 586
    mbedtls_asn1_buf alg_oid;

    memset( params, 0, sizeof(mbedtls_asn1_buf) );

    if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 )
ROOL's avatar
ROOL committed
587
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_ALG, ret ) );
ROOL's avatar
ROOL committed
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

    if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 )
        return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );

    /*
     * No parameters with RSA (only for EC)
     */
    if( *pk_alg == MBEDTLS_PK_RSA &&
            ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) ||
                params->len != 0 ) )
    {
        return( MBEDTLS_ERR_PK_INVALID_ALG );
    }

    return( 0 );
}

/*
 *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
 *       algorithm            AlgorithmIdentifier,
 *       subjectPublicKey     BIT STRING }
 */
int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end,
                        mbedtls_pk_context *pk )
{
ROOL's avatar
ROOL committed
613
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
614 615 616 617 618
    size_t len;
    mbedtls_asn1_buf alg_params;
    mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
    const mbedtls_pk_info_t *pk_info;

ROOL's avatar
ROOL committed
619 620 621 622 623
    PK_VALIDATE_RET( p != NULL );
    PK_VALIDATE_RET( *p != NULL );
    PK_VALIDATE_RET( end != NULL );
    PK_VALIDATE_RET( pk != NULL );

ROOL's avatar
ROOL committed
624 625 626
    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
    {
ROOL's avatar
ROOL committed
627
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
628 629 630 631 632 633 634 635
    }

    end = *p + len;

    if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 )
        return( ret );

    if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 )
ROOL's avatar
ROOL committed
636
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ret ) );
ROOL's avatar
ROOL committed
637 638

    if( *p + len != end )
ROOL's avatar
ROOL committed
639 640
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY,
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
ROOL's avatar
ROOL committed
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664

    if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL )
        return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );

    if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 )
        return( ret );

#if defined(MBEDTLS_RSA_C)
    if( pk_alg == MBEDTLS_PK_RSA )
    {
        ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) );
    } else
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
    if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY )
    {
        ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp );
        if( ret == 0 )
            ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) );
    } else
#endif /* MBEDTLS_ECP_C */
        ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;

    if( ret == 0 && *p != end )
ROOL's avatar
ROOL committed
665 666
        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY,
              MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
ROOL's avatar
ROOL committed
667 668 669 670 671 672 673 674

    if( ret != 0 )
        mbedtls_pk_free( pk );

    return( ret );
}

#if defined(MBEDTLS_RSA_C)
ROOL's avatar
ROOL committed
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
/*
 * Wrapper around mbedtls_asn1_get_mpi() that rejects zero.
 *
 * The value zero is:
 * - never a valid value for an RSA parameter
 * - interpreted as "omitted, please reconstruct" by mbedtls_rsa_complete().
 *
 * Since values can't be omitted in PKCS#1, passing a zero value to
 * rsa_complete() would be incorrect, so reject zero values early.
 */
static int asn1_get_nonzero_mpi( unsigned char **p,
                                 const unsigned char *end,
                                 mbedtls_mpi *X )
{
    int ret;

    ret = mbedtls_asn1_get_mpi( p, end, X );
    if( ret != 0 )
        return( ret );

    if( mbedtls_mpi_cmp_int( X, 0 ) == 0 )
        return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );

    return( 0 );
}

ROOL's avatar
ROOL committed
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
/*
 * Parse a PKCS#1 encoded private RSA key
 */
static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa,
                                   const unsigned char *key,
                                   size_t keylen )
{
    int ret, version;
    size_t len;
    unsigned char *p, *end;

    mbedtls_mpi T;
    mbedtls_mpi_init( &T );

    p = (unsigned char *) key;
    end = p + keylen;

    /*
     * This function parses the RSAPrivateKey (PKCS#1)
     *
     *  RSAPrivateKey ::= SEQUENCE {
     *      version           Version,
     *      modulus           INTEGER,  -- n
     *      publicExponent    INTEGER,  -- e
     *      privateExponent   INTEGER,  -- d
     *      prime1            INTEGER,  -- p
     *      prime2            INTEGER,  -- q
     *      exponent1         INTEGER,  -- d mod (p-1)
     *      exponent2         INTEGER,  -- d mod (q-1)
     *      coefficient       INTEGER,  -- (inverse of q) mod p
     *      otherPrimeInfos   OtherPrimeInfos OPTIONAL
     *  }
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
    {
ROOL's avatar
ROOL committed
737
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
738 739 740 741 742 743
    }

    end = p + len;

    if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 )
    {
ROOL's avatar
ROOL committed
744
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
745 746 747 748 749 750 751 752
    }

    if( version != 0 )
    {
        return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION );
    }

    /* Import N */
ROOL's avatar
ROOL committed
753 754 755
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_rsa_import( rsa, &T, NULL, NULL,
                                        NULL, NULL ) ) != 0 )
ROOL's avatar
ROOL committed
756 757 758
        goto cleanup;

    /* Import E */
ROOL's avatar
ROOL committed
759 760 761
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL,
                                        NULL, &T ) ) != 0 )
ROOL's avatar
ROOL committed
762 763 764
        goto cleanup;

    /* Import D */
ROOL's avatar
ROOL committed
765 766 767
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL,
                                        &T, NULL ) ) != 0 )
ROOL's avatar
ROOL committed
768 769 770
        goto cleanup;

    /* Import P */
ROOL's avatar
ROOL committed
771 772 773
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_rsa_import( rsa, NULL, &T, NULL,
                                        NULL, NULL ) ) != 0 )
ROOL's avatar
ROOL committed
774 775 776
        goto cleanup;

    /* Import Q */
ROOL's avatar
ROOL committed
777 778 779
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_rsa_import( rsa, NULL, NULL, &T,
                                        NULL, NULL ) ) != 0 )
ROOL's avatar
ROOL committed
780 781
        goto cleanup;

ROOL's avatar
ROOL committed
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
#if !defined(MBEDTLS_RSA_NO_CRT) && !defined(MBEDTLS_RSA_ALT)
    /*
    * The RSA CRT parameters DP, DQ and QP are nominally redundant, in
    * that they can be easily recomputed from D, P and Q. However by
    * parsing them from the PKCS1 structure it is possible to avoid
    * recalculating them which both reduces the overhead of loading
    * RSA private keys into memory and also avoids side channels which
    * can arise when computing those values, since all of D, P, and Q
    * are secret. See https://eprint.iacr.org/2020/055 for a
    * description of one such attack.
    */

    /* Import DP */
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_mpi_copy( &rsa->DP, &T ) ) != 0 )
       goto cleanup;

    /* Import DQ */
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_mpi_copy( &rsa->DQ, &T ) ) != 0 )
       goto cleanup;

    /* Import QP */
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = mbedtls_mpi_copy( &rsa->QP, &T ) ) != 0 )
       goto cleanup;

#else
ROOL's avatar
ROOL committed
810
    /* Verify existence of the CRT params */
ROOL's avatar
ROOL committed
811 812 813 814 815
    if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ||
        ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 )
       goto cleanup;
#endif
ROOL's avatar
ROOL committed
816

ROOL's avatar
ROOL committed
817 818 819 820 821 822 823 824 825 826 827 828
    /* rsa_complete() doesn't complete anything with the default
     * implementation but is still called:
     * - for the benefit of alternative implementation that may want to
     *   pre-compute stuff beyond what's provided (eg Montgomery factors)
     * - as is also sanity-checks the key
     *
     * Furthermore, we also check the public part for consistency with
     * mbedtls_pk_parse_pubkey(), as it includes size minima for example.
     */
    if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 ||
        ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 )
    {
ROOL's avatar
ROOL committed
829
        goto cleanup;
ROOL's avatar
ROOL committed
830
    }
ROOL's avatar
ROOL committed
831 832 833

    if( p != end )
    {
ROOL's avatar
ROOL committed
834 835
        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
              MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
ROOL's avatar
ROOL committed
836 837 838 839 840 841 842 843 844 845
    }

cleanup:

    mbedtls_mpi_free( &T );

    if( ret != 0 )
    {
        /* Wrap error code if it's coming from a lower level */
        if( ( ret & 0xff80 ) == 0 )
ROOL's avatar
ROOL committed
846
            ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret );
ROOL's avatar
ROOL committed
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
        else
            ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;

        mbedtls_rsa_free( rsa );
    }

    return( ret );
}
#endif /* MBEDTLS_RSA_C */

#if defined(MBEDTLS_ECP_C)
/*
 * Parse a SEC1 encoded private EC key
 */
static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck,
                                  const unsigned char *key,
                                  size_t keylen )
{
ROOL's avatar
ROOL committed
865
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
    int version, pubkey_done;
    size_t len;
    mbedtls_asn1_buf params;
    unsigned char *p = (unsigned char *) key;
    unsigned char *end = p + keylen;
    unsigned char *end2;

    /*
     * RFC 5915, or SEC1 Appendix C.4
     *
     * ECPrivateKey ::= SEQUENCE {
     *      version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
     *      privateKey     OCTET STRING,
     *      parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
     *      publicKey  [1] BIT STRING OPTIONAL
     *    }
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
    {
ROOL's avatar
ROOL committed
886
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
887 888 889 890 891
    }

    end = p + len;

    if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 )
ROOL's avatar
ROOL committed
892
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
893 894 895 896 897

    if( version != 1 )
        return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION );

    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
ROOL's avatar
ROOL committed
898
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
899 900 901 902

    if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 )
    {
        mbedtls_ecp_keypair_free( eck );
ROOL's avatar
ROOL committed
903
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
    }

    p += len;

    pubkey_done = 0;
    if( p != end )
    {
        /*
         * Is 'parameters' present?
         */
        if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
                        MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 )
        {
            if( ( ret = pk_get_ecparams( &p, p + len, &params) ) != 0 ||
                ( ret = pk_use_ecparams( &params, &eck->grp )  ) != 0 )
            {
                mbedtls_ecp_keypair_free( eck );
                return( ret );
            }
        }
        else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
        {
            mbedtls_ecp_keypair_free( eck );
ROOL's avatar
ROOL committed
927
            return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
928
        }
ROOL's avatar
ROOL committed
929
    }
ROOL's avatar
ROOL committed
930

ROOL's avatar
ROOL committed
931 932
    if( p != end )
    {
ROOL's avatar
ROOL committed
933 934 935 936 937 938 939 940 941 942
        /*
         * Is 'publickey' present? If not, or if we can't read it (eg because it
         * is compressed), create it from the private key.
         */
        if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
                        MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 )
        {
            end2 = p + len;

            if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 )
ROOL's avatar
ROOL committed
943
                return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
944 945

            if( p + len != end2 )
ROOL's avatar
ROOL committed
946 947
                return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
                        MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
ROOL's avatar
ROOL committed
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963

            if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 )
                pubkey_done = 1;
            else
            {
                /*
                 * The only acceptable failure mode of pk_get_ecpubkey() above
                 * is if the point format is not recognized.
                 */
                if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE )
                    return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
            }
        }
        else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
        {
            mbedtls_ecp_keypair_free( eck );
ROOL's avatar
ROOL committed
964
            return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
965 966 967 968 969 970 971 972
        }
    }

    if( ! pubkey_done &&
        ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G,
                                                      NULL, NULL ) ) != 0 )
    {
        mbedtls_ecp_keypair_free( eck );
ROOL's avatar
ROOL committed
973
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
    }

    if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 )
    {
        mbedtls_ecp_keypair_free( eck );
        return( ret );
    }

    return( 0 );
}
#endif /* MBEDTLS_ECP_C */

/*
 * Parse an unencrypted PKCS#8 encoded private key
 *
 * Notes:
 *
 * - This function does not own the key buffer. It is the
 *   responsibility of the caller to take care of zeroizing
 *   and freeing it after use.
 *
 * - The function is responsible for freeing the provided
 *   PK context on failure.
 *
 */
static int pk_parse_key_pkcs8_unencrypted_der(
                                    mbedtls_pk_context *pk,
                                    const unsigned char* key,
                                    size_t keylen )
{
    int ret, version;
    size_t len;
    mbedtls_asn1_buf params;
    unsigned char *p = (unsigned char *) key;
    unsigned char *end = p + keylen;
    mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
    const mbedtls_pk_info_t *pk_info;

    /*
     * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208)
     *
     *    PrivateKeyInfo ::= SEQUENCE {
     *      version                   Version,
     *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
     *      privateKey                PrivateKey,
     *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
     *
     *    Version ::= INTEGER
     *    PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
     *    PrivateKey ::= OCTET STRING
     *
     *  The PrivateKey OCTET STRING is a SEC1 ECPrivateKey
     */

    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
    {
ROOL's avatar
ROOL committed
1031
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
1032 1033 1034 1035 1036
    }

    end = p + len;

    if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 )
ROOL's avatar
ROOL committed
1037
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
1038 1039

    if( version != 0 )
ROOL's avatar
ROOL committed
1040
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_VERSION, ret ) );
ROOL's avatar
ROOL committed
1041 1042

    if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, &params ) ) != 0 )
ROOL's avatar
ROOL committed
1043
    {
ROOL's avatar
ROOL committed
1044
        return( ret );
ROOL's avatar
ROOL committed
1045
    }
ROOL's avatar
ROOL committed
1046 1047

    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
ROOL's avatar
ROOL committed
1048
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
1049 1050

    if( len < 1 )
ROOL's avatar
ROOL committed
1051 1052
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
                MBEDTLS_ERR_ASN1_OUT_OF_DATA ) );
ROOL's avatar
ROOL committed
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134

    if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL )
        return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );

    if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 )
        return( ret );

#if defined(MBEDTLS_RSA_C)
    if( pk_alg == MBEDTLS_PK_RSA )
    {
        if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 )
        {
            mbedtls_pk_free( pk );
            return( ret );
        }
    } else
#endif /* MBEDTLS_RSA_C */
#if defined(MBEDTLS_ECP_C)
    if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH )
    {
        if( ( ret = pk_use_ecparams( &params, &mbedtls_pk_ec( *pk )->grp ) ) != 0 ||
            ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len )  ) != 0 )
        {
            mbedtls_pk_free( pk );
            return( ret );
        }
    } else
#endif /* MBEDTLS_ECP_C */
        return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );

    return( 0 );
}

/*
 * Parse an encrypted PKCS#8 encoded private key
 *
 * To save space, the decryption happens in-place on the given key buffer.
 * Also, while this function may modify the keybuffer, it doesn't own it,
 * and instead it is the responsibility of the caller to zeroize and properly
 * free it after use.
 *
 */
#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
static int pk_parse_key_pkcs8_encrypted_der(
                                    mbedtls_pk_context *pk,
                                    unsigned char *key, size_t keylen,
                                    const unsigned char *pwd, size_t pwdlen )
{
    int ret, decrypted = 0;
    size_t len;
    unsigned char *buf;
    unsigned char *p, *end;
    mbedtls_asn1_buf pbe_alg_oid, pbe_params;
#if defined(MBEDTLS_PKCS12_C)
    mbedtls_cipher_type_t cipher_alg;
    mbedtls_md_type_t md_alg;
#endif

    p = key;
    end = p + keylen;

    if( pwdlen == 0 )
        return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED );

    /*
     * This function parses the EncryptedPrivateKeyInfo object (PKCS#8)
     *
     *  EncryptedPrivateKeyInfo ::= SEQUENCE {
     *    encryptionAlgorithm  EncryptionAlgorithmIdentifier,
     *    encryptedData        EncryptedData
     *  }
     *
     *  EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
     *
     *  EncryptedData ::= OCTET STRING
     *
     *  The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo
     *
     */
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
    {
ROOL's avatar
ROOL committed
1135
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
1136 1137 1138 1139 1140
    }

    end = p + len;

    if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 )
ROOL's avatar
ROOL committed
1141
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
1142 1143

    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
ROOL's avatar
ROOL committed
1144
        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret ) );
ROOL's avatar
ROOL committed
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219

    buf = p;

    /*
     * Decrypt EncryptedData with appropriate PBE
     */
#if defined(MBEDTLS_PKCS12_C)
    if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 )
    {
        if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
                                cipher_alg, md_alg,
                                pwd, pwdlen, p, len, buf ) ) != 0 )
        {
            if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH )
                return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );

            return( ret );
        }

        decrypted = 1;
    }
    else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 )
    {
        if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params,
                                             MBEDTLS_PKCS12_PBE_DECRYPT,
                                             pwd, pwdlen,
                                             p, len, buf ) ) != 0 )
        {
            return( ret );
        }

        // Best guess for password mismatch when using RC4. If first tag is
        // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
        //
        if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) )
            return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );

        decrypted = 1;
    }
    else
#endif /* MBEDTLS_PKCS12_C */
#if defined(MBEDTLS_PKCS5_C)
    if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 )
    {
        if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
                                  p, len, buf ) ) != 0 )
        {
            if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH )
                return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );

            return( ret );
        }

        decrypted = 1;
    }
    else
#endif /* MBEDTLS_PKCS5_C */
    {
        ((void) pwd);
    }

    if( decrypted == 0 )
        return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );

    return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) );
}
#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */

/*
 * Parse a private key
 */
int mbedtls_pk_parse_key( mbedtls_pk_context *pk,
                  const unsigned char *key, size_t keylen,
                  const unsigned char *pwd, size_t pwdlen )
{
ROOL's avatar
ROOL committed
1220
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
1221 1222 1223 1224
    const mbedtls_pk_info_t *pk_info;
#if defined(MBEDTLS_PEM_PARSE_C)
    size_t len;
    mbedtls_pem_context pem;
ROOL's avatar
ROOL committed
1225
#endif
ROOL's avatar
ROOL committed
1226

ROOL's avatar
ROOL committed
1227 1228 1229 1230 1231 1232 1233
    PK_VALIDATE_RET( pk != NULL );
    if( keylen == 0 )
        return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
    PK_VALIDATE_RET( key != NULL );

#if defined(MBEDTLS_PEM_PARSE_C)
   mbedtls_pem_init( &pem );
ROOL's avatar
ROOL committed
1234 1235 1236

#if defined(MBEDTLS_RSA_C)
    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
ROOL's avatar
ROOL committed
1237
    if( key[keylen - 1] != '\0' )
ROOL's avatar
ROOL committed
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
    else
        ret = mbedtls_pem_read_buffer( &pem,
                               "-----BEGIN RSA PRIVATE KEY-----",
                               "-----END RSA PRIVATE KEY-----",
                               key, pwd, pwdlen, &len );

    if( ret == 0 )
    {
        pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA );
        if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ||
            ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ),
                                            pem.buf, pem.buflen ) ) != 0 )
        {
            mbedtls_pk_free( pk );
        }

        mbedtls_pem_free( &pem );
        return( ret );
    }
    else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH )
        return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );
    else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED )
        return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED );
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
        return( ret );
#endif /* MBEDTLS_RSA_C */

#if defined(MBEDTLS_ECP_C)
    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
ROOL's avatar
ROOL committed
1268
    if( key[keylen - 1] != '\0' )
ROOL's avatar
ROOL committed
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
    else
        ret = mbedtls_pem_read_buffer( &pem,
                               "-----BEGIN EC PRIVATE KEY-----",
                               "-----END EC PRIVATE KEY-----",
                               key, pwd, pwdlen, &len );
    if( ret == 0 )
    {
        pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY );

        if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ||
            ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ),
                                           pem.buf, pem.buflen ) ) != 0 )
        {
            mbedtls_pk_free( pk );
        }

        mbedtls_pem_free( &pem );
        return( ret );
    }
    else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH )
        return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH );
    else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED )
        return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED );
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
        return( ret );
#endif /* MBEDTLS_ECP_C */

    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
ROOL's avatar
ROOL committed
1298
    if( key[keylen - 1] != '\0' )
ROOL's avatar
ROOL committed
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
    else
        ret = mbedtls_pem_read_buffer( &pem,
                               "-----BEGIN PRIVATE KEY-----",
                               "-----END PRIVATE KEY-----",
                               key, NULL, 0, &len );
    if( ret == 0 )
    {
        if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk,
                                                pem.buf, pem.buflen ) ) != 0 )
        {
            mbedtls_pk_free( pk );
        }

        mbedtls_pem_free( &pem );
        return( ret );
    }
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
        return( ret );

#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
ROOL's avatar
ROOL committed
1321
    if( key[keylen - 1] != '\0' )
ROOL's avatar
ROOL committed
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
    else
        ret = mbedtls_pem_read_buffer( &pem,
                               "-----BEGIN ENCRYPTED PRIVATE KEY-----",
                               "-----END ENCRYPTED PRIVATE KEY-----",
                               key, NULL, 0, &len );
    if( ret == 0 )
    {
        if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk,
                                                      pem.buf, pem.buflen,
                                                      pwd, pwdlen ) ) != 0 )
        {
            mbedtls_pk_free( pk );
        }

        mbedtls_pem_free( &pem );
        return( ret );
    }
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
        return( ret );
#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
#else
    ((void) pwd);
    ((void) pwdlen);
#endif /* MBEDTLS_PEM_PARSE_C */

    /*
     * At this point we only know it's not a PEM formatted key. Could be any
     * of the known DER encoded private key formats
     *
     * We try the different DER format parsers to see if one passes without
     * error
     */
#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
    {
        unsigned char *key_copy;

        if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL )
            return( MBEDTLS_ERR_PK_ALLOC_FAILED );

        memcpy( key_copy, key, keylen );

        ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen,
                                                pwd, pwdlen );

ROOL's avatar
ROOL committed
1367
        mbedtls_platform_zeroize( key_copy, keylen );
ROOL's avatar
ROOL committed
1368 1369 1370 1371 1372 1373 1374
        mbedtls_free( key_copy );
    }

    if( ret == 0 )
        return( 0 );

    mbedtls_pk_free( pk );
ROOL's avatar
ROOL committed
1375
    mbedtls_pk_init( pk );
ROOL's avatar
ROOL committed
1376 1377 1378 1379 1380 1381 1382

    if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH )
    {
        return( ret );
    }
#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */

ROOL's avatar
ROOL committed
1383 1384 1385
    ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen );
    if( ret == 0 )
    {
ROOL's avatar
ROOL committed
1386
        return( 0 );
ROOL's avatar
ROOL committed
1387
    }
ROOL's avatar
ROOL committed
1388 1389

    mbedtls_pk_free( pk );
ROOL's avatar
ROOL committed
1390
    mbedtls_pk_init( pk );
ROOL's avatar
ROOL committed
1391 1392 1393 1394

#if defined(MBEDTLS_RSA_C)

    pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA );
ROOL's avatar
ROOL committed
1395 1396
    if( mbedtls_pk_setup( pk, pk_info ) == 0 &&
        pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) == 0 )
ROOL's avatar
ROOL committed
1397 1398 1399 1400
    {
        return( 0 );
    }

ROOL's avatar
ROOL committed
1401 1402
    mbedtls_pk_free( pk );
    mbedtls_pk_init( pk );
ROOL's avatar
ROOL committed
1403 1404 1405 1406
#endif /* MBEDTLS_RSA_C */

#if defined(MBEDTLS_ECP_C)
    pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY );
ROOL's avatar
ROOL committed
1407 1408 1409
    if( mbedtls_pk_setup( pk, pk_info ) == 0 &&
        pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ),
                               key, keylen ) == 0 )
ROOL's avatar
ROOL committed
1410 1411 1412
    {
        return( 0 );
    }
ROOL's avatar
ROOL committed
1413
    mbedtls_pk_free( pk );
ROOL's avatar
ROOL committed
1414 1415
#endif /* MBEDTLS_ECP_C */

ROOL's avatar
ROOL committed
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
    /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't,
     * it is ok to leave the PK context initialized but not
     * freed: It is the caller's responsibility to call pk_init()
     * before calling this function, and to call pk_free()
     * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C
     * isn't, this leads to mbedtls_pk_free() being called
     * twice, once here and once by the caller, but this is
     * also ok and in line with the mbedtls_pk_free() calls
     * on failed PEM parsing attempts. */

ROOL's avatar
ROOL committed
1426 1427 1428 1429 1430 1431 1432 1433 1434
    return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
}

/*
 * Parse a public key
 */
int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx,
                         const unsigned char *key, size_t keylen )
{
ROOL's avatar
ROOL committed
1435
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
ROOL's avatar
ROOL committed
1436 1437 1438 1439 1440 1441 1442
    unsigned char *p;
#if defined(MBEDTLS_RSA_C)
    const mbedtls_pk_info_t *pk_info;
#endif
#if defined(MBEDTLS_PEM_PARSE_C)
    size_t len;
    mbedtls_pem_context pem;
ROOL's avatar
ROOL committed
1443 1444 1445 1446 1447 1448
#endif

    PK_VALIDATE_RET( ctx != NULL );
    if( keylen == 0 )
        return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
    PK_VALIDATE_RET( key != NULL || keylen == 0 );
ROOL's avatar
ROOL committed
1449

ROOL's avatar
ROOL committed
1450
#if defined(MBEDTLS_PEM_PARSE_C)
ROOL's avatar
ROOL committed
1451 1452 1453
    mbedtls_pem_init( &pem );
#if defined(MBEDTLS_RSA_C)
    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
ROOL's avatar
ROOL committed
1454
    if( key[keylen - 1] != '\0' )
ROOL's avatar
ROOL committed
1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
    else
        ret = mbedtls_pem_read_buffer( &pem,
                               "-----BEGIN RSA PUBLIC KEY-----",
                               "-----END RSA PUBLIC KEY-----",
                               key, NULL, 0, &len );

    if( ret == 0 )
    {
        p = pem.buf;
        if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL )
ROOL's avatar
ROOL committed
1466 1467
        {
            mbedtls_pem_free( &pem );
ROOL's avatar
ROOL committed
1468
            return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
ROOL's avatar
ROOL committed
1469
        }
ROOL's avatar
ROOL committed
1470 1471

        if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 )
ROOL's avatar
ROOL committed
1472 1473
        {
            mbedtls_pem_free( &pem );
ROOL's avatar
ROOL committed
1474
            return( ret );
ROOL's avatar
ROOL committed
1475
        }
ROOL's avatar
ROOL committed
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490

        if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 )
            mbedtls_pk_free( ctx );

        mbedtls_pem_free( &pem );
        return( ret );
    }
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
    {
        mbedtls_pem_free( &pem );
        return( ret );
    }
#endif /* MBEDTLS_RSA_C */

    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
ROOL's avatar
ROOL committed
1491
    if( key[keylen - 1] != '\0' )
ROOL's avatar
ROOL committed
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
    else
        ret = mbedtls_pem_read_buffer( &pem,
                "-----BEGIN PUBLIC KEY-----",
                "-----END PUBLIC KEY-----",
                key, NULL, 0, &len );

    if( ret == 0 )
    {
        /*
         * Was PEM encoded
         */
        p = pem.buf;

        ret = mbedtls_pk_parse_subpubkey( &p,  p + pem.buflen, ctx );
        mbedtls_pem_free( &pem );
        return( ret );
    }
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
    {
        mbedtls_pem_free( &pem );
        return( ret );
    }
    mbedtls_pem_free( &pem );
#endif /* MBEDTLS_PEM_PARSE_C */

#if defined(MBEDTLS_RSA_C)
    if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL )
        return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );

    if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 )
        return( ret );

    p = (unsigned char *)key;
    ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) );
    if( ret == 0 )
    {
        return( ret );
    }
    mbedtls_pk_free( ctx );
ROOL's avatar
ROOL committed
1532 1533
    if( ret != ( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY,
                                    MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) )
ROOL's avatar
ROOL committed
1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
    {
        return( ret );
    }
#endif /* MBEDTLS_RSA_C */
    p = (unsigned char *) key;

    ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx );

    return( ret );
}

#endif /* MBEDTLS_PK_PARSE_C */