diff options
Diffstat (limited to 'thirdparty/mbedtls/library/pk_wrap.c')
-rw-r--r-- | thirdparty/mbedtls/library/pk_wrap.c | 407 |
1 files changed, 366 insertions, 41 deletions
diff --git a/thirdparty/mbedtls/library/pk_wrap.c b/thirdparty/mbedtls/library/pk_wrap.c index 2c27552d9b..107e912ace 100644 --- a/thirdparty/mbedtls/library/pk_wrap.c +++ b/thirdparty/mbedtls/library/pk_wrap.c @@ -2,13 +2,7 @@ * Public Key abstraction layer: wrapper functions * * Copyright The Mbed TLS Contributors - * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later - * - * This file is provided under the Apache License 2.0, or the - * GNU General Public License v2.0 or later. - * - * ********** - * Apache License 2.0: + * 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. @@ -21,37 +15,13 @@ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - * ********** - * - * ********** - * GNU General Public License v2.0 or later: - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * ********** */ -#if !defined(MBEDTLS_CONFIG_FILE) -#include "mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif +#include "common.h" #if defined(MBEDTLS_PK_C) #include "mbedtls/pk_internal.h" +#include "mbedtls/error.h" /* Even if RSA not activated, for the sake of RSA-alt */ #include "mbedtls/rsa.h" @@ -66,10 +36,20 @@ #include "mbedtls/ecdsa.h" #endif +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "mbedtls/asn1write.h" +#endif + #if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) #include "mbedtls/platform_util.h" #endif +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#include "mbedtls/psa_util.h" +#include "mbedtls/asn1.h" +#endif + #if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" #else @@ -98,7 +78,7 @@ static int rsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len ) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; size_t rsa_len = mbedtls_rsa_get_len( rsa ); @@ -263,7 +243,7 @@ static int eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len ) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_init( &ecdsa ); @@ -281,7 +261,7 @@ static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, unsigned char *sig, size_t *sig_len, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_init( &ecdsa ); @@ -355,7 +335,7 @@ static int eckey_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *sig, size_t sig_len, void *rs_ctx ) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; eckey_restart_ctx *rs = rs_ctx; /* Should never happen */ @@ -380,7 +360,7 @@ static int eckey_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, void *rs_ctx ) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; eckey_restart_ctx *rs = rs_ctx; /* Should never happen */ @@ -497,11 +477,153 @@ static int ecdsa_can_do( mbedtls_pk_type_t type ) return( type == MBEDTLS_PK_ECDSA ); } +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/* + * An ASN.1 encoded signature is a sequence of two ASN.1 integers. Parse one of + * those integers and convert it to the fixed-length encoding expected by PSA. + */ +static int extract_ecdsa_sig_int( unsigned char **from, const unsigned char *end, + unsigned char *to, size_t to_len ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t unpadded_len, padding_len; + + if( ( ret = mbedtls_asn1_get_tag( from, end, &unpadded_len, + MBEDTLS_ASN1_INTEGER ) ) != 0 ) + { + return( ret ); + } + + while( unpadded_len > 0 && **from == 0x00 ) + { + ( *from )++; + unpadded_len--; + } + + if( unpadded_len > to_len || unpadded_len == 0 ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + padding_len = to_len - unpadded_len; + memset( to, 0x00, padding_len ); + memcpy( to + padding_len, *from, unpadded_len ); + ( *from ) += unpadded_len; + + return( 0 ); +} + +/* + * Convert a signature from an ASN.1 sequence of two integers + * to a raw {r,s} buffer. Note: the provided sig buffer must be at least + * twice as big as int_size. + */ +static int extract_ecdsa_sig( unsigned char **p, const unsigned char *end, + unsigned char *sig, size_t int_size ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t tmp_size; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &tmp_size, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + /* Extract r */ + if( ( ret = extract_ecdsa_sig_int( p, end, sig, int_size ) ) != 0 ) + return( ret ); + /* Extract s */ + if( ( ret = extract_ecdsa_sig_int( p, end, sig + int_size, int_size ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +static int ecdsa_verify_wrap( void *ctx_arg, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + mbedtls_ecdsa_context *ctx = ctx_arg; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id = 0; + psa_status_t status; + mbedtls_pk_context key; + int key_len; + /* see ECP_PUB_DER_MAX_BYTES in pkwrite.c */ + unsigned char buf[30 + 2 * MBEDTLS_ECP_MAX_BYTES]; + unsigned char *p; + mbedtls_pk_info_t pk_info = mbedtls_eckey_info; + psa_algorithm_t psa_sig_md = PSA_ALG_ECDSA_ANY; + size_t curve_bits; + psa_ecc_family_t curve = + mbedtls_ecc_group_to_psa( ctx->grp.id, &curve_bits ); + const size_t signature_part_size = ( ctx->grp.nbits + 7 ) / 8; + ((void) md_alg); + + if( curve == 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* mbedtls_pk_write_pubkey() expects a full PK context; + * re-construct one to make it happy */ + key.pk_info = &pk_info; + key.pk_ctx = ctx; + p = buf + sizeof( buf ); + key_len = mbedtls_pk_write_pubkey( &p, buf, &key ); + if( key_len <= 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + psa_set_key_type( &attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve ) ); + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH ); + psa_set_key_algorithm( &attributes, psa_sig_md ); + + status = psa_import_key( &attributes, + buf + sizeof( buf ) - key_len, key_len, + &key_id ); + if( status != PSA_SUCCESS ) + { + ret = mbedtls_psa_err_translate_pk( status ); + goto cleanup; + } + + /* We don't need the exported key anymore and can + * reuse its buffer for signature extraction. */ + if( 2 * signature_part_size > sizeof( buf ) ) + { + ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; + goto cleanup; + } + + p = (unsigned char*) sig; + if( ( ret = extract_ecdsa_sig( &p, sig + sig_len, buf, + signature_part_size ) ) != 0 ) + { + goto cleanup; + } + + if( psa_verify_hash( key_id, psa_sig_md, + hash, hash_len, + buf, 2 * signature_part_size ) + != PSA_SUCCESS ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + if( p != sig + sig_len ) + { + ret = MBEDTLS_ERR_PK_SIG_LEN_MISMATCH; + goto cleanup; + } + ret = 0; + +cleanup: + psa_destroy_key( key_id ); + return( ret ); +} +#else /* MBEDTLS_USE_PSA_CRYPTO */ static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len ) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; ((void) md_alg); ret = mbedtls_ecdsa_read_signature( (mbedtls_ecdsa_context *) ctx, @@ -512,6 +634,7 @@ static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, return( ret ); } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, @@ -528,7 +651,7 @@ static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *sig, size_t sig_len, void *rs_ctx ) { - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; ((void) md_alg); ret = mbedtls_ecdsa_read_signature_restartable( @@ -644,6 +767,8 @@ static int rsa_alt_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, #endif /* SIZE_MAX > UINT_MAX */ *sig_len = rsa_alt->key_len_func( rsa_alt->key ); + if( *sig_len > MBEDTLS_PK_SIGNATURE_MAX_SIZE ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); return( rsa_alt->sign_func( rsa_alt->key, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, md_alg, (unsigned int) hash_len, hash, sig ) ); @@ -672,7 +797,7 @@ static int rsa_alt_check_pair( const void *pub, const void *prv ) unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; unsigned char hash[32]; size_t sig_len = 0; - int ret; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); @@ -741,4 +866,204 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = { #endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + +static void *pk_opaque_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( psa_key_id_t ) ); + + /* no _init() function to call, an calloc() already zeroized */ + + return( ctx ); +} + +static void pk_opaque_free_wrap( void *ctx ) +{ + mbedtls_platform_zeroize( ctx, sizeof( psa_key_id_t ) ); + mbedtls_free( ctx ); +} + +static size_t pk_opaque_get_bitlen( const void *ctx ) +{ + const psa_key_id_t *key = (const psa_key_id_t *) ctx; + size_t bits; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + if( PSA_SUCCESS != psa_get_key_attributes( *key, &attributes ) ) + return( 0 ); + + bits = psa_get_key_bits( &attributes ); + psa_reset_key_attributes( &attributes ); + return( bits ); +} + +static int pk_opaque_can_do( mbedtls_pk_type_t type ) +{ + /* For now opaque PSA keys can only wrap ECC keypairs, + * as checked by setup_psa(). + * Also, ECKEY_DH does not really make sense with the current API. */ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECDSA ); +} + +#if defined(MBEDTLS_ECDSA_C) + +/* + * Simultaneously convert and move raw MPI from the beginning of a buffer + * to an ASN.1 MPI at the end of the buffer. + * See also mbedtls_asn1_write_mpi(). + * + * p: pointer to the end of the output buffer + * start: start of the output buffer, and also of the mpi to write at the end + * n_len: length of the mpi to read from start + */ +static int asn1_write_mpibuf( unsigned char **p, unsigned char *start, + size_t n_len ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len = 0; + + if( (size_t)( *p - start ) < n_len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = n_len; + *p -= len; + memmove( *p, start, len ); + + /* ASN.1 DER encoding requires minimal length, so skip leading 0s. + * Neither r nor s should be 0, but as a failsafe measure, still detect + * that rather than overflowing the buffer in case of a PSA error. */ + while( len > 0 && **p == 0x00 ) + { + ++(*p); + --len; + } + + /* this is only reached if the signature was invalid */ + if( len == 0 ) + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + + /* if the msb is 1, ASN.1 requires that we prepend a 0. + * Neither r nor s can be 0, so we can assume len > 0 at all times. */ + if( **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_INTEGER ) ); + + return( (int) len ); +} + +/* Transcode signature from PSA format to ASN.1 sequence. + * See ecdsa_signature_to_asn1 in ecdsa.c, but with byte buffers instead of + * MPIs, and in-place. + * + * [in/out] sig: the signature pre- and post-transcoding + * [in/out] sig_len: signature length pre- and post-transcoding + * [int] buf_len: the available size the in/out buffer + */ +static int pk_ecdsa_sig_asn1_from_psa( unsigned char *sig, size_t *sig_len, + size_t buf_len ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len = 0; + const size_t rs_len = *sig_len / 2; + unsigned char *p = sig + buf_len; + + MBEDTLS_ASN1_CHK_ADD( len, asn1_write_mpibuf( &p, sig + rs_len, rs_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, asn1_write_mpibuf( &p, sig, rs_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, sig, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, sig, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + memmove( sig, p, len ); + *sig_len = len; + + return( 0 ); +} + +#endif /* MBEDTLS_ECDSA_C */ + +static int pk_opaque_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ +#if !defined(MBEDTLS_ECDSA_C) + ((void) ctx); + ((void) md_alg); + ((void) hash); + ((void) hash_len); + ((void) sig); + ((void) sig_len); + ((void) f_rng); + ((void) p_rng); + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); +#else /* !MBEDTLS_ECDSA_C */ + const psa_key_id_t *key = (const psa_key_id_t *) ctx; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_algorithm_t alg = PSA_ALG_ECDSA( mbedtls_psa_translate_md( md_alg ) ); + size_t buf_len; + psa_status_t status; + + /* PSA has its own RNG */ + (void) f_rng; + (void) p_rng; + + /* PSA needs an output buffer of known size, but our API doesn't provide + * that information. Assume that the buffer is large enough for a + * maximal-length signature with that key (otherwise the application is + * buggy anyway). */ + status = psa_get_key_attributes( *key, &attributes ); + if( status != PSA_SUCCESS ) + return( mbedtls_psa_err_translate_pk( status ) ); + buf_len = MBEDTLS_ECDSA_MAX_SIG_LEN( psa_get_key_bits( &attributes ) ); + psa_reset_key_attributes( &attributes ); + if( buf_len > MBEDTLS_PK_SIGNATURE_MAX_SIZE ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* make the signature */ + status = psa_sign_hash( *key, alg, hash, hash_len, + sig, buf_len, sig_len ); + if( status != PSA_SUCCESS ) + return( mbedtls_psa_err_translate_pk( status ) ); + + /* transcode it to ASN.1 sequence */ + return( pk_ecdsa_sig_asn1_from_psa( sig, sig_len, buf_len ) ); +#endif /* !MBEDTLS_ECDSA_C */ +} + +const mbedtls_pk_info_t mbedtls_pk_opaque_info = { + MBEDTLS_PK_OPAQUE, + "Opaque", + pk_opaque_get_bitlen, + pk_opaque_can_do, + NULL, /* verify - will be done later */ + pk_opaque_sign_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, /* restartable verify - not relevant */ + NULL, /* restartable sign - not relevant */ +#endif + NULL, /* decrypt - will be done later */ + NULL, /* encrypt - will be done later */ + NULL, /* check_pair - could be done later or left NULL */ + pk_opaque_alloc_wrap, + pk_opaque_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, /* restart alloc - not relevant */ + NULL, /* restart free - not relevant */ +#endif + NULL, /* debug - could be done later, or even left NULL */ +}; + +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + #endif /* MBEDTLS_PK_C */ |