blob: 66c8f65bc6adc03ac30c6b33f26ce78b57e05f42 [file] [log] [blame]
/*
* PSA crypto layer on top of Mbed TLS crypto
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "common.h"
#if defined(MBEDTLS_PSA_CRYPTO_C)
#if defined(MBEDTLS_PSA_CRYPTO_CONFIG)
#include "check_crypto_config.h"
#endif
#include "psa_crypto_service_integration.h"
#include "psa/crypto.h"
#include "psa_crypto_core.h"
#include "psa_crypto_invasive.h"
#include "psa_crypto_driver_wrappers.h"
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
#include "psa_crypto_se.h"
#endif
#include "psa_crypto_slot_management.h"
/* Include internal declarations that are useful for implementing persistently
* stored keys. */
#include "psa_crypto_storage.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "mbedtls/platform.h"
#if !defined(MBEDTLS_PLATFORM_C)
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#include "mbedtls/arc4.h"
#include "mbedtls/asn1.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/bignum.h"
#include "mbedtls/blowfish.h"
#include "mbedtls/camellia.h"
#include "mbedtls/chacha20.h"
#include "mbedtls/chachapoly.h"
#include "mbedtls/cipher.h"
#include "mbedtls/ccm.h"
#include "mbedtls/cmac.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/des.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/ecp.h"
#include "mbedtls/entropy.h"
#include "mbedtls/error.h"
#include "mbedtls/gcm.h"
#include "mbedtls/md2.h"
#include "mbedtls/md4.h"
#include "mbedtls/md5.h"
#include "mbedtls/md.h"
#include "mbedtls/md_internal.h"
#include "mbedtls/pk.h"
#include "mbedtls/pk_internal.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include "mbedtls/ripemd160.h"
#include "mbedtls/rsa.h"
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
#include "mbedtls/xtea.h"
#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) )
/* constant-time buffer comparison */
static inline int safer_memcmp( const uint8_t *a, const uint8_t *b, size_t n )
{
size_t i;
unsigned char diff = 0;
for( i = 0; i < n; i++ )
diff |= a[i] ^ b[i];
return( diff );
}
/****************************************************************/
/* Global data, support functions and library management */
/****************************************************************/
static int key_type_is_raw_bytes( psa_key_type_t type )
{
return( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) );
}
/* Values for psa_global_data_t::rng_state */
#define RNG_NOT_INITIALIZED 0
#define RNG_INITIALIZED 1
#define RNG_SEEDED 2
typedef struct
{
void (* entropy_init )( mbedtls_entropy_context *ctx );
void (* entropy_free )( mbedtls_entropy_context *ctx );
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
unsigned initialized : 1;
unsigned rng_state : 2;
} psa_global_data_t;
static psa_global_data_t global_data;
#define GUARD_MODULE_INITIALIZED \
if( global_data.initialized == 0 ) \
return( PSA_ERROR_BAD_STATE );
psa_status_t mbedtls_to_psa_error( int ret )
{
/* If there's both a high-level code and low-level code, dispatch on
* the high-level code. */
switch( ret < -0x7f ? - ( -ret & 0x7f80 ) : ret )
{
case 0:
return( PSA_SUCCESS );
case MBEDTLS_ERR_AES_INVALID_KEY_LENGTH:
case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH:
case MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_AES_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_ASN1_OUT_OF_DATA:
case MBEDTLS_ERR_ASN1_UNEXPECTED_TAG:
case MBEDTLS_ERR_ASN1_INVALID_LENGTH:
case MBEDTLS_ERR_ASN1_LENGTH_MISMATCH:
case MBEDTLS_ERR_ASN1_INVALID_DATA:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_ASN1_ALLOC_FAILED:
return( PSA_ERROR_INSUFFICIENT_MEMORY );
case MBEDTLS_ERR_ASN1_BUF_TOO_SMALL:
return( PSA_ERROR_BUFFER_TOO_SMALL );
#if defined(MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA)
case MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA:
#elif defined(MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH)
case MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH:
#endif
case MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
#if defined(MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA)
case MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA:
#elif defined(MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH)
case MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH:
#endif
case MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_CCM_BAD_INPUT:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_CCM_AUTH_FAILED:
return( PSA_ERROR_INVALID_SIGNATURE );
case MBEDTLS_ERR_CCM_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_CHACHAPOLY_BAD_STATE:
return( PSA_ERROR_BAD_STATE );
case MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED:
return( PSA_ERROR_INVALID_SIGNATURE );
case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_CIPHER_ALLOC_FAILED:
return( PSA_ERROR_INSUFFICIENT_MEMORY );
case MBEDTLS_ERR_CIPHER_INVALID_PADDING:
return( PSA_ERROR_INVALID_PADDING );
case MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_CIPHER_AUTH_FAILED:
return( PSA_ERROR_INVALID_SIGNATURE );
case MBEDTLS_ERR_CIPHER_INVALID_CONTEXT:
return( PSA_ERROR_CORRUPTION_DETECTED );
case MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED:
return( PSA_ERROR_INSUFFICIENT_ENTROPY );
case MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG:
case MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR:
return( PSA_ERROR_INSUFFICIENT_ENTROPY );
case MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_DES_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED:
case MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE:
case MBEDTLS_ERR_ENTROPY_SOURCE_FAILED:
return( PSA_ERROR_INSUFFICIENT_ENTROPY );
case MBEDTLS_ERR_GCM_AUTH_FAILED:
return( PSA_ERROR_INVALID_SIGNATURE );
case MBEDTLS_ERR_GCM_BAD_INPUT:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_GCM_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_MD2_HW_ACCEL_FAILED:
case MBEDTLS_ERR_MD4_HW_ACCEL_FAILED:
case MBEDTLS_ERR_MD5_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_MD_BAD_INPUT_DATA:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_MD_ALLOC_FAILED:
return( PSA_ERROR_INSUFFICIENT_MEMORY );
case MBEDTLS_ERR_MD_FILE_IO_ERROR:
return( PSA_ERROR_STORAGE_FAILURE );
case MBEDTLS_ERR_MD_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_MPI_FILE_IO_ERROR:
return( PSA_ERROR_STORAGE_FAILURE );
case MBEDTLS_ERR_MPI_BAD_INPUT_DATA:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_MPI_INVALID_CHARACTER:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:
return( PSA_ERROR_BUFFER_TOO_SMALL );
case MBEDTLS_ERR_MPI_NEGATIVE_VALUE:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_MPI_DIVISION_BY_ZERO:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_MPI_NOT_ACCEPTABLE:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_MPI_ALLOC_FAILED:
return( PSA_ERROR_INSUFFICIENT_MEMORY );
case MBEDTLS_ERR_PK_ALLOC_FAILED:
return( PSA_ERROR_INSUFFICIENT_MEMORY );
case MBEDTLS_ERR_PK_TYPE_MISMATCH:
case MBEDTLS_ERR_PK_BAD_INPUT_DATA:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_PK_FILE_IO_ERROR:
return( PSA_ERROR_STORAGE_FAILURE );
case MBEDTLS_ERR_PK_KEY_INVALID_VERSION:
case MBEDTLS_ERR_PK_KEY_INVALID_FORMAT:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_PK_UNKNOWN_PK_ALG:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_PK_PASSWORD_REQUIRED:
case MBEDTLS_ERR_PK_PASSWORD_MISMATCH:
return( PSA_ERROR_NOT_PERMITTED );
case MBEDTLS_ERR_PK_INVALID_PUBKEY:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_PK_INVALID_ALG:
case MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE:
case MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_PK_SIG_LEN_MISMATCH:
return( PSA_ERROR_INVALID_SIGNATURE );
case MBEDTLS_ERR_PK_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_RSA_BAD_INPUT_DATA:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_RSA_INVALID_PADDING:
return( PSA_ERROR_INVALID_PADDING );
case MBEDTLS_ERR_RSA_KEY_GEN_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_RSA_KEY_CHECK_FAILED:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_RSA_PUBLIC_FAILED:
case MBEDTLS_ERR_RSA_PRIVATE_FAILED:
return( PSA_ERROR_CORRUPTION_DETECTED );
case MBEDTLS_ERR_RSA_VERIFY_FAILED:
return( PSA_ERROR_INVALID_SIGNATURE );
case MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE:
return( PSA_ERROR_BUFFER_TOO_SMALL );
case MBEDTLS_ERR_RSA_RNG_FAILED:
return( PSA_ERROR_INSUFFICIENT_MEMORY );
case MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_RSA_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED:
case MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED:
case MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_ECP_BAD_INPUT_DATA:
case MBEDTLS_ERR_ECP_INVALID_KEY:
return( PSA_ERROR_INVALID_ARGUMENT );
case MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL:
return( PSA_ERROR_BUFFER_TOO_SMALL );
case MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE:
return( PSA_ERROR_NOT_SUPPORTED );
case MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH:
case MBEDTLS_ERR_ECP_VERIFY_FAILED:
return( PSA_ERROR_INVALID_SIGNATURE );
case MBEDTLS_ERR_ECP_ALLOC_FAILED:
return( PSA_ERROR_INSUFFICIENT_MEMORY );
case MBEDTLS_ERR_ECP_HW_ACCEL_FAILED:
return( PSA_ERROR_HARDWARE_FAILURE );
case MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED:
return( PSA_ERROR_CORRUPTION_DETECTED );
default:
return( PSA_ERROR_GENERIC_ERROR );
}
}
/****************************************************************/
/* Key management */
/****************************************************************/
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
static inline int psa_key_slot_is_external( const psa_key_slot_t *slot )
{
return( psa_key_lifetime_is_external( slot->attr.lifetime ) );
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
/* For now the MBEDTLS_PSA_ACCEL_ guards are also used here since the
* current test driver in key_management.c is using this function
* when accelerators are used for ECC key pair and public key.
* Once that dependency is resolved these guards can be removed.
*/
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || \
defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR) || \
defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY)
mbedtls_ecp_group_id mbedtls_ecc_group_of_psa( psa_ecc_family_t curve,
size_t byte_length )
{
switch( curve )
{
case PSA_ECC_FAMILY_SECP_R1:
switch( byte_length )
{
case PSA_BITS_TO_BYTES( 192 ):
return( MBEDTLS_ECP_DP_SECP192R1 );
case PSA_BITS_TO_BYTES( 224 ):
return( MBEDTLS_ECP_DP_SECP224R1 );
case PSA_BITS_TO_BYTES( 256 ):
return( MBEDTLS_ECP_DP_SECP256R1 );
case PSA_BITS_TO_BYTES( 384 ):
return( MBEDTLS_ECP_DP_SECP384R1 );
case PSA_BITS_TO_BYTES( 521 ):
return( MBEDTLS_ECP_DP_SECP521R1 );
default:
return( MBEDTLS_ECP_DP_NONE );
}
break;
case PSA_ECC_FAMILY_BRAINPOOL_P_R1:
switch( byte_length )
{
case PSA_BITS_TO_BYTES( 256 ):
return( MBEDTLS_ECP_DP_BP256R1 );
case PSA_BITS_TO_BYTES( 384 ):
return( MBEDTLS_ECP_DP_BP384R1 );
case PSA_BITS_TO_BYTES( 512 ):
return( MBEDTLS_ECP_DP_BP512R1 );
default:
return( MBEDTLS_ECP_DP_NONE );
}
break;
case PSA_ECC_FAMILY_MONTGOMERY:
switch( byte_length )
{
case PSA_BITS_TO_BYTES( 255 ):
return( MBEDTLS_ECP_DP_CURVE25519 );
case PSA_BITS_TO_BYTES( 448 ):
return( MBEDTLS_ECP_DP_CURVE448 );
default:
return( MBEDTLS_ECP_DP_NONE );
}
break;
case PSA_ECC_FAMILY_SECP_K1:
switch( byte_length )
{
case PSA_BITS_TO_BYTES( 192 ):
return( MBEDTLS_ECP_DP_SECP192K1 );
case PSA_BITS_TO_BYTES( 224 ):
return( MBEDTLS_ECP_DP_SECP224K1 );
case PSA_BITS_TO_BYTES( 256 ):
return( MBEDTLS_ECP_DP_SECP256K1 );
default:
return( MBEDTLS_ECP_DP_NONE );
}
break;
default:
return( MBEDTLS_ECP_DP_NONE );
}
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) ||
* defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR) ||
* defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY) */
static psa_status_t validate_unstructured_key_bit_size( psa_key_type_t type,
size_t bits )
{
/* Check that the bit size is acceptable for the key type */
switch( type )
{
case PSA_KEY_TYPE_RAW_DATA:
case PSA_KEY_TYPE_HMAC:
case PSA_KEY_TYPE_DERIVE:
break;
#if defined(MBEDTLS_AES_C)
case PSA_KEY_TYPE_AES:
if( bits != 128 && bits != 192 && bits != 256 )
return( PSA_ERROR_INVALID_ARGUMENT );
break;
#endif
#if defined(MBEDTLS_CAMELLIA_C)
case PSA_KEY_TYPE_CAMELLIA:
if( bits != 128 && bits != 192 && bits != 256 )
return( PSA_ERROR_INVALID_ARGUMENT );
break;
#endif
#if defined(MBEDTLS_DES_C)
case PSA_KEY_TYPE_DES:
if( bits != 64 && bits != 128 && bits != 192 )
return( PSA_ERROR_INVALID_ARGUMENT );
break;
#endif
#if defined(MBEDTLS_ARC4_C)
case PSA_KEY_TYPE_ARC4:
if( bits < 8 || bits > 2048 )
return( PSA_ERROR_INVALID_ARGUMENT );
break;
#endif
#if defined(MBEDTLS_CHACHA20_C)
case PSA_KEY_TYPE_CHACHA20:
if( bits != 256 )
return( PSA_ERROR_INVALID_ARGUMENT );
break;
#endif
default:
return( PSA_ERROR_NOT_SUPPORTED );
}
if( bits % 8 != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
return( PSA_SUCCESS );
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
/* Mbed TLS doesn't support non-byte-aligned key sizes (i.e. key sizes
* that are not a multiple of 8) well. For example, there is only
* mbedtls_rsa_get_len(), which returns a number of bytes, and no
* way to return the exact bit size of a key.
* To keep things simple, reject non-byte-aligned key sizes. */
static psa_status_t psa_check_rsa_key_byte_aligned(
const mbedtls_rsa_context *rsa )
{
mbedtls_mpi n;
psa_status_t status;
mbedtls_mpi_init( &n );
status = mbedtls_to_psa_error(
mbedtls_rsa_export( rsa, &n, NULL, NULL, NULL, NULL ) );
if( status == PSA_SUCCESS )
{
if( mbedtls_mpi_bitlen( &n ) % 8 != 0 )
status = PSA_ERROR_NOT_SUPPORTED;
}
mbedtls_mpi_free( &n );
return( status );
}
/** Load the contents of a key buffer into an internal RSA representation
*
* \param[in] type The type of key contained in \p data.
* \param[in] data The buffer from which to load the representation.
* \param[in] data_length The size in bytes of \p data.
* \param[out] p_rsa Returns a pointer to an RSA context on success.
* The caller is responsible for freeing both the
* contents of the context and the context itself
* when done.
*/
static psa_status_t psa_load_rsa_representation( psa_key_type_t type,
const uint8_t *data,
size_t data_length,
mbedtls_rsa_context **p_rsa )
{
psa_status_t status;
mbedtls_pk_context ctx;
size_t bits;
mbedtls_pk_init( &ctx );
/* Parse the data. */
if( PSA_KEY_TYPE_IS_KEY_PAIR( type ) )
status = mbedtls_to_psa_error(
mbedtls_pk_parse_key( &ctx, data, data_length, NULL, 0 ) );
else
status = mbedtls_to_psa_error(
mbedtls_pk_parse_public_key( &ctx, data, data_length ) );
if( status != PSA_SUCCESS )
goto exit;
/* We have something that the pkparse module recognizes. If it is a
* valid RSA key, store it. */
if( mbedtls_pk_get_type( &ctx ) != MBEDTLS_PK_RSA )
{
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
/* The size of an RSA key doesn't have to be a multiple of 8. Mbed TLS
* supports non-byte-aligned key sizes, but not well. For example,
* mbedtls_rsa_get_len() returns the key size in bytes, not in bits. */
bits = PSA_BYTES_TO_BITS( mbedtls_rsa_get_len( mbedtls_pk_rsa( ctx ) ) );
if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS )
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = psa_check_rsa_key_byte_aligned( mbedtls_pk_rsa( ctx ) );
if( status != PSA_SUCCESS )
goto exit;
/* Copy out the pointer to the RSA context, and reset the PK context
* such that pk_free doesn't free the RSA context we just grabbed. */
*p_rsa = mbedtls_pk_rsa( ctx );
ctx.pk_info = NULL;
exit:
mbedtls_pk_free( &ctx );
return( status );
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
/** Export an RSA key to export representation
*
* \param[in] type The type of key (public/private) to export
* \param[in] rsa The internal RSA representation from which to export
* \param[out] data The buffer to export to
* \param[in] data_size The length of the buffer to export to
* \param[out] data_length The amount of bytes written to \p data
*/
static psa_status_t psa_export_rsa_key( psa_key_type_t type,
mbedtls_rsa_context *rsa,
uint8_t *data,
size_t data_size,
size_t *data_length )
{
#if defined(MBEDTLS_PK_WRITE_C)
int ret;
mbedtls_pk_context pk;
uint8_t *pos = data + data_size;
mbedtls_pk_init( &pk );
pk.pk_info = &mbedtls_rsa_info;
pk.pk_ctx = rsa;
/* PSA Crypto API defines the format of an RSA key as a DER-encoded
* representation of the non-encrypted PKCS#1 RSAPrivateKey for a
* private key and of the RFC3279 RSAPublicKey for a public key. */
if( PSA_KEY_TYPE_IS_KEY_PAIR( type ) )
ret = mbedtls_pk_write_key_der( &pk, data, data_size );
else
ret = mbedtls_pk_write_pubkey( &pos, data, &pk );
if( ret < 0 )
{
/* Clean up in case pk_write failed halfway through. */
memset( data, 0, data_size );
return( mbedtls_to_psa_error( ret ) );
}
/* The mbedtls_pk_xxx functions write to the end of the buffer.
* Move the data to the beginning and erase remaining data
* at the original location. */
if( 2 * (size_t) ret <= data_size )
{
memcpy( data, data + data_size - ret, ret );
memset( data + data_size - ret, 0, ret );
}
else if( (size_t) ret < data_size )
{
memmove( data, data + data_size - ret, ret );
memset( data + ret, 0, data_size - ret );
}
*data_length = ret;
return( PSA_SUCCESS );
#else
(void) type;
(void) rsa;
(void) data;
(void) data_size;
(void) data_length;
return( PSA_ERROR_NOT_SUPPORTED );
#endif /* MBEDTLS_PK_WRITE_C */
}
/** Import an RSA key from import representation to a slot
*
* \param[in,out] slot The slot where to store the export representation to
* \param[in] data The buffer containing the import representation
* \param[in] data_length The amount of bytes in \p data
*/
static psa_status_t psa_import_rsa_key( psa_key_slot_t *slot,
const uint8_t *data,
size_t data_length )
{
psa_status_t status;
uint8_t* output = NULL;
mbedtls_rsa_context *rsa = NULL;
/* Parse input */
status = psa_load_rsa_representation( slot->attr.type,
data,
data_length,
&rsa );
if( status != PSA_SUCCESS )
goto exit;
slot->attr.bits = (psa_key_bits_t) PSA_BYTES_TO_BITS(
mbedtls_rsa_get_len( rsa ) );
/* Re-export the data to PSA export format, such that we can store export
* representation in the key slot. Export representation in case of RSA is
* the smallest representation that's allowed as input, so a straight-up
* allocation of the same size as the input buffer will be large enough. */
output = mbedtls_calloc( 1, data_length );
if( output == NULL )
{
status = PSA_ERROR_INSUFFICIENT_MEMORY;
goto exit;
}
status = psa_export_rsa_key( slot->attr.type,
rsa,
output,
data_length,
&data_length);
exit:
/* Always free the RSA object */
mbedtls_rsa_free( rsa );
mbedtls_free( rsa );
/* Free the allocated buffer only on error. */
if( status != PSA_SUCCESS )
{
mbedtls_free( output );
return( status );
}
/* On success, store the allocated export-formatted key. */
slot->data.key.data = output;
slot->data.key.bytes = data_length;
return( PSA_SUCCESS );
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
/** Load the contents of a key buffer into an internal ECP representation
*
* \param[in] type The type of key contained in \p data.
* \param[in] data The buffer from which to load the representation.
* \param[in] data_length The size in bytes of \p data.
* \param[out] p_ecp Returns a pointer to an ECP context on success.
* The caller is responsible for freeing both the
* contents of the context and the context itself
* when done.
*/
static psa_status_t psa_load_ecp_representation( psa_key_type_t type,
const uint8_t *data,
size_t data_length,
mbedtls_ecp_keypair **p_ecp )
{
mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_NONE;
psa_status_t status;
mbedtls_ecp_keypair *ecp = NULL;
size_t curve_size = data_length;
if( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) &&
PSA_KEY_TYPE_ECC_GET_FAMILY( type ) != PSA_ECC_FAMILY_MONTGOMERY )
{
/* A Weierstrass public key is represented as:
* - The byte 0x04;
* - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
* - `y_P` as a `ceiling(m/8)`-byte string, big-endian.
* So its data length is 2m+1 where m is the curve size in bits.
*/
if( ( data_length & 1 ) == 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
curve_size = data_length / 2;
/* Montgomery public keys are represented in compressed format, meaning
* their curve_size is equal to the amount of input. */
/* Private keys are represented in uncompressed private random integer
* format, meaning their curve_size is equal to the amount of input. */
}
/* Allocate and initialize a key representation. */
ecp = mbedtls_calloc( 1, sizeof( mbedtls_ecp_keypair ) );
if( ecp == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
mbedtls_ecp_keypair_init( ecp );
/* Load the group. */
grp_id = mbedtls_ecc_group_of_psa( PSA_KEY_TYPE_ECC_GET_FAMILY( type ),
curve_size );
if( grp_id == MBEDTLS_ECP_DP_NONE )
{
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
status = mbedtls_to_psa_error(
mbedtls_ecp_group_load( &ecp->grp, grp_id ) );
if( status != PSA_SUCCESS )
goto exit;
/* Load the key material. */
if( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) )
{
/* Load the public value. */
status = mbedtls_to_psa_error(
mbedtls_ecp_point_read_binary( &ecp->grp, &ecp->Q,
data,
data_length ) );
if( status != PSA_SUCCESS )
goto exit;
/* Check that the point is on the curve. */
status = mbedtls_to_psa_error(
mbedtls_ecp_check_pubkey( &ecp->grp, &ecp->Q ) );
if( status != PSA_SUCCESS )
goto exit;
}
else
{
/* Load and validate the secret value. */
status = mbedtls_to_psa_error(
mbedtls_ecp_read_key( ecp->grp.id,
ecp,
data,
data_length ) );
if( status != PSA_SUCCESS )
goto exit;
}
*p_ecp = ecp;
exit:
if( status != PSA_SUCCESS )
{
mbedtls_ecp_keypair_free( ecp );
mbedtls_free( ecp );
}
return( status );
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
/** Export an ECP key to export representation
*
* \param[in] type The type of key (public/private) to export
* \param[in] ecp The internal ECP representation from which to export
* \param[out] data The buffer to export to
* \param[in] data_size The length of the buffer to export to
* \param[out] data_length The amount of bytes written to \p data
*/
static psa_status_t psa_export_ecp_key( psa_key_type_t type,
mbedtls_ecp_keypair *ecp,
uint8_t *data,
size_t data_size,
size_t *data_length )
{
psa_status_t status;
if( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) )
{
/* Check whether the public part is loaded */
if( mbedtls_ecp_is_zero( &ecp->Q ) )
{
/* Calculate the public key */
status = mbedtls_to_psa_error(
mbedtls_ecp_mul( &ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G,
mbedtls_ctr_drbg_random, &global_data.ctr_drbg ) );
if( status != PSA_SUCCESS )
return( status );
}
status = mbedtls_to_psa_error(
mbedtls_ecp_point_write_binary( &ecp->grp, &ecp->Q,
MBEDTLS_ECP_PF_UNCOMPRESSED,
data_length,
data,
data_size ) );
if( status != PSA_SUCCESS )
memset( data, 0, data_size );
return( status );
}
else
{
if( data_size < PSA_BITS_TO_BYTES( ecp->grp.nbits ) )
return( PSA_ERROR_BUFFER_TOO_SMALL );
status = mbedtls_to_psa_error(
mbedtls_ecp_write_key( ecp,
data,
PSA_BITS_TO_BYTES( ecp->grp.nbits ) ) );
if( status == PSA_SUCCESS )
*data_length = PSA_BITS_TO_BYTES( ecp->grp.nbits );
else
memset( data, 0, data_size );
return( status );
}
}
/** Import an ECP key from import representation to a slot
*
* \param[in,out] slot The slot where to store the export representation to
* \param[in] data The buffer containing the import representation
* \param[in] data_length The amount of bytes in \p data
*/
static psa_status_t psa_import_ecp_key( psa_key_slot_t *slot,
const uint8_t *data,
size_t data_length )
{
psa_status_t status;
uint8_t* output = NULL;
mbedtls_ecp_keypair *ecp = NULL;
/* Parse input */
status = psa_load_ecp_representation( slot->attr.type,
data,
data_length,
&ecp );
if( status != PSA_SUCCESS )
goto exit;
if( PSA_KEY_TYPE_ECC_GET_FAMILY( slot->attr.type ) == PSA_ECC_FAMILY_MONTGOMERY)
slot->attr.bits = (psa_key_bits_t) ecp->grp.nbits + 1;
else
slot->attr.bits = (psa_key_bits_t) ecp->grp.nbits;
/* Re-export the data to PSA export format. There is currently no support
* for other input formats then the export format, so this is a 1-1
* copy operation. */
output = mbedtls_calloc( 1, data_length );
if( output == NULL )
{
status = PSA_ERROR_INSUFFICIENT_MEMORY;
goto exit;
}
status = psa_export_ecp_key( slot->attr.type,
ecp,
output,
data_length,
&data_length);
exit:
/* Always free the PK object (will also free contained ECP context) */
mbedtls_ecp_keypair_free( ecp );
mbedtls_free( ecp );
/* Free the allocated buffer only on error. */
if( status != PSA_SUCCESS )
{
mbedtls_free( output );
return( status );
}
/* On success, store the allocated export-formatted key. */
slot->data.key.data = output;
slot->data.key.bytes = data_length;
return( PSA_SUCCESS );
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */
/** Return the size of the key in the given slot, in bits.
*
* \param[in] slot A key slot.
*
* \return The key size in bits, read from the metadata in the slot.
*/
static inline size_t psa_get_key_slot_bits( const psa_key_slot_t *slot )
{
return( slot->attr.bits );
}
/** Try to allocate a buffer to an empty key slot.
*
* \param[in,out] slot Key slot to attach buffer to.
* \param[in] buffer_length Requested size of the buffer.
*
* \retval #PSA_SUCCESS
* The buffer has been successfully allocated.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* Not enough memory was available for allocation.
* \retval #PSA_ERROR_ALREADY_EXISTS
* Trying to allocate a buffer to a non-empty key slot.
*/
static psa_status_t psa_allocate_buffer_to_slot( psa_key_slot_t *slot,
size_t buffer_length )
{
if( slot->data.key.data != NULL )
return( PSA_ERROR_ALREADY_EXISTS );
slot->data.key.data = mbedtls_calloc( 1, buffer_length );
if( slot->data.key.data == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
slot->data.key.bytes = buffer_length;
return( PSA_SUCCESS );
}
psa_status_t psa_copy_key_material_into_slot( psa_key_slot_t *slot,
const uint8_t* data,
size_t data_length )
{
psa_status_t status = psa_allocate_buffer_to_slot( slot,
data_length );
if( status != PSA_SUCCESS )
return( status );
memcpy( slot->data.key.data, data, data_length );
return( PSA_SUCCESS );
}
/** Import key data into a slot.
*
* `slot->type` must have been set previously.
* This function assumes that the slot does not contain any key material yet.
* On failure, the slot content is unchanged.
*
* Persistent storage is not affected.
*
* \param[in,out] slot The key slot to import data into.
* Its `type` field must have previously been set to
* the desired key type.
* It must not contain any key material yet.
* \param[in] data Buffer containing the key material to parse and import.
* \param data_length Size of \p data in bytes.
*
* \retval #PSA_SUCCESS
* \retval #PSA_ERROR_INVALID_ARGUMENT
* \retval #PSA_ERROR_NOT_SUPPORTED
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
*/
static psa_status_t psa_import_key_into_slot( psa_key_slot_t *slot,
const uint8_t *data,
size_t data_length )
{
psa_status_t status = PSA_SUCCESS;
size_t bit_size;
/* zero-length keys are never supported. */
if( data_length == 0 )
return( PSA_ERROR_NOT_SUPPORTED );
if( key_type_is_raw_bytes( slot->attr.type ) )
{
bit_size = PSA_BYTES_TO_BITS( data_length );
/* Ensure that the bytes-to-bits conversion hasn't overflown. */
if( data_length > SIZE_MAX / 8 )
return( PSA_ERROR_NOT_SUPPORTED );
/* Enforce a size limit, and in particular ensure that the bit
* size fits in its representation type. */
if( bit_size > PSA_MAX_KEY_BITS )
return( PSA_ERROR_NOT_SUPPORTED );
status = validate_unstructured_key_bit_size( slot->attr.type, bit_size );
if( status != PSA_SUCCESS )
return( status );
/* Allocate memory for the key */
status = psa_copy_key_material_into_slot( slot, data, data_length );
if( status != PSA_SUCCESS )
return( status );
/* Write the actual key size to the slot.
* psa_start_key_creation() wrote the size declared by the
* caller, which may be 0 (meaning unspecified) or wrong. */
slot->attr.bits = (psa_key_bits_t) bit_size;
return( PSA_SUCCESS );
}
else if( PSA_KEY_TYPE_IS_ASYMMETRIC( slot->attr.type ) )
{
/* Try validation through accelerators first. */
bit_size = slot->attr.bits;
psa_key_attributes_t attributes = {
.core = slot->attr
};
status = psa_driver_wrapper_validate_key( &attributes,
data,
data_length,
&bit_size );
if( status == PSA_SUCCESS )
{
/* Key has been validated successfully by an accelerator.
* Copy key material into slot. */
status = psa_copy_key_material_into_slot( slot, data, data_length );
if( status != PSA_SUCCESS )
return( status );
slot->attr.bits = (psa_key_bits_t) bit_size;
return( PSA_SUCCESS );
}
else if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
/* Key format is not supported by any accelerator, try software fallback
* if present. */
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
if( PSA_KEY_TYPE_IS_ECC( slot->attr.type ) )
{
return( psa_import_ecp_key( slot, data, data_length ) );
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) )
{
return( psa_import_rsa_key( slot, data, data_length ) );
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
/* Fell through the fallback as well, so have nothing else to try. */
return( PSA_ERROR_NOT_SUPPORTED );
}
else
{
/* Unknown key type */
return( PSA_ERROR_NOT_SUPPORTED );
}
}
/** Calculate the intersection of two algorithm usage policies.
*
* Return 0 (which allows no operation) on incompatibility.
*/
static psa_algorithm_t psa_key_policy_algorithm_intersection(
psa_algorithm_t alg1,
psa_algorithm_t alg2 )
{
/* Common case: both sides actually specify the same policy. */
if( alg1 == alg2 )
return( alg1 );
/* If the policies are from the same hash-and-sign family, check
* if one is a wildcard. If so the other has the specific algorithm. */
if( PSA_ALG_IS_HASH_AND_SIGN( alg1 ) &&
PSA_ALG_IS_HASH_AND_SIGN( alg2 ) &&
( alg1 & ~PSA_ALG_HASH_MASK ) == ( alg2 & ~PSA_ALG_HASH_MASK ) )
{
if( PSA_ALG_SIGN_GET_HASH( alg1 ) == PSA_ALG_ANY_HASH )
return( alg2 );
if( PSA_ALG_SIGN_GET_HASH( alg2 ) == PSA_ALG_ANY_HASH )
return( alg1 );
}
/* If the policies are incompatible, allow nothing. */
return( 0 );
}
static int psa_key_algorithm_permits( psa_algorithm_t policy_alg,
psa_algorithm_t requested_alg )
{
/* Common case: the policy only allows requested_alg. */
if( requested_alg == policy_alg )
return( 1 );
/* If policy_alg is a hash-and-sign with a wildcard for the hash,
* and requested_alg is the same hash-and-sign family with any hash,
* then requested_alg is compliant with policy_alg. */
if( PSA_ALG_IS_HASH_AND_SIGN( requested_alg ) &&
PSA_ALG_SIGN_GET_HASH( policy_alg ) == PSA_ALG_ANY_HASH )
{
return( ( policy_alg & ~PSA_ALG_HASH_MASK ) ==
( requested_alg & ~PSA_ALG_HASH_MASK ) );
}
/* If policy_alg is a generic key agreement operation, then using it for
* a key derivation with that key agreement should also be allowed. This
* behaviour is expected to be defined in a future specification version. */
if( PSA_ALG_IS_RAW_KEY_AGREEMENT( policy_alg ) &&
PSA_ALG_IS_KEY_AGREEMENT( requested_alg ) )
{
return( PSA_ALG_KEY_AGREEMENT_GET_BASE( requested_alg ) ==
policy_alg );
}
/* If it isn't permitted, it's forbidden. */
return( 0 );
}
/** Test whether a policy permits an algorithm.
*
* The caller must test usage flags separately.
*/
static int psa_key_policy_permits( const psa_key_policy_t *policy,
psa_algorithm_t alg )
{
return( psa_key_algorithm_permits( policy->alg, alg ) ||
psa_key_algorithm_permits( policy->alg2, alg ) );
}
/** Restrict a key policy based on a constraint.
*
* \param[in,out] policy The policy to restrict.
* \param[in] constraint The policy constraint to apply.
*
* \retval #PSA_SUCCESS
* \c *policy contains the intersection of the original value of
* \c *policy and \c *constraint.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* \c *policy and \c *constraint are incompatible.
* \c *policy is unchanged.
*/
static psa_status_t psa_restrict_key_policy(
psa_key_policy_t *policy,
const psa_key_policy_t *constraint )
{
psa_algorithm_t intersection_alg =
psa_key_policy_algorithm_intersection( policy->alg, constraint->alg );
psa_algorithm_t intersection_alg2 =
psa_key_policy_algorithm_intersection( policy->alg2, constraint->alg2 );
if( intersection_alg == 0 && policy->alg != 0 && constraint->alg != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
if( intersection_alg2 == 0 && policy->alg2 != 0 && constraint->alg2 != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
policy->usage &= constraint->usage;
policy->alg = intersection_alg;
policy->alg2 = intersection_alg2;
return( PSA_SUCCESS );
}
/** Get the description of a key given its identifier and policy constraints
* and lock it.
*
* The key must have allow all the usage flags set in \p usage. If \p alg is
* nonzero, the key must allow operations with this algorithm.
*
* In case of a persistent key, the function loads the description of the key
* into a key slot if not already done.
*
* On success, the returned key slot is locked. It is the responsibility of
* the caller to unlock the key slot when it does not access it anymore.
*/
static psa_status_t psa_get_and_lock_key_slot_with_policy(
mbedtls_svc_key_id_t key,
psa_key_slot_t **p_slot,
psa_key_usage_t usage,
psa_algorithm_t alg )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
status = psa_get_and_lock_key_slot( key, p_slot );
if( status != PSA_SUCCESS )
return( status );
slot = *p_slot;
/* Enforce that usage policy for the key slot contains all the flags
* required by the usage parameter. There is one exception: public
* keys can always be exported, so we treat public key objects as
* if they had the export flag. */
if( PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->attr.type ) )
usage &= ~PSA_KEY_USAGE_EXPORT;
status = PSA_ERROR_NOT_PERMITTED;
if( ( slot->attr.policy.usage & usage ) != usage )
goto error;
/* Enforce that the usage policy permits the requested algortihm. */
if( alg != 0 && ! psa_key_policy_permits( &slot->attr.policy, alg ) )
goto error;
return( PSA_SUCCESS );
error:
*p_slot = NULL;
psa_unlock_key_slot( slot );
return( status );
}
/** Get a key slot containing a transparent key and lock it.
*
* A transparent key is a key for which the key material is directly
* available, as opposed to a key in a secure element.
*
* This is a temporary function to use instead of
* psa_get_and_lock_key_slot_with_policy() until secure element support is
* fully implemented.
*
* On success, the returned key slot is locked. It is the responsibility of the
* caller to unlock the key slot when it does not access it anymore.
*/
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
static psa_status_t psa_get_and_lock_transparent_key_slot_with_policy(
mbedtls_svc_key_id_t key,
psa_key_slot_t **p_slot,
psa_key_usage_t usage,
psa_algorithm_t alg )
{
psa_status_t status = psa_get_and_lock_key_slot_with_policy( key, p_slot,
usage, alg );
if( status != PSA_SUCCESS )
return( status );
if( psa_key_slot_is_external( *p_slot ) )
{
psa_unlock_key_slot( *p_slot );
*p_slot = NULL;
return( PSA_ERROR_NOT_SUPPORTED );
}
return( PSA_SUCCESS );
}
#else /* MBEDTLS_PSA_CRYPTO_SE_C */
/* With no secure element support, all keys are transparent. */
#define psa_get_and_lock_transparent_key_slot_with_policy( key, p_slot, usage, alg ) \
psa_get_and_lock_key_slot_with_policy( key, p_slot, usage, alg )
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
/** Wipe key data from a slot. Preserve metadata such as the policy. */
static psa_status_t psa_remove_key_data_from_memory( psa_key_slot_t *slot )
{
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_key_slot_is_external( slot ) )
{
/* No key material to clean. */
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
{
/* Data pointer will always be either a valid pointer or NULL in an
* initialized slot, so we can just free it. */
if( slot->data.key.data != NULL )
mbedtls_platform_zeroize( slot->data.key.data, slot->data.key.bytes);
mbedtls_free( slot->data.key.data );
slot->data.key.data = NULL;
slot->data.key.bytes = 0;
}
return( PSA_SUCCESS );
}
/** Completely wipe a slot in memory, including its policy.
* Persistent storage is not affected. */
psa_status_t psa_wipe_key_slot( psa_key_slot_t *slot )
{
psa_status_t status = psa_remove_key_data_from_memory( slot );
/*
* As the return error code may not be handled in case of multiple errors,
* do our best to report an unexpected lock counter: if available
* call MBEDTLS_PARAM_FAILED that may terminate execution (if called as
* part of the execution of a test suite this will stop the test suite
* execution).
*/
if( slot->lock_count != 1 )
{
#ifdef MBEDTLS_CHECK_PARAMS
MBEDTLS_PARAM_FAILED( slot->lock_count == 1 );
#endif
status = PSA_ERROR_CORRUPTION_DETECTED;
}
/* Multipart operations may still be using the key. This is safe
* because all multipart operation objects are independent from
* the key slot: if they need to access the key after the setup
* phase, they have a copy of the key. Note that this means that
* key material can linger until all operations are completed. */
/* At this point, key material and other type-specific content has
* been wiped. Clear remaining metadata. We can call memset and not
* zeroize because the metadata is not particularly sensitive. */
memset( slot, 0, sizeof( *slot ) );
return( status );
}
psa_status_t psa_destroy_key( mbedtls_svc_key_id_t key )
{
psa_key_slot_t *slot;
psa_status_t status; /* status of the last operation */
psa_status_t overall_status = PSA_SUCCESS;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
psa_se_drv_table_entry_t *driver;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( mbedtls_svc_key_id_is_null( key ) )
return( PSA_SUCCESS );
/*
* Get the description of the key in a key slot. In case of a persistent
* key, this will load the key description from persistent memory if not
* done yet. We cannot avoid this loading as without it we don't know if
* the key is operated by an SE or not and this information is needed by
* the current implementation.
*/
status = psa_get_and_lock_key_slot( key, &slot );
if( status != PSA_SUCCESS )
return( status );
/*
* If the key slot containing the key description is under access by the
* library (apart from the present access), the key cannot be destroyed
* yet. For the time being, just return in error. Eventually (to be
* implemented), the key should be destroyed when all accesses have
* stopped.
*/
if( slot->lock_count > 1 )
{
psa_unlock_key_slot( slot );
return( PSA_ERROR_GENERIC_ERROR );
}
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
driver = psa_get_se_driver_entry( slot->attr.lifetime );
if( driver != NULL )
{
/* For a key in a secure element, we need to do three things:
* remove the key file in internal storage, destroy the
* key inside the secure element, and update the driver's
* persistent data. Start a transaction that will encompass these
* three actions. */
psa_crypto_prepare_transaction( PSA_CRYPTO_TRANSACTION_DESTROY_KEY );
psa_crypto_transaction.key.lifetime = slot->attr.lifetime;
psa_crypto_transaction.key.slot = slot->data.se.slot_number;
psa_crypto_transaction.key.id = slot->attr.id;
status = psa_crypto_save_transaction( );
if( status != PSA_SUCCESS )
{
(void) psa_crypto_stop_transaction( );
/* We should still try to destroy the key in the secure
* element and the key metadata in storage. This is especially
* important if the error is that the storage is full.
* But how to do it exactly without risking an inconsistent
* state after a reset?
* https://github.com/ARMmbed/mbed-crypto/issues/215
*/
overall_status = status;
goto exit;
}
status = psa_destroy_se_key( driver, slot->data.se.slot_number );
if( overall_status == PSA_SUCCESS )
overall_status = status;
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
if( ! PSA_KEY_LIFETIME_IS_VOLATILE( slot->attr.lifetime ) )
{
status = psa_destroy_persistent_key( slot->attr.id );
if( overall_status == PSA_SUCCESS )
overall_status = status;
/* TODO: other slots may have a copy of the same key. We should
* invalidate them.
* https://github.com/ARMmbed/mbed-crypto/issues/214
*/
}
#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( driver != NULL )
{
status = psa_save_se_persistent_data( driver );
if( overall_status == PSA_SUCCESS )
overall_status = status;
status = psa_crypto_stop_transaction( );
if( overall_status == PSA_SUCCESS )
overall_status = status;
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
exit:
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
status = psa_wipe_key_slot( slot );
/* Prioritize CORRUPTION_DETECTED from wiping over a storage error */
if( overall_status == PSA_SUCCESS )
overall_status = status;
return( overall_status );
}
void psa_reset_key_attributes( psa_key_attributes_t *attributes )
{
mbedtls_free( attributes->domain_parameters );
memset( attributes, 0, sizeof( *attributes ) );
}
psa_status_t psa_set_key_domain_parameters( psa_key_attributes_t *attributes,
psa_key_type_t type,
const uint8_t *data,
size_t data_length )
{
uint8_t *copy = NULL;
if( data_length != 0 )
{
copy = mbedtls_calloc( 1, data_length );
if( copy == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
memcpy( copy, data, data_length );
}
/* After this point, this function is guaranteed to succeed, so it
* can start modifying `*attributes`. */
if( attributes->domain_parameters != NULL )
{
mbedtls_free( attributes->domain_parameters );
attributes->domain_parameters = NULL;
attributes->domain_parameters_size = 0;
}
attributes->domain_parameters = copy;
attributes->domain_parameters_size = data_length;
attributes->core.type = type;
return( PSA_SUCCESS );
}
psa_status_t psa_get_key_domain_parameters(
const psa_key_attributes_t *attributes,
uint8_t *data, size_t data_size, size_t *data_length )
{
if( attributes->domain_parameters_size > data_size )
return( PSA_ERROR_BUFFER_TOO_SMALL );
*data_length = attributes->domain_parameters_size;
if( attributes->domain_parameters_size != 0 )
memcpy( data, attributes->domain_parameters,
attributes->domain_parameters_size );
return( PSA_SUCCESS );
}
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
static psa_status_t psa_get_rsa_public_exponent(
const mbedtls_rsa_context *rsa,
psa_key_attributes_t *attributes )
{
mbedtls_mpi mpi;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint8_t *buffer = NULL;
size_t buflen;
mbedtls_mpi_init( &mpi );
ret = mbedtls_rsa_export( rsa, NULL, NULL, NULL, NULL, &mpi );
if( ret != 0 )
goto exit;
if( mbedtls_mpi_cmp_int( &mpi, 65537 ) == 0 )
{
/* It's the default value, which is reported as an empty string,
* so there's nothing to do. */
goto exit;
}
buflen = mbedtls_mpi_size( &mpi );
buffer = mbedtls_calloc( 1, buflen );
if( buffer == NULL )
{
ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
goto exit;
}
ret = mbedtls_mpi_write_binary( &mpi, buffer, buflen );
if( ret != 0 )
goto exit;
attributes->domain_parameters = buffer;
attributes->domain_parameters_size = buflen;
exit:
mbedtls_mpi_free( &mpi );
if( ret != 0 )
mbedtls_free( buffer );
return( mbedtls_to_psa_error( ret ) );
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
/** Retrieve all the publicly-accessible attributes of a key.
*/
psa_status_t psa_get_key_attributes( mbedtls_svc_key_id_t key,
psa_key_attributes_t *attributes )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
psa_reset_key_attributes( attributes );
status = psa_get_and_lock_key_slot_with_policy( key, &slot, 0, 0 );
if( status != PSA_SUCCESS )
return( status );
attributes->core = slot->attr;
attributes->core.flags &= ( MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY |
MBEDTLS_PSA_KA_MASK_DUAL_USE );
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_key_slot_is_external( slot ) )
psa_set_key_slot_number( attributes, slot->data.se.slot_number );
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
switch( slot->attr.type )
{
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
case PSA_KEY_TYPE_RSA_KEY_PAIR:
case PSA_KEY_TYPE_RSA_PUBLIC_KEY:
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* TODO: reporting the public exponent for opaque keys
* is not yet implemented.
* https://github.com/ARMmbed/mbed-crypto/issues/216
*/
if( psa_key_slot_is_external( slot ) )
break;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
{
mbedtls_rsa_context *rsa = NULL;
status = psa_load_rsa_representation( slot->attr.type,
slot->data.key.data,
slot->data.key.bytes,
&rsa );
if( status != PSA_SUCCESS )
break;
status = psa_get_rsa_public_exponent( rsa,
attributes );
mbedtls_rsa_free( rsa );
mbedtls_free( rsa );
}
break;
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
default:
/* Nothing else to do. */
break;
}
if( status != PSA_SUCCESS )
psa_reset_key_attributes( attributes );
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
psa_status_t psa_get_key_slot_number(
const psa_key_attributes_t *attributes,
psa_key_slot_number_t *slot_number )
{
if( attributes->core.flags & MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER )
{
*slot_number = attributes->slot_number;
return( PSA_SUCCESS );
}
else
return( PSA_ERROR_INVALID_ARGUMENT );
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
static psa_status_t psa_internal_export_key_buffer( const psa_key_slot_t *slot,
uint8_t *data,
size_t data_size,
size_t *data_length )
{
if( slot->data.key.bytes > data_size )
return( PSA_ERROR_BUFFER_TOO_SMALL );
memcpy( data, slot->data.key.data, slot->data.key.bytes );
memset( data + slot->data.key.bytes, 0,
data_size - slot->data.key.bytes );
*data_length = slot->data.key.bytes;
return( PSA_SUCCESS );
}
static psa_status_t psa_internal_export_key( const psa_key_slot_t *slot,
uint8_t *data,
size_t data_size,
size_t *data_length,
int export_public_key )
{
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
*data_length = 0;
if( export_public_key && ! PSA_KEY_TYPE_IS_ASYMMETRIC( slot->attr.type ) )
return( PSA_ERROR_INVALID_ARGUMENT );
/* Reject a zero-length output buffer now, since this can never be a
* valid key representation. This way we know that data must be a valid
* pointer and we can do things like memset(data, ..., data_size). */
if( data_size == 0 )
return( PSA_ERROR_BUFFER_TOO_SMALL );
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
{
psa_drv_se_export_key_t method;
if( drv->key_management == NULL )
return( PSA_ERROR_NOT_SUPPORTED );
method = ( export_public_key ?
drv->key_management->p_export_public :
drv->key_management->p_export );
if( method == NULL )
return( PSA_ERROR_NOT_SUPPORTED );
return( method( drv_context,
slot->data.se.slot_number,
data, data_size, data_length ) );
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( key_type_is_raw_bytes( slot->attr.type ) )
{
return( psa_internal_export_key_buffer( slot, data, data_size, data_length ) );
}
else if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) ||
PSA_KEY_TYPE_IS_ECC( slot->attr.type ) )
{
if( PSA_KEY_TYPE_IS_PUBLIC_KEY( slot->attr.type ) )
{
/* Exporting public -> public */
return( psa_internal_export_key_buffer( slot, data, data_size, data_length ) );
}
else if( !export_public_key )
{
/* Exporting private -> private */
return( psa_internal_export_key_buffer( slot, data, data_size, data_length ) );
}
/* Need to export the public part of a private key,
* so conversion is needed. Try the accelerators first. */
psa_status_t status = psa_driver_wrapper_export_public_key( slot,
data,
data_size,
data_length );
if( status != PSA_ERROR_NOT_SUPPORTED ||
psa_key_lifetime_is_external( slot->attr.lifetime ) )
return( status );
if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) )
{
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
mbedtls_rsa_context *rsa = NULL;
status = psa_load_rsa_representation(
slot->attr.type,
slot->data.key.data,
slot->data.key.bytes,
&rsa );
if( status != PSA_SUCCESS )
return( status );
status = psa_export_rsa_key( PSA_KEY_TYPE_RSA_PUBLIC_KEY,
rsa,
data,
data_size,
data_length );
mbedtls_rsa_free( rsa );
mbedtls_free( rsa );
return( status );
#else
/* We don't know how to convert a private RSA key to public. */
return( PSA_ERROR_NOT_SUPPORTED );
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
}
else
{
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
mbedtls_ecp_keypair *ecp = NULL;
status = psa_load_ecp_representation(
slot->attr.type,
slot->data.key.data,
slot->data.key.bytes,
&ecp );
if( status != PSA_SUCCESS )
return( status );
status = psa_export_ecp_key( PSA_KEY_TYPE_ECC_PUBLIC_KEY(
PSA_KEY_TYPE_ECC_GET_FAMILY(
slot->attr.type ) ),
ecp,
data,
data_size,
data_length );
mbedtls_ecp_keypair_free( ecp );
mbedtls_free( ecp );
return( status );
#else
/* We don't know how to convert a private ECC key to public */
return( PSA_ERROR_NOT_SUPPORTED );
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */
}
}
else
{
/* This shouldn't happen in the reference implementation, but
it is valid for a special-purpose implementation to omit
support for exporting certain key types. */
return( PSA_ERROR_NOT_SUPPORTED );
}
}
psa_status_t psa_export_key( mbedtls_svc_key_id_t key,
uint8_t *data,
size_t data_size,
size_t *data_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
/* Set the key to empty now, so that even when there are errors, we always
* set data_length to a value between 0 and data_size. On error, setting
* the key to empty is a good choice because an empty key representation is
* unlikely to be accepted anywhere. */
*data_length = 0;
/* Export requires the EXPORT flag. There is an exception for public keys,
* which don't require any flag, but
* psa_get_and_lock_key_slot_with_policy() takes care of this.
*/
status = psa_get_and_lock_key_slot_with_policy( key, &slot,
PSA_KEY_USAGE_EXPORT, 0 );
if( status != PSA_SUCCESS )
return( status );
status = psa_internal_export_key( slot, data, data_size, data_length, 0 );
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
psa_status_t psa_export_public_key( mbedtls_svc_key_id_t key,
uint8_t *data,
size_t data_size,
size_t *data_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
/* Set the key to empty now, so that even when there are errors, we always
* set data_length to a value between 0 and data_size. On error, setting
* the key to empty is a good choice because an empty key representation is
* unlikely to be accepted anywhere. */
*data_length = 0;
/* Exporting a public key doesn't require a usage flag. */
status = psa_get_and_lock_key_slot_with_policy( key, &slot, 0, 0 );
if( status != PSA_SUCCESS )
return( status );
status = psa_internal_export_key( slot, data, data_size, data_length, 1 );
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
#if defined(static_assert)
static_assert( ( MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE ) == 0,
"One or more key attribute flag is listed as both external-only and dual-use" );
static_assert( ( PSA_KA_MASK_INTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE ) == 0,
"One or more key attribute flag is listed as both internal-only and dual-use" );
static_assert( ( PSA_KA_MASK_INTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY ) == 0,
"One or more key attribute flag is listed as both internal-only and external-only" );
#endif
/** Validate that a key policy is internally well-formed.
*
* This function only rejects invalid policies. It does not validate the
* consistency of the policy with respect to other attributes of the key
* such as the key type.
*/
static psa_status_t psa_validate_key_policy( const psa_key_policy_t *policy )
{
if( ( policy->usage & ~( PSA_KEY_USAGE_EXPORT |
PSA_KEY_USAGE_COPY |
PSA_KEY_USAGE_ENCRYPT |
PSA_KEY_USAGE_DECRYPT |
PSA_KEY_USAGE_SIGN_HASH |
PSA_KEY_USAGE_VERIFY_HASH |
PSA_KEY_USAGE_DERIVE ) ) != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
return( PSA_SUCCESS );
}
/** Validate the internal consistency of key attributes.
*
* This function only rejects invalid attribute values. If does not
* validate the consistency of the attributes with any key data that may
* be involved in the creation of the key.
*
* Call this function early in the key creation process.
*
* \param[in] attributes Key attributes for the new key.
* \param[out] p_drv On any return, the driver for the key, if any.
* NULL for a transparent key.
*
*/
static psa_status_t psa_validate_key_attributes(
const psa_key_attributes_t *attributes,
psa_se_drv_table_entry_t **p_drv )
{
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
psa_key_lifetime_t lifetime = psa_get_key_lifetime( attributes );
mbedtls_svc_key_id_t key = psa_get_key_id( attributes );
status = psa_validate_key_location( lifetime, p_drv );
if( status != PSA_SUCCESS )
return( status );
status = psa_validate_key_persistence( lifetime );
if( status != PSA_SUCCESS )
return( status );
if ( PSA_KEY_LIFETIME_IS_VOLATILE( lifetime ) )
{
if( MBEDTLS_SVC_KEY_ID_GET_KEY_ID( key ) != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
}
else
{
status = psa_validate_key_id( psa_get_key_id( attributes ), 0 );
if( status != PSA_SUCCESS )
return( status );
}
status = psa_validate_key_policy( &attributes->core.policy );
if( status != PSA_SUCCESS )
return( status );
/* Refuse to create overly large keys.
* Note that this doesn't trigger on import if the attributes don't
* explicitly specify a size (so psa_get_key_bits returns 0), so
* psa_import_key() needs its own checks. */
if( psa_get_key_bits( attributes ) > PSA_MAX_KEY_BITS )
return( PSA_ERROR_NOT_SUPPORTED );
/* Reject invalid flags. These should not be reachable through the API. */
if( attributes->core.flags & ~ ( MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY |
MBEDTLS_PSA_KA_MASK_DUAL_USE ) )
return( PSA_ERROR_INVALID_ARGUMENT );
return( PSA_SUCCESS );
}
/** Prepare a key slot to receive key material.
*
* This function allocates a key slot and sets its metadata.
*
* If this function fails, call psa_fail_key_creation().
*
* This function is intended to be used as follows:
* -# Call psa_start_key_creation() to allocate a key slot, prepare
* it with the specified attributes, and in case of a volatile key assign it
* a volatile key identifier.
* -# Populate the slot with the key material.
* -# Call psa_finish_key_creation() to finalize the creation of the slot.
* In case of failure at any step, stop the sequence and call
* psa_fail_key_creation().
*
* On success, the key slot is locked. It is the responsibility of the caller
* to unlock the key slot when it does not access it anymore.
*
* \param method An identification of the calling function.
* \param[in] attributes Key attributes for the new key.
* \param[out] p_slot On success, a pointer to the prepared slot.
* \param[out] p_drv On any return, the driver for the key, if any.
* NULL for a transparent key.
*
* \retval #PSA_SUCCESS
* The key slot is ready to receive key material.
* \return If this function fails, the key slot is an invalid state.
* You must call psa_fail_key_creation() to wipe and free the slot.
*/
static psa_status_t psa_start_key_creation(
psa_key_creation_method_t method,
const psa_key_attributes_t *attributes,
psa_key_slot_t **p_slot,
psa_se_drv_table_entry_t **p_drv )
{
psa_status_t status;
psa_key_id_t volatile_key_id;
psa_key_slot_t *slot;
(void) method;
*p_drv = NULL;
status = psa_validate_key_attributes( attributes, p_drv );
if( status != PSA_SUCCESS )
return( status );
status = psa_get_empty_key_slot( &volatile_key_id, p_slot );
if( status != PSA_SUCCESS )
return( status );
slot = *p_slot;
/* We're storing the declared bit-size of the key. It's up to each
* creation mechanism to verify that this information is correct.
* It's automatically correct for mechanisms that use the bit-size as
* an input (generate, device) but not for those where the bit-size
* is optional (import, copy). In case of a volatile key, assign it the
* volatile key identifier associated to the slot returned to contain its
* definition. */
slot->attr = attributes->core;
if( PSA_KEY_LIFETIME_IS_VOLATILE( slot->attr.lifetime ) )
{
#if !defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
slot->attr.id = volatile_key_id;
#else
slot->attr.id.key_id = volatile_key_id;
#endif
}
/* Erase external-only flags from the internal copy. To access
* external-only flags, query `attributes`. Thanks to the check
* in psa_validate_key_attributes(), this leaves the dual-use
* flags and any internal flag that psa_get_empty_key_slot()
* may have set. */
slot->attr.flags &= ~MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* For a key in a secure element, we need to do three things
* when creating or registering a persistent key:
* create the key file in internal storage, create the
* key inside the secure element, and update the driver's
* persistent data. This is done by starting a transaction that will
* encompass these three actions.
* For registering a volatile key, we just need to find an appropriate
* slot number inside the SE. Since the key is designated volatile, creating
* a transaction is not required. */
/* The first thing to do is to find a slot number for the new key.
* We save the slot number in persistent storage as part of the
* transaction data. It will be needed to recover if the power
* fails during the key creation process, to clean up on the secure
* element side after restarting. Obtaining a slot number from the
* secure element driver updates its persistent state, but we do not yet
* save the driver's persistent state, so that if the power fails,
* we can roll back to a state where the key doesn't exist. */
if( *p_drv != NULL )
{
status = psa_find_se_slot_for_key( attributes, method, *p_drv,
&slot->data.se.slot_number );
if( status != PSA_SUCCESS )
return( status );
if( ! PSA_KEY_LIFETIME_IS_VOLATILE( attributes->core.lifetime ) )
{
psa_crypto_prepare_transaction( PSA_CRYPTO_TRANSACTION_CREATE_KEY );
psa_crypto_transaction.key.lifetime = slot->attr.lifetime;
psa_crypto_transaction.key.slot = slot->data.se.slot_number;
psa_crypto_transaction.key.id = slot->attr.id;
status = psa_crypto_save_transaction( );
if( status != PSA_SUCCESS )
{
(void) psa_crypto_stop_transaction( );
return( status );
}
}
}
if( *p_drv == NULL && method == PSA_KEY_CREATION_REGISTER )
{
/* Key registration only makes sense with a secure element. */
return( PSA_ERROR_INVALID_ARGUMENT );
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
return( PSA_SUCCESS );
}
/** Finalize the creation of a key once its key material has been set.
*
* This entails writing the key to persistent storage.
*
* If this function fails, call psa_fail_key_creation().
* See the documentation of psa_start_key_creation() for the intended use
* of this function.
*
* If the finalization succeeds, the function unlocks the key slot (it was
* locked by psa_start_key_creation()) and the key slot cannot be accessed
* anymore as part of the key creation process.
*
* \param[in,out] slot Pointer to the slot with key material.
* \param[in] driver The secure element driver for the key,
* or NULL for a transparent key.
* \param[out] key On success, identifier of the key. Note that the
* key identifier is also stored in the key slot.
*
* \retval #PSA_SUCCESS
* The key was successfully created.
* \return If this function fails, the key slot is an invalid state.
* You must call psa_fail_key_creation() to wipe and free the slot.
*/
static psa_status_t psa_finish_key_creation(
psa_key_slot_t *slot,
psa_se_drv_table_entry_t *driver,
mbedtls_svc_key_id_t *key)
{
psa_status_t status = PSA_SUCCESS;
(void) slot;
(void) driver;
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
if( ! PSA_KEY_LIFETIME_IS_VOLATILE( slot->attr.lifetime ) )
{
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( driver != NULL )
{
psa_se_key_data_storage_t data;
#if defined(static_assert)
static_assert( sizeof( slot->data.se.slot_number ) ==
sizeof( data.slot_number ),
"Slot number size does not match psa_se_key_data_storage_t" );
#endif
memcpy( &data.slot_number, &slot->data.se.slot_number,
sizeof( slot->data.se.slot_number ) );
status = psa_save_persistent_key( &slot->attr,
(uint8_t*) &data,
sizeof( data ) );
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
{
/* Key material is saved in export representation in the slot, so
* just pass the slot buffer for storage. */
status = psa_save_persistent_key( &slot->attr,
slot->data.key.data,
slot->data.key.bytes );
}
}
#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* Finish the transaction for a key creation. This does not
* happen when registering an existing key. Detect this case
* by checking whether a transaction is in progress (actual
* creation of a persistent key in a secure element requires a transaction,
* but registration or volatile key creation doesn't use one). */
if( driver != NULL &&
psa_crypto_transaction.unknown.type == PSA_CRYPTO_TRANSACTION_CREATE_KEY )
{
status = psa_save_se_persistent_data( driver );
if( status != PSA_SUCCESS )
{
psa_destroy_persistent_key( slot->attr.id );
return( status );
}
status = psa_crypto_stop_transaction( );
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
if( status == PSA_SUCCESS )
{
*key = slot->attr.id;
status = psa_unlock_key_slot( slot );
if( status != PSA_SUCCESS )
*key = MBEDTLS_SVC_KEY_ID_INIT;
}
return( status );
}
/** Abort the creation of a key.
*
* You may call this function after calling psa_start_key_creation(),
* or after psa_finish_key_creation() fails. In other circumstances, this
* function may not clean up persistent storage.
* See the documentation of psa_start_key_creation() for the intended use
* of this function.
*
* \param[in,out] slot Pointer to the slot with key material.
* \param[in] driver The secure element driver for the key,
* or NULL for a transparent key.
*/
static void psa_fail_key_creation( psa_key_slot_t *slot,
psa_se_drv_table_entry_t *driver )
{
(void) driver;
if( slot == NULL )
return;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
/* TODO: If the key has already been created in the secure
* element, and the failure happened later (when saving metadata
* to internal storage), we need to destroy the key in the secure
* element.
* https://github.com/ARMmbed/mbed-crypto/issues/217
*/
/* Abort the ongoing transaction if any (there may not be one if
* the creation process failed before starting one, or if the
* key creation is a registration of a key in a secure element).
* Earlier functions must already have done what it takes to undo any
* partial creation. All that's left is to update the transaction data
* itself. */
(void) psa_crypto_stop_transaction( );
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
psa_wipe_key_slot( slot );
}
/** Validate optional attributes during key creation.
*
* Some key attributes are optional during key creation. If they are
* specified in the attributes structure, check that they are consistent
* with the data in the slot.
*
* This function should be called near the end of key creation, after
* the slot in memory is fully populated but before saving persistent data.
*/
static psa_status_t psa_validate_optional_attributes(
const psa_key_slot_t *slot,
const psa_key_attributes_t *attributes )
{
if( attributes->core.type != 0 )
{
if( attributes->core.type != slot->attr.type )
return( PSA_ERROR_INVALID_ARGUMENT );
}
if( attributes->domain_parameters_size != 0 )
{
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) || \
defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY)
if( PSA_KEY_TYPE_IS_RSA( slot->attr.type ) )
{
mbedtls_rsa_context *rsa = NULL;
mbedtls_mpi actual, required;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
psa_status_t status = psa_load_rsa_representation(
slot->attr.type,
slot->data.key.data,
slot->data.key.bytes,
&rsa );
if( status != PSA_SUCCESS )
return( status );
mbedtls_mpi_init( &actual );
mbedtls_mpi_init( &required );
ret = mbedtls_rsa_export( rsa,
NULL, NULL, NULL, NULL, &actual );
mbedtls_rsa_free( rsa );
mbedtls_free( rsa );
if( ret != 0 )
goto rsa_exit;
ret = mbedtls_mpi_read_binary( &required,
attributes->domain_parameters,
attributes->domain_parameters_size );
if( ret != 0 )
goto rsa_exit;
if( mbedtls_mpi_cmp_mpi( &actual, &required ) != 0 )
ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
rsa_exit:
mbedtls_mpi_free( &actual );
mbedtls_mpi_free( &required );
if( ret != 0)
return( mbedtls_to_psa_error( ret ) );
}
else
#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR) ||
* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_PUBLIC_KEY) */
{
return( PSA_ERROR_INVALID_ARGUMENT );
}
}
if( attributes->core.bits != 0 )
{
if( attributes->core.bits != slot->attr.bits )
return( PSA_ERROR_INVALID_ARGUMENT );
}
return( PSA_SUCCESS );
}
psa_status_t psa_import_key( const psa_key_attributes_t *attributes,
const uint8_t *data,
size_t data_length,
mbedtls_svc_key_id_t *key )
{
psa_status_t status;
psa_key_slot_t *slot = NULL;
psa_se_drv_table_entry_t *driver = NULL;
*key = MBEDTLS_SVC_KEY_ID_INIT;
/* Reject zero-length symmetric keys (including raw data key objects).
* This also rejects any key which might be encoded as an empty string,
* which is never valid. */
if( data_length == 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
status = psa_start_key_creation( PSA_KEY_CREATION_IMPORT, attributes,
&slot, &driver );
if( status != PSA_SUCCESS )
goto exit;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( driver != NULL )
{
const psa_drv_se_t *drv = psa_get_se_driver_methods( driver );
/* The driver should set the number of key bits, however in
* case it doesn't, we initialize bits to an invalid value. */
size_t bits = PSA_MAX_KEY_BITS + 1;
if( drv->key_management == NULL ||
drv->key_management->p_import == NULL )
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = drv->key_management->p_import(
psa_get_se_driver_context( driver ),
slot->data.se.slot_number, attributes, data, data_length,
&bits );
if( status != PSA_SUCCESS )
goto exit;
if( bits > PSA_MAX_KEY_BITS )
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
slot->attr.bits = (psa_key_bits_t) bits;
}
else
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
{
status = psa_import_key_into_slot( slot, data, data_length );
if( status != PSA_SUCCESS )
goto exit;
}
status = psa_validate_optional_attributes( slot, attributes );
if( status != PSA_SUCCESS )
goto exit;
status = psa_finish_key_creation( slot, driver, key );
exit:
if( status != PSA_SUCCESS )
psa_fail_key_creation( slot, driver );
return( status );
}
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
psa_status_t mbedtls_psa_register_se_key(
const psa_key_attributes_t *attributes )
{
psa_status_t status;
psa_key_slot_t *slot = NULL;
psa_se_drv_table_entry_t *driver = NULL;
mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
/* Leaving attributes unspecified is not currently supported.
* It could make sense to query the key type and size from the
* secure element, but not all secure elements support this
* and the driver HAL doesn't currently support it. */
if( psa_get_key_type( attributes ) == PSA_KEY_TYPE_NONE )
return( PSA_ERROR_NOT_SUPPORTED );
if( psa_get_key_bits( attributes ) == 0 )
return( PSA_ERROR_NOT_SUPPORTED );
status = psa_start_key_creation( PSA_KEY_CREATION_REGISTER, attributes,
&slot, &driver );
if( status != PSA_SUCCESS )
goto exit;
status = psa_finish_key_creation( slot, driver, &key );
exit:
if( status != PSA_SUCCESS )
psa_fail_key_creation( slot, driver );
/* Registration doesn't keep the key in RAM. */
psa_close_key( key );
return( status );
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
static psa_status_t psa_copy_key_material( const psa_key_slot_t *source,
psa_key_slot_t *target )
{
psa_status_t status = psa_copy_key_material_into_slot( target,
source->data.key.data,
source->data.key.bytes );
if( status != PSA_SUCCESS )
return( status );
target->attr.type = source->attr.type;
target->attr.bits = source->attr.bits;
return( PSA_SUCCESS );
}
psa_status_t psa_copy_key( mbedtls_svc_key_id_t source_key,
const psa_key_attributes_t *specified_attributes,
mbedtls_svc_key_id_t *target_key )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *source_slot = NULL;
psa_key_slot_t *target_slot = NULL;
psa_key_attributes_t actual_attributes = *specified_attributes;
psa_se_drv_table_entry_t *driver = NULL;
*target_key = MBEDTLS_SVC_KEY_ID_INIT;
status = psa_get_and_lock_transparent_key_slot_with_policy(
source_key, &source_slot, PSA_KEY_USAGE_COPY, 0 );
if( status != PSA_SUCCESS )
goto exit;
status = psa_validate_optional_attributes( source_slot,
specified_attributes );
if( status != PSA_SUCCESS )
goto exit;
status = psa_restrict_key_policy( &actual_attributes.core.policy,
&source_slot->attr.policy );
if( status != PSA_SUCCESS )
goto exit;
status = psa_start_key_creation( PSA_KEY_CREATION_COPY, &actual_attributes,
&target_slot, &driver );
if( status != PSA_SUCCESS )
goto exit;
#if defined(MBEDTLS_PSA_CRYPTO_SE_C)
if( driver != NULL )
{
/* Copying to a secure element is not implemented yet. */
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
status = psa_copy_key_material( source_slot, target_slot );
if( status != PSA_SUCCESS )
goto exit;
status = psa_finish_key_creation( target_slot, driver, target_key );
exit:
if( status != PSA_SUCCESS )
psa_fail_key_creation( target_slot, driver );
unlock_status = psa_unlock_key_slot( source_slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
/****************************************************************/
/* Message digests */
/****************************************************************/
#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
static const mbedtls_md_info_t *mbedtls_md_info_from_psa( psa_algorithm_t alg )
{
switch( alg )
{
#if defined(MBEDTLS_MD2_C)
case PSA_ALG_MD2:
return( &mbedtls_md2_info );
#endif
#if defined(MBEDTLS_MD4_C)
case PSA_ALG_MD4:
return( &mbedtls_md4_info );
#endif
#if defined(MBEDTLS_MD5_C)
case PSA_ALG_MD5:
return( &mbedtls_md5_info );
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case PSA_ALG_RIPEMD160:
return( &mbedtls_ripemd160_info );
#endif
#if defined(MBEDTLS_SHA1_C)
case PSA_ALG_SHA_1:
return( &mbedtls_sha1_info );
#endif
#if defined(MBEDTLS_SHA256_C)
case PSA_ALG_SHA_224:
return( &mbedtls_sha224_info );
case PSA_ALG_SHA_256:
return( &mbedtls_sha256_info );
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case PSA_ALG_SHA_384:
return( &mbedtls_sha384_info );
#endif
case PSA_ALG_SHA_512:
return( &mbedtls_sha512_info );
#endif
default:
return( NULL );
}
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) ||
* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */
psa_status_t psa_hash_abort( psa_hash_operation_t *operation )
{
switch( operation->alg )
{
case 0:
/* The object has (apparently) been initialized but it is not
* in use. It's ok to call abort on such an object, and there's
* nothing to do. */
break;
#if defined(MBEDTLS_MD2_C)
case PSA_ALG_MD2:
mbedtls_md2_free( &operation->ctx.md2 );
break;
#endif
#if defined(MBEDTLS_MD4_C)
case PSA_ALG_MD4:
mbedtls_md4_free( &operation->ctx.md4 );
break;
#endif
#if defined(MBEDTLS_MD5_C)
case PSA_ALG_MD5:
mbedtls_md5_free( &operation->ctx.md5 );
break;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case PSA_ALG_RIPEMD160:
mbedtls_ripemd160_free( &operation->ctx.ripemd160 );
break;
#endif
#if defined(MBEDTLS_SHA1_C)
case PSA_ALG_SHA_1:
mbedtls_sha1_free( &operation->ctx.sha1 );
break;
#endif
#if defined(MBEDTLS_SHA256_C)
case PSA_ALG_SHA_224:
case PSA_ALG_SHA_256:
mbedtls_sha256_free( &operation->ctx.sha256 );
break;
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case PSA_ALG_SHA_384:
#endif
case PSA_ALG_SHA_512:
mbedtls_sha512_free( &operation->ctx.sha512 );
break;
#endif
default:
return( PSA_ERROR_BAD_STATE );
}
operation->alg = 0;
return( PSA_SUCCESS );
}
psa_status_t psa_hash_setup( psa_hash_operation_t *operation,
psa_algorithm_t alg )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* A context must be freshly initialized before it can be set up. */
if( operation->alg != 0 )
{
return( PSA_ERROR_BAD_STATE );
}
switch( alg )
{
#if defined(MBEDTLS_MD2_C)
case PSA_ALG_MD2:
mbedtls_md2_init( &operation->ctx.md2 );
ret = mbedtls_md2_starts_ret( &operation->ctx.md2 );
break;
#endif
#if defined(MBEDTLS_MD4_C)
case PSA_ALG_MD4:
mbedtls_md4_init( &operation->ctx.md4 );
ret = mbedtls_md4_starts_ret( &operation->ctx.md4 );
break;
#endif
#if defined(MBEDTLS_MD5_C)
case PSA_ALG_MD5:
mbedtls_md5_init( &operation->ctx.md5 );
ret = mbedtls_md5_starts_ret( &operation->ctx.md5 );
break;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case PSA_ALG_RIPEMD160:
mbedtls_ripemd160_init( &operation->ctx.ripemd160 );
ret = mbedtls_ripemd160_starts_ret( &operation->ctx.ripemd160 );
break;
#endif
#if defined(MBEDTLS_SHA1_C)
case PSA_ALG_SHA_1:
mbedtls_sha1_init( &operation->ctx.sha1 );
ret = mbedtls_sha1_starts_ret( &operation->ctx.sha1 );
break;
#endif
#if defined(MBEDTLS_SHA256_C)
case PSA_ALG_SHA_224:
mbedtls_sha256_init( &operation->ctx.sha256 );
ret = mbedtls_sha256_starts_ret( &operation->ctx.sha256, 1 );
break;
case PSA_ALG_SHA_256:
mbedtls_sha256_init( &operation->ctx.sha256 );
ret = mbedtls_sha256_starts_ret( &operation->ctx.sha256, 0 );
break;
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case PSA_ALG_SHA_384:
mbedtls_sha512_init( &operation->ctx.sha512 );
ret = mbedtls_sha512_starts_ret( &operation->ctx.sha512, 1 );
break;
#endif
case PSA_ALG_SHA_512:
mbedtls_sha512_init( &operation->ctx.sha512 );
ret = mbedtls_sha512_starts_ret( &operation->ctx.sha512, 0 );
break;
#endif
default:
return( PSA_ALG_IS_HASH( alg ) ?
PSA_ERROR_NOT_SUPPORTED :
PSA_ERROR_INVALID_ARGUMENT );
}
if( ret == 0 )
operation->alg = alg;
else
psa_hash_abort( operation );
return( mbedtls_to_psa_error( ret ) );
}
psa_status_t psa_hash_update( psa_hash_operation_t *operation,
const uint8_t *input,
size_t input_length )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* Don't require hash implementations to behave correctly on a
* zero-length input, which may have an invalid pointer. */
if( input_length == 0 )
return( PSA_SUCCESS );
switch( operation->alg )
{
#if defined(MBEDTLS_MD2_C)
case PSA_ALG_MD2:
ret = mbedtls_md2_update_ret( &operation->ctx.md2,
input, input_length );
break;
#endif
#if defined(MBEDTLS_MD4_C)
case PSA_ALG_MD4:
ret = mbedtls_md4_update_ret( &operation->ctx.md4,
input, input_length );
break;
#endif
#if defined(MBEDTLS_MD5_C)
case PSA_ALG_MD5:
ret = mbedtls_md5_update_ret( &operation->ctx.md5,
input, input_length );
break;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case PSA_ALG_RIPEMD160:
ret = mbedtls_ripemd160_update_ret( &operation->ctx.ripemd160,
input, input_length );
break;
#endif
#if defined(MBEDTLS_SHA1_C)
case PSA_ALG_SHA_1:
ret = mbedtls_sha1_update_ret( &operation->ctx.sha1,
input, input_length );
break;
#endif
#if defined(MBEDTLS_SHA256_C)
case PSA_ALG_SHA_224:
case PSA_ALG_SHA_256:
ret = mbedtls_sha256_update_ret( &operation->ctx.sha256,
input, input_length );
break;
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case PSA_ALG_SHA_384:
#endif
case PSA_ALG_SHA_512:
ret = mbedtls_sha512_update_ret( &operation->ctx.sha512,
input, input_length );
break;
#endif
default:
return( PSA_ERROR_BAD_STATE );
}
if( ret != 0 )
psa_hash_abort( operation );
return( mbedtls_to_psa_error( ret ) );
}
psa_status_t psa_hash_finish( psa_hash_operation_t *operation,
uint8_t *hash,
size_t hash_size,
size_t *hash_length )
{
psa_status_t status;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t actual_hash_length = PSA_HASH_SIZE( operation->alg );
/* Fill the output buffer with something that isn't a valid hash
* (barring an attack on the hash and deliberately-crafted input),
* in case the caller doesn't check the return status properly. */
*hash_length = hash_size;
/* If hash_size is 0 then hash may be NULL and then the
* call to memset would have undefined behavior. */
if( hash_size != 0 )
memset( hash, '!', hash_size );
if( hash_size < actual_hash_length )
{
status = PSA_ERROR_BUFFER_TOO_SMALL;
goto exit;
}
switch( operation->alg )
{
#if defined(MBEDTLS_MD2_C)
case PSA_ALG_MD2:
ret = mbedtls_md2_finish_ret( &operation->ctx.md2, hash );
break;
#endif
#if defined(MBEDTLS_MD4_C)
case PSA_ALG_MD4:
ret = mbedtls_md4_finish_ret( &operation->ctx.md4, hash );
break;
#endif
#if defined(MBEDTLS_MD5_C)
case PSA_ALG_MD5:
ret = mbedtls_md5_finish_ret( &operation->ctx.md5, hash );
break;
#endif
#if defined(MBEDTLS_RIPEMD160_C)
case PSA_ALG_RIPEMD160:
ret = mbedtls_ripemd160_finish_ret( &operation->ctx.ripemd160, hash );
break;
#endif
#if defined(MBEDTLS_SHA1_C)
case PSA_ALG_SHA_1:
ret = mbedtls_sha1_finish_ret( &operation->ctx.sha1, hash );
break;
#endif
#if defined(MBEDTLS_SHA256_C)
case PSA_ALG_SHA_224:
case PSA_ALG_SHA_256:
ret = mbedtls_sha256_finish_ret( &operation->ctx.sha256, hash );
break;
#endif
#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
case PSA_ALG_SHA_384:
#endif
case PSA_ALG_SHA_512:
ret = mbedtls_sha512_finish_ret( &operation->ctx.sha512, hash );
break;
#endif
default:
return( PSA_ERROR_BAD_STATE );
}
status = mbedtls_to_psa_error( ret );
exit:
if( status == PSA_SUCCESS )
{
*hash_length = actual_hash_length;
return( psa_hash_abort( operation ) );
}
else
{
psa_hash_abort( operation );
return( status );
}
}
psa_status_t psa_hash_verify( psa_hash_operation_t *operation,
const uint8_t *hash,
size_t hash_length )
{
uint8_t actual_hash[MBEDTLS_MD_MAX_SIZE];
size_t actual_hash_length;
psa_status_t status = psa_hash_finish( operation,
actual_hash, sizeof( actual_hash ),
&actual_hash_length );
if( status != PSA_SUCCESS )
return( status );
if( actual_hash_length != hash_length )
return( PSA_ERROR_INVALID_SIGNATURE );
if( safer_memcmp( hash, actual_hash, actual_hash_length ) != 0 )
return( PSA_ERROR_INVALID_SIGNATURE );
return( PSA_SUCCESS );
}
psa_status_t psa_hash_compute( psa_algorithm_t alg,
const uint8_t *input, size_t input_length,
uint8_t *hash, size_t hash_size,
size_t *hash_length )
{
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
*hash_length = hash_size;
status = psa_hash_setup( &operation, alg );
if( status != PSA_SUCCESS )
goto exit;
status = psa_hash_update( &operation, input, input_length );
if( status != PSA_SUCCESS )
goto exit;
status = psa_hash_finish( &operation, hash, hash_size, hash_length );
if( status != PSA_SUCCESS )
goto exit;
exit:
if( status == PSA_SUCCESS )
status = psa_hash_abort( &operation );
else
psa_hash_abort( &operation );
return( status );
}
psa_status_t psa_hash_compare( psa_algorithm_t alg,
const uint8_t *input, size_t input_length,
const uint8_t *hash, size_t hash_length )
{
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
status = psa_hash_setup( &operation, alg );
if( status != PSA_SUCCESS )
goto exit;
status = psa_hash_update( &operation, input, input_length );
if( status != PSA_SUCCESS )
goto exit;
status = psa_hash_verify( &operation, hash, hash_length );
if( status != PSA_SUCCESS )
goto exit;
exit:
if( status == PSA_SUCCESS )
status = psa_hash_abort( &operation );
else
psa_hash_abort( &operation );
return( status );
}
psa_status_t psa_hash_clone( const psa_hash_operation_t *source_operation,
psa_hash_operation_t *target_operation )
{
if( target_operation->alg != 0 )
return( PSA_ERROR_BAD_STATE );
switch( source_operation->alg )
{
case 0:
return( PSA_ERROR_BAD_STATE );
#if defined(MBEDTLS_MD2_C)
case PSA_ALG_MD2:
mbedtls_md2_clone( &target_operation->ctx.md2,
&source_operation->ctx.md2 );
break;
#endif
#if defined(MBEDTLS_MD4_C)