1*c6672fdcSEdison 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" 33817466cbSJens Wiklander 34817466cbSJens Wiklander #include <string.h> 35817466cbSJens Wiklander 36817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 37817466cbSJens Wiklander #include "mbedtls/rsa.h" 38817466cbSJens Wiklander #endif 39817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 40817466cbSJens Wiklander #include "mbedtls/ecp.h" 41817466cbSJens Wiklander #endif 42817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_C) 43817466cbSJens Wiklander #include "mbedtls/ecdsa.h" 44817466cbSJens Wiklander #endif 45817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 46817466cbSJens Wiklander #include "mbedtls/pem.h" 47817466cbSJens Wiklander #endif 48817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 49817466cbSJens Wiklander #include "mbedtls/pkcs5.h" 50817466cbSJens Wiklander #endif 51817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 52817466cbSJens Wiklander #include "mbedtls/pkcs12.h" 53817466cbSJens Wiklander #endif 54817466cbSJens Wiklander 55817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 56817466cbSJens Wiklander #include "mbedtls/platform.h" 57817466cbSJens Wiklander #else 58817466cbSJens Wiklander #include <stdlib.h> 59817466cbSJens Wiklander #define mbedtls_calloc calloc 60817466cbSJens Wiklander #define mbedtls_free free 61817466cbSJens Wiklander #endif 62817466cbSJens Wiklander 63817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 64817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */ 65817466cbSJens Wiklander static void mbedtls_zeroize( void *v, size_t n ) { 66817466cbSJens Wiklander volatile unsigned char *p = v; while( n-- ) *p++ = 0; 67817466cbSJens Wiklander } 68817466cbSJens Wiklander 69817466cbSJens Wiklander /* 70817466cbSJens Wiklander * Load all data from a file into a given buffer. 71817466cbSJens Wiklander * 72817466cbSJens Wiklander * The file is expected to contain either PEM or DER encoded data. 73817466cbSJens Wiklander * A terminating null byte is always appended. It is included in the announced 74817466cbSJens Wiklander * length only if the data looks like it is PEM encoded. 75817466cbSJens Wiklander */ 76817466cbSJens Wiklander int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) 77817466cbSJens Wiklander { 78817466cbSJens Wiklander FILE *f; 79817466cbSJens Wiklander long size; 80817466cbSJens Wiklander 81817466cbSJens Wiklander if( ( f = fopen( path, "rb" ) ) == NULL ) 82817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 83817466cbSJens Wiklander 84817466cbSJens Wiklander fseek( f, 0, SEEK_END ); 85817466cbSJens Wiklander if( ( size = ftell( f ) ) == -1 ) 86817466cbSJens Wiklander { 87817466cbSJens Wiklander fclose( f ); 88817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 89817466cbSJens Wiklander } 90817466cbSJens Wiklander fseek( f, 0, SEEK_SET ); 91817466cbSJens Wiklander 92817466cbSJens Wiklander *n = (size_t) size; 93817466cbSJens Wiklander 94817466cbSJens Wiklander if( *n + 1 == 0 || 95817466cbSJens Wiklander ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) 96817466cbSJens Wiklander { 97817466cbSJens Wiklander fclose( f ); 98817466cbSJens Wiklander return( MBEDTLS_ERR_PK_ALLOC_FAILED ); 99817466cbSJens Wiklander } 100817466cbSJens Wiklander 101817466cbSJens Wiklander if( fread( *buf, 1, *n, f ) != *n ) 102817466cbSJens Wiklander { 103817466cbSJens Wiklander fclose( f ); 104817466cbSJens Wiklander mbedtls_free( *buf ); 105817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); 106817466cbSJens Wiklander } 107817466cbSJens Wiklander 108817466cbSJens Wiklander fclose( f ); 109817466cbSJens Wiklander 110817466cbSJens Wiklander (*buf)[*n] = '\0'; 111817466cbSJens Wiklander 112817466cbSJens Wiklander if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) 113817466cbSJens Wiklander ++*n; 114817466cbSJens Wiklander 115817466cbSJens Wiklander return( 0 ); 116817466cbSJens Wiklander } 117817466cbSJens Wiklander 118817466cbSJens Wiklander /* 119817466cbSJens Wiklander * Load and parse a private key 120817466cbSJens Wiklander */ 121817466cbSJens Wiklander int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, 122817466cbSJens Wiklander const char *path, const char *pwd ) 123817466cbSJens Wiklander { 124817466cbSJens Wiklander int ret; 125817466cbSJens Wiklander size_t n; 126817466cbSJens Wiklander unsigned char *buf; 127817466cbSJens Wiklander 128817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 129817466cbSJens Wiklander return( ret ); 130817466cbSJens Wiklander 131817466cbSJens Wiklander if( pwd == NULL ) 132817466cbSJens Wiklander ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); 133817466cbSJens Wiklander else 134817466cbSJens Wiklander ret = mbedtls_pk_parse_key( ctx, buf, n, 135817466cbSJens Wiklander (const unsigned char *) pwd, strlen( pwd ) ); 136817466cbSJens Wiklander 137817466cbSJens Wiklander mbedtls_zeroize( buf, n ); 138817466cbSJens Wiklander mbedtls_free( buf ); 139817466cbSJens Wiklander 140817466cbSJens Wiklander return( ret ); 141817466cbSJens Wiklander } 142817466cbSJens Wiklander 143817466cbSJens Wiklander /* 144817466cbSJens Wiklander * Load and parse a public key 145817466cbSJens Wiklander */ 146817466cbSJens Wiklander int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) 147817466cbSJens Wiklander { 148817466cbSJens Wiklander int ret; 149817466cbSJens Wiklander size_t n; 150817466cbSJens Wiklander unsigned char *buf; 151817466cbSJens Wiklander 152817466cbSJens Wiklander if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) 153817466cbSJens Wiklander return( ret ); 154817466cbSJens Wiklander 155817466cbSJens Wiklander ret = mbedtls_pk_parse_public_key( ctx, buf, n ); 156817466cbSJens Wiklander 157817466cbSJens Wiklander mbedtls_zeroize( buf, n ); 158817466cbSJens Wiklander mbedtls_free( buf ); 159817466cbSJens Wiklander 160817466cbSJens Wiklander return( ret ); 161817466cbSJens Wiklander } 162817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 163817466cbSJens Wiklander 164817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 165817466cbSJens Wiklander /* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf 166817466cbSJens Wiklander * 167817466cbSJens Wiklander * ECParameters ::= CHOICE { 168817466cbSJens Wiklander * namedCurve OBJECT IDENTIFIER 169817466cbSJens Wiklander * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } 170817466cbSJens Wiklander * -- implicitCurve NULL 171817466cbSJens Wiklander * } 172817466cbSJens Wiklander */ 173817466cbSJens Wiklander static int pk_get_ecparams( unsigned char **p, const unsigned char *end, 174817466cbSJens Wiklander mbedtls_asn1_buf *params ) 175817466cbSJens Wiklander { 176817466cbSJens Wiklander int ret; 177817466cbSJens Wiklander 178817466cbSJens Wiklander /* Tag may be either OID or SEQUENCE */ 179817466cbSJens Wiklander params->tag = **p; 180817466cbSJens Wiklander if( params->tag != MBEDTLS_ASN1_OID 181817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 182817466cbSJens Wiklander && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) 183817466cbSJens Wiklander #endif 184817466cbSJens Wiklander ) 185817466cbSJens Wiklander { 186817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 187817466cbSJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); 188817466cbSJens Wiklander } 189817466cbSJens Wiklander 190817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 ) 191817466cbSJens Wiklander { 192817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 193817466cbSJens Wiklander } 194817466cbSJens Wiklander 195817466cbSJens Wiklander params->p = *p; 196817466cbSJens Wiklander *p += params->len; 197817466cbSJens Wiklander 198817466cbSJens Wiklander if( *p != end ) 199817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 200817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 201817466cbSJens Wiklander 202817466cbSJens Wiklander return( 0 ); 203817466cbSJens Wiklander } 204817466cbSJens Wiklander 205817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 206817466cbSJens Wiklander /* 207817466cbSJens Wiklander * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. 208817466cbSJens Wiklander * WARNING: the resulting group should only be used with 209817466cbSJens Wiklander * pk_group_id_from_specified(), since its base point may not be set correctly 210817466cbSJens Wiklander * if it was encoded compressed. 211817466cbSJens Wiklander * 212817466cbSJens Wiklander * SpecifiedECDomain ::= SEQUENCE { 213817466cbSJens Wiklander * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), 214817466cbSJens Wiklander * fieldID FieldID {{FieldTypes}}, 215817466cbSJens Wiklander * curve Curve, 216817466cbSJens Wiklander * base ECPoint, 217817466cbSJens Wiklander * order INTEGER, 218817466cbSJens Wiklander * cofactor INTEGER OPTIONAL, 219817466cbSJens Wiklander * hash HashAlgorithm OPTIONAL, 220817466cbSJens Wiklander * ... 221817466cbSJens Wiklander * } 222817466cbSJens Wiklander * 223817466cbSJens Wiklander * We only support prime-field as field type, and ignore hash and cofactor. 224817466cbSJens Wiklander */ 225817466cbSJens Wiklander static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) 226817466cbSJens Wiklander { 227817466cbSJens Wiklander int ret; 228817466cbSJens Wiklander unsigned char *p = params->p; 229817466cbSJens Wiklander const unsigned char * const end = params->p + params->len; 230817466cbSJens Wiklander const unsigned char *end_field, *end_curve; 231817466cbSJens Wiklander size_t len; 232817466cbSJens Wiklander int ver; 233817466cbSJens Wiklander 234817466cbSJens Wiklander /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ 235817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) 236817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 237817466cbSJens Wiklander 238817466cbSJens Wiklander if( ver < 1 || ver > 3 ) 239817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 240817466cbSJens Wiklander 241817466cbSJens Wiklander /* 242817466cbSJens Wiklander * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field 243817466cbSJens Wiklander * fieldType FIELD-ID.&id({IOSet}), 244817466cbSJens Wiklander * parameters FIELD-ID.&Type({IOSet}{@fieldType}) 245817466cbSJens Wiklander * } 246817466cbSJens Wiklander */ 247817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 248817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 249817466cbSJens Wiklander return( ret ); 250817466cbSJens Wiklander 251817466cbSJens Wiklander end_field = p + len; 252817466cbSJens Wiklander 253817466cbSJens Wiklander /* 254817466cbSJens Wiklander * FIELD-ID ::= TYPE-IDENTIFIER 255817466cbSJens Wiklander * FieldTypes FIELD-ID ::= { 256817466cbSJens Wiklander * { Prime-p IDENTIFIED BY prime-field } | 257817466cbSJens Wiklander * { Characteristic-two IDENTIFIED BY characteristic-two-field } 258817466cbSJens Wiklander * } 259817466cbSJens Wiklander * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } 260817466cbSJens Wiklander */ 261817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) 262817466cbSJens Wiklander return( ret ); 263817466cbSJens Wiklander 264817466cbSJens Wiklander if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || 265817466cbSJens Wiklander memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) 266817466cbSJens Wiklander { 267817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 268817466cbSJens Wiklander } 269817466cbSJens Wiklander 270817466cbSJens Wiklander p += len; 271817466cbSJens Wiklander 272817466cbSJens Wiklander /* Prime-p ::= INTEGER -- Field of size p. */ 273817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) 274817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 275817466cbSJens Wiklander 276817466cbSJens Wiklander grp->pbits = mbedtls_mpi_bitlen( &grp->P ); 277817466cbSJens Wiklander 278817466cbSJens Wiklander if( p != end_field ) 279817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 280817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 281817466cbSJens Wiklander 282817466cbSJens Wiklander /* 283817466cbSJens Wiklander * Curve ::= SEQUENCE { 284817466cbSJens Wiklander * a FieldElement, 285817466cbSJens Wiklander * b FieldElement, 286817466cbSJens Wiklander * seed BIT STRING OPTIONAL 287817466cbSJens Wiklander * -- Shall be present if used in SpecifiedECDomain 288817466cbSJens Wiklander * -- with version equal to ecdpVer2 or ecdpVer3 289817466cbSJens Wiklander * } 290817466cbSJens Wiklander */ 291817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 292817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 293817466cbSJens Wiklander return( ret ); 294817466cbSJens Wiklander 295817466cbSJens Wiklander end_curve = p + len; 296817466cbSJens Wiklander 297817466cbSJens Wiklander /* 298817466cbSJens Wiklander * FieldElement ::= OCTET STRING 299817466cbSJens Wiklander * containing an integer in the case of a prime field 300817466cbSJens Wiklander */ 301817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || 302817466cbSJens Wiklander ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) 303817466cbSJens Wiklander { 304817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 305817466cbSJens Wiklander } 306817466cbSJens Wiklander 307817466cbSJens Wiklander p += len; 308817466cbSJens Wiklander 309817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || 310817466cbSJens Wiklander ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) 311817466cbSJens Wiklander { 312817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 313817466cbSJens Wiklander } 314817466cbSJens Wiklander 315817466cbSJens Wiklander p += len; 316817466cbSJens Wiklander 317817466cbSJens Wiklander /* Ignore seed BIT STRING OPTIONAL */ 318817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) 319817466cbSJens Wiklander p += len; 320817466cbSJens Wiklander 321817466cbSJens Wiklander if( p != end_curve ) 322817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 323817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 324817466cbSJens Wiklander 325817466cbSJens Wiklander /* 326817466cbSJens Wiklander * ECPoint ::= OCTET STRING 327817466cbSJens Wiklander */ 328817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 329817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 330817466cbSJens Wiklander 331817466cbSJens Wiklander if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, 332817466cbSJens Wiklander ( const unsigned char *) p, len ) ) != 0 ) 333817466cbSJens Wiklander { 334817466cbSJens Wiklander /* 335817466cbSJens Wiklander * If we can't read the point because it's compressed, cheat by 336817466cbSJens Wiklander * reading only the X coordinate and the parity bit of Y. 337817466cbSJens Wiklander */ 338817466cbSJens Wiklander if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || 339817466cbSJens Wiklander ( p[0] != 0x02 && p[0] != 0x03 ) || 340817466cbSJens Wiklander len != mbedtls_mpi_size( &grp->P ) + 1 || 341817466cbSJens Wiklander mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || 342817466cbSJens Wiklander mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || 343817466cbSJens Wiklander mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) 344817466cbSJens Wiklander { 345817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 346817466cbSJens Wiklander } 347817466cbSJens Wiklander } 348817466cbSJens Wiklander 349817466cbSJens Wiklander p += len; 350817466cbSJens Wiklander 351817466cbSJens Wiklander /* 352817466cbSJens Wiklander * order INTEGER 353817466cbSJens Wiklander */ 354817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) 355817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 356817466cbSJens Wiklander 357817466cbSJens Wiklander grp->nbits = mbedtls_mpi_bitlen( &grp->N ); 358817466cbSJens Wiklander 359817466cbSJens Wiklander /* 360817466cbSJens Wiklander * Allow optional elements by purposefully not enforcing p == end here. 361817466cbSJens Wiklander */ 362817466cbSJens Wiklander 363817466cbSJens Wiklander return( 0 ); 364817466cbSJens Wiklander } 365817466cbSJens Wiklander 366817466cbSJens Wiklander /* 367817466cbSJens Wiklander * Find the group id associated with an (almost filled) group as generated by 368817466cbSJens Wiklander * pk_group_from_specified(), or return an error if unknown. 369817466cbSJens Wiklander */ 370817466cbSJens Wiklander static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) 371817466cbSJens Wiklander { 372817466cbSJens Wiklander int ret = 0; 373817466cbSJens Wiklander mbedtls_ecp_group ref; 374817466cbSJens Wiklander const mbedtls_ecp_group_id *id; 375817466cbSJens Wiklander 376817466cbSJens Wiklander mbedtls_ecp_group_init( &ref ); 377817466cbSJens Wiklander 378817466cbSJens Wiklander for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) 379817466cbSJens Wiklander { 380817466cbSJens Wiklander /* Load the group associated to that id */ 381817466cbSJens Wiklander mbedtls_ecp_group_free( &ref ); 382817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); 383817466cbSJens Wiklander 384817466cbSJens Wiklander /* Compare to the group we were given, starting with easy tests */ 385817466cbSJens Wiklander if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && 386817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && 387817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && 388817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && 389817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && 390817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && 391817466cbSJens Wiklander mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && 392817466cbSJens Wiklander /* For Y we may only know the parity bit, so compare only that */ 393817466cbSJens Wiklander mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) 394817466cbSJens Wiklander { 395817466cbSJens Wiklander break; 396817466cbSJens Wiklander } 397817466cbSJens Wiklander 398817466cbSJens Wiklander } 399817466cbSJens Wiklander 400817466cbSJens Wiklander cleanup: 401817466cbSJens Wiklander mbedtls_ecp_group_free( &ref ); 402817466cbSJens Wiklander 403817466cbSJens Wiklander *grp_id = *id; 404817466cbSJens Wiklander 405817466cbSJens Wiklander if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) 406817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 407817466cbSJens Wiklander 408817466cbSJens Wiklander return( ret ); 409817466cbSJens Wiklander } 410817466cbSJens Wiklander 411817466cbSJens Wiklander /* 412817466cbSJens Wiklander * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID 413817466cbSJens Wiklander */ 414817466cbSJens Wiklander static int pk_group_id_from_specified( const mbedtls_asn1_buf *params, 415817466cbSJens Wiklander mbedtls_ecp_group_id *grp_id ) 416817466cbSJens Wiklander { 417817466cbSJens Wiklander int ret; 418817466cbSJens Wiklander mbedtls_ecp_group grp; 419817466cbSJens Wiklander 420817466cbSJens Wiklander mbedtls_ecp_group_init( &grp ); 421817466cbSJens Wiklander 422817466cbSJens Wiklander if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 ) 423817466cbSJens Wiklander goto cleanup; 424817466cbSJens Wiklander 425817466cbSJens Wiklander ret = pk_group_id_from_group( &grp, grp_id ); 426817466cbSJens Wiklander 427817466cbSJens Wiklander cleanup: 428817466cbSJens Wiklander mbedtls_ecp_group_free( &grp ); 429817466cbSJens Wiklander 430817466cbSJens Wiklander return( ret ); 431817466cbSJens Wiklander } 432817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ 433817466cbSJens Wiklander 434817466cbSJens Wiklander /* 435817466cbSJens Wiklander * Use EC parameters to initialise an EC group 436817466cbSJens Wiklander * 437817466cbSJens Wiklander * ECParameters ::= CHOICE { 438817466cbSJens Wiklander * namedCurve OBJECT IDENTIFIER 439817466cbSJens Wiklander * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } 440817466cbSJens Wiklander * -- implicitCurve NULL 441817466cbSJens Wiklander */ 442817466cbSJens Wiklander static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) 443817466cbSJens Wiklander { 444817466cbSJens Wiklander int ret; 445817466cbSJens Wiklander mbedtls_ecp_group_id grp_id; 446817466cbSJens Wiklander 447817466cbSJens Wiklander if( params->tag == MBEDTLS_ASN1_OID ) 448817466cbSJens Wiklander { 449817466cbSJens Wiklander if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) 450817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); 451817466cbSJens Wiklander } 452817466cbSJens Wiklander else 453817466cbSJens Wiklander { 454817466cbSJens Wiklander #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) 455817466cbSJens Wiklander if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 ) 456817466cbSJens Wiklander return( ret ); 457817466cbSJens Wiklander #else 458817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 459817466cbSJens Wiklander #endif 460817466cbSJens Wiklander } 461817466cbSJens Wiklander 462817466cbSJens Wiklander /* 463817466cbSJens Wiklander * grp may already be initilialized; if so, make sure IDs match 464817466cbSJens Wiklander */ 465817466cbSJens Wiklander if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id ) 466817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 467817466cbSJens Wiklander 468817466cbSJens Wiklander if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 ) 469817466cbSJens Wiklander return( ret ); 470817466cbSJens Wiklander 471817466cbSJens Wiklander return( 0 ); 472817466cbSJens Wiklander } 473817466cbSJens Wiklander 474817466cbSJens Wiklander /* 475817466cbSJens Wiklander * EC public key is an EC point 476817466cbSJens Wiklander * 477817466cbSJens Wiklander * The caller is responsible for clearing the structure upon failure if 478817466cbSJens Wiklander * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE 479817466cbSJens Wiklander * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. 480817466cbSJens Wiklander */ 481817466cbSJens Wiklander static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, 482817466cbSJens Wiklander mbedtls_ecp_keypair *key ) 483817466cbSJens Wiklander { 484817466cbSJens Wiklander int ret; 485817466cbSJens Wiklander 486817466cbSJens Wiklander if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, 487817466cbSJens Wiklander (const unsigned char *) *p, end - *p ) ) == 0 ) 488817466cbSJens Wiklander { 489817466cbSJens Wiklander ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); 490817466cbSJens Wiklander } 491817466cbSJens Wiklander 492817466cbSJens Wiklander /* 493817466cbSJens Wiklander * We know mbedtls_ecp_point_read_binary consumed all bytes or failed 494817466cbSJens Wiklander */ 495817466cbSJens Wiklander *p = (unsigned char *) end; 496817466cbSJens Wiklander 497817466cbSJens Wiklander return( ret ); 498817466cbSJens Wiklander } 499817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 500817466cbSJens Wiklander 501817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 502817466cbSJens Wiklander /* 503817466cbSJens Wiklander * RSAPublicKey ::= SEQUENCE { 504817466cbSJens Wiklander * modulus INTEGER, -- n 505817466cbSJens Wiklander * publicExponent INTEGER -- e 506817466cbSJens Wiklander * } 507817466cbSJens Wiklander */ 508817466cbSJens Wiklander static int pk_get_rsapubkey( unsigned char **p, 509817466cbSJens Wiklander const unsigned char *end, 510817466cbSJens Wiklander mbedtls_rsa_context *rsa ) 511817466cbSJens Wiklander { 512817466cbSJens Wiklander int ret; 513817466cbSJens Wiklander size_t len; 514817466cbSJens Wiklander 515817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 516817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 517817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 518817466cbSJens Wiklander 519817466cbSJens Wiklander if( *p + len != end ) 520817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 521817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 522817466cbSJens Wiklander 523817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->N ) ) != 0 || 524817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->E ) ) != 0 ) 525817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 526817466cbSJens Wiklander 527817466cbSJens Wiklander if( *p != end ) 528817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 529817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 530817466cbSJens Wiklander 531817466cbSJens Wiklander if( ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 ) 532817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); 533817466cbSJens Wiklander 534817466cbSJens Wiklander rsa->len = mbedtls_mpi_size( &rsa->N ); 535817466cbSJens Wiklander 536817466cbSJens Wiklander return( 0 ); 537817466cbSJens Wiklander } 538817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 539817466cbSJens Wiklander 540817466cbSJens Wiklander /* Get a PK algorithm identifier 541817466cbSJens Wiklander * 542817466cbSJens Wiklander * AlgorithmIdentifier ::= SEQUENCE { 543817466cbSJens Wiklander * algorithm OBJECT IDENTIFIER, 544817466cbSJens Wiklander * parameters ANY DEFINED BY algorithm OPTIONAL } 545817466cbSJens Wiklander */ 546817466cbSJens Wiklander static int pk_get_pk_alg( unsigned char **p, 547817466cbSJens Wiklander const unsigned char *end, 548817466cbSJens Wiklander mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params ) 549817466cbSJens Wiklander { 550817466cbSJens Wiklander int ret; 551817466cbSJens Wiklander mbedtls_asn1_buf alg_oid; 552817466cbSJens Wiklander 553817466cbSJens Wiklander memset( params, 0, sizeof(mbedtls_asn1_buf) ); 554817466cbSJens Wiklander 555817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 ) 556817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_ALG + ret ); 557817466cbSJens Wiklander 558817466cbSJens Wiklander if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 ) 559817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 560817466cbSJens Wiklander 561817466cbSJens Wiklander /* 562817466cbSJens Wiklander * No parameters with RSA (only for EC) 563817466cbSJens Wiklander */ 564817466cbSJens Wiklander if( *pk_alg == MBEDTLS_PK_RSA && 565817466cbSJens Wiklander ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) || 566817466cbSJens Wiklander params->len != 0 ) ) 567817466cbSJens Wiklander { 568817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_ALG ); 569817466cbSJens Wiklander } 570817466cbSJens Wiklander 571817466cbSJens Wiklander return( 0 ); 572817466cbSJens Wiklander } 573817466cbSJens Wiklander 574817466cbSJens Wiklander /* 575817466cbSJens Wiklander * SubjectPublicKeyInfo ::= SEQUENCE { 576817466cbSJens Wiklander * algorithm AlgorithmIdentifier, 577817466cbSJens Wiklander * subjectPublicKey BIT STRING } 578817466cbSJens Wiklander */ 579817466cbSJens Wiklander int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, 580817466cbSJens Wiklander mbedtls_pk_context *pk ) 581817466cbSJens Wiklander { 582817466cbSJens Wiklander int ret; 583817466cbSJens Wiklander size_t len; 584817466cbSJens Wiklander mbedtls_asn1_buf alg_params; 585817466cbSJens Wiklander mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; 586817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 587817466cbSJens Wiklander 588817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( p, end, &len, 589817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 590817466cbSJens Wiklander { 591817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 592817466cbSJens Wiklander } 593817466cbSJens Wiklander 594817466cbSJens Wiklander end = *p + len; 595817466cbSJens Wiklander 596817466cbSJens Wiklander if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 ) 597817466cbSJens Wiklander return( ret ); 598817466cbSJens Wiklander 599817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) 600817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); 601817466cbSJens Wiklander 602817466cbSJens Wiklander if( *p + len != end ) 603817466cbSJens Wiklander return( MBEDTLS_ERR_PK_INVALID_PUBKEY + 604817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 605817466cbSJens Wiklander 606817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) 607817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 608817466cbSJens Wiklander 609817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) 610817466cbSJens Wiklander return( ret ); 611817466cbSJens Wiklander 612817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 613817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA ) 614817466cbSJens Wiklander { 615817466cbSJens Wiklander ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) ); 616817466cbSJens Wiklander } else 617817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 618817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 619817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY ) 620817466cbSJens Wiklander { 621817466cbSJens Wiklander ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp ); 622817466cbSJens Wiklander if( ret == 0 ) 623817466cbSJens Wiklander ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) ); 624817466cbSJens Wiklander } else 625817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 626817466cbSJens Wiklander ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; 627817466cbSJens Wiklander 628817466cbSJens Wiklander if( ret == 0 && *p != end ) 629817466cbSJens Wiklander ret = MBEDTLS_ERR_PK_INVALID_PUBKEY 630817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; 631817466cbSJens Wiklander 632817466cbSJens Wiklander if( ret != 0 ) 633817466cbSJens Wiklander mbedtls_pk_free( pk ); 634817466cbSJens Wiklander 635817466cbSJens Wiklander return( ret ); 636817466cbSJens Wiklander } 637817466cbSJens Wiklander 638817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 639817466cbSJens Wiklander /* 640817466cbSJens Wiklander * Parse a PKCS#1 encoded private RSA key 641817466cbSJens Wiklander */ 642817466cbSJens Wiklander static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, 643817466cbSJens Wiklander const unsigned char *key, 644817466cbSJens Wiklander size_t keylen ) 645817466cbSJens Wiklander { 646817466cbSJens Wiklander int ret; 647817466cbSJens Wiklander size_t len; 648817466cbSJens Wiklander unsigned char *p, *end; 649817466cbSJens Wiklander 650817466cbSJens Wiklander p = (unsigned char *) key; 651817466cbSJens Wiklander end = p + keylen; 652817466cbSJens Wiklander 653817466cbSJens Wiklander /* 654817466cbSJens Wiklander * This function parses the RSAPrivateKey (PKCS#1) 655817466cbSJens Wiklander * 656817466cbSJens Wiklander * RSAPrivateKey ::= SEQUENCE { 657817466cbSJens Wiklander * version Version, 658817466cbSJens Wiklander * modulus INTEGER, -- n 659817466cbSJens Wiklander * publicExponent INTEGER, -- e 660817466cbSJens Wiklander * privateExponent INTEGER, -- d 661817466cbSJens Wiklander * prime1 INTEGER, -- p 662817466cbSJens Wiklander * prime2 INTEGER, -- q 663817466cbSJens Wiklander * exponent1 INTEGER, -- d mod (p-1) 664817466cbSJens Wiklander * exponent2 INTEGER, -- d mod (q-1) 665817466cbSJens Wiklander * coefficient INTEGER, -- (inverse of q) mod p 666817466cbSJens Wiklander * otherPrimeInfos OtherPrimeInfos OPTIONAL 667817466cbSJens Wiklander * } 668817466cbSJens Wiklander */ 669817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 670817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 671817466cbSJens Wiklander { 672817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 673817466cbSJens Wiklander } 674817466cbSJens Wiklander 675817466cbSJens Wiklander end = p + len; 676817466cbSJens Wiklander 677817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) 678817466cbSJens Wiklander { 679817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 680817466cbSJens Wiklander } 681817466cbSJens Wiklander 682817466cbSJens Wiklander if( rsa->ver != 0 ) 683817466cbSJens Wiklander { 684817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 685817466cbSJens Wiklander } 686817466cbSJens Wiklander 687817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->N ) ) != 0 || 688817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->E ) ) != 0 || 689817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->D ) ) != 0 || 690817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->P ) ) != 0 || 691817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->Q ) ) != 0 || 692817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 || 693817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 || 694817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 ) 695817466cbSJens Wiklander { 696817466cbSJens Wiklander mbedtls_rsa_free( rsa ); 697817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 698817466cbSJens Wiklander } 699817466cbSJens Wiklander 700817466cbSJens Wiklander rsa->len = mbedtls_mpi_size( &rsa->N ); 701817466cbSJens Wiklander 702817466cbSJens Wiklander if( p != end ) 703817466cbSJens Wiklander { 704817466cbSJens Wiklander mbedtls_rsa_free( rsa ); 705817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 706817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 707817466cbSJens Wiklander } 708817466cbSJens Wiklander 709817466cbSJens Wiklander if( ( ret = mbedtls_rsa_check_privkey( rsa ) ) != 0 ) 710817466cbSJens Wiklander { 711817466cbSJens Wiklander mbedtls_rsa_free( rsa ); 712817466cbSJens Wiklander return( ret ); 713817466cbSJens Wiklander } 714817466cbSJens Wiklander 715817466cbSJens Wiklander return( 0 ); 716817466cbSJens Wiklander } 717817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 718817466cbSJens Wiklander 719817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 720817466cbSJens Wiklander /* 721817466cbSJens Wiklander * Parse a SEC1 encoded private EC key 722817466cbSJens Wiklander */ 723817466cbSJens Wiklander static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, 724817466cbSJens Wiklander const unsigned char *key, 725817466cbSJens Wiklander size_t keylen ) 726817466cbSJens Wiklander { 727817466cbSJens Wiklander int ret; 728817466cbSJens Wiklander int version, pubkey_done; 729817466cbSJens Wiklander size_t len; 730817466cbSJens Wiklander mbedtls_asn1_buf params; 731817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 732817466cbSJens Wiklander unsigned char *end = p + keylen; 733817466cbSJens Wiklander unsigned char *end2; 734817466cbSJens Wiklander 735817466cbSJens Wiklander /* 736817466cbSJens Wiklander * RFC 5915, or SEC1 Appendix C.4 737817466cbSJens Wiklander * 738817466cbSJens Wiklander * ECPrivateKey ::= SEQUENCE { 739817466cbSJens Wiklander * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), 740817466cbSJens Wiklander * privateKey OCTET STRING, 741817466cbSJens Wiklander * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, 742817466cbSJens Wiklander * publicKey [1] BIT STRING OPTIONAL 743817466cbSJens Wiklander * } 744817466cbSJens Wiklander */ 745817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 746817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 747817466cbSJens Wiklander { 748817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 749817466cbSJens Wiklander } 750817466cbSJens Wiklander 751817466cbSJens Wiklander end = p + len; 752817466cbSJens Wiklander 753817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 754817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 755817466cbSJens Wiklander 756817466cbSJens Wiklander if( version != 1 ) 757817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); 758817466cbSJens Wiklander 759817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 760817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 761817466cbSJens Wiklander 762817466cbSJens Wiklander if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) 763817466cbSJens Wiklander { 764817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 765817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 766817466cbSJens Wiklander } 767817466cbSJens Wiklander 768817466cbSJens Wiklander p += len; 769817466cbSJens Wiklander 770817466cbSJens Wiklander pubkey_done = 0; 771817466cbSJens Wiklander if( p != end ) 772817466cbSJens Wiklander { 773817466cbSJens Wiklander /* 774817466cbSJens Wiklander * Is 'parameters' present? 775817466cbSJens Wiklander */ 776817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 777817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) 778817466cbSJens Wiklander { 779817466cbSJens Wiklander if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || 780817466cbSJens Wiklander ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) 781817466cbSJens Wiklander { 782817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 783817466cbSJens Wiklander return( ret ); 784817466cbSJens Wiklander } 785817466cbSJens Wiklander } 786817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 787817466cbSJens Wiklander { 788817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 789817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 790817466cbSJens Wiklander } 791817466cbSJens Wiklander 792817466cbSJens Wiklander /* 793817466cbSJens Wiklander * Is 'publickey' present? If not, or if we can't read it (eg because it 794817466cbSJens Wiklander * is compressed), create it from the private key. 795817466cbSJens Wiklander */ 796817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 797817466cbSJens Wiklander MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) 798817466cbSJens Wiklander { 799817466cbSJens Wiklander end2 = p + len; 800817466cbSJens Wiklander 801817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) 802817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 803817466cbSJens Wiklander 804817466cbSJens Wiklander if( p + len != end2 ) 805817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 806817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); 807817466cbSJens Wiklander 808817466cbSJens Wiklander if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) 809817466cbSJens Wiklander pubkey_done = 1; 810817466cbSJens Wiklander else 811817466cbSJens Wiklander { 812817466cbSJens Wiklander /* 813817466cbSJens Wiklander * The only acceptable failure mode of pk_get_ecpubkey() above 814817466cbSJens Wiklander * is if the point format is not recognized. 815817466cbSJens Wiklander */ 816817466cbSJens Wiklander if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) 817817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 818817466cbSJens Wiklander } 819817466cbSJens Wiklander } 820817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) 821817466cbSJens Wiklander { 822817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 823817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 824817466cbSJens Wiklander } 825817466cbSJens Wiklander } 826817466cbSJens Wiklander 827817466cbSJens Wiklander if( ! pubkey_done && 828817466cbSJens Wiklander ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, 829817466cbSJens Wiklander NULL, NULL ) ) != 0 ) 830817466cbSJens Wiklander { 831817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 832817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 833817466cbSJens Wiklander } 834817466cbSJens Wiklander 835817466cbSJens Wiklander if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) 836817466cbSJens Wiklander { 837817466cbSJens Wiklander mbedtls_ecp_keypair_free( eck ); 838817466cbSJens Wiklander return( ret ); 839817466cbSJens Wiklander } 840817466cbSJens Wiklander 841817466cbSJens Wiklander return( 0 ); 842817466cbSJens Wiklander } 843817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 844817466cbSJens Wiklander 845817466cbSJens Wiklander /* 846817466cbSJens Wiklander * Parse an unencrypted PKCS#8 encoded private key 847817466cbSJens Wiklander */ 848817466cbSJens Wiklander static int pk_parse_key_pkcs8_unencrypted_der( 849817466cbSJens Wiklander mbedtls_pk_context *pk, 850817466cbSJens Wiklander const unsigned char* key, 851817466cbSJens Wiklander size_t keylen ) 852817466cbSJens Wiklander { 853817466cbSJens Wiklander int ret, version; 854817466cbSJens Wiklander size_t len; 855817466cbSJens Wiklander mbedtls_asn1_buf params; 856817466cbSJens Wiklander unsigned char *p = (unsigned char *) key; 857817466cbSJens Wiklander unsigned char *end = p + keylen; 858817466cbSJens Wiklander mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; 859817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 860817466cbSJens Wiklander 861817466cbSJens Wiklander /* 862817466cbSJens Wiklander * This function parses the PrivatKeyInfo object (PKCS#8 v1.2 = RFC 5208) 863817466cbSJens Wiklander * 864817466cbSJens Wiklander * PrivateKeyInfo ::= SEQUENCE { 865817466cbSJens Wiklander * version Version, 866817466cbSJens Wiklander * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 867817466cbSJens Wiklander * privateKey PrivateKey, 868817466cbSJens Wiklander * attributes [0] IMPLICIT Attributes OPTIONAL } 869817466cbSJens Wiklander * 870817466cbSJens Wiklander * Version ::= INTEGER 871817466cbSJens Wiklander * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier 872817466cbSJens Wiklander * PrivateKey ::= OCTET STRING 873817466cbSJens Wiklander * 874817466cbSJens Wiklander * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey 875817466cbSJens Wiklander */ 876817466cbSJens Wiklander 877817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 878817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 879817466cbSJens Wiklander { 880817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 881817466cbSJens Wiklander } 882817466cbSJens Wiklander 883817466cbSJens Wiklander end = p + len; 884817466cbSJens Wiklander 885817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) 886817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 887817466cbSJens Wiklander 888817466cbSJens Wiklander if( version != 0 ) 889817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); 890817466cbSJens Wiklander 891817466cbSJens Wiklander if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) 892817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 893817466cbSJens Wiklander 894817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 895817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 896817466cbSJens Wiklander 897817466cbSJens Wiklander if( len < 1 ) 898817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + 899817466cbSJens Wiklander MBEDTLS_ERR_ASN1_OUT_OF_DATA ); 900817466cbSJens Wiklander 901817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) 902817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 903817466cbSJens Wiklander 904817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) 905817466cbSJens Wiklander return( ret ); 906817466cbSJens Wiklander 907817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 908817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_RSA ) 909817466cbSJens Wiklander { 910817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) 911817466cbSJens Wiklander { 912817466cbSJens Wiklander mbedtls_pk_free( pk ); 913817466cbSJens Wiklander return( ret ); 914817466cbSJens Wiklander } 915817466cbSJens Wiklander } else 916817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 917817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 918817466cbSJens Wiklander if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) 919817466cbSJens Wiklander { 920817466cbSJens Wiklander if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || 921817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) 922817466cbSJens Wiklander { 923817466cbSJens Wiklander mbedtls_pk_free( pk ); 924817466cbSJens Wiklander return( ret ); 925817466cbSJens Wiklander } 926817466cbSJens Wiklander } else 927817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 928817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 929817466cbSJens Wiklander 930817466cbSJens Wiklander return( 0 ); 931817466cbSJens Wiklander } 932817466cbSJens Wiklander 933817466cbSJens Wiklander /* 934817466cbSJens Wiklander * Parse an encrypted PKCS#8 encoded private key 935817466cbSJens Wiklander */ 936817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 937817466cbSJens Wiklander static int pk_parse_key_pkcs8_encrypted_der( 938817466cbSJens Wiklander mbedtls_pk_context *pk, 939817466cbSJens Wiklander const unsigned char *key, size_t keylen, 940817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 941817466cbSJens Wiklander { 942817466cbSJens Wiklander int ret, decrypted = 0; 943817466cbSJens Wiklander size_t len; 944817466cbSJens Wiklander unsigned char buf[2048]; 945817466cbSJens Wiklander unsigned char *p, *end; 946817466cbSJens Wiklander mbedtls_asn1_buf pbe_alg_oid, pbe_params; 947817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 948817466cbSJens Wiklander mbedtls_cipher_type_t cipher_alg; 949817466cbSJens Wiklander mbedtls_md_type_t md_alg; 950817466cbSJens Wiklander #endif 951817466cbSJens Wiklander 952817466cbSJens Wiklander memset( buf, 0, sizeof( buf ) ); 953817466cbSJens Wiklander 954817466cbSJens Wiklander p = (unsigned char *) key; 955817466cbSJens Wiklander end = p + keylen; 956817466cbSJens Wiklander 957817466cbSJens Wiklander if( pwdlen == 0 ) 958817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 959817466cbSJens Wiklander 960817466cbSJens Wiklander /* 961817466cbSJens Wiklander * This function parses the EncryptedPrivatKeyInfo object (PKCS#8) 962817466cbSJens Wiklander * 963817466cbSJens Wiklander * EncryptedPrivateKeyInfo ::= SEQUENCE { 964817466cbSJens Wiklander * encryptionAlgorithm EncryptionAlgorithmIdentifier, 965817466cbSJens Wiklander * encryptedData EncryptedData 966817466cbSJens Wiklander * } 967817466cbSJens Wiklander * 968817466cbSJens Wiklander * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier 969817466cbSJens Wiklander * 970817466cbSJens Wiklander * EncryptedData ::= OCTET STRING 971817466cbSJens Wiklander * 972817466cbSJens Wiklander * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo 973817466cbSJens Wiklander */ 974817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 975817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 976817466cbSJens Wiklander { 977817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 978817466cbSJens Wiklander } 979817466cbSJens Wiklander 980817466cbSJens Wiklander end = p + len; 981817466cbSJens Wiklander 982817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) 983817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 984817466cbSJens Wiklander 985817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 986817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); 987817466cbSJens Wiklander 988817466cbSJens Wiklander if( len > sizeof( buf ) ) 989817466cbSJens Wiklander return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); 990817466cbSJens Wiklander 991817466cbSJens Wiklander /* 992817466cbSJens Wiklander * Decrypt EncryptedData with appropriate PDE 993817466cbSJens Wiklander */ 994817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 995817466cbSJens Wiklander if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) 996817466cbSJens Wiklander { 997817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, 998817466cbSJens Wiklander cipher_alg, md_alg, 999817466cbSJens Wiklander pwd, pwdlen, p, len, buf ) ) != 0 ) 1000817466cbSJens Wiklander { 1001817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) 1002817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1003817466cbSJens Wiklander 1004817466cbSJens Wiklander return( ret ); 1005817466cbSJens Wiklander } 1006817466cbSJens Wiklander 1007817466cbSJens Wiklander decrypted = 1; 1008817466cbSJens Wiklander } 1009817466cbSJens Wiklander else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) 1010817466cbSJens Wiklander { 1011817466cbSJens Wiklander if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, 1012817466cbSJens Wiklander MBEDTLS_PKCS12_PBE_DECRYPT, 1013817466cbSJens Wiklander pwd, pwdlen, 1014817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1015817466cbSJens Wiklander { 1016817466cbSJens Wiklander return( ret ); 1017817466cbSJens Wiklander } 1018817466cbSJens Wiklander 1019817466cbSJens Wiklander // Best guess for password mismatch when using RC4. If first tag is 1020817466cbSJens Wiklander // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE 1021817466cbSJens Wiklander // 1022817466cbSJens Wiklander if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) 1023817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1024817466cbSJens Wiklander 1025817466cbSJens Wiklander decrypted = 1; 1026817466cbSJens Wiklander } 1027817466cbSJens Wiklander else 1028817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C */ 1029817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 1030817466cbSJens Wiklander if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) 1031817466cbSJens Wiklander { 1032817466cbSJens Wiklander if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, 1033817466cbSJens Wiklander p, len, buf ) ) != 0 ) 1034817466cbSJens Wiklander { 1035817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) 1036817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1037817466cbSJens Wiklander 1038817466cbSJens Wiklander return( ret ); 1039817466cbSJens Wiklander } 1040817466cbSJens Wiklander 1041817466cbSJens Wiklander decrypted = 1; 1042817466cbSJens Wiklander } 1043817466cbSJens Wiklander else 1044817466cbSJens Wiklander #endif /* MBEDTLS_PKCS5_C */ 1045817466cbSJens Wiklander { 1046817466cbSJens Wiklander ((void) pwd); 1047817466cbSJens Wiklander } 1048817466cbSJens Wiklander 1049817466cbSJens Wiklander if( decrypted == 0 ) 1050817466cbSJens Wiklander return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); 1051817466cbSJens Wiklander 1052817466cbSJens Wiklander return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); 1053817466cbSJens Wiklander } 1054817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1055817466cbSJens Wiklander 1056817466cbSJens Wiklander /* 1057817466cbSJens Wiklander * Parse a private key 1058817466cbSJens Wiklander */ 1059817466cbSJens Wiklander int mbedtls_pk_parse_key( mbedtls_pk_context *pk, 1060817466cbSJens Wiklander const unsigned char *key, size_t keylen, 1061817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen ) 1062817466cbSJens Wiklander { 1063817466cbSJens Wiklander int ret; 1064817466cbSJens Wiklander const mbedtls_pk_info_t *pk_info; 1065817466cbSJens Wiklander 1066817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1067817466cbSJens Wiklander size_t len; 1068817466cbSJens Wiklander mbedtls_pem_context pem; 1069817466cbSJens Wiklander 1070817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1071817466cbSJens Wiklander 1072817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1073817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1074817466cbSJens Wiklander if( keylen == 0 || key[keylen - 1] != '\0' ) 1075817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1076817466cbSJens Wiklander else 1077817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1078817466cbSJens Wiklander "-----BEGIN RSA PRIVATE KEY-----", 1079817466cbSJens Wiklander "-----END RSA PRIVATE KEY-----", 1080817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1081817466cbSJens Wiklander 1082817466cbSJens Wiklander if( ret == 0 ) 1083817466cbSJens Wiklander { 1084817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 1085817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1086817466cbSJens Wiklander 1087817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1088817466cbSJens Wiklander ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), 1089817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1090817466cbSJens Wiklander { 1091817466cbSJens Wiklander mbedtls_pk_free( pk ); 1092817466cbSJens Wiklander } 1093817466cbSJens Wiklander 1094817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1095817466cbSJens Wiklander return( ret ); 1096817466cbSJens Wiklander } 1097817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1098817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1099817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1100817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1101817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1102817466cbSJens Wiklander return( ret ); 1103817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1104817466cbSJens Wiklander 1105817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1106817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1107817466cbSJens Wiklander if( keylen == 0 || key[keylen - 1] != '\0' ) 1108817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1109817466cbSJens Wiklander else 1110817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1111817466cbSJens Wiklander "-----BEGIN EC PRIVATE KEY-----", 1112817466cbSJens Wiklander "-----END EC PRIVATE KEY-----", 1113817466cbSJens Wiklander key, pwd, pwdlen, &len ); 1114817466cbSJens Wiklander if( ret == 0 ) 1115817466cbSJens Wiklander { 1116817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) 1117817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1118817466cbSJens Wiklander 1119817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1120817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), 1121817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1122817466cbSJens Wiklander { 1123817466cbSJens Wiklander mbedtls_pk_free( pk ); 1124817466cbSJens Wiklander } 1125817466cbSJens Wiklander 1126817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1127817466cbSJens Wiklander return( ret ); 1128817466cbSJens Wiklander } 1129817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) 1130817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); 1131817466cbSJens Wiklander else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) 1132817466cbSJens Wiklander return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); 1133817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1134817466cbSJens Wiklander return( ret ); 1135817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1136817466cbSJens Wiklander 1137817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1138817466cbSJens Wiklander if( keylen == 0 || key[keylen - 1] != '\0' ) 1139817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1140817466cbSJens Wiklander else 1141817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1142817466cbSJens Wiklander "-----BEGIN PRIVATE KEY-----", 1143817466cbSJens Wiklander "-----END PRIVATE KEY-----", 1144817466cbSJens Wiklander key, NULL, 0, &len ); 1145817466cbSJens Wiklander if( ret == 0 ) 1146817466cbSJens Wiklander { 1147817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, 1148817466cbSJens Wiklander pem.buf, pem.buflen ) ) != 0 ) 1149817466cbSJens Wiklander { 1150817466cbSJens Wiklander mbedtls_pk_free( pk ); 1151817466cbSJens Wiklander } 1152817466cbSJens Wiklander 1153817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1154817466cbSJens Wiklander return( ret ); 1155817466cbSJens Wiklander } 1156817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1157817466cbSJens Wiklander return( ret ); 1158817466cbSJens Wiklander 1159817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1160817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1161817466cbSJens Wiklander if( keylen == 0 || key[keylen - 1] != '\0' ) 1162817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1163817466cbSJens Wiklander else 1164817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1165817466cbSJens Wiklander "-----BEGIN ENCRYPTED PRIVATE KEY-----", 1166817466cbSJens Wiklander "-----END ENCRYPTED PRIVATE KEY-----", 1167817466cbSJens Wiklander key, NULL, 0, &len ); 1168817466cbSJens Wiklander if( ret == 0 ) 1169817466cbSJens Wiklander { 1170817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, 1171817466cbSJens Wiklander pem.buf, pem.buflen, 1172817466cbSJens Wiklander pwd, pwdlen ) ) != 0 ) 1173817466cbSJens Wiklander { 1174817466cbSJens Wiklander mbedtls_pk_free( pk ); 1175817466cbSJens Wiklander } 1176817466cbSJens Wiklander 1177817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1178817466cbSJens Wiklander return( ret ); 1179817466cbSJens Wiklander } 1180817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1181817466cbSJens Wiklander return( ret ); 1182817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1183817466cbSJens Wiklander #else 1184817466cbSJens Wiklander ((void) ret); 1185817466cbSJens Wiklander ((void) pwd); 1186817466cbSJens Wiklander ((void) pwdlen); 1187817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1188817466cbSJens Wiklander 1189817466cbSJens Wiklander /* 1190817466cbSJens Wiklander * At this point we only know it's not a PEM formatted key. Could be any 1191817466cbSJens Wiklander * of the known DER encoded private key formats 1192817466cbSJens Wiklander * 1193817466cbSJens Wiklander * We try the different DER format parsers to see if one passes without 1194817466cbSJens Wiklander * error 1195817466cbSJens Wiklander */ 1196817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) 1197817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, 1198817466cbSJens Wiklander pwd, pwdlen ) ) == 0 ) 1199817466cbSJens Wiklander { 1200817466cbSJens Wiklander return( 0 ); 1201817466cbSJens Wiklander } 1202817466cbSJens Wiklander 1203817466cbSJens Wiklander mbedtls_pk_free( pk ); 1204817466cbSJens Wiklander 1205817466cbSJens Wiklander if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) 1206817466cbSJens Wiklander { 1207817466cbSJens Wiklander return( ret ); 1208817466cbSJens Wiklander } 1209817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ 1210817466cbSJens Wiklander 1211817466cbSJens Wiklander if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) 1212817466cbSJens Wiklander return( 0 ); 1213817466cbSJens Wiklander 1214817466cbSJens Wiklander mbedtls_pk_free( pk ); 1215817466cbSJens Wiklander 1216817466cbSJens Wiklander #if defined(MBEDTLS_RSA_C) 1217817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) 1218817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1219817466cbSJens Wiklander 1220817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1221817466cbSJens Wiklander ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) ) == 0 ) 1222817466cbSJens Wiklander { 1223817466cbSJens Wiklander return( 0 ); 1224817466cbSJens Wiklander } 1225817466cbSJens Wiklander 1226817466cbSJens Wiklander mbedtls_pk_free( pk ); 1227817466cbSJens Wiklander #endif /* MBEDTLS_RSA_C */ 1228817466cbSJens Wiklander 1229817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C) 1230817466cbSJens Wiklander if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) 1231817466cbSJens Wiklander return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); 1232817466cbSJens Wiklander 1233817466cbSJens Wiklander if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || 1234817466cbSJens Wiklander ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), key, keylen ) ) == 0 ) 1235817466cbSJens Wiklander { 1236817466cbSJens Wiklander return( 0 ); 1237817466cbSJens Wiklander } 1238817466cbSJens Wiklander 1239817466cbSJens Wiklander mbedtls_pk_free( pk ); 1240817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */ 1241817466cbSJens Wiklander 1242817466cbSJens Wiklander return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); 1243817466cbSJens Wiklander } 1244817466cbSJens Wiklander 1245817466cbSJens Wiklander /* 1246817466cbSJens Wiklander * Parse a public key 1247817466cbSJens Wiklander */ 1248817466cbSJens Wiklander int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, 1249817466cbSJens Wiklander const unsigned char *key, size_t keylen ) 1250817466cbSJens Wiklander { 1251817466cbSJens Wiklander int ret; 1252817466cbSJens Wiklander unsigned char *p; 1253817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1254817466cbSJens Wiklander size_t len; 1255817466cbSJens Wiklander mbedtls_pem_context pem; 1256817466cbSJens Wiklander 1257817466cbSJens Wiklander mbedtls_pem_init( &pem ); 1258817466cbSJens Wiklander 1259817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 1260817466cbSJens Wiklander if( keylen == 0 || key[keylen - 1] != '\0' ) 1261817466cbSJens Wiklander ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; 1262817466cbSJens Wiklander else 1263817466cbSJens Wiklander ret = mbedtls_pem_read_buffer( &pem, 1264817466cbSJens Wiklander "-----BEGIN PUBLIC KEY-----", 1265817466cbSJens Wiklander "-----END PUBLIC KEY-----", 1266817466cbSJens Wiklander key, NULL, 0, &len ); 1267817466cbSJens Wiklander 1268817466cbSJens Wiklander if( ret == 0 ) 1269817466cbSJens Wiklander { 1270817466cbSJens Wiklander /* 1271817466cbSJens Wiklander * Was PEM encoded 1272817466cbSJens Wiklander */ 1273817466cbSJens Wiklander key = pem.buf; 1274817466cbSJens Wiklander keylen = pem.buflen; 1275817466cbSJens Wiklander } 1276817466cbSJens Wiklander else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) 1277817466cbSJens Wiklander { 1278817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1279817466cbSJens Wiklander return( ret ); 1280817466cbSJens Wiklander } 1281817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 1282817466cbSJens Wiklander p = (unsigned char *) key; 1283817466cbSJens Wiklander 1284817466cbSJens Wiklander ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); 1285817466cbSJens Wiklander 1286817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 1287817466cbSJens Wiklander mbedtls_pem_free( &pem ); 1288817466cbSJens Wiklander #endif 1289817466cbSJens Wiklander 1290817466cbSJens Wiklander return( ret ); 1291817466cbSJens Wiklander } 1292817466cbSJens Wiklander 1293817466cbSJens Wiklander #endif /* MBEDTLS_PK_PARSE_C */ 1294