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" 34817466cbSJens Wiklander 35817466cbSJens Wiklander #include <string.h> 36817466cbSJens Wiklander 37817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 38817466cbSJens Wiklander #include "mbedtls/rsa.h" 39817466cbSJens Wiklander #endif 40817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 41817466cbSJens Wiklander #include "mbedtls/ecp.h" 42817466cbSJens Wiklander #endif 43817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_C) 44817466cbSJens Wiklander #include "mbedtls/ecdsa.h" 45817466cbSJens Wiklander #endif 46817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 47817466cbSJens Wiklander #include "mbedtls/pem.h" 48817466cbSJens Wiklander #endif 49817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 50817466cbSJens Wiklander #include "mbedtls/pkcs5.h" 51817466cbSJens Wiklander #endif 52817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 53817466cbSJens Wiklander #include "mbedtls/pkcs12.h" 54817466cbSJens Wiklander #endif 55817466cbSJens Wiklander 56817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 57817466cbSJens Wiklander #include "mbedtls/platform.h" 58817466cbSJens Wiklander #else 59817466cbSJens Wiklander #include <stdlib.h> 60817466cbSJens Wiklander #define mbedtls_calloc calloc 61817466cbSJens Wiklander #define mbedtls_free free 62817466cbSJens Wiklander #endif 63817466cbSJens Wiklander 643d3b0591SJens Wiklander /* Parameter validation macros based on platform_util.h */ 653d3b0591SJens Wiklander #define PK_VALIDATE_RET( cond ) \ 663d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) 673d3b0591SJens Wiklander #define PK_VALIDATE( cond ) \ 683d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 69817466cbSJens Wiklander 703d3b0591SJens Wiklander #if defined(MBEDTLS_FS_IO) 71817466cbSJens Wiklander /* 72817466cbSJens Wiklander * Load all data from a file into a given buffer. 73817466cbSJens Wiklander * 74817466cbSJens Wiklander * The file is expected to contain either PEM or DER encoded data. 75817466cbSJens Wiklander * A terminating null byte is always appended. It is included in the announced 76817466cbSJens Wiklander * length only if the data looks like it is PEM encoded. 77817466cbSJens Wiklander */ 78817466cbSJens Wiklander int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) 79817466cbSJens Wiklander { 80817466cbSJens Wiklander FILE *f; 81817466cbSJens Wiklander long size; 82817466cbSJens Wiklander 833d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 843d3b0591SJens Wiklander PK_VALIDATE_RET( buf != NULL ); 853d3b0591SJens Wiklander PK_VALIDATE_RET( n != NULL ); 863d3b0591SJens Wiklander 87817466cbSJens Wiklander if( ( f = fopen( path, "rb" ) ) == NULL ) 88817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 89817466cbSJens Wiklander 90817466cbSJens Wiklander fseek( f, 0, SEEK_END ); 91817466cbSJens Wiklander if( ( size = ftell( f ) ) == -1 ) 92817466cbSJens Wiklander { 93817466cbSJens Wiklander fclose( f ); 94817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 95817466cbSJens Wiklander } 96817466cbSJens Wiklander fseek( f, 0, SEEK_SET ); 97817466cbSJens Wiklander 98817466cbSJens Wiklander *n = (size_t) size; 99817466cbSJens Wiklander 100817466cbSJens Wiklander if( *n + 1 == 0 || 101817466cbSJens Wiklander ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) 102817466cbSJens Wiklander { 103817466cbSJens Wiklander fclose( f ); 104817466cbSJens Wiklander return( MBEDTLS_ERR_PK_ALLOC_FAILED ); 105817466cbSJens Wiklander } 106817466cbSJens Wiklander 107817466cbSJens Wiklander if( fread( *buf, 1, *n, f ) != *n ) 108817466cbSJens Wiklander { 109817466cbSJens Wiklander fclose( f ); 1103d3b0591SJens Wiklander 1113d3b0591SJens Wiklander mbedtls_platform_zeroize( *buf, *n ); 112817466cbSJens Wiklander mbedtls_free( *buf ); 1133d3b0591SJens Wiklander 114817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 115817466cbSJens Wiklander } 116817466cbSJens Wiklander 117817466cbSJens Wiklander fclose( f ); 118817466cbSJens Wiklander 119817466cbSJens Wiklander (*buf)[*n] = '\0'; 120817466cbSJens Wiklander 121817466cbSJens Wiklander if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) 122817466cbSJens Wiklander ++*n; 123817466cbSJens Wiklander 124817466cbSJens Wiklander return( 0 ); 125817466cbSJens Wiklander } 126817466cbSJens Wiklander 127817466cbSJens Wiklander /* 128817466cbSJens Wiklander * Load and parse a private key 129817466cbSJens Wiklander */ 130817466cbSJens Wiklander int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, 131817466cbSJens Wiklander const char *path, const char *pwd ) 132817466cbSJens Wiklander { 133817466cbSJens Wiklander int ret; 134817466cbSJens Wiklander size_t n; 135817466cbSJens Wiklander unsigned char *buf; 136817466cbSJens Wiklander 1373d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 1383d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 1393d3b0591SJens Wiklander 140817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 141817466cbSJens Wiklander return( ret ); 142817466cbSJens Wiklander 143817466cbSJens Wiklander if( pwd == NULL ) 144817466cbSJens Wiklander ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); 145817466cbSJens Wiklander else 146817466cbSJens Wiklander ret = mbedtls_pk_parse_key( ctx, buf, n, 147817466cbSJens Wiklander (const unsigned char *) pwd, strlen( pwd ) ); 148817466cbSJens Wiklander 1493d3b0591SJens Wiklander mbedtls_platform_zeroize( buf, n ); 150817466cbSJens Wiklander mbedtls_free( buf ); 151817466cbSJens Wiklander 152817466cbSJens Wiklander return( ret ); 153817466cbSJens Wiklander } 154817466cbSJens Wiklander 155817466cbSJens Wiklander /* 156817466cbSJens Wiklander * Load and parse a public key 157817466cbSJens Wiklander */ 158817466cbSJens Wiklander int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) 159817466cbSJens Wiklander { 160817466cbSJens Wiklander int ret; 161817466cbSJens Wiklander size_t n; 162817466cbSJens Wiklander unsigned char *buf; 163817466cbSJens Wiklander 1643d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 1653d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 1663d3b0591SJens Wiklander 167817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 168817466cbSJens Wiklander return( ret ); 169817466cbSJens Wiklander 170817466cbSJens Wiklander ret = mbedtls_pk_parse_public_key( ctx, buf, n ); 171817466cbSJens Wiklander 1723d3b0591SJens Wiklander mbedtls_platform_zeroize( buf, n ); 173817466cbSJens Wiklander mbedtls_free( buf ); 174817466cbSJens Wiklander 175817466cbSJens Wiklander return( ret ); 176817466cbSJens Wiklander } 177817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 178817466cbSJens Wiklander 179817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 180817466cbSJens Wiklander /* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf 181817466cbSJens Wiklander * 182817466cbSJens Wiklander * ECParameters ::= CHOICE { 183817466cbSJens Wiklander * namedCurve OBJECT IDENTIFIER 184817466cbSJens Wiklander * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } 185817466cbSJens Wiklander * -- implicitCurve NULL 186817466cbSJens Wiklander * } 187817466cbSJens Wiklander */ 188817466cbSJens Wiklander static int pk_get_ecparams( unsigned char **p, const unsigned char *end, 189817466cbSJens Wiklander mbedtls_asn1_buf *params ) 190817466cbSJens Wiklander { 191817466cbSJens Wiklander int ret; 192817466cbSJens Wiklander 1933d3b0591SJens Wiklander if ( end - *p < 1 ) 1943d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 1953d3b0591SJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 1963d3b0591SJens Wiklander 197817466cbSJens Wiklander /* Tag may be either OID or SEQUENCE */ 198817466cbSJens Wiklander params->tag = **p; 199817466cbSJens Wiklander if( params->tag != MBEDTLS_ASN1_OID 200817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 201817466cbSJens Wiklander && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) 202817466cbSJens Wiklander #endif 203817466cbSJens Wiklander ) 204817466cbSJens Wiklander { 205817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 206817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 207817466cbSJens Wiklander } 208817466cbSJens Wiklander 209817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 ) 210817466cbSJens Wiklander { 211817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 212817466cbSJens Wiklander } 213817466cbSJens Wiklander 214817466cbSJens Wiklander params->p = *p; 215817466cbSJens Wiklander *p += params->len; 216817466cbSJens Wiklander 217817466cbSJens Wiklander if( *p != end ) 218817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 219817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 220817466cbSJens Wiklander 221817466cbSJens Wiklander return( 0 ); 222817466cbSJens Wiklander } 223817466cbSJens Wiklander 224817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 225817466cbSJens Wiklander /* 226817466cbSJens Wiklander * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. 227817466cbSJens Wiklander * WARNING: the resulting group should only be used with 228817466cbSJens Wiklander * pk_group_id_from_specified(), since its base point may not be set correctly 229817466cbSJens Wiklander * if it was encoded compressed. 230817466cbSJens Wiklander * 231817466cbSJens Wiklander * SpecifiedECDomain ::= SEQUENCE { 232817466cbSJens Wiklander * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), 233817466cbSJens Wiklander * fieldID FieldID {{FieldTypes}}, 234817466cbSJens Wiklander * curve Curve, 235817466cbSJens Wiklander * base ECPoint, 236817466cbSJens Wiklander * order INTEGER, 237817466cbSJens Wiklander * cofactor INTEGER OPTIONAL, 238817466cbSJens Wiklander * hash HashAlgorithm OPTIONAL, 239817466cbSJens Wiklander * ... 240817466cbSJens Wiklander * } 241817466cbSJens Wiklander * 242817466cbSJens Wiklander * We only support prime-field as field type, and ignore hash and cofactor. 243817466cbSJens Wiklander */ 244817466cbSJens Wiklander static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) 245817466cbSJens Wiklander { 246817466cbSJens Wiklander int ret; 247817466cbSJens Wiklander unsigned char *p = params->p; 248817466cbSJens Wiklander const unsigned char * const end = params->p + params->len; 249817466cbSJens Wiklander const unsigned char *end_field, *end_curve; 250817466cbSJens Wiklander size_t len; 251817466cbSJens Wiklander int ver; 252817466cbSJens Wiklander 253817466cbSJens Wiklander /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ 254817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) 255817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 256817466cbSJens Wiklander 257817466cbSJens Wiklander if( ver < 1 || ver > 3 ) 258817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 259817466cbSJens Wiklander 260817466cbSJens Wiklander /* 261817466cbSJens Wiklander * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field 262817466cbSJens Wiklander * fieldType FIELD-ID.&id({IOSet}), 263817466cbSJens Wiklander * parameters FIELD-ID.&Type({IOSet}{@fieldType}) 264817466cbSJens Wiklander * } 265817466cbSJens Wiklander */ 266817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 267817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 268817466cbSJens Wiklander return( ret ); 269817466cbSJens Wiklander 270817466cbSJens Wiklander end_field = p + len; 271817466cbSJens Wiklander 272817466cbSJens Wiklander /* 273817466cbSJens Wiklander * FIELD-ID ::= TYPE-IDENTIFIER 274817466cbSJens Wiklander * FieldTypes FIELD-ID ::= { 275817466cbSJens Wiklander * { Prime-p IDENTIFIED BY prime-field } | 276817466cbSJens Wiklander * { Characteristic-two IDENTIFIED BY characteristic-two-field } 277817466cbSJens Wiklander * } 278817466cbSJens Wiklander * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } 279817466cbSJens Wiklander */ 280817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) 281817466cbSJens Wiklander return( ret ); 282817466cbSJens Wiklander 283817466cbSJens Wiklander if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || 284817466cbSJens Wiklander memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) 285817466cbSJens Wiklander { 286817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 287817466cbSJens Wiklander } 288817466cbSJens Wiklander 289817466cbSJens Wiklander p += len; 290817466cbSJens Wiklander 291817466cbSJens Wiklander /* Prime-p ::= INTEGER -- Field of size p. */ 292817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) 293817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 294817466cbSJens Wiklander 295817466cbSJens Wiklander grp->pbits = mbedtls_mpi_bitlen( &grp->P ); 296817466cbSJens Wiklander 297817466cbSJens Wiklander if( p != end_field ) 298817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 299817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 300817466cbSJens Wiklander 301817466cbSJens Wiklander /* 302817466cbSJens Wiklander * Curve ::= SEQUENCE { 303817466cbSJens Wiklander * a FieldElement, 304817466cbSJens Wiklander * b FieldElement, 305817466cbSJens Wiklander * seed BIT STRING OPTIONAL 306817466cbSJens Wiklander * -- Shall be present if used in SpecifiedECDomain 307817466cbSJens Wiklander * -- with version equal to ecdpVer2 or ecdpVer3 308817466cbSJens Wiklander * } 309817466cbSJens Wiklander */ 310817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 311817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 312817466cbSJens Wiklander return( ret ); 313817466cbSJens Wiklander 314817466cbSJens Wiklander end_curve = p + len; 315817466cbSJens Wiklander 316817466cbSJens Wiklander /* 317817466cbSJens Wiklander * FieldElement ::= OCTET STRING 318817466cbSJens Wiklander * containing an integer in the case of a prime field 319817466cbSJens Wiklander */ 320817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || 321817466cbSJens Wiklander ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) 322817466cbSJens Wiklander { 323817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 324817466cbSJens Wiklander } 325817466cbSJens Wiklander 326817466cbSJens Wiklander p += len; 327817466cbSJens Wiklander 328817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || 329817466cbSJens Wiklander ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) 330817466cbSJens Wiklander { 331817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 332817466cbSJens Wiklander } 333817466cbSJens Wiklander 334817466cbSJens Wiklander p += len; 335817466cbSJens Wiklander 336817466cbSJens Wiklander /* Ignore seed BIT STRING OPTIONAL */ 337817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) 338817466cbSJens Wiklander p += len; 339817466cbSJens Wiklander 340817466cbSJens Wiklander if( p != end_curve ) 341817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 342817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 343817466cbSJens Wiklander 344817466cbSJens Wiklander /* 345817466cbSJens Wiklander * ECPoint ::= OCTET STRING 346817466cbSJens Wiklander */ 347817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 348817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 349817466cbSJens Wiklander 350817466cbSJens Wiklander if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, 351817466cbSJens Wiklander ( const unsigned char *) p, len ) ) != 0 ) 352817466cbSJens Wiklander { 353817466cbSJens Wiklander /* 354817466cbSJens Wiklander * If we can't read the point because it's compressed, cheat by 355817466cbSJens Wiklander * reading only the X coordinate and the parity bit of Y. 356817466cbSJens Wiklander */ 357817466cbSJens Wiklander if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || 358817466cbSJens Wiklander ( p[0] != 0x02 && p[0] != 0x03 ) || 359817466cbSJens Wiklander len != mbedtls_mpi_size( &grp->P ) + 1 || 360817466cbSJens Wiklander mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || 361817466cbSJens Wiklander mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || 362817466cbSJens Wiklander mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) 363817466cbSJens Wiklander { 364817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 365817466cbSJens Wiklander } 366817466cbSJens Wiklander } 367817466cbSJens Wiklander 368817466cbSJens Wiklander p += len; 369817466cbSJens Wiklander 370817466cbSJens Wiklander /* 371817466cbSJens Wiklander * order INTEGER 372817466cbSJens Wiklander */ 373817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) 374817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 375817466cbSJens Wiklander 376817466cbSJens Wiklander grp->nbits = mbedtls_mpi_bitlen( &grp->N ); 377817466cbSJens Wiklander 378817466cbSJens Wiklander /* 379817466cbSJens Wiklander * Allow optional elements by purposefully not enforcing p == end here. 380817466cbSJens Wiklander */ 381817466cbSJens Wiklander 382817466cbSJens Wiklander return( 0 ); 383817466cbSJens Wiklander } 384817466cbSJens Wiklander 385817466cbSJens Wiklander /* 386817466cbSJens Wiklander * Find the group id associated with an (almost filled) group as generated by 387817466cbSJens Wiklander * pk_group_from_specified(), or return an error if unknown. 388817466cbSJens Wiklander */ 389817466cbSJens Wiklander static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) 390817466cbSJens Wiklander { 391817466cbSJens Wiklander int ret = 0; 392817466cbSJens Wiklander mbedtls_ecp_group ref; 393817466cbSJens Wiklander const mbedtls_ecp_group_id *id; 394817466cbSJens Wiklander 395817466cbSJens Wiklander mbedtls_ecp_group_init( &ref ); 396817466cbSJens Wiklander 397817466cbSJens Wiklander for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) 398817466cbSJens Wiklander { 399817466cbSJens Wiklander /* Load the group associated to that id */ 400817466cbSJens Wiklander mbedtls_ecp_group_free( &ref ); 401817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); 402817466cbSJens Wiklander 403817466cbSJens Wiklander /* Compare to the group we were given, starting with easy tests */ 404817466cbSJens Wiklander if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && 405817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && 406817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && 407817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && 408817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && 409817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && 410817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && 411817466cbSJens Wiklander /* For Y we may only know the parity bit, so compare only that */ 412817466cbSJens Wiklander mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) 413817466cbSJens Wiklander { 414817466cbSJens Wiklander break; 415817466cbSJens Wiklander } 416817466cbSJens Wiklander 417817466cbSJens Wiklander } 418817466cbSJens Wiklander 419817466cbSJens Wiklander cleanup: 420817466cbSJens Wiklander mbedtls_ecp_group_free( &ref ); 421817466cbSJens Wiklander 422817466cbSJens Wiklander *grp_id = *id; 423817466cbSJens Wiklander 424817466cbSJens Wiklander if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) 425817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 426817466cbSJens Wiklander 427817466cbSJens Wiklander return( ret ); 428817466cbSJens Wiklander } 429817466cbSJens Wiklander 430817466cbSJens Wiklander /* 431817466cbSJens Wiklander * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID 432817466cbSJens Wiklander */ 433817466cbSJens Wiklander static int pk_group_id_from_specified( const mbedtls_asn1_buf *params, 434817466cbSJens Wiklander mbedtls_ecp_group_id *grp_id ) 435817466cbSJens Wiklander { 436817466cbSJens Wiklander int ret; 437817466cbSJens Wiklander mbedtls_ecp_group grp; 438817466cbSJens Wiklander 439817466cbSJens Wiklander mbedtls_ecp_group_init( &grp ); 440817466cbSJens Wiklander 441817466cbSJens Wiklander if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 ) 442817466cbSJens Wiklander goto cleanup; 443817466cbSJens Wiklander 444817466cbSJens Wiklander ret = pk_group_id_from_group( &grp, grp_id ); 445817466cbSJens Wiklander 446817466cbSJens Wiklander cleanup: 447817466cbSJens Wiklander mbedtls_ecp_group_free( &grp ); 448817466cbSJens Wiklander 449817466cbSJens Wiklander return( ret ); 450817466cbSJens Wiklander } 451817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ 452817466cbSJens Wiklander 453817466cbSJens Wiklander /* 454817466cbSJens Wiklander * Use EC parameters to initialise an EC group 455817466cbSJens Wiklander * 456817466cbSJens Wiklander * ECParameters ::= CHOICE { 457817466cbSJens Wiklander * namedCurve OBJECT IDENTIFIER 458817466cbSJens Wiklander * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } 459817466cbSJens Wiklander * -- implicitCurve NULL 460817466cbSJens Wiklander */ 461817466cbSJens Wiklander static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) 462817466cbSJens Wiklander { 463817466cbSJens Wiklander int ret; 464817466cbSJens Wiklander mbedtls_ecp_group_id grp_id; 465817466cbSJens Wiklander 466817466cbSJens Wiklander if( params->tag == MBEDTLS_ASN1_OID ) 467817466cbSJens Wiklander { 468817466cbSJens Wiklander if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) 469817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); 470817466cbSJens Wiklander } 471817466cbSJens Wiklander else 472817466cbSJens Wiklander { 473817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 474817466cbSJens Wiklander if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 ) 475817466cbSJens Wiklander return( ret ); 476817466cbSJens Wiklander #else 477817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 478817466cbSJens Wiklander #endif 479817466cbSJens Wiklander } 480817466cbSJens Wiklander 481817466cbSJens Wiklander /* 482817466cbSJens Wiklander * grp may already be initilialized; if so, make sure IDs match 483817466cbSJens Wiklander */ 484817466cbSJens Wiklander if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id ) 485817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 486817466cbSJens Wiklander 487817466cbSJens Wiklander if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 ) 488817466cbSJens Wiklander return( ret ); 489817466cbSJens Wiklander 490817466cbSJens Wiklander return( 0 ); 491817466cbSJens Wiklander } 492817466cbSJens Wiklander 493817466cbSJens Wiklander /* 494817466cbSJens Wiklander * EC public key is an EC point 495817466cbSJens Wiklander * 496817466cbSJens Wiklander * The caller is responsible for clearing the structure upon failure if 497817466cbSJens Wiklander * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE 498817466cbSJens Wiklander * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. 499817466cbSJens Wiklander */ 500817466cbSJens Wiklander static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, 501817466cbSJens Wiklander mbedtls_ecp_keypair *key ) 502817466cbSJens Wiklander { 503817466cbSJens Wiklander int ret; 504817466cbSJens Wiklander 505817466cbSJens Wiklander if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, 506817466cbSJens Wiklander (const unsigned char *) *p, end - *p ) ) == 0 ) 507817466cbSJens Wiklander { 508817466cbSJens Wiklander ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); 509817466cbSJens Wiklander } 510817466cbSJens Wiklander 511817466cbSJens Wiklander /* 512817466cbSJens Wiklander * We know mbedtls_ecp_point_read_binary consumed all bytes or failed 513817466cbSJens Wiklander */ 514817466cbSJens Wiklander *p = (unsigned char *) end; 515817466cbSJens Wiklander 516817466cbSJens Wiklander return( ret ); 517817466cbSJens Wiklander } 518817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 519817466cbSJens Wiklander 520817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 521817466cbSJens Wiklander /* 522817466cbSJens Wiklander * RSAPublicKey ::= SEQUENCE { 523817466cbSJens Wiklander * modulus INTEGER, -- n 524817466cbSJens Wiklander * publicExponent INTEGER -- e 525817466cbSJens Wiklander * } 526817466cbSJens Wiklander */ 527817466cbSJens Wiklander static int pk_get_rsapubkey( unsigned char **p, 528817466cbSJens Wiklander const unsigned char *end, 529817466cbSJens Wiklander mbedtls_rsa_context *rsa ) 530817466cbSJens Wiklander { 531817466cbSJens Wiklander int ret; 532817466cbSJens Wiklander size_t len; 533817466cbSJens Wiklander 534817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 535817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 536817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 537817466cbSJens Wiklander 538817466cbSJens Wiklander if( *p + len != end ) 539817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 540817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 541817466cbSJens Wiklander 5423d3b0591SJens Wiklander /* Import N */ 5433d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) 544817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 545817466cbSJens Wiklander 5463d3b0591SJens Wiklander if( ( ret = mbedtls_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0, 5473d3b0591SJens Wiklander NULL, 0, NULL, 0 ) ) != 0 ) 5483d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 5493d3b0591SJens Wiklander 5503d3b0591SJens Wiklander *p += len; 5513d3b0591SJens Wiklander 5523d3b0591SJens Wiklander /* Import E */ 5533d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) 5543d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 5553d3b0591SJens Wiklander 5563d3b0591SJens Wiklander if( ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, 5573d3b0591SJens Wiklander NULL, 0, *p, len ) ) != 0 ) 5583d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 5593d3b0591SJens Wiklander 5603d3b0591SJens Wiklander *p += len; 5613d3b0591SJens Wiklander 5623d3b0591SJens Wiklander if( mbedtls_rsa_complete( rsa ) != 0 || 5633d3b0591SJens Wiklander mbedtls_rsa_check_pubkey( rsa ) != 0 ) 5643d3b0591SJens Wiklander { 5653d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 5663d3b0591SJens Wiklander } 5673d3b0591SJens Wiklander 568817466cbSJens Wiklander if( *p != end ) 569817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 570817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 571817466cbSJens Wiklander 572817466cbSJens Wiklander return( 0 ); 573817466cbSJens Wiklander } 574817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 575817466cbSJens Wiklander 576817466cbSJens Wiklander /* Get a PK algorithm identifier 577817466cbSJens Wiklander * 578817466cbSJens Wiklander * AlgorithmIdentifier ::= SEQUENCE { 579817466cbSJens Wiklander * algorithm OBJECT IDENTIFIER, 580817466cbSJens Wiklander * parameters ANY DEFINED BY algorithm OPTIONAL } 581817466cbSJens Wiklander */ 582817466cbSJens Wiklander static int pk_get_pk_alg( unsigned char **p, 583817466cbSJens Wiklander const unsigned char *end, 584817466cbSJens Wiklander mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params ) 585817466cbSJens Wiklander { 586817466cbSJens Wiklander int ret; 587817466cbSJens Wiklander mbedtls_asn1_buf alg_oid; 588817466cbSJens Wiklander 589817466cbSJens Wiklander memset( params, 0, sizeof(mbedtls_asn1_buf) ); 590817466cbSJens Wiklander 591817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 ) 592817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_ALG + ret ); 593817466cbSJens Wiklander 594817466cbSJens Wiklander if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 ) 595817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 596817466cbSJens Wiklander 597817466cbSJens Wiklander /* 598817466cbSJens Wiklander * No parameters with RSA (only for EC) 599817466cbSJens Wiklander */ 600817466cbSJens Wiklander if( *pk_alg == MBEDTLS_PK_RSA && 601817466cbSJens Wiklander ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) || 602817466cbSJens Wiklander params->len != 0 ) ) 603817466cbSJens Wiklander { 604817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_ALG ); 605817466cbSJens Wiklander } 606817466cbSJens Wiklander 607817466cbSJens Wiklander return( 0 ); 608817466cbSJens Wiklander } 609817466cbSJens Wiklander 610817466cbSJens Wiklander /* 611817466cbSJens Wiklander * SubjectPublicKeyInfo ::= SEQUENCE { 612817466cbSJens Wiklander * algorithm AlgorithmIdentifier, 613817466cbSJens Wiklander * subjectPublicKey BIT STRING } 614817466cbSJens Wiklander */ 615817466cbSJens Wiklander int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, 616817466cbSJens Wiklander mbedtls_pk_context *pk ) 617817466cbSJens Wiklander { 618817466cbSJens Wiklander int ret; 619817466cbSJens Wiklander size_t len; 620817466cbSJens Wiklander mbedtls_asn1_buf alg_params; 621817466cbSJens Wiklander mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; 622817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 623817466cbSJens Wiklander 6243d3b0591SJens Wiklander PK_VALIDATE_RET( p != NULL ); 6253d3b0591SJens Wiklander PK_VALIDATE_RET( *p != NULL ); 6263d3b0591SJens Wiklander PK_VALIDATE_RET( end != NULL ); 6273d3b0591SJens Wiklander PK_VALIDATE_RET( pk != NULL ); 6283d3b0591SJens Wiklander 629817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 630817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 631817466cbSJens Wiklander { 632817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 633817466cbSJens Wiklander } 634817466cbSJens Wiklander 635817466cbSJens Wiklander end = *p + len; 636817466cbSJens Wiklander 637817466cbSJens Wiklander if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 ) 638817466cbSJens Wiklander return( ret ); 639817466cbSJens Wiklander 640817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) 641817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 642817466cbSJens Wiklander 643817466cbSJens Wiklander if( *p + len != end ) 644817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 645817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 646817466cbSJens Wiklander 647817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) 648817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 649817466cbSJens Wiklander 650817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) 651817466cbSJens Wiklander return( ret ); 652817466cbSJens Wiklander 653817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 654817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA ) 655817466cbSJens Wiklander { 656817466cbSJens Wiklander ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) ); 657817466cbSJens Wiklander } else 658817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 659817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 660817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY ) 661817466cbSJens Wiklander { 662817466cbSJens Wiklander ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp ); 663817466cbSJens Wiklander if( ret == 0 ) 664817466cbSJens Wiklander ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) ); 665817466cbSJens Wiklander } else 666817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 667817466cbSJens Wiklander ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; 668817466cbSJens Wiklander 669817466cbSJens Wiklander if( ret == 0 && *p != end ) 670817466cbSJens Wiklander ret = MBEDTLS_ERR_PK_INVALID_PUBKEY 671817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; 672817466cbSJens Wiklander 673817466cbSJens Wiklander if( ret != 0 ) 674817466cbSJens Wiklander mbedtls_pk_free( pk ); 675817466cbSJens Wiklander 676817466cbSJens Wiklander return( ret ); 677817466cbSJens Wiklander } 678817466cbSJens Wiklander 679817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 680817466cbSJens Wiklander /* 681*5b25c76aSJerome Forissier * Wrapper around mbedtls_asn1_get_mpi() that rejects zero. 682*5b25c76aSJerome Forissier * 683*5b25c76aSJerome Forissier * The value zero is: 684*5b25c76aSJerome Forissier * - never a valid value for an RSA parameter 685*5b25c76aSJerome Forissier * - interpreted as "omitted, please reconstruct" by mbedtls_rsa_complete(). 686*5b25c76aSJerome Forissier * 687*5b25c76aSJerome Forissier * Since values can't be omitted in PKCS#1, passing a zero value to 688*5b25c76aSJerome Forissier * rsa_complete() would be incorrect, so reject zero values early. 689*5b25c76aSJerome Forissier */ 690*5b25c76aSJerome Forissier static int asn1_get_nonzero_mpi( unsigned char **p, 691*5b25c76aSJerome Forissier const unsigned char *end, 692*5b25c76aSJerome Forissier mbedtls_mpi *X ) 693*5b25c76aSJerome Forissier { 694*5b25c76aSJerome Forissier int ret; 695*5b25c76aSJerome Forissier 696*5b25c76aSJerome Forissier ret = mbedtls_asn1_get_mpi( p, end, X ); 697*5b25c76aSJerome Forissier if( ret != 0 ) 698*5b25c76aSJerome Forissier return( ret ); 699*5b25c76aSJerome Forissier 700*5b25c76aSJerome Forissier if( mbedtls_mpi_cmp_int( X, 0 ) == 0 ) 701*5b25c76aSJerome Forissier return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 702*5b25c76aSJerome Forissier 703*5b25c76aSJerome Forissier return( 0 ); 704*5b25c76aSJerome Forissier } 705*5b25c76aSJerome Forissier 706*5b25c76aSJerome Forissier /* 707817466cbSJens Wiklander * Parse a PKCS#1 encoded private RSA key 708817466cbSJens Wiklander */ 709817466cbSJens Wiklander static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, 710817466cbSJens Wiklander const unsigned char *key, 711817466cbSJens Wiklander size_t keylen ) 712817466cbSJens Wiklander { 7133d3b0591SJens Wiklander int ret, version; 714817466cbSJens Wiklander size_t len; 715817466cbSJens Wiklander unsigned char *p, *end; 716817466cbSJens Wiklander 7173d3b0591SJens Wiklander mbedtls_mpi T; 7183d3b0591SJens Wiklander mbedtls_mpi_init( &T ); 7193d3b0591SJens Wiklander 720817466cbSJens Wiklander p = (unsigned char *) key; 721817466cbSJens Wiklander end = p + keylen; 722817466cbSJens Wiklander 723817466cbSJens Wiklander /* 724817466cbSJens Wiklander * This function parses the RSAPrivateKey (PKCS#1) 725817466cbSJens Wiklander * 726817466cbSJens Wiklander * RSAPrivateKey ::= SEQUENCE { 727817466cbSJens Wiklander * version Version, 728817466cbSJens Wiklander * modulus INTEGER, -- n 729817466cbSJens Wiklander * publicExponent INTEGER, -- e 730817466cbSJens Wiklander * privateExponent INTEGER, -- d 731817466cbSJens Wiklander * prime1 INTEGER, -- p 732817466cbSJens Wiklander * prime2 INTEGER, -- q 733817466cbSJens Wiklander * exponent1 INTEGER, -- d mod (p-1) 734817466cbSJens Wiklander * exponent2 INTEGER, -- d mod (q-1) 735817466cbSJens Wiklander * coefficient INTEGER, -- (inverse of q) mod p 736817466cbSJens Wiklander * otherPrimeInfos OtherPrimeInfos OPTIONAL 737817466cbSJens Wiklander * } 738817466cbSJens Wiklander */ 739817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 740817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 741817466cbSJens Wiklander { 742817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 743817466cbSJens Wiklander } 744817466cbSJens Wiklander 745817466cbSJens Wiklander end = p + len; 746817466cbSJens Wiklander 7473d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 748817466cbSJens Wiklander { 749817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 750817466cbSJens Wiklander } 751817466cbSJens Wiklander 7523d3b0591SJens Wiklander if( version != 0 ) 753817466cbSJens Wiklander { 754817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 755817466cbSJens Wiklander } 756817466cbSJens Wiklander 7573d3b0591SJens Wiklander /* Import N */ 758*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 759*5b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, &T, NULL, NULL, 760*5b25c76aSJerome Forissier NULL, NULL ) ) != 0 ) 7613d3b0591SJens Wiklander goto cleanup; 762817466cbSJens Wiklander 7633d3b0591SJens Wiklander /* Import E */ 764*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 765*5b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL, 766*5b25c76aSJerome Forissier NULL, &T ) ) != 0 ) 7673d3b0591SJens Wiklander goto cleanup; 7683d3b0591SJens Wiklander 7693d3b0591SJens Wiklander /* Import D */ 770*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 771*5b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, NULL, NULL, 772*5b25c76aSJerome Forissier &T, NULL ) ) != 0 ) 7733d3b0591SJens Wiklander goto cleanup; 7743d3b0591SJens Wiklander 7753d3b0591SJens Wiklander /* Import P */ 776*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 777*5b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, &T, NULL, 778*5b25c76aSJerome Forissier NULL, NULL ) ) != 0 ) 7793d3b0591SJens Wiklander goto cleanup; 7803d3b0591SJens Wiklander 7813d3b0591SJens Wiklander /* Import Q */ 782*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 783*5b25c76aSJerome Forissier ( ret = mbedtls_rsa_import( rsa, NULL, NULL, &T, 784*5b25c76aSJerome Forissier NULL, NULL ) ) != 0 ) 7853d3b0591SJens Wiklander goto cleanup; 7863d3b0591SJens Wiklander 787*5b25c76aSJerome Forissier #if !defined(MBEDTLS_RSA_NO_CRT) && !defined(MBEDTLS_RSA_ALT) 788*5b25c76aSJerome Forissier /* 789*5b25c76aSJerome Forissier * The RSA CRT parameters DP, DQ and QP are nominally redundant, in 790*5b25c76aSJerome Forissier * that they can be easily recomputed from D, P and Q. However by 791*5b25c76aSJerome Forissier * parsing them from the PKCS1 structure it is possible to avoid 792*5b25c76aSJerome Forissier * recalculating them which both reduces the overhead of loading 793*5b25c76aSJerome Forissier * RSA private keys into memory and also avoids side channels which 794*5b25c76aSJerome Forissier * can arise when computing those values, since all of D, P, and Q 795*5b25c76aSJerome Forissier * are secret. See https://eprint.iacr.org/2020/055 for a 796*5b25c76aSJerome Forissier * description of one such attack. 797*5b25c76aSJerome Forissier */ 798*5b25c76aSJerome Forissier 799*5b25c76aSJerome Forissier /* Import DP */ 800*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 801*5b25c76aSJerome Forissier ( ret = mbedtls_mpi_copy( &rsa->DP, &T ) ) != 0 ) 8023d3b0591SJens Wiklander goto cleanup; 803817466cbSJens Wiklander 804*5b25c76aSJerome Forissier /* Import DQ */ 805*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 806*5b25c76aSJerome Forissier ( ret = mbedtls_mpi_copy( &rsa->DQ, &T ) ) != 0 ) 807*5b25c76aSJerome Forissier goto cleanup; 808*5b25c76aSJerome Forissier 809*5b25c76aSJerome Forissier /* Import QP */ 810*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 811*5b25c76aSJerome Forissier ( ret = mbedtls_mpi_copy( &rsa->QP, &T ) ) != 0 ) 812*5b25c76aSJerome Forissier goto cleanup; 813*5b25c76aSJerome Forissier 814*5b25c76aSJerome Forissier #else 815*5b25c76aSJerome Forissier /* Verify existance of the CRT params */ 816*5b25c76aSJerome Forissier if( ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 817*5b25c76aSJerome Forissier ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 || 818*5b25c76aSJerome Forissier ( ret = asn1_get_nonzero_mpi( &p, end, &T ) ) != 0 ) 819*5b25c76aSJerome Forissier goto cleanup; 820*5b25c76aSJerome Forissier #endif 821*5b25c76aSJerome Forissier 822*5b25c76aSJerome Forissier /* rsa_complete() doesn't complete anything with the default 823*5b25c76aSJerome Forissier * implementation but is still called: 824*5b25c76aSJerome Forissier * - for the benefit of alternative implementation that may want to 825*5b25c76aSJerome Forissier * pre-compute stuff beyond what's provided (eg Montgomery factors) 826*5b25c76aSJerome Forissier * - as is also sanity-checks the key 827*5b25c76aSJerome Forissier * 828*5b25c76aSJerome Forissier * Furthermore, we also check the public part for consistency with 829*5b25c76aSJerome Forissier * mbedtls_pk_parse_pubkey(), as it includes size minima for example. 830*5b25c76aSJerome Forissier */ 831*5b25c76aSJerome Forissier if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 || 832*5b25c76aSJerome Forissier ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 ) 833*5b25c76aSJerome Forissier { 834*5b25c76aSJerome Forissier goto cleanup; 835*5b25c76aSJerome Forissier } 836*5b25c76aSJerome Forissier 837817466cbSJens Wiklander if( p != end ) 838817466cbSJens Wiklander { 8393d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 8403d3b0591SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ; 841817466cbSJens Wiklander } 842817466cbSJens Wiklander 8433d3b0591SJens Wiklander cleanup: 8443d3b0591SJens Wiklander 8453d3b0591SJens Wiklander mbedtls_mpi_free( &T ); 8463d3b0591SJens Wiklander 8473d3b0591SJens Wiklander if( ret != 0 ) 848817466cbSJens Wiklander { 8493d3b0591SJens Wiklander /* Wrap error code if it's coming from a lower level */ 8503d3b0591SJens Wiklander if( ( ret & 0xff80 ) == 0 ) 8513d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret; 8523d3b0591SJens Wiklander else 8533d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; 8543d3b0591SJens Wiklander 855817466cbSJens Wiklander mbedtls_rsa_free( rsa ); 856817466cbSJens Wiklander } 857817466cbSJens Wiklander 8583d3b0591SJens Wiklander return( ret ); 859817466cbSJens Wiklander } 860817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 861817466cbSJens Wiklander 862817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 863817466cbSJens Wiklander /* 864817466cbSJens Wiklander * Parse a SEC1 encoded private EC key 865817466cbSJens Wiklander */ 866817466cbSJens Wiklander static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, 867817466cbSJens Wiklander const unsigned char *key, 868817466cbSJens Wiklander size_t keylen ) 869817466cbSJens Wiklander { 870817466cbSJens Wiklander int ret; 871817466cbSJens Wiklander int version, pubkey_done; 872817466cbSJens Wiklander size_t len; 873817466cbSJens Wiklander mbedtls_asn1_buf params; 874817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 875817466cbSJens Wiklander unsigned char *end = p + keylen; 876817466cbSJens Wiklander unsigned char *end2; 877817466cbSJens Wiklander 878817466cbSJens Wiklander /* 879817466cbSJens Wiklander * RFC 5915, or SEC1 Appendix C.4 880817466cbSJens Wiklander * 881817466cbSJens Wiklander * ECPrivateKey ::= SEQUENCE { 882817466cbSJens Wiklander * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), 883817466cbSJens Wiklander * privateKey OCTET STRING, 884817466cbSJens Wiklander * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, 885817466cbSJens Wiklander * publicKey [1] BIT STRING OPTIONAL 886817466cbSJens Wiklander * } 887817466cbSJens Wiklander */ 888817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 889817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 890817466cbSJens Wiklander { 891817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 892817466cbSJens Wiklander } 893817466cbSJens Wiklander 894817466cbSJens Wiklander end = p + len; 895817466cbSJens Wiklander 896817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 897817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 898817466cbSJens Wiklander 899817466cbSJens Wiklander if( version != 1 ) 900817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 901817466cbSJens Wiklander 902817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 903817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 904817466cbSJens Wiklander 905817466cbSJens Wiklander if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) 906817466cbSJens Wiklander { 907817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 908817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 909817466cbSJens Wiklander } 910817466cbSJens Wiklander 911817466cbSJens Wiklander p += len; 912817466cbSJens Wiklander 913817466cbSJens Wiklander pubkey_done = 0; 914817466cbSJens Wiklander if( p != end ) 915817466cbSJens Wiklander { 916817466cbSJens Wiklander /* 917817466cbSJens Wiklander * Is 'parameters' present? 918817466cbSJens Wiklander */ 919817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 920817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) 921817466cbSJens Wiklander { 922817466cbSJens Wiklander if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || 923817466cbSJens Wiklander ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) 924817466cbSJens Wiklander { 925817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 926817466cbSJens Wiklander return( ret ); 927817466cbSJens Wiklander } 928817466cbSJens Wiklander } 929817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 930817466cbSJens Wiklander { 931817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 932817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 933817466cbSJens Wiklander } 9343d3b0591SJens Wiklander } 935817466cbSJens Wiklander 9363d3b0591SJens Wiklander if( p != end ) 9373d3b0591SJens Wiklander { 938817466cbSJens Wiklander /* 939817466cbSJens Wiklander * Is 'publickey' present? If not, or if we can't read it (eg because it 940817466cbSJens Wiklander * is compressed), create it from the private key. 941817466cbSJens Wiklander */ 942817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 943817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) 944817466cbSJens Wiklander { 945817466cbSJens Wiklander end2 = p + len; 946817466cbSJens Wiklander 947817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) 948817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 949817466cbSJens Wiklander 950817466cbSJens Wiklander if( p + len != end2 ) 951817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 952817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 953817466cbSJens Wiklander 954817466cbSJens Wiklander if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) 955817466cbSJens Wiklander pubkey_done = 1; 956817466cbSJens Wiklander else 957817466cbSJens Wiklander { 958817466cbSJens Wiklander /* 959817466cbSJens Wiklander * The only acceptable failure mode of pk_get_ecpubkey() above 960817466cbSJens Wiklander * is if the point format is not recognized. 961817466cbSJens Wiklander */ 962817466cbSJens Wiklander if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) 963817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 964817466cbSJens Wiklander } 965817466cbSJens Wiklander } 966817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 967817466cbSJens Wiklander { 968817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 969817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 970817466cbSJens Wiklander } 971817466cbSJens Wiklander } 972817466cbSJens Wiklander 973817466cbSJens Wiklander if( ! pubkey_done && 974817466cbSJens Wiklander ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, 975817466cbSJens Wiklander NULL, NULL ) ) != 0 ) 976817466cbSJens Wiklander { 977817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 978817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 979817466cbSJens Wiklander } 980817466cbSJens Wiklander 981817466cbSJens Wiklander if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) 982817466cbSJens Wiklander { 983817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 984817466cbSJens Wiklander return( ret ); 985817466cbSJens Wiklander } 986817466cbSJens Wiklander 987817466cbSJens Wiklander return( 0 ); 988817466cbSJens Wiklander } 989817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 990817466cbSJens Wiklander 991817466cbSJens Wiklander /* 992817466cbSJens Wiklander * Parse an unencrypted PKCS#8 encoded private key 9933d3b0591SJens Wiklander * 9943d3b0591SJens Wiklander * Notes: 9953d3b0591SJens Wiklander * 9963d3b0591SJens Wiklander * - This function does not own the key buffer. It is the 9973d3b0591SJens Wiklander * responsibility of the caller to take care of zeroizing 9983d3b0591SJens Wiklander * and freeing it after use. 9993d3b0591SJens Wiklander * 10003d3b0591SJens Wiklander * - The function is responsible for freeing the provided 10013d3b0591SJens Wiklander * PK context on failure. 10023d3b0591SJens Wiklander * 1003817466cbSJens Wiklander */ 1004817466cbSJens Wiklander static int pk_parse_key_pkcs8_unencrypted_der( 1005817466cbSJens Wiklander mbedtls_pk_context *pk, 1006817466cbSJens Wiklander const unsigned char* key, 1007817466cbSJens Wiklander size_t keylen ) 1008817466cbSJens Wiklander { 1009817466cbSJens Wiklander int ret, version; 1010817466cbSJens Wiklander size_t len; 1011817466cbSJens Wiklander mbedtls_asn1_buf params; 1012817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 1013817466cbSJens Wiklander unsigned char *end = p + keylen; 1014817466cbSJens Wiklander mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; 1015817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 1016817466cbSJens Wiklander 1017817466cbSJens Wiklander /* 10183d3b0591SJens Wiklander * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208) 1019817466cbSJens Wiklander * 1020817466cbSJens Wiklander * PrivateKeyInfo ::= SEQUENCE { 1021817466cbSJens Wiklander * version Version, 1022817466cbSJens Wiklander * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 1023817466cbSJens Wiklander * privateKey PrivateKey, 1024817466cbSJens Wiklander * attributes [0] IMPLICIT Attributes OPTIONAL } 1025817466cbSJens Wiklander * 1026817466cbSJens Wiklander * Version ::= INTEGER 1027817466cbSJens Wiklander * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier 1028817466cbSJens Wiklander * PrivateKey ::= OCTET STRING 1029817466cbSJens Wiklander * 1030817466cbSJens Wiklander * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey 1031817466cbSJens Wiklander */ 1032817466cbSJens Wiklander 1033817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1034817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1035817466cbSJens Wiklander { 1036817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1037817466cbSJens Wiklander } 1038817466cbSJens Wiklander 1039817466cbSJens Wiklander end = p + len; 1040817466cbSJens Wiklander 1041817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 1042817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1043817466cbSJens Wiklander 1044817466cbSJens Wiklander if( version != 0 ) 1045817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); 1046817466cbSJens Wiklander 1047817466cbSJens Wiklander if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) 1048817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1049817466cbSJens Wiklander 1050817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 1051817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1052817466cbSJens Wiklander 1053817466cbSJens Wiklander if( len < 1 ) 1054817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 1055817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 1056817466cbSJens Wiklander 1057817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) 1058817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1059817466cbSJens Wiklander 1060817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) 1061817466cbSJens Wiklander return( ret ); 1062817466cbSJens Wiklander 1063817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1064817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA ) 1065817466cbSJens Wiklander { 1066817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) 1067817466cbSJens Wiklander { 1068817466cbSJens Wiklander mbedtls_pk_free( pk ); 1069817466cbSJens Wiklander return( ret ); 1070817466cbSJens Wiklander } 1071817466cbSJens Wiklander } else 1072817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1073817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1074817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) 1075817466cbSJens Wiklander { 1076817466cbSJens Wiklander if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || 1077817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) 1078817466cbSJens Wiklander { 1079817466cbSJens Wiklander mbedtls_pk_free( pk ); 1080817466cbSJens Wiklander return( ret ); 1081817466cbSJens Wiklander } 1082817466cbSJens Wiklander } else 1083817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1084817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1085817466cbSJens Wiklander 1086817466cbSJens Wiklander return( 0 ); 1087817466cbSJens Wiklander } 1088817466cbSJens Wiklander 1089817466cbSJens Wiklander /* 1090817466cbSJens Wiklander * Parse an encrypted PKCS#8 encoded private key 10913d3b0591SJens Wiklander * 10923d3b0591SJens Wiklander * To save space, the decryption happens in-place on the given key buffer. 10933d3b0591SJens Wiklander * Also, while this function may modify the keybuffer, it doesn't own it, 10943d3b0591SJens Wiklander * and instead it is the responsibility of the caller to zeroize and properly 10953d3b0591SJens Wiklander * free it after use. 10963d3b0591SJens Wiklander * 1097817466cbSJens Wiklander */ 1098817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1099817466cbSJens Wiklander static int pk_parse_key_pkcs8_encrypted_der( 1100817466cbSJens Wiklander mbedtls_pk_context *pk, 11013d3b0591SJens Wiklander unsigned char *key, size_t keylen, 1102817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 1103817466cbSJens Wiklander { 1104817466cbSJens Wiklander int ret, decrypted = 0; 1105817466cbSJens Wiklander size_t len; 11063d3b0591SJens Wiklander unsigned char *buf; 1107817466cbSJens Wiklander unsigned char *p, *end; 1108817466cbSJens Wiklander mbedtls_asn1_buf pbe_alg_oid, pbe_params; 1109817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 1110817466cbSJens Wiklander mbedtls_cipher_type_t cipher_alg; 1111817466cbSJens Wiklander mbedtls_md_type_t md_alg; 1112817466cbSJens Wiklander #endif 1113817466cbSJens Wiklander 11143d3b0591SJens Wiklander p = key; 1115817466cbSJens Wiklander end = p + keylen; 1116817466cbSJens Wiklander 1117817466cbSJens Wiklander if( pwdlen == 0 ) 1118817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1119817466cbSJens Wiklander 1120817466cbSJens Wiklander /* 11213d3b0591SJens Wiklander * This function parses the EncryptedPrivateKeyInfo object (PKCS#8) 1122817466cbSJens Wiklander * 1123817466cbSJens Wiklander * EncryptedPrivateKeyInfo ::= SEQUENCE { 1124817466cbSJens Wiklander * encryptionAlgorithm EncryptionAlgorithmIdentifier, 1125817466cbSJens Wiklander * encryptedData EncryptedData 1126817466cbSJens Wiklander * } 1127817466cbSJens Wiklander * 1128817466cbSJens Wiklander * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier 1129817466cbSJens Wiklander * 1130817466cbSJens Wiklander * EncryptedData ::= OCTET STRING 1131817466cbSJens Wiklander * 1132817466cbSJens Wiklander * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo 11333d3b0591SJens Wiklander * 1134817466cbSJens Wiklander */ 1135817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1136817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1137817466cbSJens Wiklander { 1138817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1139817466cbSJens Wiklander } 1140817466cbSJens Wiklander 1141817466cbSJens Wiklander end = p + len; 1142817466cbSJens Wiklander 1143817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) 1144817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1145817466cbSJens Wiklander 1146817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 1147817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1148817466cbSJens Wiklander 11493d3b0591SJens Wiklander buf = p; 1150817466cbSJens Wiklander 1151817466cbSJens Wiklander /* 11523d3b0591SJens Wiklander * Decrypt EncryptedData with appropriate PBE 1153817466cbSJens Wiklander */ 1154817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 1155817466cbSJens Wiklander if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) 1156817466cbSJens Wiklander { 1157817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, 1158817466cbSJens Wiklander cipher_alg, md_alg, 1159817466cbSJens Wiklander pwd, pwdlen, p, len, buf ) ) != 0 ) 1160817466cbSJens Wiklander { 1161817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) 1162817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1163817466cbSJens Wiklander 1164817466cbSJens Wiklander return( ret ); 1165817466cbSJens Wiklander } 1166817466cbSJens Wiklander 1167817466cbSJens Wiklander decrypted = 1; 1168817466cbSJens Wiklander } 1169817466cbSJens Wiklander else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) 1170817466cbSJens Wiklander { 1171817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, 1172817466cbSJens Wiklander MBEDTLS_PKCS12_PBE_DECRYPT, 1173817466cbSJens Wiklander pwd, pwdlen, 1174817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1175817466cbSJens Wiklander { 1176817466cbSJens Wiklander return( ret ); 1177817466cbSJens Wiklander } 1178817466cbSJens Wiklander 1179817466cbSJens Wiklander // Best guess for password mismatch when using RC4. If first tag is 1180817466cbSJens Wiklander // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE 1181817466cbSJens Wiklander // 1182817466cbSJens Wiklander if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) 1183817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1184817466cbSJens Wiklander 1185817466cbSJens Wiklander decrypted = 1; 1186817466cbSJens Wiklander } 1187817466cbSJens Wiklander else 1188817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C */ 1189817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 1190817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) 1191817466cbSJens Wiklander { 1192817466cbSJens Wiklander if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, 1193817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1194817466cbSJens Wiklander { 1195817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) 1196817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1197817466cbSJens Wiklander 1198817466cbSJens Wiklander return( ret ); 1199817466cbSJens Wiklander } 1200817466cbSJens Wiklander 1201817466cbSJens Wiklander decrypted = 1; 1202817466cbSJens Wiklander } 1203817466cbSJens Wiklander else 1204817466cbSJens Wiklander #endif /* MBEDTLS_PKCS5_C */ 1205817466cbSJens Wiklander { 1206817466cbSJens Wiklander ((void) pwd); 1207817466cbSJens Wiklander } 1208817466cbSJens Wiklander 1209817466cbSJens Wiklander if( decrypted == 0 ) 1210817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 1211817466cbSJens Wiklander 1212817466cbSJens Wiklander return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); 1213817466cbSJens Wiklander } 1214817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1215817466cbSJens Wiklander 1216817466cbSJens Wiklander /* 1217817466cbSJens Wiklander * Parse a private key 1218817466cbSJens Wiklander */ 1219817466cbSJens Wiklander int mbedtls_pk_parse_key( mbedtls_pk_context *pk, 1220817466cbSJens Wiklander const unsigned char *key, size_t keylen, 1221817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 1222817466cbSJens Wiklander { 1223817466cbSJens Wiklander int ret; 1224817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 1225817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1226817466cbSJens Wiklander size_t len; 1227817466cbSJens Wiklander mbedtls_pem_context pem; 12283d3b0591SJens Wiklander #endif 1229817466cbSJens Wiklander 12303d3b0591SJens Wiklander PK_VALIDATE_RET( pk != NULL ); 12313d3b0591SJens Wiklander if( keylen == 0 ) 12323d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 12333d3b0591SJens Wiklander PK_VALIDATE_RET( key != NULL ); 12343d3b0591SJens Wiklander 12353d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1236817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1237817466cbSJens Wiklander 1238817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1239817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 12403d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1241817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1242817466cbSJens Wiklander else 1243817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1244817466cbSJens Wiklander "-----BEGIN RSA PRIVATE KEY-----", 1245817466cbSJens Wiklander "-----END RSA PRIVATE KEY-----", 1246817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1247817466cbSJens Wiklander 1248817466cbSJens Wiklander if( ret == 0 ) 1249817466cbSJens Wiklander { 12503d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); 1251817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1252817466cbSJens Wiklander ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), 1253817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1254817466cbSJens Wiklander { 1255817466cbSJens Wiklander mbedtls_pk_free( pk ); 1256817466cbSJens Wiklander } 1257817466cbSJens Wiklander 1258817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1259817466cbSJens Wiklander return( ret ); 1260817466cbSJens Wiklander } 1261817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1262817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1263817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1264817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1265817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1266817466cbSJens Wiklander return( ret ); 1267817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1268817466cbSJens Wiklander 1269817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1270817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 12713d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1272817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1273817466cbSJens Wiklander else 1274817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1275817466cbSJens Wiklander "-----BEGIN EC PRIVATE KEY-----", 1276817466cbSJens Wiklander "-----END EC PRIVATE KEY-----", 1277817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1278817466cbSJens Wiklander if( ret == 0 ) 1279817466cbSJens Wiklander { 12803d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); 1281817466cbSJens Wiklander 1282817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1283817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), 1284817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1285817466cbSJens Wiklander { 1286817466cbSJens Wiklander mbedtls_pk_free( pk ); 1287817466cbSJens Wiklander } 1288817466cbSJens Wiklander 1289817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1290817466cbSJens Wiklander return( ret ); 1291817466cbSJens Wiklander } 1292817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1293817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1294817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1295817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1296817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1297817466cbSJens Wiklander return( ret ); 1298817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1299817466cbSJens Wiklander 1300817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 13013d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1302817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1303817466cbSJens Wiklander else 1304817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1305817466cbSJens Wiklander "-----BEGIN PRIVATE KEY-----", 1306817466cbSJens Wiklander "-----END PRIVATE KEY-----", 1307817466cbSJens Wiklander key, NULL, 0, &len ); 1308817466cbSJens Wiklander if( ret == 0 ) 1309817466cbSJens Wiklander { 1310817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, 1311817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1312817466cbSJens Wiklander { 1313817466cbSJens Wiklander mbedtls_pk_free( pk ); 1314817466cbSJens Wiklander } 1315817466cbSJens Wiklander 1316817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1317817466cbSJens Wiklander return( ret ); 1318817466cbSJens Wiklander } 1319817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1320817466cbSJens Wiklander return( ret ); 1321817466cbSJens Wiklander 1322817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1323817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 13243d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1325817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1326817466cbSJens Wiklander else 1327817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1328817466cbSJens Wiklander "-----BEGIN ENCRYPTED PRIVATE KEY-----", 1329817466cbSJens Wiklander "-----END ENCRYPTED PRIVATE KEY-----", 1330817466cbSJens Wiklander key, NULL, 0, &len ); 1331817466cbSJens Wiklander if( ret == 0 ) 1332817466cbSJens Wiklander { 1333817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, 1334817466cbSJens Wiklander pem.buf, pem.buflen, 1335817466cbSJens Wiklander pwd, pwdlen ) ) != 0 ) 1336817466cbSJens Wiklander { 1337817466cbSJens Wiklander mbedtls_pk_free( pk ); 1338817466cbSJens Wiklander } 1339817466cbSJens Wiklander 1340817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1341817466cbSJens Wiklander return( ret ); 1342817466cbSJens Wiklander } 1343817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1344817466cbSJens Wiklander return( ret ); 1345817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1346817466cbSJens Wiklander #else 1347817466cbSJens Wiklander ((void) pwd); 1348817466cbSJens Wiklander ((void) pwdlen); 1349817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1350817466cbSJens Wiklander 1351817466cbSJens Wiklander /* 1352817466cbSJens Wiklander * At this point we only know it's not a PEM formatted key. Could be any 1353817466cbSJens Wiklander * of the known DER encoded private key formats 1354817466cbSJens Wiklander * 1355817466cbSJens Wiklander * We try the different DER format parsers to see if one passes without 1356817466cbSJens Wiklander * error 1357817466cbSJens Wiklander */ 1358817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1359817466cbSJens Wiklander { 13603d3b0591SJens Wiklander unsigned char *key_copy; 13613d3b0591SJens Wiklander 13623d3b0591SJens Wiklander if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL ) 13633d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_ALLOC_FAILED ); 13643d3b0591SJens Wiklander 13653d3b0591SJens Wiklander memcpy( key_copy, key, keylen ); 13663d3b0591SJens Wiklander 13673d3b0591SJens Wiklander ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen, 13683d3b0591SJens Wiklander pwd, pwdlen ); 13693d3b0591SJens Wiklander 13703d3b0591SJens Wiklander mbedtls_platform_zeroize( key_copy, keylen ); 13713d3b0591SJens Wiklander mbedtls_free( key_copy ); 1372817466cbSJens Wiklander } 1373817466cbSJens Wiklander 13743d3b0591SJens Wiklander if( ret == 0 ) 13753d3b0591SJens Wiklander return( 0 ); 13763d3b0591SJens Wiklander 1377817466cbSJens Wiklander mbedtls_pk_free( pk ); 13783d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1379817466cbSJens Wiklander 1380817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) 1381817466cbSJens Wiklander { 1382817466cbSJens Wiklander return( ret ); 1383817466cbSJens Wiklander } 1384817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1385817466cbSJens Wiklander 1386817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) 1387817466cbSJens Wiklander return( 0 ); 1388817466cbSJens Wiklander 1389817466cbSJens Wiklander mbedtls_pk_free( pk ); 13903d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1391817466cbSJens Wiklander 1392817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1393817466cbSJens Wiklander 13943d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); 13953d3b0591SJens Wiklander if( mbedtls_pk_setup( pk, pk_info ) == 0 && 13963d3b0591SJens Wiklander pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) == 0 ) 1397817466cbSJens Wiklander { 1398817466cbSJens Wiklander return( 0 ); 1399817466cbSJens Wiklander } 1400817466cbSJens Wiklander 1401817466cbSJens Wiklander mbedtls_pk_free( pk ); 14023d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1403817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1404817466cbSJens Wiklander 1405817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 14063d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); 14073d3b0591SJens Wiklander if( mbedtls_pk_setup( pk, pk_info ) == 0 && 14083d3b0591SJens Wiklander pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), 14093d3b0591SJens Wiklander key, keylen ) == 0 ) 1410817466cbSJens Wiklander { 1411817466cbSJens Wiklander return( 0 ); 1412817466cbSJens Wiklander } 1413817466cbSJens Wiklander mbedtls_pk_free( pk ); 1414817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1415817466cbSJens Wiklander 14163d3b0591SJens Wiklander /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't, 14173d3b0591SJens Wiklander * it is ok to leave the PK context initialized but not 14183d3b0591SJens Wiklander * freed: It is the caller's responsibility to call pk_init() 14193d3b0591SJens Wiklander * before calling this function, and to call pk_free() 14203d3b0591SJens Wiklander * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C 14213d3b0591SJens Wiklander * isn't, this leads to mbedtls_pk_free() being called 14223d3b0591SJens Wiklander * twice, once here and once by the caller, but this is 14233d3b0591SJens Wiklander * also ok and in line with the mbedtls_pk_free() calls 14243d3b0591SJens Wiklander * on failed PEM parsing attempts. */ 14253d3b0591SJens Wiklander 1426817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 1427817466cbSJens Wiklander } 1428817466cbSJens Wiklander 1429817466cbSJens Wiklander /* 1430817466cbSJens Wiklander * Parse a public key 1431817466cbSJens Wiklander */ 1432817466cbSJens Wiklander int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, 1433817466cbSJens Wiklander const unsigned char *key, size_t keylen ) 1434817466cbSJens Wiklander { 1435817466cbSJens Wiklander int ret; 1436817466cbSJens Wiklander unsigned char *p; 14373d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 14383d3b0591SJens Wiklander const mbedtls_pk_info_t *pk_info; 14393d3b0591SJens Wiklander #endif 1440817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1441817466cbSJens Wiklander size_t len; 1442817466cbSJens Wiklander mbedtls_pem_context pem; 14433d3b0591SJens Wiklander #endif 1444817466cbSJens Wiklander 14453d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 14463d3b0591SJens Wiklander if( keylen == 0 ) 14473d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 14483d3b0591SJens Wiklander PK_VALIDATE_RET( key != NULL || keylen == 0 ); 14493d3b0591SJens Wiklander 14503d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1451817466cbSJens Wiklander mbedtls_pem_init( &pem ); 14523d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 14533d3b0591SJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 14543d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 14553d3b0591SJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 14563d3b0591SJens Wiklander else 14573d3b0591SJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 14583d3b0591SJens Wiklander "-----BEGIN RSA PUBLIC KEY-----", 14593d3b0591SJens Wiklander "-----END RSA PUBLIC KEY-----", 14603d3b0591SJens Wiklander key, NULL, 0, &len ); 14613d3b0591SJens Wiklander 14623d3b0591SJens Wiklander if( ret == 0 ) 14633d3b0591SJens Wiklander { 14643d3b0591SJens Wiklander p = pem.buf; 14653d3b0591SJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 14663d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 14673d3b0591SJens Wiklander 14683d3b0591SJens Wiklander if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) 14693d3b0591SJens Wiklander return( ret ); 14703d3b0591SJens Wiklander 14713d3b0591SJens Wiklander if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 ) 14723d3b0591SJens Wiklander mbedtls_pk_free( ctx ); 14733d3b0591SJens Wiklander 14743d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 14753d3b0591SJens Wiklander return( ret ); 14763d3b0591SJens Wiklander } 14773d3b0591SJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 14783d3b0591SJens Wiklander { 14793d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 14803d3b0591SJens Wiklander return( ret ); 14813d3b0591SJens Wiklander } 14823d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */ 1483817466cbSJens Wiklander 1484817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 14853d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1486817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1487817466cbSJens Wiklander else 1488817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1489817466cbSJens Wiklander "-----BEGIN PUBLIC KEY-----", 1490817466cbSJens Wiklander "-----END PUBLIC KEY-----", 1491817466cbSJens Wiklander key, NULL, 0, &len ); 1492817466cbSJens Wiklander 1493817466cbSJens Wiklander if( ret == 0 ) 1494817466cbSJens Wiklander { 1495817466cbSJens Wiklander /* 1496817466cbSJens Wiklander * Was PEM encoded 1497817466cbSJens Wiklander */ 14983d3b0591SJens Wiklander p = pem.buf; 14993d3b0591SJens Wiklander 15003d3b0591SJens Wiklander ret = mbedtls_pk_parse_subpubkey( &p, p + pem.buflen, ctx ); 15013d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 15023d3b0591SJens Wiklander return( ret ); 1503817466cbSJens Wiklander } 1504817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1505817466cbSJens Wiklander { 1506817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1507817466cbSJens Wiklander return( ret ); 1508817466cbSJens Wiklander } 15093d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 1510817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 15113d3b0591SJens Wiklander 15123d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 15133d3b0591SJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 15143d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 15153d3b0591SJens Wiklander 15163d3b0591SJens Wiklander if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) 15173d3b0591SJens Wiklander return( ret ); 15183d3b0591SJens Wiklander 15193d3b0591SJens Wiklander p = (unsigned char *)key; 15203d3b0591SJens Wiklander ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) ); 15213d3b0591SJens Wiklander if( ret == 0 ) 15223d3b0591SJens Wiklander { 15233d3b0591SJens Wiklander return( ret ); 15243d3b0591SJens Wiklander } 15253d3b0591SJens Wiklander mbedtls_pk_free( ctx ); 15263d3b0591SJens Wiklander if( ret != ( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) 15273d3b0591SJens Wiklander { 15283d3b0591SJens Wiklander return( ret ); 15293d3b0591SJens Wiklander } 15303d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */ 1531817466cbSJens Wiklander p = (unsigned char *) key; 1532817466cbSJens Wiklander 1533817466cbSJens Wiklander ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); 1534817466cbSJens Wiklander 1535817466cbSJens Wiklander return( ret ); 1536817466cbSJens Wiklander } 1537817466cbSJens Wiklander 1538817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_C */ 1539