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" 33*3d3b0591SJens 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 64*3d3b0591SJens Wiklander /* Parameter validation macros based on platform_util.h */ 65*3d3b0591SJens Wiklander #define PK_VALIDATE_RET( cond ) \ 66*3d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) 67*3d3b0591SJens Wiklander #define PK_VALIDATE( cond ) \ 68*3d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 69817466cbSJens Wiklander 70*3d3b0591SJens 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 83*3d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 84*3d3b0591SJens Wiklander PK_VALIDATE_RET( buf != NULL ); 85*3d3b0591SJens Wiklander PK_VALIDATE_RET( n != NULL ); 86*3d3b0591SJens 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 ); 110*3d3b0591SJens Wiklander 111*3d3b0591SJens Wiklander mbedtls_platform_zeroize( *buf, *n ); 112817466cbSJens Wiklander mbedtls_free( *buf ); 113*3d3b0591SJens 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 137*3d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 138*3d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 139*3d3b0591SJens 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 149*3d3b0591SJens 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 164*3d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 165*3d3b0591SJens Wiklander PK_VALIDATE_RET( path != NULL ); 166*3d3b0591SJens 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 172*3d3b0591SJens 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 193*3d3b0591SJens Wiklander if ( end - *p < 1 ) 194*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 195*3d3b0591SJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 196*3d3b0591SJens 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 542*3d3b0591SJens Wiklander /* Import N */ 543*3d3b0591SJens 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 546*3d3b0591SJens Wiklander if( ( ret = mbedtls_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0, 547*3d3b0591SJens Wiklander NULL, 0, NULL, 0 ) ) != 0 ) 548*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 549*3d3b0591SJens Wiklander 550*3d3b0591SJens Wiklander *p += len; 551*3d3b0591SJens Wiklander 552*3d3b0591SJens Wiklander /* Import E */ 553*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) 554*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 555*3d3b0591SJens Wiklander 556*3d3b0591SJens Wiklander if( ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, 557*3d3b0591SJens Wiklander NULL, 0, *p, len ) ) != 0 ) 558*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 559*3d3b0591SJens Wiklander 560*3d3b0591SJens Wiklander *p += len; 561*3d3b0591SJens Wiklander 562*3d3b0591SJens Wiklander if( mbedtls_rsa_complete( rsa ) != 0 || 563*3d3b0591SJens Wiklander mbedtls_rsa_check_pubkey( rsa ) != 0 ) 564*3d3b0591SJens Wiklander { 565*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 566*3d3b0591SJens Wiklander } 567*3d3b0591SJens 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 624*3d3b0591SJens Wiklander PK_VALIDATE_RET( p != NULL ); 625*3d3b0591SJens Wiklander PK_VALIDATE_RET( *p != NULL ); 626*3d3b0591SJens Wiklander PK_VALIDATE_RET( end != NULL ); 627*3d3b0591SJens Wiklander PK_VALIDATE_RET( pk != NULL ); 628*3d3b0591SJens 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 /* 681817466cbSJens Wiklander * Parse a PKCS#1 encoded private RSA key 682817466cbSJens Wiklander */ 683817466cbSJens Wiklander static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, 684817466cbSJens Wiklander const unsigned char *key, 685817466cbSJens Wiklander size_t keylen ) 686817466cbSJens Wiklander { 687*3d3b0591SJens Wiklander int ret, version; 688817466cbSJens Wiklander size_t len; 689817466cbSJens Wiklander unsigned char *p, *end; 690817466cbSJens Wiklander 691*3d3b0591SJens Wiklander mbedtls_mpi T; 692*3d3b0591SJens Wiklander mbedtls_mpi_init( &T ); 693*3d3b0591SJens Wiklander 694817466cbSJens Wiklander p = (unsigned char *) key; 695817466cbSJens Wiklander end = p + keylen; 696817466cbSJens Wiklander 697817466cbSJens Wiklander /* 698817466cbSJens Wiklander * This function parses the RSAPrivateKey (PKCS#1) 699817466cbSJens Wiklander * 700817466cbSJens Wiklander * RSAPrivateKey ::= SEQUENCE { 701817466cbSJens Wiklander * version Version, 702817466cbSJens Wiklander * modulus INTEGER, -- n 703817466cbSJens Wiklander * publicExponent INTEGER, -- e 704817466cbSJens Wiklander * privateExponent INTEGER, -- d 705817466cbSJens Wiklander * prime1 INTEGER, -- p 706817466cbSJens Wiklander * prime2 INTEGER, -- q 707817466cbSJens Wiklander * exponent1 INTEGER, -- d mod (p-1) 708817466cbSJens Wiklander * exponent2 INTEGER, -- d mod (q-1) 709817466cbSJens Wiklander * coefficient INTEGER, -- (inverse of q) mod p 710817466cbSJens Wiklander * otherPrimeInfos OtherPrimeInfos OPTIONAL 711817466cbSJens Wiklander * } 712817466cbSJens Wiklander */ 713817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 714817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 715817466cbSJens Wiklander { 716817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 717817466cbSJens Wiklander } 718817466cbSJens Wiklander 719817466cbSJens Wiklander end = p + len; 720817466cbSJens Wiklander 721*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 722817466cbSJens Wiklander { 723817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 724817466cbSJens Wiklander } 725817466cbSJens Wiklander 726*3d3b0591SJens Wiklander if( version != 0 ) 727817466cbSJens Wiklander { 728817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 729817466cbSJens Wiklander } 730817466cbSJens Wiklander 731*3d3b0591SJens Wiklander /* Import N */ 732*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 733*3d3b0591SJens Wiklander MBEDTLS_ASN1_INTEGER ) ) != 0 || 734*3d3b0591SJens Wiklander ( ret = mbedtls_rsa_import_raw( rsa, p, len, NULL, 0, NULL, 0, 735*3d3b0591SJens Wiklander NULL, 0, NULL, 0 ) ) != 0 ) 736*3d3b0591SJens Wiklander goto cleanup; 737*3d3b0591SJens Wiklander p += len; 738817466cbSJens Wiklander 739*3d3b0591SJens Wiklander /* Import E */ 740*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 741*3d3b0591SJens Wiklander MBEDTLS_ASN1_INTEGER ) ) != 0 || 742*3d3b0591SJens Wiklander ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, 743*3d3b0591SJens Wiklander NULL, 0, p, len ) ) != 0 ) 744*3d3b0591SJens Wiklander goto cleanup; 745*3d3b0591SJens Wiklander p += len; 746*3d3b0591SJens Wiklander 747*3d3b0591SJens Wiklander /* Import D */ 748*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 749*3d3b0591SJens Wiklander MBEDTLS_ASN1_INTEGER ) ) != 0 || 750*3d3b0591SJens Wiklander ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, 751*3d3b0591SJens Wiklander p, len, NULL, 0 ) ) != 0 ) 752*3d3b0591SJens Wiklander goto cleanup; 753*3d3b0591SJens Wiklander p += len; 754*3d3b0591SJens Wiklander 755*3d3b0591SJens Wiklander /* Import P */ 756*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 757*3d3b0591SJens Wiklander MBEDTLS_ASN1_INTEGER ) ) != 0 || 758*3d3b0591SJens Wiklander ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, p, len, NULL, 0, 759*3d3b0591SJens Wiklander NULL, 0, NULL, 0 ) ) != 0 ) 760*3d3b0591SJens Wiklander goto cleanup; 761*3d3b0591SJens Wiklander p += len; 762*3d3b0591SJens Wiklander 763*3d3b0591SJens Wiklander /* Import Q */ 764*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 765*3d3b0591SJens Wiklander MBEDTLS_ASN1_INTEGER ) ) != 0 || 766*3d3b0591SJens Wiklander ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, p, len, 767*3d3b0591SJens Wiklander NULL, 0, NULL, 0 ) ) != 0 ) 768*3d3b0591SJens Wiklander goto cleanup; 769*3d3b0591SJens Wiklander p += len; 770*3d3b0591SJens Wiklander 771*3d3b0591SJens Wiklander /* Complete the RSA private key */ 772*3d3b0591SJens Wiklander if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 ) 773*3d3b0591SJens Wiklander goto cleanup; 774*3d3b0591SJens Wiklander 775*3d3b0591SJens Wiklander /* Check optional parameters */ 776*3d3b0591SJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 || 777*3d3b0591SJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 || 778*3d3b0591SJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 ) 779*3d3b0591SJens Wiklander goto cleanup; 780817466cbSJens Wiklander 781817466cbSJens Wiklander if( p != end ) 782817466cbSJens Wiklander { 783*3d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 784*3d3b0591SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ; 785817466cbSJens Wiklander } 786817466cbSJens Wiklander 787*3d3b0591SJens Wiklander cleanup: 788*3d3b0591SJens Wiklander 789*3d3b0591SJens Wiklander mbedtls_mpi_free( &T ); 790*3d3b0591SJens Wiklander 791*3d3b0591SJens Wiklander if( ret != 0 ) 792817466cbSJens Wiklander { 793*3d3b0591SJens Wiklander /* Wrap error code if it's coming from a lower level */ 794*3d3b0591SJens Wiklander if( ( ret & 0xff80 ) == 0 ) 795*3d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret; 796*3d3b0591SJens Wiklander else 797*3d3b0591SJens Wiklander ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; 798*3d3b0591SJens Wiklander 799817466cbSJens Wiklander mbedtls_rsa_free( rsa ); 800817466cbSJens Wiklander } 801817466cbSJens Wiklander 802*3d3b0591SJens Wiklander return( ret ); 803817466cbSJens Wiklander } 804817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 805817466cbSJens Wiklander 806817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 807817466cbSJens Wiklander /* 808817466cbSJens Wiklander * Parse a SEC1 encoded private EC key 809817466cbSJens Wiklander */ 810817466cbSJens Wiklander static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, 811817466cbSJens Wiklander const unsigned char *key, 812817466cbSJens Wiklander size_t keylen ) 813817466cbSJens Wiklander { 814817466cbSJens Wiklander int ret; 815817466cbSJens Wiklander int version, pubkey_done; 816817466cbSJens Wiklander size_t len; 817817466cbSJens Wiklander mbedtls_asn1_buf params; 818817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 819817466cbSJens Wiklander unsigned char *end = p + keylen; 820817466cbSJens Wiklander unsigned char *end2; 821817466cbSJens Wiklander 822817466cbSJens Wiklander /* 823817466cbSJens Wiklander * RFC 5915, or SEC1 Appendix C.4 824817466cbSJens Wiklander * 825817466cbSJens Wiklander * ECPrivateKey ::= SEQUENCE { 826817466cbSJens Wiklander * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), 827817466cbSJens Wiklander * privateKey OCTET STRING, 828817466cbSJens Wiklander * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, 829817466cbSJens Wiklander * publicKey [1] BIT STRING OPTIONAL 830817466cbSJens Wiklander * } 831817466cbSJens Wiklander */ 832817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 833817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 834817466cbSJens Wiklander { 835817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 836817466cbSJens Wiklander } 837817466cbSJens Wiklander 838817466cbSJens Wiklander end = p + len; 839817466cbSJens Wiklander 840817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 841817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 842817466cbSJens Wiklander 843817466cbSJens Wiklander if( version != 1 ) 844817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 845817466cbSJens Wiklander 846817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 847817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 848817466cbSJens Wiklander 849817466cbSJens Wiklander if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) 850817466cbSJens Wiklander { 851817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 852817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 853817466cbSJens Wiklander } 854817466cbSJens Wiklander 855817466cbSJens Wiklander p += len; 856817466cbSJens Wiklander 857817466cbSJens Wiklander pubkey_done = 0; 858817466cbSJens Wiklander if( p != end ) 859817466cbSJens Wiklander { 860817466cbSJens Wiklander /* 861817466cbSJens Wiklander * Is 'parameters' present? 862817466cbSJens Wiklander */ 863817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 864817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) 865817466cbSJens Wiklander { 866817466cbSJens Wiklander if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || 867817466cbSJens Wiklander ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) 868817466cbSJens Wiklander { 869817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 870817466cbSJens Wiklander return( ret ); 871817466cbSJens Wiklander } 872817466cbSJens Wiklander } 873817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 874817466cbSJens Wiklander { 875817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 876817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 877817466cbSJens Wiklander } 878*3d3b0591SJens Wiklander } 879817466cbSJens Wiklander 880*3d3b0591SJens Wiklander if( p != end ) 881*3d3b0591SJens Wiklander { 882817466cbSJens Wiklander /* 883817466cbSJens Wiklander * Is 'publickey' present? If not, or if we can't read it (eg because it 884817466cbSJens Wiklander * is compressed), create it from the private key. 885817466cbSJens Wiklander */ 886817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 887817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) 888817466cbSJens Wiklander { 889817466cbSJens Wiklander end2 = p + len; 890817466cbSJens Wiklander 891817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) 892817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 893817466cbSJens Wiklander 894817466cbSJens Wiklander if( p + len != end2 ) 895817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 896817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 897817466cbSJens Wiklander 898817466cbSJens Wiklander if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) 899817466cbSJens Wiklander pubkey_done = 1; 900817466cbSJens Wiklander else 901817466cbSJens Wiklander { 902817466cbSJens Wiklander /* 903817466cbSJens Wiklander * The only acceptable failure mode of pk_get_ecpubkey() above 904817466cbSJens Wiklander * is if the point format is not recognized. 905817466cbSJens Wiklander */ 906817466cbSJens Wiklander if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) 907817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 908817466cbSJens Wiklander } 909817466cbSJens Wiklander } 910817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 911817466cbSJens Wiklander { 912817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 913817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 914817466cbSJens Wiklander } 915817466cbSJens Wiklander } 916817466cbSJens Wiklander 917817466cbSJens Wiklander if( ! pubkey_done && 918817466cbSJens Wiklander ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, 919817466cbSJens Wiklander NULL, NULL ) ) != 0 ) 920817466cbSJens Wiklander { 921817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 922817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 923817466cbSJens Wiklander } 924817466cbSJens Wiklander 925817466cbSJens Wiklander if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) 926817466cbSJens Wiklander { 927817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 928817466cbSJens Wiklander return( ret ); 929817466cbSJens Wiklander } 930817466cbSJens Wiklander 931817466cbSJens Wiklander return( 0 ); 932817466cbSJens Wiklander } 933817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 934817466cbSJens Wiklander 935817466cbSJens Wiklander /* 936817466cbSJens Wiklander * Parse an unencrypted PKCS#8 encoded private key 937*3d3b0591SJens Wiklander * 938*3d3b0591SJens Wiklander * Notes: 939*3d3b0591SJens Wiklander * 940*3d3b0591SJens Wiklander * - This function does not own the key buffer. It is the 941*3d3b0591SJens Wiklander * responsibility of the caller to take care of zeroizing 942*3d3b0591SJens Wiklander * and freeing it after use. 943*3d3b0591SJens Wiklander * 944*3d3b0591SJens Wiklander * - The function is responsible for freeing the provided 945*3d3b0591SJens Wiklander * PK context on failure. 946*3d3b0591SJens Wiklander * 947817466cbSJens Wiklander */ 948817466cbSJens Wiklander static int pk_parse_key_pkcs8_unencrypted_der( 949817466cbSJens Wiklander mbedtls_pk_context *pk, 950817466cbSJens Wiklander const unsigned char* key, 951817466cbSJens Wiklander size_t keylen ) 952817466cbSJens Wiklander { 953817466cbSJens Wiklander int ret, version; 954817466cbSJens Wiklander size_t len; 955817466cbSJens Wiklander mbedtls_asn1_buf params; 956817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 957817466cbSJens Wiklander unsigned char *end = p + keylen; 958817466cbSJens Wiklander mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; 959817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 960817466cbSJens Wiklander 961817466cbSJens Wiklander /* 962*3d3b0591SJens Wiklander * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208) 963817466cbSJens Wiklander * 964817466cbSJens Wiklander * PrivateKeyInfo ::= SEQUENCE { 965817466cbSJens Wiklander * version Version, 966817466cbSJens Wiklander * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 967817466cbSJens Wiklander * privateKey PrivateKey, 968817466cbSJens Wiklander * attributes [0] IMPLICIT Attributes OPTIONAL } 969817466cbSJens Wiklander * 970817466cbSJens Wiklander * Version ::= INTEGER 971817466cbSJens Wiklander * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier 972817466cbSJens Wiklander * PrivateKey ::= OCTET STRING 973817466cbSJens Wiklander * 974817466cbSJens Wiklander * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey 975817466cbSJens Wiklander */ 976817466cbSJens Wiklander 977817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 978817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 979817466cbSJens Wiklander { 980817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 981817466cbSJens Wiklander } 982817466cbSJens Wiklander 983817466cbSJens Wiklander end = p + len; 984817466cbSJens Wiklander 985817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 986817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 987817466cbSJens Wiklander 988817466cbSJens Wiklander if( version != 0 ) 989817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); 990817466cbSJens Wiklander 991817466cbSJens Wiklander if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) 992817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 993817466cbSJens Wiklander 994817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 995817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 996817466cbSJens Wiklander 997817466cbSJens Wiklander if( len < 1 ) 998817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 999817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 1000817466cbSJens Wiklander 1001817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) 1002817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1003817466cbSJens Wiklander 1004817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) 1005817466cbSJens Wiklander return( ret ); 1006817466cbSJens Wiklander 1007817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1008817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA ) 1009817466cbSJens Wiklander { 1010817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) 1011817466cbSJens Wiklander { 1012817466cbSJens Wiklander mbedtls_pk_free( pk ); 1013817466cbSJens Wiklander return( ret ); 1014817466cbSJens Wiklander } 1015817466cbSJens Wiklander } else 1016817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1017817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1018817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) 1019817466cbSJens Wiklander { 1020817466cbSJens Wiklander if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || 1021817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) 1022817466cbSJens Wiklander { 1023817466cbSJens Wiklander mbedtls_pk_free( pk ); 1024817466cbSJens Wiklander return( ret ); 1025817466cbSJens Wiklander } 1026817466cbSJens Wiklander } else 1027817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1028817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1029817466cbSJens Wiklander 1030817466cbSJens Wiklander return( 0 ); 1031817466cbSJens Wiklander } 1032817466cbSJens Wiklander 1033817466cbSJens Wiklander /* 1034817466cbSJens Wiklander * Parse an encrypted PKCS#8 encoded private key 1035*3d3b0591SJens Wiklander * 1036*3d3b0591SJens Wiklander * To save space, the decryption happens in-place on the given key buffer. 1037*3d3b0591SJens Wiklander * Also, while this function may modify the keybuffer, it doesn't own it, 1038*3d3b0591SJens Wiklander * and instead it is the responsibility of the caller to zeroize and properly 1039*3d3b0591SJens Wiklander * free it after use. 1040*3d3b0591SJens Wiklander * 1041817466cbSJens Wiklander */ 1042817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1043817466cbSJens Wiklander static int pk_parse_key_pkcs8_encrypted_der( 1044817466cbSJens Wiklander mbedtls_pk_context *pk, 1045*3d3b0591SJens Wiklander unsigned char *key, size_t keylen, 1046817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 1047817466cbSJens Wiklander { 1048817466cbSJens Wiklander int ret, decrypted = 0; 1049817466cbSJens Wiklander size_t len; 1050*3d3b0591SJens Wiklander unsigned char *buf; 1051817466cbSJens Wiklander unsigned char *p, *end; 1052817466cbSJens Wiklander mbedtls_asn1_buf pbe_alg_oid, pbe_params; 1053817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 1054817466cbSJens Wiklander mbedtls_cipher_type_t cipher_alg; 1055817466cbSJens Wiklander mbedtls_md_type_t md_alg; 1056817466cbSJens Wiklander #endif 1057817466cbSJens Wiklander 1058*3d3b0591SJens Wiklander p = key; 1059817466cbSJens Wiklander end = p + keylen; 1060817466cbSJens Wiklander 1061817466cbSJens Wiklander if( pwdlen == 0 ) 1062817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1063817466cbSJens Wiklander 1064817466cbSJens Wiklander /* 1065*3d3b0591SJens Wiklander * This function parses the EncryptedPrivateKeyInfo object (PKCS#8) 1066817466cbSJens Wiklander * 1067817466cbSJens Wiklander * EncryptedPrivateKeyInfo ::= SEQUENCE { 1068817466cbSJens Wiklander * encryptionAlgorithm EncryptionAlgorithmIdentifier, 1069817466cbSJens Wiklander * encryptedData EncryptedData 1070817466cbSJens Wiklander * } 1071817466cbSJens Wiklander * 1072817466cbSJens Wiklander * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier 1073817466cbSJens Wiklander * 1074817466cbSJens Wiklander * EncryptedData ::= OCTET STRING 1075817466cbSJens Wiklander * 1076817466cbSJens Wiklander * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo 1077*3d3b0591SJens Wiklander * 1078817466cbSJens Wiklander */ 1079817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 1080817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 1081817466cbSJens Wiklander { 1082817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1083817466cbSJens Wiklander } 1084817466cbSJens Wiklander 1085817466cbSJens Wiklander end = p + len; 1086817466cbSJens Wiklander 1087817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) 1088817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1089817466cbSJens Wiklander 1090817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 1091817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 1092817466cbSJens Wiklander 1093*3d3b0591SJens Wiklander buf = p; 1094817466cbSJens Wiklander 1095817466cbSJens Wiklander /* 1096*3d3b0591SJens Wiklander * Decrypt EncryptedData with appropriate PBE 1097817466cbSJens Wiklander */ 1098817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 1099817466cbSJens Wiklander if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) 1100817466cbSJens Wiklander { 1101817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, 1102817466cbSJens Wiklander cipher_alg, md_alg, 1103817466cbSJens Wiklander pwd, pwdlen, p, len, buf ) ) != 0 ) 1104817466cbSJens Wiklander { 1105817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) 1106817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1107817466cbSJens Wiklander 1108817466cbSJens Wiklander return( ret ); 1109817466cbSJens Wiklander } 1110817466cbSJens Wiklander 1111817466cbSJens Wiklander decrypted = 1; 1112817466cbSJens Wiklander } 1113817466cbSJens Wiklander else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) 1114817466cbSJens Wiklander { 1115817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, 1116817466cbSJens Wiklander MBEDTLS_PKCS12_PBE_DECRYPT, 1117817466cbSJens Wiklander pwd, pwdlen, 1118817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1119817466cbSJens Wiklander { 1120817466cbSJens Wiklander return( ret ); 1121817466cbSJens Wiklander } 1122817466cbSJens Wiklander 1123817466cbSJens Wiklander // Best guess for password mismatch when using RC4. If first tag is 1124817466cbSJens Wiklander // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE 1125817466cbSJens Wiklander // 1126817466cbSJens Wiklander if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) 1127817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1128817466cbSJens Wiklander 1129817466cbSJens Wiklander decrypted = 1; 1130817466cbSJens Wiklander } 1131817466cbSJens Wiklander else 1132817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C */ 1133817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 1134817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) 1135817466cbSJens Wiklander { 1136817466cbSJens Wiklander if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, 1137817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1138817466cbSJens Wiklander { 1139817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) 1140817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1141817466cbSJens Wiklander 1142817466cbSJens Wiklander return( ret ); 1143817466cbSJens Wiklander } 1144817466cbSJens Wiklander 1145817466cbSJens Wiklander decrypted = 1; 1146817466cbSJens Wiklander } 1147817466cbSJens Wiklander else 1148817466cbSJens Wiklander #endif /* MBEDTLS_PKCS5_C */ 1149817466cbSJens Wiklander { 1150817466cbSJens Wiklander ((void) pwd); 1151817466cbSJens Wiklander } 1152817466cbSJens Wiklander 1153817466cbSJens Wiklander if( decrypted == 0 ) 1154817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 1155817466cbSJens Wiklander 1156817466cbSJens Wiklander return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); 1157817466cbSJens Wiklander } 1158817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1159817466cbSJens Wiklander 1160817466cbSJens Wiklander /* 1161817466cbSJens Wiklander * Parse a private key 1162817466cbSJens Wiklander */ 1163817466cbSJens Wiklander int mbedtls_pk_parse_key( mbedtls_pk_context *pk, 1164817466cbSJens Wiklander const unsigned char *key, size_t keylen, 1165817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 1166817466cbSJens Wiklander { 1167817466cbSJens Wiklander int ret; 1168817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 1169817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1170817466cbSJens Wiklander size_t len; 1171817466cbSJens Wiklander mbedtls_pem_context pem; 1172*3d3b0591SJens Wiklander #endif 1173817466cbSJens Wiklander 1174*3d3b0591SJens Wiklander PK_VALIDATE_RET( pk != NULL ); 1175*3d3b0591SJens Wiklander if( keylen == 0 ) 1176*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 1177*3d3b0591SJens Wiklander PK_VALIDATE_RET( key != NULL ); 1178*3d3b0591SJens Wiklander 1179*3d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1180817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1181817466cbSJens Wiklander 1182817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1183817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1184*3d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1185817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1186817466cbSJens Wiklander else 1187817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1188817466cbSJens Wiklander "-----BEGIN RSA PRIVATE KEY-----", 1189817466cbSJens Wiklander "-----END RSA PRIVATE KEY-----", 1190817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1191817466cbSJens Wiklander 1192817466cbSJens Wiklander if( ret == 0 ) 1193817466cbSJens Wiklander { 1194*3d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); 1195817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1196817466cbSJens Wiklander ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), 1197817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1198817466cbSJens Wiklander { 1199817466cbSJens Wiklander mbedtls_pk_free( pk ); 1200817466cbSJens Wiklander } 1201817466cbSJens Wiklander 1202817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1203817466cbSJens Wiklander return( ret ); 1204817466cbSJens Wiklander } 1205817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1206817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1207817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1208817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1209817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1210817466cbSJens Wiklander return( ret ); 1211817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1212817466cbSJens Wiklander 1213817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1214817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1215*3d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1216817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1217817466cbSJens Wiklander else 1218817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1219817466cbSJens Wiklander "-----BEGIN EC PRIVATE KEY-----", 1220817466cbSJens Wiklander "-----END EC PRIVATE KEY-----", 1221817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1222817466cbSJens Wiklander if( ret == 0 ) 1223817466cbSJens Wiklander { 1224*3d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); 1225817466cbSJens Wiklander 1226817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1227817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), 1228817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1229817466cbSJens Wiklander { 1230817466cbSJens Wiklander mbedtls_pk_free( pk ); 1231817466cbSJens Wiklander } 1232817466cbSJens Wiklander 1233817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1234817466cbSJens Wiklander return( ret ); 1235817466cbSJens Wiklander } 1236817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1237817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1238817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1239817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1240817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1241817466cbSJens Wiklander return( ret ); 1242817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1243817466cbSJens Wiklander 1244817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1245*3d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1246817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1247817466cbSJens Wiklander else 1248817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1249817466cbSJens Wiklander "-----BEGIN PRIVATE KEY-----", 1250817466cbSJens Wiklander "-----END PRIVATE KEY-----", 1251817466cbSJens Wiklander key, NULL, 0, &len ); 1252817466cbSJens Wiklander if( ret == 0 ) 1253817466cbSJens Wiklander { 1254817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, 1255817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1256817466cbSJens Wiklander { 1257817466cbSJens Wiklander mbedtls_pk_free( pk ); 1258817466cbSJens Wiklander } 1259817466cbSJens Wiklander 1260817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1261817466cbSJens Wiklander return( ret ); 1262817466cbSJens Wiklander } 1263817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1264817466cbSJens Wiklander return( ret ); 1265817466cbSJens Wiklander 1266817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1267817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1268*3d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1269817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1270817466cbSJens Wiklander else 1271817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1272817466cbSJens Wiklander "-----BEGIN ENCRYPTED PRIVATE KEY-----", 1273817466cbSJens Wiklander "-----END ENCRYPTED PRIVATE KEY-----", 1274817466cbSJens Wiklander key, NULL, 0, &len ); 1275817466cbSJens Wiklander if( ret == 0 ) 1276817466cbSJens Wiklander { 1277817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, 1278817466cbSJens Wiklander pem.buf, pem.buflen, 1279817466cbSJens Wiklander pwd, pwdlen ) ) != 0 ) 1280817466cbSJens Wiklander { 1281817466cbSJens Wiklander mbedtls_pk_free( pk ); 1282817466cbSJens Wiklander } 1283817466cbSJens Wiklander 1284817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1285817466cbSJens Wiklander return( ret ); 1286817466cbSJens Wiklander } 1287817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1288817466cbSJens Wiklander return( ret ); 1289817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1290817466cbSJens Wiklander #else 1291817466cbSJens Wiklander ((void) pwd); 1292817466cbSJens Wiklander ((void) pwdlen); 1293817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1294817466cbSJens Wiklander 1295817466cbSJens Wiklander /* 1296817466cbSJens Wiklander * At this point we only know it's not a PEM formatted key. Could be any 1297817466cbSJens Wiklander * of the known DER encoded private key formats 1298817466cbSJens Wiklander * 1299817466cbSJens Wiklander * We try the different DER format parsers to see if one passes without 1300817466cbSJens Wiklander * error 1301817466cbSJens Wiklander */ 1302817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1303817466cbSJens Wiklander { 1304*3d3b0591SJens Wiklander unsigned char *key_copy; 1305*3d3b0591SJens Wiklander 1306*3d3b0591SJens Wiklander if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL ) 1307*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_ALLOC_FAILED ); 1308*3d3b0591SJens Wiklander 1309*3d3b0591SJens Wiklander memcpy( key_copy, key, keylen ); 1310*3d3b0591SJens Wiklander 1311*3d3b0591SJens Wiklander ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen, 1312*3d3b0591SJens Wiklander pwd, pwdlen ); 1313*3d3b0591SJens Wiklander 1314*3d3b0591SJens Wiklander mbedtls_platform_zeroize( key_copy, keylen ); 1315*3d3b0591SJens Wiklander mbedtls_free( key_copy ); 1316817466cbSJens Wiklander } 1317817466cbSJens Wiklander 1318*3d3b0591SJens Wiklander if( ret == 0 ) 1319*3d3b0591SJens Wiklander return( 0 ); 1320*3d3b0591SJens Wiklander 1321817466cbSJens Wiklander mbedtls_pk_free( pk ); 1322*3d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1323817466cbSJens Wiklander 1324817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) 1325817466cbSJens Wiklander { 1326817466cbSJens Wiklander return( ret ); 1327817466cbSJens Wiklander } 1328817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1329817466cbSJens Wiklander 1330817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) 1331817466cbSJens Wiklander return( 0 ); 1332817466cbSJens Wiklander 1333817466cbSJens Wiklander mbedtls_pk_free( pk ); 1334*3d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1335817466cbSJens Wiklander 1336817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1337817466cbSJens Wiklander 1338*3d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); 1339*3d3b0591SJens Wiklander if( mbedtls_pk_setup( pk, pk_info ) == 0 && 1340*3d3b0591SJens Wiklander pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) == 0 ) 1341817466cbSJens Wiklander { 1342817466cbSJens Wiklander return( 0 ); 1343817466cbSJens Wiklander } 1344817466cbSJens Wiklander 1345817466cbSJens Wiklander mbedtls_pk_free( pk ); 1346*3d3b0591SJens Wiklander mbedtls_pk_init( pk ); 1347817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1348817466cbSJens Wiklander 1349817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1350*3d3b0591SJens Wiklander pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); 1351*3d3b0591SJens Wiklander if( mbedtls_pk_setup( pk, pk_info ) == 0 && 1352*3d3b0591SJens Wiklander pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), 1353*3d3b0591SJens Wiklander key, keylen ) == 0 ) 1354817466cbSJens Wiklander { 1355817466cbSJens Wiklander return( 0 ); 1356817466cbSJens Wiklander } 1357817466cbSJens Wiklander mbedtls_pk_free( pk ); 1358817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1359817466cbSJens Wiklander 1360*3d3b0591SJens Wiklander /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't, 1361*3d3b0591SJens Wiklander * it is ok to leave the PK context initialized but not 1362*3d3b0591SJens Wiklander * freed: It is the caller's responsibility to call pk_init() 1363*3d3b0591SJens Wiklander * before calling this function, and to call pk_free() 1364*3d3b0591SJens Wiklander * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C 1365*3d3b0591SJens Wiklander * isn't, this leads to mbedtls_pk_free() being called 1366*3d3b0591SJens Wiklander * twice, once here and once by the caller, but this is 1367*3d3b0591SJens Wiklander * also ok and in line with the mbedtls_pk_free() calls 1368*3d3b0591SJens Wiklander * on failed PEM parsing attempts. */ 1369*3d3b0591SJens Wiklander 1370817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 1371817466cbSJens Wiklander } 1372817466cbSJens Wiklander 1373817466cbSJens Wiklander /* 1374817466cbSJens Wiklander * Parse a public key 1375817466cbSJens Wiklander */ 1376817466cbSJens Wiklander int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, 1377817466cbSJens Wiklander const unsigned char *key, size_t keylen ) 1378817466cbSJens Wiklander { 1379817466cbSJens Wiklander int ret; 1380817466cbSJens Wiklander unsigned char *p; 1381*3d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 1382*3d3b0591SJens Wiklander const mbedtls_pk_info_t *pk_info; 1383*3d3b0591SJens Wiklander #endif 1384817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1385817466cbSJens Wiklander size_t len; 1386817466cbSJens Wiklander mbedtls_pem_context pem; 1387*3d3b0591SJens Wiklander #endif 1388817466cbSJens Wiklander 1389*3d3b0591SJens Wiklander PK_VALIDATE_RET( ctx != NULL ); 1390*3d3b0591SJens Wiklander if( keylen == 0 ) 1391*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 1392*3d3b0591SJens Wiklander PK_VALIDATE_RET( key != NULL || keylen == 0 ); 1393*3d3b0591SJens Wiklander 1394*3d3b0591SJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1395817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1396*3d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 1397*3d3b0591SJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1398*3d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1399*3d3b0591SJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1400*3d3b0591SJens Wiklander else 1401*3d3b0591SJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1402*3d3b0591SJens Wiklander "-----BEGIN RSA PUBLIC KEY-----", 1403*3d3b0591SJens Wiklander "-----END RSA PUBLIC KEY-----", 1404*3d3b0591SJens Wiklander key, NULL, 0, &len ); 1405*3d3b0591SJens Wiklander 1406*3d3b0591SJens Wiklander if( ret == 0 ) 1407*3d3b0591SJens Wiklander { 1408*3d3b0591SJens Wiklander p = pem.buf; 1409*3d3b0591SJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 1410*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1411*3d3b0591SJens Wiklander 1412*3d3b0591SJens Wiklander if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) 1413*3d3b0591SJens Wiklander return( ret ); 1414*3d3b0591SJens Wiklander 1415*3d3b0591SJens Wiklander if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 ) 1416*3d3b0591SJens Wiklander mbedtls_pk_free( ctx ); 1417*3d3b0591SJens Wiklander 1418*3d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 1419*3d3b0591SJens Wiklander return( ret ); 1420*3d3b0591SJens Wiklander } 1421*3d3b0591SJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1422*3d3b0591SJens Wiklander { 1423*3d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 1424*3d3b0591SJens Wiklander return( ret ); 1425*3d3b0591SJens Wiklander } 1426*3d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */ 1427817466cbSJens Wiklander 1428817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1429*3d3b0591SJens Wiklander if( key[keylen - 1] != '\0' ) 1430817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1431817466cbSJens Wiklander else 1432817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1433817466cbSJens Wiklander "-----BEGIN PUBLIC KEY-----", 1434817466cbSJens Wiklander "-----END PUBLIC KEY-----", 1435817466cbSJens Wiklander key, NULL, 0, &len ); 1436817466cbSJens Wiklander 1437817466cbSJens Wiklander if( ret == 0 ) 1438817466cbSJens Wiklander { 1439817466cbSJens Wiklander /* 1440817466cbSJens Wiklander * Was PEM encoded 1441817466cbSJens Wiklander */ 1442*3d3b0591SJens Wiklander p = pem.buf; 1443*3d3b0591SJens Wiklander 1444*3d3b0591SJens Wiklander ret = mbedtls_pk_parse_subpubkey( &p, p + pem.buflen, ctx ); 1445*3d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 1446*3d3b0591SJens Wiklander return( ret ); 1447817466cbSJens Wiklander } 1448817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1449817466cbSJens Wiklander { 1450817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1451817466cbSJens Wiklander return( ret ); 1452817466cbSJens Wiklander } 1453*3d3b0591SJens Wiklander mbedtls_pem_free( &pem ); 1454817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1455*3d3b0591SJens Wiklander 1456*3d3b0591SJens Wiklander #if defined(MBEDTLS_RSA_C) 1457*3d3b0591SJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 1458*3d3b0591SJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1459*3d3b0591SJens Wiklander 1460*3d3b0591SJens Wiklander if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) 1461*3d3b0591SJens Wiklander return( ret ); 1462*3d3b0591SJens Wiklander 1463*3d3b0591SJens Wiklander p = (unsigned char *)key; 1464*3d3b0591SJens Wiklander ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) ); 1465*3d3b0591SJens Wiklander if( ret == 0 ) 1466*3d3b0591SJens Wiklander { 1467*3d3b0591SJens Wiklander return( ret ); 1468*3d3b0591SJens Wiklander } 1469*3d3b0591SJens Wiklander mbedtls_pk_free( ctx ); 1470*3d3b0591SJens Wiklander if( ret != ( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) 1471*3d3b0591SJens Wiklander { 1472*3d3b0591SJens Wiklander return( ret ); 1473*3d3b0591SJens Wiklander } 1474*3d3b0591SJens Wiklander #endif /* MBEDTLS_RSA_C */ 1475817466cbSJens Wiklander p = (unsigned char *) key; 1476817466cbSJens Wiklander 1477817466cbSJens Wiklander ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); 1478817466cbSJens Wiklander 1479817466cbSJens Wiklander return( ret ); 1480817466cbSJens Wiklander } 1481817466cbSJens Wiklander 1482817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_C */ 1483