1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * Public Key layer for parsing key files and structures 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander * 19817466cbSJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander 22817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 23817466cbSJens Wiklander #include "mbedtls/config.h" 24817466cbSJens Wiklander #else 25817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 26817466cbSJens Wiklander #endif 27817466cbSJens Wiklander 28817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_C) 29817466cbSJens Wiklander 30817466cbSJens Wiklander #include "mbedtls/pk.h" 31817466cbSJens Wiklander #include "mbedtls/asn1.h" 32817466cbSJens Wiklander #include "mbedtls/oid.h" 333d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 34*11fa71b9SJerome Forissier #include "mbedtls/error.h" 35817466cbSJens Wiklander 36817466cbSJens Wiklander #include <string.h> 37817466cbSJens Wiklander 38817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 39817466cbSJens Wiklander #include "mbedtls/rsa.h" 40817466cbSJens Wiklander #endif 41817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 42817466cbSJens Wiklander #include "mbedtls/ecp.h" 43817466cbSJens Wiklander #endif 44817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_C) 45817466cbSJens Wiklander #include "mbedtls/ecdsa.h" 46817466cbSJens Wiklander #endif 47817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 48817466cbSJens Wiklander #include "mbedtls/pem.h" 49817466cbSJens Wiklander #endif 50817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 51817466cbSJens Wiklander #include "mbedtls/pkcs5.h" 52817466cbSJens Wiklander #endif 53817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 54817466cbSJens Wiklander #include "mbedtls/pkcs12.h" 55817466cbSJens Wiklander #endif 56817466cbSJens Wiklander 57817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 58817466cbSJens Wiklander #include "mbedtls/platform.h" 59817466cbSJens Wiklander #else 60817466cbSJens Wiklander #include <stdlib.h> 61817466cbSJens Wiklander #define mbedtls_calloc calloc 62817466cbSJens Wiklander #define mbedtls_free free 63817466cbSJens Wiklander #endif 64817466cbSJens Wiklander 653d3b0591SJens Wiklander /* Parameter validation macros based on platform_util.h */ 663d3b0591SJens Wiklander #define PK_VALIDATE_RET( cond ) \ 673d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) 683d3b0591SJens Wiklander #define PK_VALIDATE( cond ) \ 693d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 70817466cbSJens Wiklander 713d3b0591SJens Wiklander #if defined(MBEDTLS_FS_IO) 72817466cbSJens Wiklander /* 73817466cbSJens Wiklander * Load all data from a file into a given buffer. 74817466cbSJens Wiklander * 75817466cbSJens Wiklander * The file is expected to contain either PEM or DER encoded data. 76817466cbSJens Wiklander * A terminating null byte is always appended. It is included in the announced 77817466cbSJens Wiklander * length only if the data looks like it is PEM encoded. 78817466cbSJens Wiklander */ 79817466cbSJens Wiklander int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) 80817466cbSJens Wiklander { 81817466cbSJens Wiklander FILE *f; 82817466cbSJens Wiklander long size; 83817466cbSJens Wiklander 843d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 853d3b0591SJens Wiklander PK_VALIDATE_RET( buf != NULL ); 863d3b0591SJens Wiklander PK_VALIDATE_RET( n != NULL ); 873d3b0591SJens Wiklander 88817466cbSJens Wiklander if( ( f = fopen( path, "rb" ) ) == NULL ) 89817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 90817466cbSJens Wiklander 91817466cbSJens Wiklander fseek( f, 0, SEEK_END ); 92817466cbSJens Wiklander if( ( size = ftell( f ) ) == -1 ) 93817466cbSJens Wiklander { 94817466cbSJens Wiklander fclose( f ); 95817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 96817466cbSJens Wiklander } 97817466cbSJens Wiklander fseek( f, 0, SEEK_SET ); 98817466cbSJens Wiklander 99817466cbSJens Wiklander *n = (size_t) size; 100817466cbSJens Wiklander 101817466cbSJens Wiklander if( *n + 1 == 0 || 102817466cbSJens Wiklander ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) 103817466cbSJens Wiklander { 104817466cbSJens Wiklander fclose( f ); 105817466cbSJens Wiklander return( MBEDTLS_ERR_PK_ALLOC_FAILED ); 106817466cbSJens Wiklander } 107817466cbSJens Wiklander 108817466cbSJens Wiklander if( fread( *buf, 1, *n, f ) != *n ) 109817466cbSJens Wiklander { 110817466cbSJens Wiklander fclose( f ); 1113d3b0591SJens Wiklander 1123d3b0591SJens Wiklander mbedtls_platform_zeroize( *buf, *n ); 113817466cbSJens Wiklander mbedtls_free( *buf ); 1143d3b0591SJens Wiklander 115817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 116817466cbSJens Wiklander } 117817466cbSJens Wiklander 118817466cbSJens Wiklander fclose( f ); 119817466cbSJens Wiklander 120817466cbSJens Wiklander (*buf)[*n] = '\0'; 121817466cbSJens Wiklander 122817466cbSJens Wiklander if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) 123817466cbSJens Wiklander ++*n; 124817466cbSJens Wiklander 125817466cbSJens Wiklander return( 0 ); 126817466cbSJens Wiklander } 127817466cbSJens Wiklander 128817466cbSJens Wiklander /* 129817466cbSJens Wiklander * Load and parse a private key 130817466cbSJens Wiklander */ 131817466cbSJens Wiklander int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, 132817466cbSJens Wiklander const char *path, const char *pwd ) 133817466cbSJens Wiklander { 134*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 135817466cbSJens Wiklander size_t n; 136817466cbSJens Wiklander unsigned char *buf; 137817466cbSJens Wiklander 1383d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 1393d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 1403d3b0591SJens Wiklander 141817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 142817466cbSJens Wiklander return( ret ); 143817466cbSJens Wiklander 144817466cbSJens Wiklander if( pwd == NULL ) 145817466cbSJens Wiklander ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); 146817466cbSJens Wiklander else 147817466cbSJens Wiklander ret = mbedtls_pk_parse_key( ctx, buf, n, 148817466cbSJens Wiklander (const unsigned char *) pwd, strlen( pwd ) ); 149817466cbSJens Wiklander 1503d3b0591SJens Wiklander mbedtls_platform_zeroize( buf, n ); 151817466cbSJens Wiklander mbedtls_free( buf ); 152817466cbSJens Wiklander 153817466cbSJens Wiklander return( ret ); 154817466cbSJens Wiklander } 155817466cbSJens Wiklander 156817466cbSJens Wiklander /* 157817466cbSJens Wiklander * Load and parse a public key 158817466cbSJens Wiklander */ 159817466cbSJens Wiklander int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) 160817466cbSJens Wiklander { 161*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 162817466cbSJens Wiklander size_t n; 163817466cbSJens Wiklander unsigned char *buf; 164817466cbSJens Wiklander 1653d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 1663d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 1673d3b0591SJens Wiklander 168817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 169817466cbSJens Wiklander return( ret ); 170817466cbSJens Wiklander 171817466cbSJens Wiklander ret = mbedtls_pk_parse_public_key( ctx, buf, n ); 172817466cbSJens Wiklander 1733d3b0591SJens Wiklander mbedtls_platform_zeroize( buf, n ); 174817466cbSJens Wiklander mbedtls_free( buf ); 175817466cbSJens Wiklander 176817466cbSJens Wiklander return( ret ); 177817466cbSJens Wiklander } 178817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 179817466cbSJens Wiklander 180817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 181817466cbSJens Wiklander /* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf 182817466cbSJens Wiklander * 183817466cbSJens Wiklander * ECParameters ::= CHOICE { 184817466cbSJens Wiklander * namedCurve OBJECT IDENTIFIER 185817466cbSJens Wiklander * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } 186817466cbSJens Wiklander * -- implicitCurve NULL 187817466cbSJens Wiklander * } 188817466cbSJens Wiklander */ 189817466cbSJens Wiklander static int pk_get_ecparams( unsigned char **p, const unsigned char *end, 190817466cbSJens Wiklander mbedtls_asn1_buf *params ) 191817466cbSJens Wiklander { 192*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 193817466cbSJens Wiklander 1943d3b0591SJens Wiklander if ( end - *p < 1 ) 1953d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 1963d3b0591SJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 1973d3b0591SJens Wiklander 198817466cbSJens Wiklander /* Tag may be either OID or SEQUENCE */ 199817466cbSJens Wiklander params->tag = **p; 200817466cbSJens Wiklander if( params->tag != MBEDTLS_ASN1_OID 201817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 202817466cbSJens Wiklander && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) 203817466cbSJens Wiklander #endif 204817466cbSJens Wiklander ) 205817466cbSJens Wiklander { 206817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 207817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 208817466cbSJens Wiklander } 209817466cbSJens Wiklander 210817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 ) 211817466cbSJens Wiklander { 212817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 213817466cbSJens Wiklander } 214817466cbSJens Wiklander 215817466cbSJens Wiklander params->p = *p; 216817466cbSJens Wiklander *p += params->len; 217817466cbSJens Wiklander 218817466cbSJens Wiklander if( *p != end ) 219817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 220817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 221817466cbSJens Wiklander 222817466cbSJens Wiklander return( 0 ); 223817466cbSJens Wiklander } 224817466cbSJens Wiklander 225817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 226817466cbSJens Wiklander /* 227817466cbSJens Wiklander * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. 228817466cbSJens Wiklander * WARNING: the resulting group should only be used with 229817466cbSJens Wiklander * pk_group_id_from_specified(), since its base point may not be set correctly 230817466cbSJens Wiklander * if it was encoded compressed. 231817466cbSJens Wiklander * 232817466cbSJens Wiklander * SpecifiedECDomain ::= SEQUENCE { 233817466cbSJens Wiklander * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), 234817466cbSJens Wiklander * fieldID FieldID {{FieldTypes}}, 235817466cbSJens Wiklander * curve Curve, 236817466cbSJens Wiklander * base ECPoint, 237817466cbSJens Wiklander * order INTEGER, 238817466cbSJens Wiklander * cofactor INTEGER OPTIONAL, 239817466cbSJens Wiklander * hash HashAlgorithm OPTIONAL, 240817466cbSJens Wiklander * ... 241817466cbSJens Wiklander * } 242817466cbSJens Wiklander * 243817466cbSJens Wiklander * We only support prime-field as field type, and ignore hash and cofactor. 244817466cbSJens Wiklander */ 245817466cbSJens Wiklander static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) 246817466cbSJens Wiklander { 247*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 248817466cbSJens Wiklander unsigned char *p = params->p; 249817466cbSJens Wiklander const unsigned char * const end = params->p + params->len; 250817466cbSJens Wiklander const unsigned char *end_field, *end_curve; 251817466cbSJens Wiklander size_t len; 252817466cbSJens Wiklander int ver; 253817466cbSJens Wiklander 254817466cbSJens Wiklander /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ 255817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) 256817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 257817466cbSJens Wiklander 258817466cbSJens Wiklander if( ver < 1 || ver > 3 ) 259817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 260817466cbSJens Wiklander 261817466cbSJens Wiklander /* 262817466cbSJens Wiklander * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field 263817466cbSJens Wiklander * fieldType FIELD-ID.&id({IOSet}), 264817466cbSJens Wiklander * parameters FIELD-ID.&Type({IOSet}{@fieldType}) 265817466cbSJens Wiklander * } 266817466cbSJens Wiklander */ 267817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 268817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 269817466cbSJens Wiklander return( ret ); 270817466cbSJens Wiklander 271817466cbSJens Wiklander end_field = p + len; 272817466cbSJens Wiklander 273817466cbSJens Wiklander /* 274817466cbSJens Wiklander * FIELD-ID ::= TYPE-IDENTIFIER 275817466cbSJens Wiklander * FieldTypes FIELD-ID ::= { 276817466cbSJens Wiklander * { Prime-p IDENTIFIED BY prime-field } | 277817466cbSJens Wiklander * { Characteristic-two IDENTIFIED BY characteristic-two-field } 278817466cbSJens Wiklander * } 279817466cbSJens Wiklander * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } 280817466cbSJens Wiklander */ 281817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) 282817466cbSJens Wiklander return( ret ); 283817466cbSJens Wiklander 284817466cbSJens Wiklander if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || 285817466cbSJens Wiklander memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) 286817466cbSJens Wiklander { 287817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 288817466cbSJens Wiklander } 289817466cbSJens Wiklander 290817466cbSJens Wiklander p += len; 291817466cbSJens Wiklander 292817466cbSJens Wiklander /* Prime-p ::= INTEGER -- Field of size p. */ 293817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) 294817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 295817466cbSJens Wiklander 296817466cbSJens Wiklander grp->pbits = mbedtls_mpi_bitlen( &grp->P ); 297817466cbSJens Wiklander 298817466cbSJens Wiklander if( p != end_field ) 299817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 300817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 301817466cbSJens Wiklander 302817466cbSJens Wiklander /* 303817466cbSJens Wiklander * Curve ::= SEQUENCE { 304817466cbSJens Wiklander * a FieldElement, 305817466cbSJens Wiklander * b FieldElement, 306817466cbSJens Wiklander * seed BIT STRING OPTIONAL 307817466cbSJens Wiklander * -- Shall be present if used in SpecifiedECDomain 308817466cbSJens Wiklander * -- with version equal to ecdpVer2 or ecdpVer3 309817466cbSJens Wiklander * } 310817466cbSJens Wiklander */ 311817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 312817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 313817466cbSJens Wiklander return( ret ); 314817466cbSJens Wiklander 315817466cbSJens Wiklander end_curve = p + len; 316817466cbSJens Wiklander 317817466cbSJens Wiklander /* 318817466cbSJens Wiklander * FieldElement ::= OCTET STRING 319817466cbSJens Wiklander * containing an integer in the case of a prime field 320817466cbSJens Wiklander */ 321817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || 322817466cbSJens Wiklander ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) 323817466cbSJens Wiklander { 324817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 325817466cbSJens Wiklander } 326817466cbSJens Wiklander 327817466cbSJens Wiklander p += len; 328817466cbSJens Wiklander 329817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || 330817466cbSJens Wiklander ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) 331817466cbSJens Wiklander { 332817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 333817466cbSJens Wiklander } 334817466cbSJens Wiklander 335817466cbSJens Wiklander p += len; 336817466cbSJens Wiklander 337817466cbSJens Wiklander /* Ignore seed BIT STRING OPTIONAL */ 338817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) 339817466cbSJens Wiklander p += len; 340817466cbSJens Wiklander 341817466cbSJens Wiklander if( p != end_curve ) 342817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 343817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 344817466cbSJens Wiklander 345817466cbSJens Wiklander /* 346817466cbSJens Wiklander * ECPoint ::= OCTET STRING 347817466cbSJens Wiklander */ 348817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 349817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 350817466cbSJens Wiklander 351817466cbSJens Wiklander if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, 352817466cbSJens Wiklander ( const unsigned char *) p, len ) ) != 0 ) 353817466cbSJens Wiklander { 354817466cbSJens Wiklander /* 355817466cbSJens Wiklander * If we can't read the point because it's compressed, cheat by 356817466cbSJens Wiklander * reading only the X coordinate and the parity bit of Y. 357817466cbSJens Wiklander */ 358817466cbSJens Wiklander if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || 359817466cbSJens Wiklander ( p[0] != 0x02 && p[0] != 0x03 ) || 360817466cbSJens Wiklander len != mbedtls_mpi_size( &grp->P ) + 1 || 361817466cbSJens Wiklander mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || 362817466cbSJens Wiklander mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || 363817466cbSJens Wiklander mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) 364817466cbSJens Wiklander { 365817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 366817466cbSJens Wiklander } 367817466cbSJens Wiklander } 368817466cbSJens Wiklander 369817466cbSJens Wiklander p += len; 370817466cbSJens Wiklander 371817466cbSJens Wiklander /* 372817466cbSJens Wiklander * order INTEGER 373817466cbSJens Wiklander */ 374817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) 375817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 376817466cbSJens Wiklander 377817466cbSJens Wiklander grp->nbits = mbedtls_mpi_bitlen( &grp->N ); 378817466cbSJens Wiklander 379817466cbSJens Wiklander /* 380817466cbSJens Wiklander * Allow optional elements by purposefully not enforcing p == end here. 381817466cbSJens Wiklander */ 382817466cbSJens Wiklander 383817466cbSJens Wiklander return( 0 ); 384817466cbSJens Wiklander } 385817466cbSJens Wiklander 386817466cbSJens Wiklander /* 387817466cbSJens Wiklander * Find the group id associated with an (almost filled) group as generated by 388817466cbSJens Wiklander * pk_group_from_specified(), or return an error if unknown. 389817466cbSJens Wiklander */ 390817466cbSJens Wiklander static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) 391817466cbSJens Wiklander { 392817466cbSJens Wiklander int ret = 0; 393817466cbSJens Wiklander mbedtls_ecp_group ref; 394817466cbSJens Wiklander const mbedtls_ecp_group_id *id; 395817466cbSJens Wiklander 396817466cbSJens Wiklander mbedtls_ecp_group_init( &ref ); 397817466cbSJens Wiklander 398817466cbSJens Wiklander for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) 399817466cbSJens Wiklander { 400817466cbSJens Wiklander /* Load the group associated to that id */ 401817466cbSJens Wiklander mbedtls_ecp_group_free( &ref ); 402817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); 403817466cbSJens Wiklander 404817466cbSJens Wiklander /* Compare to the group we were given, starting with easy tests */ 405817466cbSJens Wiklander if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && 406817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && 407817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && 408817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && 409817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && 410817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && 411817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && 412817466cbSJens Wiklander /* For Y we may only know the parity bit, so compare only that */ 413817466cbSJens Wiklander mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) 414817466cbSJens Wiklander { 415817466cbSJens Wiklander break; 416817466cbSJens Wiklander } 417817466cbSJens Wiklander 418817466cbSJens Wiklander } 419817466cbSJens Wiklander 420817466cbSJens Wiklander cleanup: 421817466cbSJens Wiklander mbedtls_ecp_group_free( &ref ); 422817466cbSJens Wiklander 423817466cbSJens Wiklander *grp_id = *id; 424817466cbSJens Wiklander 425817466cbSJens Wiklander if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) 426817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 427817466cbSJens Wiklander 428817466cbSJens Wiklander return( ret ); 429817466cbSJens Wiklander } 430817466cbSJens Wiklander 431817466cbSJens Wiklander /* 432817466cbSJens Wiklander * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID 433817466cbSJens Wiklander */ 434817466cbSJens Wiklander static int pk_group_id_from_specified( const mbedtls_asn1_buf *params, 435817466cbSJens Wiklander mbedtls_ecp_group_id *grp_id ) 436817466cbSJens Wiklander { 437*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 438817466cbSJens Wiklander mbedtls_ecp_group grp; 439817466cbSJens Wiklander 440817466cbSJens Wiklander mbedtls_ecp_group_init( &grp ); 441817466cbSJens Wiklander 442817466cbSJens Wiklander if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 ) 443817466cbSJens Wiklander goto cleanup; 444817466cbSJens Wiklander 445817466cbSJens Wiklander ret = pk_group_id_from_group( &grp, grp_id ); 446817466cbSJens Wiklander 447817466cbSJens Wiklander cleanup: 448817466cbSJens Wiklander mbedtls_ecp_group_free( &grp ); 449817466cbSJens Wiklander 450817466cbSJens Wiklander return( ret ); 451817466cbSJens Wiklander } 452817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ 453817466cbSJens Wiklander 454817466cbSJens Wiklander /* 455817466cbSJens Wiklander * Use EC parameters to initialise an EC group 456817466cbSJens Wiklander * 457817466cbSJens Wiklander * ECParameters ::= CHOICE { 458817466cbSJens Wiklander * namedCurve OBJECT IDENTIFIER 459817466cbSJens Wiklander * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } 460817466cbSJens Wiklander * -- implicitCurve NULL 461817466cbSJens Wiklander */ 462817466cbSJens Wiklander static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) 463817466cbSJens Wiklander { 464*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 465817466cbSJens Wiklander mbedtls_ecp_group_id grp_id; 466817466cbSJens Wiklander 467817466cbSJens Wiklander if( params->tag == MBEDTLS_ASN1_OID ) 468817466cbSJens Wiklander { 469817466cbSJens Wiklander if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) 470817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); 471817466cbSJens Wiklander } 472817466cbSJens Wiklander else 473817466cbSJens Wiklander { 474817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 475817466cbSJens Wiklander if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 ) 476817466cbSJens Wiklander return( ret ); 477817466cbSJens Wiklander #else 478817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 479817466cbSJens Wiklander #endif 480817466cbSJens Wiklander } 481817466cbSJens Wiklander 482817466cbSJens Wiklander /* 483817466cbSJens Wiklander * grp may already be initilialized; if so, make sure IDs match 484817466cbSJens Wiklander */ 485817466cbSJens Wiklander if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id ) 486817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 487817466cbSJens Wiklander 488817466cbSJens Wiklander if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 ) 489817466cbSJens Wiklander return( ret ); 490817466cbSJens Wiklander 491817466cbSJens Wiklander return( 0 ); 492817466cbSJens Wiklander } 493817466cbSJens Wiklander 494817466cbSJens Wiklander /* 495817466cbSJens Wiklander * EC public key is an EC point 496817466cbSJens Wiklander * 497817466cbSJens Wiklander * The caller is responsible for clearing the structure upon failure if 498817466cbSJens Wiklander * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE 499817466cbSJens Wiklander * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. 500817466cbSJens Wiklander */ 501817466cbSJens Wiklander static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, 502817466cbSJens Wiklander mbedtls_ecp_keypair *key ) 503817466cbSJens Wiklander { 504*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 505817466cbSJens Wiklander 506817466cbSJens Wiklander if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, 507817466cbSJens Wiklander (const unsigned char *) *p, end - *p ) ) == 0 ) 508817466cbSJens Wiklander { 509817466cbSJens Wiklander ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); 510817466cbSJens Wiklander } 511817466cbSJens Wiklander 512817466cbSJens Wiklander /* 513817466cbSJens Wiklander * We know mbedtls_ecp_point_read_binary consumed all bytes or failed 514817466cbSJens Wiklander */ 515817466cbSJens Wiklander *p = (unsigned char *) end; 516817466cbSJens Wiklander 517817466cbSJens Wiklander return( ret ); 518817466cbSJens Wiklander } 519817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 520817466cbSJens Wiklander 521817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 522817466cbSJens Wiklander /* 523817466cbSJens Wiklander * RSAPublicKey ::= SEQUENCE { 524817466cbSJens Wiklander * modulus INTEGER, -- n 525817466cbSJens Wiklander * publicExponent INTEGER -- e 526817466cbSJens Wiklander * } 527817466cbSJens Wiklander */ 528817466cbSJens Wiklander static int pk_get_rsapubkey( unsigned char **p, 529817466cbSJens Wiklander const unsigned char *end, 530817466cbSJens Wiklander mbedtls_rsa_context *rsa ) 531817466cbSJens Wiklander { 532*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 533817466cbSJens Wiklander size_t len; 534817466cbSJens Wiklander 535817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 536817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 537817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 538817466cbSJens Wiklander 539817466cbSJens Wiklander if( *p + len != end ) 540817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 541817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 542817466cbSJens Wiklander 5433d3b0591SJens Wiklander /* Import N */ 5443d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) 545817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 546817466cbSJens Wiklander 5473d3b0591SJens Wiklander if( ( ret = mbedtls_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0, 5483d3b0591SJens Wiklander NULL, 0, NULL, 0 ) ) != 0 ) 5493d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 5503d3b0591SJens Wiklander 5513d3b0591SJens Wiklander *p += len; 5523d3b0591SJens Wiklander 5533d3b0591SJens Wiklander /* Import E */ 5543d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) 5553d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 5563d3b0591SJens Wiklander 5573d3b0591SJens Wiklander if( ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, 5583d3b0591SJens Wiklander NULL, 0, *p, len ) ) != 0 ) 5593d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 5603d3b0591SJens Wiklander 5613d3b0591SJens Wiklander *p += len; 5623d3b0591SJens Wiklander 5633d3b0591SJens Wiklander if( mbedtls_rsa_complete( rsa ) != 0 || 5643d3b0591SJens Wiklander mbedtls_rsa_check_pubkey( rsa ) != 0 ) 5653d3b0591SJens Wiklander { 5663d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 5673d3b0591SJens Wiklander } 5683d3b0591SJens Wiklander 569817466cbSJens Wiklander if( *p != end ) 570817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 571817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 572817466cbSJens Wiklander 573817466cbSJens Wiklander return( 0 ); 574817466cbSJens Wiklander } 575817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 576817466cbSJens Wiklander 577817466cbSJens Wiklander /* Get a PK algorithm identifier 578817466cbSJens Wiklander * 579817466cbSJens Wiklander * AlgorithmIdentifier ::= SEQUENCE { 580817466cbSJens Wiklander * algorithm OBJECT IDENTIFIER, 581817466cbSJens Wiklander * parameters ANY DEFINED BY algorithm OPTIONAL } 582817466cbSJens Wiklander */ 583817466cbSJens Wiklander static int pk_get_pk_alg( unsigned char **p, 584817466cbSJens Wiklander const unsigned char *end, 585817466cbSJens Wiklander mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params ) 586817466cbSJens Wiklander { 587*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 588817466cbSJens Wiklander mbedtls_asn1_buf alg_oid; 589817466cbSJens Wiklander 590817466cbSJens Wiklander memset( params, 0, sizeof(mbedtls_asn1_buf) ); 591817466cbSJens Wiklander 592817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 ) 593817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_ALG + ret ); 594817466cbSJens Wiklander 595817466cbSJens Wiklander if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 ) 596817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 597817466cbSJens Wiklander 598817466cbSJens Wiklander /* 599817466cbSJens Wiklander * No parameters with RSA (only for EC) 600817466cbSJens Wiklander */ 601817466cbSJens Wiklander if( *pk_alg == MBEDTLS_PK_RSA && 602817466cbSJens Wiklander ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) || 603817466cbSJens Wiklander params->len != 0 ) ) 604817466cbSJens Wiklander { 605817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_ALG ); 606817466cbSJens Wiklander } 607817466cbSJens Wiklander 608817466cbSJens Wiklander return( 0 ); 609817466cbSJens Wiklander } 610817466cbSJens Wiklander 611817466cbSJens Wiklander /* 612817466cbSJens Wiklander * SubjectPublicKeyInfo ::= SEQUENCE { 613817466cbSJens Wiklander * algorithm AlgorithmIdentifier, 614817466cbSJens Wiklander * subjectPublicKey BIT STRING } 615817466cbSJens Wiklander */ 616817466cbSJens Wiklander int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, 617817466cbSJens Wiklander mbedtls_pk_context *pk ) 618817466cbSJens Wiklander { 619*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 620817466cbSJens Wiklander size_t len; 621817466cbSJens Wiklander mbedtls_asn1_buf alg_params; 622817466cbSJens Wiklander mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; 623817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 624817466cbSJens Wiklander 6253d3b0591SJens Wiklander PK_VALIDATE_RET( p != NULL ); 6263d3b0591SJens Wiklander PK_VALIDATE_RET( *p != NULL ); 6273d3b0591SJens Wiklander PK_VALIDATE_RET( end != NULL ); 6283d3b0591SJens Wiklander PK_VALIDATE_RET( pk != NULL ); 6293d3b0591SJens Wiklander 630817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 631817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 632817466cbSJens Wiklander { 633817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 634817466cbSJens Wiklander } 635817466cbSJens Wiklander 636817466cbSJens Wiklander end = *p + len; 637817466cbSJens Wiklander 638817466cbSJens Wiklander if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 ) 639817466cbSJens Wiklander return( ret ); 640817466cbSJens Wiklander 641817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) 642817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 643817466cbSJens Wiklander 644817466cbSJens Wiklander if( *p + len != end ) 645817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 646817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 647817466cbSJens Wiklander 648817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) 649817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 650817466cbSJens Wiklander 651817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) 652817466cbSJens Wiklander return( ret ); 653817466cbSJens Wiklander 654817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 655817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA ) 656817466cbSJens Wiklander { 657817466cbSJens Wiklander ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) ); 658817466cbSJens Wiklander } else 659817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 660817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 661817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY ) 662817466cbSJens Wiklander { 663817466cbSJens Wiklander ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp ); 664817466cbSJens Wiklander if( ret == 0 ) 665817466cbSJens Wiklander ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) ); 666817466cbSJens Wiklander } else 667817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 668817466cbSJens Wiklander ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; 669817466cbSJens Wiklander 670817466cbSJens Wiklander if( ret == 0 && *p != end ) 671817466cbSJens Wiklander ret = MBEDTLS_ERR_PK_INVALID_PUBKEY 672817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; 673817466cbSJens Wiklander 674817466cbSJens Wiklander if( ret != 0 ) 675817466cbSJens Wiklander mbedtls_pk_free( pk ); 676817466cbSJens Wiklander 677817466cbSJens Wiklander return( ret ); 678817466cbSJens Wiklander } 679817466cbSJens Wiklander 680817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 681817466cbSJens Wiklander /* 6825b25c76aSJerome Forissier * Wrapper around mbedtls_asn1_get_mpi() that rejects zero. 6835b25c76aSJerome Forissier * 6845b25c76aSJerome Forissier * The value zero is: 6855b25c76aSJerome Forissier * - never a valid value for an RSA parameter 6865b25c76aSJerome Forissier * - interpreted as "omitted, please reconstruct" by mbedtls_rsa_complete(). 6875b25c76aSJerome Forissier * 6885b25c76aSJerome Forissier * Since values can't be omitted in PKCS#1, passing a zero value to 6895b25c76aSJerome Forissier * rsa_complete() would be incorrect, so reject zero values early. 6905b25c76aSJerome Forissier */ 6915b25c76aSJerome Forissier static int asn1_get_nonzero_mpi( unsigned char **p, 6925b25c76aSJerome Forissier const unsigned char *end, 6935b25c76aSJerome Forissier mbedtls_mpi *X ) 6945b25c76aSJerome Forissier { 6955b25c76aSJerome Forissier int ret; 6965b25c76aSJerome Forissier 6975b25c76aSJerome Forissier ret = mbedtls_asn1_get_mpi( p, end, X ); 6985b25c76aSJerome Forissier if( ret != 0 ) 6995b25c76aSJerome Forissier return( ret ); 7005b25c76aSJerome Forissier 7015b25c76aSJerome Forissier if( mbedtls_mpi_cmp_int( X, 0 ) == 0 ) 7025b25c76aSJerome Forissier return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 7035b25c76aSJerome Forissier 7045b25c76aSJerome Forissier return( 0 ); 7055b25c76aSJerome Forissier } 7065b25c76aSJerome Forissier 7075b25c76aSJerome Forissier /* 708817466cbSJens Wiklander * Parse a PKCS#1 encoded private RSA key 709817466cbSJens Wiklander */ 710817466cbSJens Wiklander static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, 711817466cbSJens Wiklander const unsigned char *key, 712817466cbSJens Wiklander size_t keylen ) 713817466cbSJens Wiklander { 7143d3b0591SJens Wiklander int ret, version; 715817466cbSJens Wiklander size_t len; 716817466cbSJens Wiklander unsigned char *p, *end; 717817466cbSJens Wiklander 7183d3b0591SJens Wiklander mbedtls_mpi T; 7193d3b0591SJens Wiklander mbedtls_mpi_init( &T ); 7203d3b0591SJens Wiklander 721817466cbSJens Wiklander p = (unsigned char *) key; 722817466cbSJens Wiklander end = p + keylen; 723817466cbSJens Wiklander 724817466cbSJens Wiklander /* 725817466cbSJens Wiklander * This function parses the RSAPrivateKey (PKCS#1) 726817466cbSJens Wiklander * 727817466cbSJens Wiklander * RSAPrivateKey ::= SEQUENCE { 728817466cbSJens Wiklander * version Version, 729817466cbSJens Wiklander * modulus INTEGER, -- n 730817466cbSJens Wiklander * publicExponent INTEGER, -- e 731817466cbSJens Wiklander * privateExponent INTEGER, -- d 732817466cbSJens Wiklander * prime1 INTEGER, -- p 733817466cbSJens Wiklander * prime2 INTEGER, -- q 734817466cbSJens Wiklander * exponent1 INTEGER, -- d mod (p-1) 735817466cbSJens Wiklander * exponent2 INTEGER, -- d mod (q-1) 736817466cbSJens Wiklander * coefficient INTEGER, -- (inverse of q) mod p 737817466cbSJens Wiklander * otherPrimeInfos OtherPrimeInfos OPTIONAL 738817466cbSJens Wiklander * } 739817466cbSJens Wiklander */ 740817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 741817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 742817466cbSJens Wiklander { 743817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 744817466cbSJens Wiklander } 745817466cbSJens Wiklander 746817466cbSJens Wiklander end = p + len; 747817466cbSJens Wiklander 7483d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 749817466cbSJens Wiklander { 750817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 751817466cbSJens Wiklander } 752817466cbSJens Wiklander 7533d3b0591SJens Wiklander if( version != 0 ) 754817466cbSJens Wiklander { 755817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 756817466cbSJens Wiklander } 757817466cbSJens Wiklander 7583d3b0591SJens Wiklander /* Import N */ 7595b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 7605b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, &T, NULL, NULL, 7615b25c76aSJerome Forissier NULL, NULL ) ) != 0 ) 7623d3b0591SJens Wiklander goto cleanup; 763817466cbSJens Wiklander 7643d3b0591SJens Wiklander /* Import E */ 7655b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 7665b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL, 7675b25c76aSJerome Forissier NULL, &T ) ) != 0 ) 7683d3b0591SJens Wiklander goto cleanup; 7693d3b0591SJens Wiklander 7703d3b0591SJens Wiklander /* Import D */ 7715b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 7725b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL, 7735b25c76aSJerome Forissier &T, NULL ) ) != 0 ) 7743d3b0591SJens Wiklander goto cleanup; 7753d3b0591SJens Wiklander 7763d3b0591SJens Wiklander /* Import P */ 7775b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 7785b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, &T, NULL, 7795b25c76aSJerome Forissier NULL, NULL ) ) != 0 ) 7803d3b0591SJens Wiklander goto cleanup; 7813d3b0591SJens Wiklander 7823d3b0591SJens Wiklander /* Import Q */ 7835b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 7845b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, NULL, &T, 7855b25c76aSJerome Forissier NULL, NULL ) ) != 0 ) 7863d3b0591SJens Wiklander goto cleanup; 7873d3b0591SJens Wiklander 7885b25c76aSJerome Forissier #if !defined(MBEDTLS_RSA_NO_CRT) && !defined(MBEDTLS_RSA_ALT) 7895b25c76aSJerome Forissier /* 7905b25c76aSJerome Forissier * The RSA CRT parameters DP, DQ and QP are nominally redundant, in 7915b25c76aSJerome Forissier * that they can be easily recomputed from D, P and Q. However by 7925b25c76aSJerome Forissier * parsing them from the PKCS1 structure it is possible to avoid 7935b25c76aSJerome Forissier * recalculating them which both reduces the overhead of loading 7945b25c76aSJerome Forissier * RSA private keys into memory and also avoids side channels which 7955b25c76aSJerome Forissier * can arise when computing those values, since all of D, P, and Q 7965b25c76aSJerome Forissier * are secret. See https://eprint.iacr.org/2020/055 for a 7975b25c76aSJerome Forissier * description of one such attack. 7985b25c76aSJerome Forissier */ 7995b25c76aSJerome Forissier 8005b25c76aSJerome Forissier /* Import DP */ 8015b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 8025b25c76aSJerome Forissier ( ret = mbedtls_mpi_copy( &rsa->DP, &T ) ) != 0 ) 8033d3b0591SJens Wiklander goto cleanup; 804817466cbSJens Wiklander 8055b25c76aSJerome Forissier /* Import DQ */ 8065b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 8075b25c76aSJerome Forissier ( ret = mbedtls_mpi_copy( &rsa->DQ, &T ) ) != 0 ) 8085b25c76aSJerome Forissier goto cleanup; 8095b25c76aSJerome Forissier 8105b25c76aSJerome Forissier /* Import QP */ 8115b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 8125b25c76aSJerome Forissier ( ret = mbedtls_mpi_copy( &rsa->QP, &T ) ) != 0 ) 8135b25c76aSJerome Forissier goto cleanup; 8145b25c76aSJerome Forissier 8155b25c76aSJerome Forissier #else 8165b25c76aSJerome Forissier /* Verify existance of the CRT params */ 8175b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 8185b25c76aSJerome Forissier ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 8195b25c76aSJerome Forissier ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ) 8205b25c76aSJerome Forissier goto cleanup; 8215b25c76aSJerome Forissier #endif 8225b25c76aSJerome Forissier 8235b25c76aSJerome Forissier /* rsa_complete() doesn't complete anything with the default 8245b25c76aSJerome Forissier * implementation but is still called: 8255b25c76aSJerome Forissier * - for the benefit of alternative implementation that may want to 8265b25c76aSJerome Forissier * pre-compute stuff beyond what's provided (eg Montgomery factors) 8275b25c76aSJerome Forissier * - as is also sanity-checks the key 8285b25c76aSJerome Forissier * 8295b25c76aSJerome Forissier * Furthermore, we also check the public part for consistency with 8305b25c76aSJerome Forissier * mbedtls_pk_parse_pubkey(), as it includes size minima for example. 8315b25c76aSJerome Forissier */ 8325b25c76aSJerome Forissier if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 || 8335b25c76aSJerome Forissier ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 ) 8345b25c76aSJerome Forissier { 8355b25c76aSJerome Forissier goto cleanup; 8365b25c76aSJerome Forissier } 8375b25c76aSJerome Forissier 838817466cbSJens Wiklander if( p != end ) 839817466cbSJens Wiklander { 8403d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 8413d3b0591SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ; 842817466cbSJens Wiklander } 843817466cbSJens Wiklander 8443d3b0591SJens Wiklander cleanup: 8453d3b0591SJens Wiklander 8463d3b0591SJens Wiklander mbedtls_mpi_free( &T ); 8473d3b0591SJens Wiklander 8483d3b0591SJens Wiklander if( ret != 0 ) 849817466cbSJens Wiklander { 8503d3b0591SJens Wiklander /* Wrap error code if it's coming from a lower level */ 8513d3b0591SJens Wiklander if( ( ret & 0xff80 ) == 0 ) 8523d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret; 8533d3b0591SJens Wiklander else 8543d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; 8553d3b0591SJens Wiklander 856817466cbSJens Wiklander mbedtls_rsa_free( rsa ); 857817466cbSJens Wiklander } 858817466cbSJens Wiklander 8593d3b0591SJens Wiklander return( ret ); 860817466cbSJens Wiklander } 861817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 862817466cbSJens Wiklander 863817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 864817466cbSJens Wiklander /* 865817466cbSJens Wiklander * Parse a SEC1 encoded private EC key 866817466cbSJens Wiklander */ 867817466cbSJens Wiklander static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, 868817466cbSJens Wiklander const unsigned char *key, 869817466cbSJens Wiklander size_t keylen ) 870817466cbSJens Wiklander { 871*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 872817466cbSJens Wiklander int version, pubkey_done; 873817466cbSJens Wiklander size_t len; 874817466cbSJens Wiklander mbedtls_asn1_buf params; 875817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 876817466cbSJens Wiklander unsigned char *end = p + keylen; 877817466cbSJens Wiklander unsigned char *end2; 878817466cbSJens Wiklander 879817466cbSJens Wiklander /* 880817466cbSJens Wiklander * RFC 5915, or SEC1 Appendix C.4 881817466cbSJens Wiklander * 882817466cbSJens Wiklander * ECPrivateKey ::= SEQUENCE { 883817466cbSJens Wiklander * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), 884817466cbSJens Wiklander * privateKey OCTET STRING, 885817466cbSJens Wiklander * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, 886817466cbSJens Wiklander * publicKey [1] BIT STRING OPTIONAL 887817466cbSJens Wiklander * } 888817466cbSJens Wiklander */ 889817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 890817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 891817466cbSJens Wiklander { 892817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 893817466cbSJens Wiklander } 894817466cbSJens Wiklander 895817466cbSJens Wiklander end = p + len; 896817466cbSJens Wiklander 897817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 898817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 899817466cbSJens Wiklander 900817466cbSJens Wiklander if( version != 1 ) 901817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 902817466cbSJens Wiklander 903817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 904817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 905817466cbSJens Wiklander 906817466cbSJens Wiklander if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) 907817466cbSJens Wiklander { 908817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 909817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 910817466cbSJens Wiklander } 911817466cbSJens Wiklander 912817466cbSJens Wiklander p += len; 913817466cbSJens Wiklander 914817466cbSJens Wiklander pubkey_done = 0; 915817466cbSJens Wiklander if( p != end ) 916817466cbSJens Wiklander { 917817466cbSJens Wiklander /* 918817466cbSJens Wiklander * Is 'parameters' present? 919817466cbSJens Wiklander */ 920817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 921817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) 922817466cbSJens Wiklander { 923817466cbSJens Wiklander if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || 924817466cbSJens Wiklander ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) 925817466cbSJens Wiklander { 926817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 927817466cbSJens Wiklander return( ret ); 928817466cbSJens Wiklander } 929817466cbSJens Wiklander } 930817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 931817466cbSJens Wiklander { 932817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 933817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 934817466cbSJens Wiklander } 9353d3b0591SJens Wiklander } 936817466cbSJens Wiklander 9373d3b0591SJens Wiklander if( p != end ) 9383d3b0591SJens Wiklander { 939817466cbSJens Wiklander /* 940817466cbSJens Wiklander * Is 'publickey' present? If not, or if we can't read it (eg because it 941817466cbSJens Wiklander * is compressed), create it from the private key. 942817466cbSJens Wiklander */ 943817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 944817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) 945817466cbSJens Wiklander { 946817466cbSJens Wiklander end2 = p + len; 947817466cbSJens Wiklander 948817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) 949817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 950817466cbSJens Wiklander 951817466cbSJens Wiklander if( p + len != end2 ) 952817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 953817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 954817466cbSJens Wiklander 955817466cbSJens Wiklander if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) 956817466cbSJens Wiklander pubkey_done = 1; 957817466cbSJens Wiklander else 958817466cbSJens Wiklander { 959817466cbSJens Wiklander /* 960817466cbSJens Wiklander * The only acceptable failure mode of pk_get_ecpubkey() above 961817466cbSJens Wiklander * is if the point format is not recognized. 962817466cbSJens Wiklander */ 963817466cbSJens Wiklander if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) 964817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 965817466cbSJens Wiklander } 966817466cbSJens Wiklander } 967817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 968817466cbSJens Wiklander { 969817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 970817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 971817466cbSJens Wiklander } 972817466cbSJens Wiklander } 973817466cbSJens Wiklander 974817466cbSJens Wiklander if( ! pubkey_done && 975817466cbSJens Wiklander ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, 976817466cbSJens Wiklander NULL, NULL ) ) != 0 ) 977817466cbSJens Wiklander { 978817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 979817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 980817466cbSJens Wiklander } 981817466cbSJens Wiklander 982817466cbSJens Wiklander if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) 983817466cbSJens Wiklander { 984817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 985817466cbSJens Wiklander return( ret ); 986817466cbSJens Wiklander } 987817466cbSJens Wiklander 988817466cbSJens Wiklander return( 0 ); 989817466cbSJens Wiklander } 990817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 991817466cbSJens Wiklander 992817466cbSJens Wiklander /* 993817466cbSJens Wiklander * Parse an unencrypted PKCS#8 encoded private key 9943d3b0591SJens Wiklander * 9953d3b0591SJens Wiklander * Notes: 9963d3b0591SJens Wiklander * 9973d3b0591SJens Wiklander * - This function does not own the key buffer. It is the 9983d3b0591SJens Wiklander * responsibility of the caller to take care of zeroizing 9993d3b0591SJens Wiklander * and freeing it after use. 10003d3b0591SJens Wiklander * 10013d3b0591SJens Wiklander * - The function is responsible for freeing the provided 10023d3b0591SJens Wiklander * PK context on failure. 10033d3b0591SJens Wiklander * 1004817466cbSJens Wiklander */ 1005817466cbSJens Wiklander static int pk_parse_key_pkcs8_unencrypted_der( 1006817466cbSJens Wiklander mbedtls_pk_context *pk, 1007817466cbSJens Wiklander const unsigned char* key, 1008817466cbSJens Wiklander size_t keylen ) 1009817466cbSJens Wiklander { 1010817466cbSJens Wiklander int ret, version; 1011817466cbSJens Wiklander size_t len; 1012817466cbSJens Wiklander mbedtls_asn1_buf params; 1013817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 1014817466cbSJens Wiklander unsigned char *end = p + keylen; 1015817466cbSJens Wiklander mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; 1016817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 1017817466cbSJens Wiklander 1018817466cbSJens Wiklander /* 10193d3b0591SJens Wiklander * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208) 1020817466cbSJens Wiklander * 1021817466cbSJens Wiklander * PrivateKeyInfo ::= SEQUENCE { 1022817466cbSJens Wiklander * version Version, 1023817466cbSJens Wiklander * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 1024817466cbSJens Wiklander * privateKey PrivateKey, 1025817466cbSJens Wiklander * attributes [0] IMPLICIT Attributes OPTIONAL } 1026817466cbSJens Wiklander * 1027817466cbSJens Wiklander * Version ::= INTEGER 1028817466cbSJens Wiklander * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier 1029817466cbSJens Wiklander * PrivateKey ::= OCTET STRING 1030817466cbSJens Wiklander * 1031817466cbSJens Wiklander * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey 1032817466cbSJens Wiklander */ 1033817466cbSJens Wiklander 1034817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1035817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1036817466cbSJens Wiklander { 1037817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1038817466cbSJens Wiklander } 1039817466cbSJens Wiklander 1040817466cbSJens Wiklander end = p + len; 1041817466cbSJens Wiklander 1042817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 1043817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1044817466cbSJens Wiklander 1045817466cbSJens Wiklander if( version != 0 ) 1046817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); 1047817466cbSJens Wiklander 1048817466cbSJens Wiklander if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) 1049817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1050817466cbSJens Wiklander 1051817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 1052817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1053817466cbSJens Wiklander 1054817466cbSJens Wiklander if( len < 1 ) 1055817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 1056817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 1057817466cbSJens Wiklander 1058817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) 1059817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1060817466cbSJens Wiklander 1061817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) 1062817466cbSJens Wiklander return( ret ); 1063817466cbSJens Wiklander 1064817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1065817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA ) 1066817466cbSJens Wiklander { 1067817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) 1068817466cbSJens Wiklander { 1069817466cbSJens Wiklander mbedtls_pk_free( pk ); 1070817466cbSJens Wiklander return( ret ); 1071817466cbSJens Wiklander } 1072817466cbSJens Wiklander } else 1073817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1074817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1075817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) 1076817466cbSJens Wiklander { 1077817466cbSJens Wiklander if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || 1078817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) 1079817466cbSJens Wiklander { 1080817466cbSJens Wiklander mbedtls_pk_free( pk ); 1081817466cbSJens Wiklander return( ret ); 1082817466cbSJens Wiklander } 1083817466cbSJens Wiklander } else 1084817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1085817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1086817466cbSJens Wiklander 1087817466cbSJens Wiklander return( 0 ); 1088817466cbSJens Wiklander } 1089817466cbSJens Wiklander 1090817466cbSJens Wiklander /* 1091817466cbSJens Wiklander * Parse an encrypted PKCS#8 encoded private key 10923d3b0591SJens Wiklander * 10933d3b0591SJens Wiklander * To save space, the decryption happens in-place on the given key buffer. 10943d3b0591SJens Wiklander * Also, while this function may modify the keybuffer, it doesn't own it, 10953d3b0591SJens Wiklander * and instead it is the responsibility of the caller to zeroize and properly 10963d3b0591SJens Wiklander * free it after use. 10973d3b0591SJens Wiklander * 1098817466cbSJens Wiklander */ 1099817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1100817466cbSJens Wiklander static int pk_parse_key_pkcs8_encrypted_der( 1101817466cbSJens Wiklander mbedtls_pk_context *pk, 11023d3b0591SJens Wiklander unsigned char *key, size_t keylen, 1103817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 1104817466cbSJens Wiklander { 1105817466cbSJens Wiklander int ret, decrypted = 0; 1106817466cbSJens Wiklander size_t len; 11073d3b0591SJens Wiklander unsigned char *buf; 1108817466cbSJens Wiklander unsigned char *p, *end; 1109817466cbSJens Wiklander mbedtls_asn1_buf pbe_alg_oid, pbe_params; 1110817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 1111817466cbSJens Wiklander mbedtls_cipher_type_t cipher_alg; 1112817466cbSJens Wiklander mbedtls_md_type_t md_alg; 1113817466cbSJens Wiklander #endif 1114817466cbSJens Wiklander 11153d3b0591SJens Wiklander p = key; 1116817466cbSJens Wiklander end = p + keylen; 1117817466cbSJens Wiklander 1118817466cbSJens Wiklander if( pwdlen == 0 ) 1119817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1120817466cbSJens Wiklander 1121817466cbSJens Wiklander /* 11223d3b0591SJens Wiklander * This function parses the EncryptedPrivateKeyInfo object (PKCS#8) 1123817466cbSJens Wiklander * 1124817466cbSJens Wiklander * EncryptedPrivateKeyInfo ::= SEQUENCE { 1125817466cbSJens Wiklander * encryptionAlgorithm EncryptionAlgorithmIdentifier, 1126817466cbSJens Wiklander * encryptedData EncryptedData 1127817466cbSJens Wiklander * } 1128817466cbSJens Wiklander * 1129817466cbSJens Wiklander * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier 1130817466cbSJens Wiklander * 1131817466cbSJens Wiklander * EncryptedData ::= OCTET STRING 1132817466cbSJens Wiklander * 1133817466cbSJens Wiklander * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo 11343d3b0591SJens Wiklander * 1135817466cbSJens Wiklander */ 1136817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1137817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1138817466cbSJens Wiklander { 1139817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1140817466cbSJens Wiklander } 1141817466cbSJens Wiklander 1142817466cbSJens Wiklander end = p + len; 1143817466cbSJens Wiklander 1144817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) 1145817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1146817466cbSJens Wiklander 1147817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 1148817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1149817466cbSJens Wiklander 11503d3b0591SJens Wiklander buf = p; 1151817466cbSJens Wiklander 1152817466cbSJens Wiklander /* 11533d3b0591SJens Wiklander * Decrypt EncryptedData with appropriate PBE 1154817466cbSJens Wiklander */ 1155817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 1156817466cbSJens Wiklander if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) 1157817466cbSJens Wiklander { 1158817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, 1159817466cbSJens Wiklander cipher_alg, md_alg, 1160817466cbSJens Wiklander pwd, pwdlen, p, len, buf ) ) != 0 ) 1161817466cbSJens Wiklander { 1162817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) 1163817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1164817466cbSJens Wiklander 1165817466cbSJens Wiklander return( ret ); 1166817466cbSJens Wiklander } 1167817466cbSJens Wiklander 1168817466cbSJens Wiklander decrypted = 1; 1169817466cbSJens Wiklander } 1170817466cbSJens Wiklander else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) 1171817466cbSJens Wiklander { 1172817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, 1173817466cbSJens Wiklander MBEDTLS_PKCS12_PBE_DECRYPT, 1174817466cbSJens Wiklander pwd, pwdlen, 1175817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1176817466cbSJens Wiklander { 1177817466cbSJens Wiklander return( ret ); 1178817466cbSJens Wiklander } 1179817466cbSJens Wiklander 1180817466cbSJens Wiklander // Best guess for password mismatch when using RC4. If first tag is 1181817466cbSJens Wiklander // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE 1182817466cbSJens Wiklander // 1183817466cbSJens Wiklander if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) 1184817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1185817466cbSJens Wiklander 1186817466cbSJens Wiklander decrypted = 1; 1187817466cbSJens Wiklander } 1188817466cbSJens Wiklander else 1189817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C */ 1190817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 1191817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) 1192817466cbSJens Wiklander { 1193817466cbSJens Wiklander if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, 1194817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1195817466cbSJens Wiklander { 1196817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) 1197817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1198817466cbSJens Wiklander 1199817466cbSJens Wiklander return( ret ); 1200817466cbSJens Wiklander } 1201817466cbSJens Wiklander 1202817466cbSJens Wiklander decrypted = 1; 1203817466cbSJens Wiklander } 1204817466cbSJens Wiklander else 1205817466cbSJens Wiklander #endif /* MBEDTLS_PKCS5_C */ 1206817466cbSJens Wiklander { 1207817466cbSJens Wiklander ((void) pwd); 1208817466cbSJens Wiklander } 1209817466cbSJens Wiklander 1210817466cbSJens Wiklander if( decrypted == 0 ) 1211817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 1212817466cbSJens Wiklander 1213817466cbSJens Wiklander return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); 1214817466cbSJens Wiklander } 1215817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1216817466cbSJens Wiklander 1217817466cbSJens Wiklander /* 1218817466cbSJens Wiklander * Parse a private key 1219817466cbSJens Wiklander */ 1220817466cbSJens Wiklander int mbedtls_pk_parse_key( mbedtls_pk_context *pk, 1221817466cbSJens Wiklander const unsigned char *key, size_t keylen, 1222817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 1223817466cbSJens Wiklander { 1224*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1225817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 1226817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1227817466cbSJens Wiklander size_t len; 1228817466cbSJens Wiklander mbedtls_pem_context pem; 12293d3b0591SJens Wiklander #endif 1230817466cbSJens Wiklander 12313d3b0591SJens Wiklander PK_VALIDATE_RET( pk != NULL ); 12323d3b0591SJens Wiklander if( keylen == 0 ) 12333d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 12343d3b0591SJens Wiklander PK_VALIDATE_RET( key != NULL ); 12353d3b0591SJens Wiklander 12363d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1237817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1238817466cbSJens Wiklander 1239817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1240817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 12413d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1242817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1243817466cbSJens Wiklander else 1244817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1245817466cbSJens Wiklander "-----BEGIN RSA PRIVATE KEY-----", 1246817466cbSJens Wiklander "-----END RSA PRIVATE KEY-----", 1247817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1248817466cbSJens Wiklander 1249817466cbSJens Wiklander if( ret == 0 ) 1250817466cbSJens Wiklander { 12513d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); 1252817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1253817466cbSJens Wiklander ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), 1254817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1255817466cbSJens Wiklander { 1256817466cbSJens Wiklander mbedtls_pk_free( pk ); 1257817466cbSJens Wiklander } 1258817466cbSJens Wiklander 1259817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1260817466cbSJens Wiklander return( ret ); 1261817466cbSJens Wiklander } 1262817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1263817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1264817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1265817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1266817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1267817466cbSJens Wiklander return( ret ); 1268817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1269817466cbSJens Wiklander 1270817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1271817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 12723d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1273817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1274817466cbSJens Wiklander else 1275817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1276817466cbSJens Wiklander "-----BEGIN EC PRIVATE KEY-----", 1277817466cbSJens Wiklander "-----END EC PRIVATE KEY-----", 1278817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1279817466cbSJens Wiklander if( ret == 0 ) 1280817466cbSJens Wiklander { 12813d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); 1282817466cbSJens Wiklander 1283817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1284817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), 1285817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1286817466cbSJens Wiklander { 1287817466cbSJens Wiklander mbedtls_pk_free( pk ); 1288817466cbSJens Wiklander } 1289817466cbSJens Wiklander 1290817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1291817466cbSJens Wiklander return( ret ); 1292817466cbSJens Wiklander } 1293817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1294817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1295817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1296817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1297817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1298817466cbSJens Wiklander return( ret ); 1299817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1300817466cbSJens Wiklander 1301817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 13023d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1303817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1304817466cbSJens Wiklander else 1305817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1306817466cbSJens Wiklander "-----BEGIN PRIVATE KEY-----", 1307817466cbSJens Wiklander "-----END PRIVATE KEY-----", 1308817466cbSJens Wiklander key, NULL, 0, &len ); 1309817466cbSJens Wiklander if( ret == 0 ) 1310817466cbSJens Wiklander { 1311817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, 1312817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1313817466cbSJens Wiklander { 1314817466cbSJens Wiklander mbedtls_pk_free( pk ); 1315817466cbSJens Wiklander } 1316817466cbSJens Wiklander 1317817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1318817466cbSJens Wiklander return( ret ); 1319817466cbSJens Wiklander } 1320817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1321817466cbSJens Wiklander return( ret ); 1322817466cbSJens Wiklander 1323817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1324817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 13253d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1326817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1327817466cbSJens Wiklander else 1328817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1329817466cbSJens Wiklander "-----BEGIN ENCRYPTED PRIVATE KEY-----", 1330817466cbSJens Wiklander "-----END ENCRYPTED PRIVATE KEY-----", 1331817466cbSJens Wiklander key, NULL, 0, &len ); 1332817466cbSJens Wiklander if( ret == 0 ) 1333817466cbSJens Wiklander { 1334817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, 1335817466cbSJens Wiklander pem.buf, pem.buflen, 1336817466cbSJens Wiklander pwd, pwdlen ) ) != 0 ) 1337817466cbSJens Wiklander { 1338817466cbSJens Wiklander mbedtls_pk_free( pk ); 1339817466cbSJens Wiklander } 1340817466cbSJens Wiklander 1341817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1342817466cbSJens Wiklander return( ret ); 1343817466cbSJens Wiklander } 1344817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1345817466cbSJens Wiklander return( ret ); 1346817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1347817466cbSJens Wiklander #else 1348817466cbSJens Wiklander ((void) pwd); 1349817466cbSJens Wiklander ((void) pwdlen); 1350817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1351817466cbSJens Wiklander 1352817466cbSJens Wiklander /* 1353817466cbSJens Wiklander * At this point we only know it's not a PEM formatted key. Could be any 1354817466cbSJens Wiklander * of the known DER encoded private key formats 1355817466cbSJens Wiklander * 1356817466cbSJens Wiklander * We try the different DER format parsers to see if one passes without 1357817466cbSJens Wiklander * error 1358817466cbSJens Wiklander */ 1359817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1360817466cbSJens Wiklander { 13613d3b0591SJens Wiklander unsigned char *key_copy; 13623d3b0591SJens Wiklander 13633d3b0591SJens Wiklander if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL ) 13643d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_ALLOC_FAILED ); 13653d3b0591SJens Wiklander 13663d3b0591SJens Wiklander memcpy( key_copy, key, keylen ); 13673d3b0591SJens Wiklander 13683d3b0591SJens Wiklander ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen, 13693d3b0591SJens Wiklander pwd, pwdlen ); 13703d3b0591SJens Wiklander 13713d3b0591SJens Wiklander mbedtls_platform_zeroize( key_copy, keylen ); 13723d3b0591SJens Wiklander mbedtls_free( key_copy ); 1373817466cbSJens Wiklander } 1374817466cbSJens Wiklander 13753d3b0591SJens Wiklander if( ret == 0 ) 13763d3b0591SJens Wiklander return( 0 ); 13773d3b0591SJens Wiklander 1378817466cbSJens Wiklander mbedtls_pk_free( pk ); 13793d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1380817466cbSJens Wiklander 1381817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) 1382817466cbSJens Wiklander { 1383817466cbSJens Wiklander return( ret ); 1384817466cbSJens Wiklander } 1385817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1386817466cbSJens Wiklander 1387817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) 1388817466cbSJens Wiklander return( 0 ); 1389817466cbSJens Wiklander 1390817466cbSJens Wiklander mbedtls_pk_free( pk ); 13913d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1392817466cbSJens Wiklander 1393817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1394817466cbSJens Wiklander 13953d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); 13963d3b0591SJens Wiklander if( mbedtls_pk_setup( pk, pk_info ) == 0 && 13973d3b0591SJens Wiklander pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) == 0 ) 1398817466cbSJens Wiklander { 1399817466cbSJens Wiklander return( 0 ); 1400817466cbSJens Wiklander } 1401817466cbSJens Wiklander 1402817466cbSJens Wiklander mbedtls_pk_free( pk ); 14033d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1404817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1405817466cbSJens Wiklander 1406817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 14073d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); 14083d3b0591SJens Wiklander if( mbedtls_pk_setup( pk, pk_info ) == 0 && 14093d3b0591SJens Wiklander pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), 14103d3b0591SJens Wiklander key, keylen ) == 0 ) 1411817466cbSJens Wiklander { 1412817466cbSJens Wiklander return( 0 ); 1413817466cbSJens Wiklander } 1414817466cbSJens Wiklander mbedtls_pk_free( pk ); 1415817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1416817466cbSJens Wiklander 14173d3b0591SJens Wiklander /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't, 14183d3b0591SJens Wiklander * it is ok to leave the PK context initialized but not 14193d3b0591SJens Wiklander * freed: It is the caller's responsibility to call pk_init() 14203d3b0591SJens Wiklander * before calling this function, and to call pk_free() 14213d3b0591SJens Wiklander * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C 14223d3b0591SJens Wiklander * isn't, this leads to mbedtls_pk_free() being called 14233d3b0591SJens Wiklander * twice, once here and once by the caller, but this is 14243d3b0591SJens Wiklander * also ok and in line with the mbedtls_pk_free() calls 14253d3b0591SJens Wiklander * on failed PEM parsing attempts. */ 14263d3b0591SJens Wiklander 1427817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 1428817466cbSJens Wiklander } 1429817466cbSJens Wiklander 1430817466cbSJens Wiklander /* 1431817466cbSJens Wiklander * Parse a public key 1432817466cbSJens Wiklander */ 1433817466cbSJens Wiklander int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, 1434817466cbSJens Wiklander const unsigned char *key, size_t keylen ) 1435817466cbSJens Wiklander { 1436*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1437817466cbSJens Wiklander unsigned char *p; 14383d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 14393d3b0591SJens Wiklander const mbedtls_pk_info_t *pk_info; 14403d3b0591SJens Wiklander #endif 1441817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1442817466cbSJens Wiklander size_t len; 1443817466cbSJens Wiklander mbedtls_pem_context pem; 14443d3b0591SJens Wiklander #endif 1445817466cbSJens Wiklander 14463d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 14473d3b0591SJens Wiklander if( keylen == 0 ) 14483d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 14493d3b0591SJens Wiklander PK_VALIDATE_RET( key != NULL || keylen == 0 ); 14503d3b0591SJens Wiklander 14513d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1452817466cbSJens Wiklander mbedtls_pem_init( &pem ); 14533d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 14543d3b0591SJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 14553d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 14563d3b0591SJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 14573d3b0591SJens Wiklander else 14583d3b0591SJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 14593d3b0591SJens Wiklander "-----BEGIN RSA PUBLIC KEY-----", 14603d3b0591SJens Wiklander "-----END RSA PUBLIC KEY-----", 14613d3b0591SJens Wiklander key, NULL, 0, &len ); 14623d3b0591SJens Wiklander 14633d3b0591SJens Wiklander if( ret == 0 ) 14643d3b0591SJens Wiklander { 14653d3b0591SJens Wiklander p = pem.buf; 14663d3b0591SJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 14673d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 14683d3b0591SJens Wiklander 14693d3b0591SJens Wiklander if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) 14703d3b0591SJens Wiklander return( ret ); 14713d3b0591SJens Wiklander 14723d3b0591SJens Wiklander if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 ) 14733d3b0591SJens Wiklander mbedtls_pk_free( ctx ); 14743d3b0591SJens Wiklander 14753d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 14763d3b0591SJens Wiklander return( ret ); 14773d3b0591SJens Wiklander } 14783d3b0591SJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 14793d3b0591SJens Wiklander { 14803d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 14813d3b0591SJens Wiklander return( ret ); 14823d3b0591SJens Wiklander } 14833d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */ 1484817466cbSJens Wiklander 1485817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 14863d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1487817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1488817466cbSJens Wiklander else 1489817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1490817466cbSJens Wiklander "-----BEGIN PUBLIC KEY-----", 1491817466cbSJens Wiklander "-----END PUBLIC KEY-----", 1492817466cbSJens Wiklander key, NULL, 0, &len ); 1493817466cbSJens Wiklander 1494817466cbSJens Wiklander if( ret == 0 ) 1495817466cbSJens Wiklander { 1496817466cbSJens Wiklander /* 1497817466cbSJens Wiklander * Was PEM encoded 1498817466cbSJens Wiklander */ 14993d3b0591SJens Wiklander p = pem.buf; 15003d3b0591SJens Wiklander 15013d3b0591SJens Wiklander ret = mbedtls_pk_parse_subpubkey( &p, p + pem.buflen, ctx ); 15023d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 15033d3b0591SJens Wiklander return( ret ); 1504817466cbSJens Wiklander } 1505817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1506817466cbSJens Wiklander { 1507817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1508817466cbSJens Wiklander return( ret ); 1509817466cbSJens Wiklander } 15103d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 1511817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 15123d3b0591SJens Wiklander 15133d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 15143d3b0591SJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 15153d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 15163d3b0591SJens Wiklander 15173d3b0591SJens Wiklander if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) 15183d3b0591SJens Wiklander return( ret ); 15193d3b0591SJens Wiklander 15203d3b0591SJens Wiklander p = (unsigned char *)key; 15213d3b0591SJens Wiklander ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) ); 15223d3b0591SJens Wiklander if( ret == 0 ) 15233d3b0591SJens Wiklander { 15243d3b0591SJens Wiklander return( ret ); 15253d3b0591SJens Wiklander } 15263d3b0591SJens Wiklander mbedtls_pk_free( ctx ); 15273d3b0591SJens Wiklander if( ret != ( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) 15283d3b0591SJens Wiklander { 15293d3b0591SJens Wiklander return( ret ); 15303d3b0591SJens Wiklander } 15313d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */ 1532817466cbSJens Wiklander p = (unsigned char *) key; 1533817466cbSJens Wiklander 1534817466cbSJens Wiklander ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); 1535817466cbSJens Wiklander 1536817466cbSJens Wiklander return( ret ); 1537817466cbSJens Wiklander } 1538817466cbSJens Wiklander 1539817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_C */ 1540