From 02768b436b8673beff406bc6df09d9eb2a6ca5fe Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 3 Nov 2017 19:20:27 +0100 Subject: [PATCH] PK: support for opaque keys Add a new key pair object type: MBEDTLS_PK_OPAQUE, intended for implementations of asymmetric cryptography operations that call an external cryptographic module. External cryptographic module engines must implement the API described by a mbedtls_pk_info_t structure and, usually, a custom setup function. Document the fields of the mbedtls_pk_info_t structure and the requirements on a PK engine. Also document non-obvious aspects of the behavior of the pk interface functions on opaque keys. Change the interface of check_pair_func to take a pointer to a full mbedtls_pk_context as its pub argument, and not just the data part of the context. This is necessary because when prv is opaque, pub may legitimately be of a different type (typically prv would be opaque and pub would be transparent). --- include/mbedtls/error.h | 2 +- include/mbedtls/pk.h | 27 +- include/mbedtls/pk_info.h | 166 +++++++- library/error.c | 6 + library/pk.c | 27 +- library/pk_wrap.c | 16 +- tests/suites/test_suite_pk.data | 13 + tests/suites/test_suite_pk.function | 602 +++++++++++++++++++++++++--- 8 files changed, 766 insertions(+), 93 deletions(-) diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h index 4eb7b78eb..301b73daa 100644 --- a/include/mbedtls/error.h +++ b/include/mbedtls/error.h @@ -74,7 +74,7 @@ * X509 2 20 * PKCS5 2 4 (Started from top) * DHM 3 9 - * PK 3 14 (Started from top) + * PK 3 17 (Started from top) * RSA 4 10 * ECP 4 8 (Started from top) * MD 5 4 diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 92f43ac77..0fd5ec8f2 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -3,7 +3,7 @@ * * \brief Public Key cryptography abstraction layer * - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -66,6 +66,9 @@ #define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */ #define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */ #define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The signature is valid but its length is less than expected. */ +#define MBEDTLS_ERR_PK_INVALID_SIGNATURE -0x3880 /**< Invalid signature */ +#define MBEDTLS_ERR_PK_BUFFER_TOO_SMALL -0x3800 /**< Output buffer too small */ +#define MBEDTLS_ERR_PK_NOT_PERMITTED -0x3780 /**< Operation not permitted */ /**@}*/ @@ -87,6 +90,10 @@ typedef enum { MBEDTLS_PK_ECDSA, /**< ECC key pair with ECDSA context */ MBEDTLS_PK_RSA_ALT, /**< RSA (alternative implementation) */ MBEDTLS_PK_RSASSA_PSS, /**< RSA key pair; same context as MBEDTLS_PK_RSA, but used to represent keys with the algorithm identifier id-RSASSA-PSS */ + /** Opaque key pair (cryptographic material held in an external module). + * This may be an RSA or ECC key or a key of an unrecognized type. Call + * \c mbedtls_pk_can_do() to check whether a key is of a recognized type. */ + MBEDTLS_PK_OPAQUE, } mbedtls_pk_type_t; /** @@ -216,6 +223,12 @@ void mbedtls_pk_free( mbedtls_pk_context *ctx ); * MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input, * MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. * + * \note Engines that implement of opaque keys may offer an + * alternative setup function that take engine-dependent + * parameters. If such a function exists, call it + * instead of mbedtls_pk_setup. The implementation-specific + * setup function should call mbedtls_pk_setup internally. + * * \note For contexts holding an RSA-alt key pair, use * \c mbedtls_pk_setup_rsa_alt() instead. */ @@ -448,7 +461,13 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, * is ill-formed. * * MBEDTLS_ERR_PK_TYPE_MISMATCH if the contexts cannot * represent keys of the same type. + * * MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE if it is impossible + * to determine whether the keys match. This is guaranteed + * not to happen if \c prv is a transparent key pair. * * Or a type-specific error code. + * + * \note Opaque key types may not implement this function. + * An opaque \c pub never matches a transparent \c prv. */ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); @@ -481,6 +500,12 @@ const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); * \param ctx Context to use * * \return Type on success, or MBEDTLS_PK_NONE + * + * \note This function returns the type of the key pair object. The + * type encodes the representation of the object as well as + * the operations that it can be used for. To test whether + * the object represents a key of a recognized type such + * as RSA or ECDSA, call \c mbedtls_pk_can_do(). */ mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index fe2dbdfc1..a90e489c4 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -32,58 +32,196 @@ #include "pk.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Methods that opaque key pair objects must implement. + * + * Engines that interface with external cryptographic processors must + * implement this interface. Platform-specific hardware accelerators + * that can be used for all keys of a given type should use alternative + * ("xxx_alt") interfaces instead. This interface allows using different + * engines for each key. + * + * An engine for asymmetric cryptography must implement the interface + * described in this structure. The interface for the engine may be + * exposed in one of two ways: + * + * - Declare the mbedtls_pk_info_t structure and instruct users to call + * mbedtls_pk_setup with that structure. + * - Keep the mbedtls_pk_info_t structure hidden and declare a function + * to call instead of mbedtls_pk_setup. This function should have an + * interface of the form + * `int mbedtls_pk_setup_myengine(mbedtls_pk_context *, ...)` + * where the extra parameters depend on the engine, e.g. handles to keys + * stored in an external cryptographic module. + * + * Unless otherwise indicated, functions returning int must return an + * Mbed TLS status code, either 0 for success or a negative value to indicate + * an error. It is recommended to use the MBEDTLS_ERR_PK_XXX error codes + * defined in pk.h. + * + * Some methods are optional; this is clearly indicated in their description. + * If a method is optional, then an opaque key implementation may put NULL + * in the corresponding field. The corresponding function in pk.h will + * return MBEDTLS_ERR_PK_TYPE_MISMATCH in this case. + * + * \note If you are using the PK interface to perform operations on + * keys, call the functions in pk.h. The interface in this file should only + * be used by implementers of opaque key engines. + */ struct mbedtls_pk_info_t { - /** Key pair type with indication of supported algorithms */ + /** Key pair type. + * + * mbedtls_pk_get_type() returns this value. + * + * For transparent keys, this contains an indication of supported + * algorithms. For opaque keys, this is \c MBEDTLS_PK_OPAQUE. */ mbedtls_pk_type_t type; - /** Type name */ + /** Type name. + * + * mbedtls_pk_get_name() returns this value. It must be a + * null-terminated string. + * + * For transparent keys, this reflects the key type. For opaque keys, + * this reflects the cryptographic module driver. */ const char *name; - /** Get key size in bits */ + /** Get key size in bits. + * + * mbedtls_pk_get_bitlen() returns this value. + * + * This function cannot fail. */ size_t (*get_bitlen)( const void *ctx ); - /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ + /** Tell if the context implements this type (e.g.\ ECKEY can do ECDSA). + * + * mbedtls_pk_can_do() calls this function. + * + * This function is only based on the key type. It does not take any + * usage restrictions into account. */ int (*can_do)( const void * ctx, mbedtls_pk_type_t type ); - /** Verify signature */ + /** Verify signature + * + * mbedtls_pk_verify() calls this function. + * + * Opaque implementations may omit this method if they do not support + * signature verification. */ int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len ); - /** Make signature */ + /** Make signature + * + * mbedtls_pk_sign() calls this function. + * + * Assume that the buffer \c sig has room for + * \c signature_size_func(ctx) bytes. + * + * The arguments \c f_rng and \c p_rng are provided in case the + * algorithm requires randomization. Implementations are not + * required to use it if they have their own random source. If \c + * f_rng is null, the implementation should operate if it can, and + * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. + * + * Opaque implementations may omit this method if they do not support + * signature. */ int (*sign_func)( 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 ); - /** Decrypt message */ + /** Decrypt message + * + * mbedtls_pk_decrypt() calls this function. + * + * The arguments \c f_rng and \c p_rng are provided in case the + * algorithm requires randomization. Implementations are not + * required to use it if they have their own random source. If \c + * f_rng is null, the implementation should operate if it can, and + * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. + * + * Opaque implementations may omit this method if they do not support + * decryption. */ int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); - /** Encrypt message */ + /** Encrypt message + * + * mbedtls_pk_decrypt() calls this function. + * + * The arguments \c f_rng and \c p_rng are provided in case the + * algorithm requires randomization. Implementations are not + * required to use it if they have their own random source. If \c + * f_rng is null, the implementation should operate if it can, and + * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. + * + * Opaque implementations may omit this method if they do not support + * encryption. */ int (*encrypt_func)( void *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); - /** Check public-private key pair */ - int (*check_pair_func)( const void *pub, const void *prv ); + /** Check public-private key pair + * + * mbedtls_pk_check_pair() calls this function on the private key pair + * object \c prv. The other argument \c pub may be of any type, but it + * is guaranteed to be initialized. + * + * Opaque implementations may omit this method. */ + int (*check_pair_func)( const mbedtls_pk_context *pub, const void *prv ); - /** Allocate a new context */ + /** Allocate a new context + * + * mbedtls_pk_setup() calls this function. + * + * If this function returns NULL, the allocation is considered to + * have failed and the the object remains uninitialized. + * + * Opaque implementations may omit this method. In this case, + * mbedtls_pk_setup will set the \c pk_ctx field of the mbedtls_pk_context + * object to NULL, and it is up to an engine-specific setup function to + * initialize the \c pk_ctx field. This is useful if the size of the + * memory depends on extra parameters passed to the engine-specific setup + * function. */ void * (*ctx_alloc_func)( void ); - /** Free the given context */ + /** Free the given context + * + * mbedtls_pk_free() calls this function. It must free the data allocated + * by \b ctx_alloc_func as well as any other resource that belongs to + * the object. + * */ void (*ctx_free_func)( void *ctx ); - /** Interface with the debug module */ + /** Interface with the debug module + * + * mbedtls_pk_debug() calls this function. + * + * Opaque implementations may omit this method. */ void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); - /** Signature size */ + /** Signature size + * + * mbedtls_pk_signature_size() returns this value. + * + * Opaque implementations may omit this method. In this case, the value + * returned by \c get_bitlen (rounded up to a whole number of bytes) + * is used instead. */ size_t (*signature_size_func)( const void *ctx ); }; +#ifdef __cplusplus +} +#endif + #endif /* MBEDTLS_PK_INFO_H */ diff --git a/library/error.c b/library/error.c index 151ca4eae..d60f652fb 100644 --- a/library/error.c +++ b/library/error.c @@ -288,6 +288,12 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "PK - Unavailable feature, e.g. RSA disabled for RSA key" ); if( use_ret == -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH) ) mbedtls_snprintf( buf, buflen, "PK - The signature is valid but its length is less than expected" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_SIGNATURE) ) + mbedtls_snprintf( buf, buflen, "PK - Invalid signature" ); + if( use_ret == -(MBEDTLS_ERR_PK_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "PK - Output buffer too small" ); + if( use_ret == -(MBEDTLS_ERR_PK_NOT_PERMITTED) ) + mbedtls_snprintf( buf, buflen, "PK - Operation not permitted" ); #endif /* MBEDTLS_PK_C */ #if defined(MBEDTLS_PKCS12_C) diff --git a/library/pk.c b/library/pk.c index d080c7599..d8801b551 100644 --- a/library/pk.c +++ b/library/pk.c @@ -94,6 +94,7 @@ const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ) return( &mbedtls_ecdsa_info ); #endif /* MBEDTLS_PK_RSA_ALT omitted on purpose */ + /* MBEDTLS_PK_OPAQUE omitted on purpose: they can't be built by parsing */ default: return( NULL ); } @@ -107,8 +108,11 @@ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ) if( ctx == NULL || info == NULL || ctx->pk_info != NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); - if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) - return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + if( info->ctx_alloc_func != NULL ) + { + if( ( ctx->pk_ctx = info->ctx_alloc_func( ) ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + } ctx->pk_info = info; @@ -312,24 +316,31 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ) { if( pub == NULL || pub->pk_info == NULL || - prv == NULL || prv->pk_info == NULL || - prv->pk_info->check_pair_func == NULL ) + prv == NULL || prv->pk_info == NULL ) { return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); } + if( pub->pk_info == prv->pk_info && pub->pk_ctx == prv->pk_ctx ) + return( 0 ); + + if( prv->pk_info->check_pair_func == NULL ) + { + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) { if( pub->pk_info->type != MBEDTLS_PK_RSA ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); } - else + else if( prv->pk_info->type != MBEDTLS_PK_OPAQUE ) { if( pub->pk_info != prv->pk_info ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); } - return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) ); + return( prv->pk_info->check_pair_func( pub, prv->pk_ctx ) ); } /* @@ -384,7 +395,9 @@ const char *mbedtls_pk_get_name( const mbedtls_pk_context *ctx ) } /* - * Access the PK type + * Access the PK type. + * For an opaque key pair object, this does not give any information on the + * underlying cryptographic material. */ mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ) { diff --git a/library/pk_wrap.c b/library/pk_wrap.c index dafd7a469..393fdebe0 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -148,10 +148,9 @@ static int rsa_encrypt_wrap( void *ctx, ilen, input, output ) ); } -static int rsa_check_pair_wrap( const void *pub, const void *prv ) +static int rsa_check_pair_wrap( const mbedtls_pk_context *pub, const void *prv ) { - return( mbedtls_rsa_check_pub_priv( (const mbedtls_rsa_context *) pub, - (const mbedtls_rsa_context *) prv ) ); + return( mbedtls_rsa_check_pub_priv( pub->pk_ctx, prv ) ); } static void *rsa_alloc_wrap( void ) @@ -272,10 +271,9 @@ static size_t ecdsa_signature_size( const void *ctx_arg ) #endif /* MBEDTLS_ECDSA_C */ -static int eckey_check_pair( const void *pub, const void *prv ) +static int eckey_check_pair( const mbedtls_pk_context *pub, const void *prv ) { - return( mbedtls_ecp_check_pub_priv( (const mbedtls_ecp_keypair *) pub, - (const mbedtls_ecp_keypair *) prv ) ); + return( mbedtls_ecp_check_pub_priv( pub->pk_ctx, prv ) ); } static void *eckey_alloc_wrap( void ) @@ -472,14 +470,14 @@ static int rsa_alt_decrypt_wrap( void *ctx, } #if defined(MBEDTLS_RSA_C) -static int rsa_alt_check_pair( const void *pub, const void *prv ) +static int rsa_alt_check_pair( const mbedtls_pk_context *pub, const void *prv ) { unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; unsigned char hash[32]; size_t sig_len = 0; int ret; - if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) ) + if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub->pk_ctx ) ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); memset( hash, 0x2a, sizeof( hash ) ); @@ -491,7 +489,7 @@ static int rsa_alt_check_pair( const void *pub, const void *prv ) return( ret ); } - if( rsa_verify_wrap( (void *) pub, MBEDTLS_MD_NONE, + if( rsa_verify_wrap( pub->pk_ctx, MBEDTLS_MD_NONE, hash, sizeof( hash ), sig, sig_len ) != 0 ) { return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data index cfb4281be..bf1bcc74e 100644 --- a/tests/suites/test_suite_pk.data +++ b/tests/suites/test_suite_pk.data @@ -153,3 +153,16 @@ mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server1.key":MBEDT RSA hash_len overflow (size_t vs unsigned int) depends_on:MBEDTLS_RSA_C:MBEDTLS_HAVE_INT64 pk_rsa_overflow: + +PK opaque mock +pk_opaque_mock: + +PK opaque with failed allocation +pk_opaque_fail_allocation: + +PK opaque minimal +pk_opaque_minimal: + +PK opaque wrapper (RSA) +depends_on:MBEDTLS_RSA_C +pk_opaque_wrapper: diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index b8b222b2f..f73022c26 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -1,5 +1,8 @@ /* BEGIN_HEADER */ +#include + #include "mbedtls/pk.h" +#include "mbedtls/pk_info.h" /* For error codes */ #include "mbedtls/ecp.h" @@ -39,14 +42,15 @@ static int pk_genkey( mbedtls_pk_context *pk ) } #if defined(MBEDTLS_RSA_C) -int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen, + +static int mbedtls_rsa_decrypt_func( void *ctx, int mode, size_t *olen, const unsigned char *input, unsigned char *output, size_t output_max_len ) { return( mbedtls_rsa_pkcs1_decrypt( (mbedtls_rsa_context *) ctx, NULL, NULL, mode, olen, input, output, output_max_len ) ); } -int mbedtls_rsa_sign_func( void *ctx, +static int mbedtls_rsa_sign_func( void *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig ) @@ -54,11 +58,269 @@ int mbedtls_rsa_sign_func( void *ctx, return( mbedtls_rsa_pkcs1_sign( (mbedtls_rsa_context *) ctx, f_rng, p_rng, mode, md_alg, hashlen, hash, sig ) ); } -size_t mbedtls_rsa_key_len_func( void *ctx ) +static size_t mbedtls_rsa_key_len_func( void *ctx ) { return( ((const mbedtls_rsa_context *) ctx)->len ); } + +/* Prepare a raw RSA context with a small random key. */ +static void pk_rsa_prepare( mbedtls_rsa_context *raw ) +{ + mbedtls_rsa_init( raw, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); + mbedtls_rsa_gen_key( raw, rnd_std_rand, NULL, RSA_KEY_SIZE, 3 ); +} + +/* Test the RSA context tested_ctx by comparing its operation with a + generic RSA context which is initialized with the key in raw. */ +static void pk_rsa_match( mbedtls_rsa_context *raw, + mbedtls_pk_context *tested_ctx, + int sign_ret, int verify_ret, + int encrypt_ret, int decrypt_ret, + int debug_ret ) +{ + mbedtls_pk_context basic_ctx; + mbedtls_pk_debug_item dbg_items[10]; + unsigned char hash[50], sig[1000]; + unsigned char msg[50], ciph[1000], test[1000]; + size_t sig_len, ciph_len, test_len; + + memset( hash, 0x2a, sizeof hash ); + memset( sig, 0, sizeof sig ); + memset( msg, 0x2a, sizeof msg ); + memset( ciph, 0, sizeof ciph ); + memset( test, 0, sizeof test ); + + /* Initiliaze basic PK RSA context with raw key */ + mbedtls_pk_init( &basic_ctx ); + TEST_ASSERT( mbedtls_pk_setup( &basic_ctx, + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); + TEST_ASSERT( mbedtls_rsa_copy( mbedtls_pk_rsa( basic_ctx ), raw ) == 0 ); + + /* Test administrative functions */ + TEST_ASSERT( mbedtls_pk_can_do( tested_ctx, MBEDTLS_PK_RSA ) ); + TEST_ASSERT( mbedtls_pk_get_bitlen( tested_ctx ) == RSA_KEY_SIZE ); + TEST_ASSERT( mbedtls_pk_get_len( tested_ctx ) == RSA_KEY_LEN ); + TEST_ASSERT( mbedtls_pk_signature_size( tested_ctx ) == RSA_KEY_LEN ); + + /* Test signature */ + TEST_ASSERT( mbedtls_pk_sign( tested_ctx, MBEDTLS_MD_NONE, hash, sizeof hash, + sig, &sig_len, rnd_std_rand, NULL ) == sign_ret ); + if( sign_ret == 0 ) + { +#if defined(MBEDTLS_HAVE_INT64) + TEST_ASSERT( mbedtls_pk_sign( tested_ctx, MBEDTLS_MD_NONE, hash, (size_t)-1, + NULL, NULL, rnd_std_rand, NULL ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + TEST_ASSERT( sig_len == RSA_KEY_LEN ); + TEST_ASSERT( mbedtls_pk_verify( &basic_ctx, MBEDTLS_MD_NONE, + hash, sizeof hash, sig, sig_len ) == 0 ); + } + + /* Test verification */ + TEST_ASSERT( mbedtls_pk_sign( &basic_ctx, MBEDTLS_MD_NONE, hash, sizeof hash, + sig, &sig_len, rnd_std_rand, NULL ) == 0 ); + TEST_ASSERT( mbedtls_pk_verify( tested_ctx, MBEDTLS_MD_NONE, + hash, sizeof hash, sig, sig_len ) == verify_ret ); + if( verify_ret == 0 ) + { + TEST_ASSERT( mbedtls_pk_verify( tested_ctx, MBEDTLS_MD_NONE, + hash, sizeof hash, sig, sig_len - 1 ) == MBEDTLS_ERR_RSA_VERIFY_FAILED ); + sig[sig_len-1] ^= 1; + TEST_ASSERT( mbedtls_pk_verify( tested_ctx, MBEDTLS_MD_NONE, + hash, sizeof hash, sig, sig_len ) == MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + /* Test encryption */ + TEST_ASSERT( mbedtls_pk_encrypt( tested_ctx, msg, sizeof msg, + ciph, &ciph_len, sizeof ciph, + rnd_std_rand, NULL ) == encrypt_ret ); + if( encrypt_ret == 0 ) + { + TEST_ASSERT( mbedtls_pk_decrypt( &basic_ctx, ciph, ciph_len, + test, &test_len, sizeof test, + rnd_std_rand, NULL ) == 0 ); + TEST_ASSERT( test_len == sizeof msg ); + TEST_ASSERT( memcmp( test, msg, test_len ) == 0 ); + } + + /* Test decryption */ + TEST_ASSERT( mbedtls_pk_encrypt( &basic_ctx, msg, sizeof msg, + ciph, &ciph_len, sizeof ciph, + rnd_std_rand, NULL ) == 0 ); + TEST_ASSERT( mbedtls_pk_decrypt( tested_ctx, ciph, ciph_len, + test, &test_len, sizeof test, + rnd_std_rand, NULL ) == decrypt_ret ); + if( decrypt_ret == 0 ) + { + TEST_ASSERT( test_len == sizeof msg ); + TEST_ASSERT( memcmp( test, msg, test_len ) == 0 ); + } + + /* Test debug */ + TEST_ASSERT( mbedtls_pk_debug( tested_ctx, dbg_items ) == debug_ret ); + +exit: + mbedtls_pk_free( &basic_ctx ); +} + +#define OPAQUE_MOCK_CAN_DO MBEDTLS_PK_RSA +#define OPAQUE_MOCK_BITLEN 'b' +#define OPAQUE_MOCK_MD_ALG MBEDTLS_MD_SHA256 +#define OPAQUE_MOCK_SIGNATURE_SIZE 4 +#define OPAQUE_MOCK_GOOD_SIGNATURE "good" +static const unsigned char opaque_mock_hash[8] = "HASHhash"; +static const unsigned char opaque_mock_reference_input[10] = "INPUTinput"; +static const unsigned char opaque_mock_input[10] = "INPUTinput"; +static const unsigned char opaque_mock_reference_encrypted[12] = "C:JOQVUjoqvu"; +static const unsigned char opaque_mock_reference_decrypted[12] = "P:HMOTShmots"; +static char opaque_mock_fake_ctx = 'c'; +static mbedtls_pk_debug_item opaque_mock_pk_debug_item; +static int opaque_mock_debug_called_correctly = 0; +static int opaque_mock_free_called_correctly = 0; + +static size_t opaque_mock_get_bitlen( const void *ctx ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + return( OPAQUE_MOCK_BITLEN ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_can_do( const void *ctx, + mbedtls_pk_type_t type ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + return( type == OPAQUE_MOCK_CAN_DO ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_verify_func( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( md_alg == OPAQUE_MOCK_MD_ALG ); + TEST_ASSERT( hash_len == sizeof( opaque_mock_hash ) ); + TEST_ASSERT( hash == opaque_mock_hash ); + if( sig_len != OPAQUE_MOCK_SIGNATURE_SIZE ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + if( memcmp( sig, OPAQUE_MOCK_GOOD_SIGNATURE, OPAQUE_MOCK_SIGNATURE_SIZE ) ) + return( MBEDTLS_ERR_PK_INVALID_SIGNATURE ); + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_sign_func( 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 ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( md_alg == OPAQUE_MOCK_MD_ALG ); + TEST_ASSERT( hash_len == sizeof( opaque_mock_hash ) ); + TEST_ASSERT( hash == opaque_mock_hash ); + memcpy( sig, OPAQUE_MOCK_GOOD_SIGNATURE, OPAQUE_MOCK_SIGNATURE_SIZE ); + *sig_len = OPAQUE_MOCK_SIGNATURE_SIZE; + (void) f_rng; + (void) p_rng; + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_decrypt_func( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( ilen == sizeof( opaque_mock_reference_input ) ); + TEST_ASSERT( !memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) ); + if( osize < sizeof( opaque_mock_reference_decrypted ) ) + return( MBEDTLS_ERR_PK_BUFFER_TOO_SMALL ); + *olen = sizeof( opaque_mock_reference_decrypted ); + memcpy( output, opaque_mock_reference_decrypted, sizeof( opaque_mock_reference_decrypted ) ); + (void) f_rng; + (void) p_rng; + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_encrypt_func( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( ilen == sizeof( opaque_mock_reference_input ) ); + TEST_ASSERT( !memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) ); + if( osize < sizeof( opaque_mock_reference_encrypted ) ) + return( MBEDTLS_ERR_PK_BUFFER_TOO_SMALL ); + *olen = sizeof( opaque_mock_reference_encrypted ); + memcpy( output, opaque_mock_reference_encrypted, sizeof( opaque_mock_reference_encrypted ) ); + (void) f_rng; + (void) p_rng; + return( 0 ); +exit: + return( INT_MIN ); +} + +static int opaque_mock_check_pair_func( const mbedtls_pk_context *pub, + const void *prv ) +{ + TEST_ASSERT( prv == &opaque_mock_fake_ctx ); + if( mbedtls_pk_get_type( pub ) != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + return( 0 ); +exit: + return( INT_MIN ); +} + +static void *opaque_mock_ctx_alloc_func( void ) +{ + return( &opaque_mock_fake_ctx ); +} +static void *opaque_mock_ctx_alloc_fail( void ) +{ + return( NULL ); +} + +static void opaque_mock_ctx_free_func( void *ctx ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + opaque_mock_free_called_correctly = 1; +exit: + return; +} + +static void opaque_mock_debug_func( const void *ctx, + mbedtls_pk_debug_item *items ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + TEST_ASSERT( items == &opaque_mock_pk_debug_item ); + opaque_mock_debug_called_correctly = 1; +exit: + return; +} + +static size_t opaque_mock_signature_size_func( const void *ctx ) +{ + TEST_ASSERT( ctx == &opaque_mock_fake_ctx ); + return( OPAQUE_MOCK_SIGNATURE_SIZE ); +exit: + return( -1 ); +} + + #endif /* MBEDTLS_RSA_C */ + /* END_HEADER */ /* BEGIN_DEPENDENCIES @@ -451,74 +713,292 @@ void pk_rsa_alt( ) * Test it against the public operations (encrypt, verify) of a * corresponding rsa context. */ + mbedtls_pk_context alt; mbedtls_rsa_context raw; - mbedtls_pk_context rsa, alt; - mbedtls_pk_debug_item dbg_items[10]; - unsigned char hash[50], sig[1000]; - unsigned char msg[50], ciph[1000], test[1000]; - size_t sig_len, ciph_len, test_len; - int ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; - mbedtls_rsa_init( &raw, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); - mbedtls_pk_init( &rsa ); mbedtls_pk_init( &alt ); + /* Generate an RSA key to use in both contexts */ + pk_rsa_prepare( &raw ); - memset( hash, 0x2a, sizeof hash ); - memset( sig, 0, sizeof sig ); - memset( msg, 0x2a, sizeof msg ); - memset( ciph, 0, sizeof ciph ); - memset( test, 0, sizeof test ); - - /* Initiliaze PK RSA context with random key */ - TEST_ASSERT( mbedtls_pk_setup( &rsa, - mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); - TEST_ASSERT( pk_genkey( &rsa ) == 0 ); - - /* Extract key to the raw rsa context */ - TEST_ASSERT( mbedtls_rsa_copy( &raw, mbedtls_pk_rsa( rsa ) ) == 0 ); - - /* Initialize PK RSA_ALT context */ + /* Set up the alt context with the generated key */ + mbedtls_pk_init( &alt ); TEST_ASSERT( mbedtls_pk_setup_rsa_alt( &alt, (void *) &raw, - mbedtls_rsa_decrypt_func, mbedtls_rsa_sign_func, mbedtls_rsa_key_len_func ) == 0 ); + mbedtls_rsa_decrypt_func, + mbedtls_rsa_sign_func, + mbedtls_rsa_key_len_func ) == 0 ); - /* Test administrative functions */ - TEST_ASSERT( mbedtls_pk_can_do( &alt, MBEDTLS_PK_RSA ) ); - TEST_ASSERT( mbedtls_pk_get_bitlen( &alt ) == RSA_KEY_SIZE ); - TEST_ASSERT( mbedtls_pk_get_len( &alt ) == RSA_KEY_LEN ); + /* Check the metadata in the alt context */ TEST_ASSERT( mbedtls_pk_get_type( &alt ) == MBEDTLS_PK_RSA_ALT ); TEST_ASSERT( strcmp( mbedtls_pk_get_name( &alt ), "RSA-alt" ) == 0 ); - /* Test signature */ - TEST_ASSERT( mbedtls_pk_sign( &alt, MBEDTLS_MD_NONE, hash, sizeof hash, - sig, &sig_len, rnd_std_rand, NULL ) == 0 ); -#if defined(MBEDTLS_HAVE_INT64) - TEST_ASSERT( mbedtls_pk_sign( &alt, MBEDTLS_MD_NONE, hash, (size_t)-1, - NULL, NULL, rnd_std_rand, NULL ) == - MBEDTLS_ERR_PK_BAD_INPUT_DATA ); -#endif /* MBEDTLS_HAVE_INT64 */ - TEST_ASSERT( sig_len == RSA_KEY_LEN ); - TEST_ASSERT( mbedtls_pk_verify( &rsa, MBEDTLS_MD_NONE, - hash, sizeof hash, sig, sig_len ) == 0 ); - - /* Test decrypt */ - TEST_ASSERT( mbedtls_pk_encrypt( &rsa, msg, sizeof msg, - ciph, &ciph_len, sizeof ciph, - rnd_std_rand, NULL ) == 0 ); - TEST_ASSERT( mbedtls_pk_decrypt( &alt, ciph, ciph_len, - test, &test_len, sizeof test, - rnd_std_rand, NULL ) == 0 ); - TEST_ASSERT( test_len == sizeof msg ); - TEST_ASSERT( memcmp( test, msg, test_len ) == 0 ); - - /* Test forbidden operations */ - TEST_ASSERT( mbedtls_pk_encrypt( &alt, msg, sizeof msg, - ciph, &ciph_len, sizeof ciph, - rnd_std_rand, NULL ) == ret ); - TEST_ASSERT( mbedtls_pk_verify( &alt, MBEDTLS_MD_NONE, - hash, sizeof hash, sig, sig_len ) == ret ); - TEST_ASSERT( mbedtls_pk_debug( &alt, dbg_items ) == ret ); + /* Exercise the alt context */ + pk_rsa_match( &raw, &alt, + 0, MBEDTLS_ERR_PK_TYPE_MISMATCH, + MBEDTLS_ERR_PK_TYPE_MISMATCH, 0, + MBEDTLS_ERR_PK_TYPE_MISMATCH ); exit: mbedtls_rsa_free( &raw ); - mbedtls_pk_free( &rsa ); mbedtls_pk_free( &alt ); + mbedtls_pk_free( &alt ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void pk_opaque_mock( ) +{ + mbedtls_pk_info_t info = + { + MBEDTLS_PK_OPAQUE, + "mock", + opaque_mock_get_bitlen, + opaque_mock_can_do, + opaque_mock_verify_func, + opaque_mock_sign_func, + opaque_mock_decrypt_func, + opaque_mock_encrypt_func, + opaque_mock_check_pair_func, + opaque_mock_ctx_alloc_func, + opaque_mock_ctx_free_func, + opaque_mock_debug_func, + opaque_mock_signature_size_func, + }; + mbedtls_pk_context ctx; + unsigned char sig[OPAQUE_MOCK_SIGNATURE_SIZE] = OPAQUE_MOCK_GOOD_SIGNATURE; + unsigned char input[sizeof( opaque_mock_reference_input )]; + unsigned char output[sizeof( opaque_mock_reference_decrypted )] = "garbage"; + size_t len; + + mbedtls_pk_init( &ctx ); + TEST_ASSERT( mbedtls_pk_setup( &ctx, &info ) == 0 ); + + TEST_ASSERT( mbedtls_pk_get_type( &ctx ) == MBEDTLS_PK_OPAQUE ); + TEST_ASSERT( mbedtls_pk_get_name( &ctx ) == info.name ); + TEST_ASSERT( mbedtls_pk_get_bitlen( &ctx ) == OPAQUE_MOCK_BITLEN ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ) == 1 ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ^ 1 ) == 0 ); + TEST_ASSERT( mbedtls_pk_signature_size( &ctx ) == OPAQUE_MOCK_SIGNATURE_SIZE ); + + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, OPAQUE_MOCK_SIGNATURE_SIZE ) == 0 ); + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, OPAQUE_MOCK_SIGNATURE_SIZE - 1 ) == + MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + sig[0] ^= 1; + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, OPAQUE_MOCK_SIGNATURE_SIZE ) == + MBEDTLS_ERR_PK_INVALID_SIGNATURE ); + len = -42; + TEST_ASSERT( mbedtls_pk_sign( &ctx, OPAQUE_MOCK_MD_ALG, + opaque_mock_hash, sizeof( opaque_mock_hash ), + sig, &len, NULL, NULL ) == 0 ); + TEST_ASSERT( len == OPAQUE_MOCK_SIGNATURE_SIZE ); + + memcpy( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ); + len = -42; + TEST_ASSERT( mbedtls_pk_encrypt( &ctx, input, sizeof( input ), + output, &len, + sizeof( opaque_mock_reference_encrypted ), + NULL, NULL ) == 0); + TEST_ASSERT( memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) == 0 ); + TEST_ASSERT( len == sizeof( opaque_mock_reference_encrypted ) ); + TEST_ASSERT( memcmp( output, opaque_mock_reference_encrypted, + sizeof( opaque_mock_reference_encrypted ) ) == 0 ); + len = -42; + TEST_ASSERT( mbedtls_pk_decrypt( &ctx, input, sizeof( input ), + output, &len, + sizeof( opaque_mock_reference_decrypted ), + NULL, NULL ) == 0); + TEST_ASSERT( memcmp( input, opaque_mock_reference_input, + sizeof( opaque_mock_reference_input ) ) == 0 ); + TEST_ASSERT( len == sizeof( opaque_mock_reference_decrypted ) ); + TEST_ASSERT( memcmp( output, opaque_mock_reference_decrypted, + sizeof( opaque_mock_reference_decrypted ) ) == 0 ); + + TEST_ASSERT( mbedtls_pk_check_pair( NULL, &ctx ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + TEST_ASSERT( mbedtls_pk_check_pair( &ctx, &ctx ) == 0 ); + { + mbedtls_pk_context pub; + mbedtls_pk_init( &pub ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + TEST_ASSERT( mbedtls_pk_setup( &pub, + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == 0 ); + mbedtls_pk_free( &pub ); + + TEST_ASSERT( mbedtls_pk_setup( &pub, + mbedtls_pk_info_from_type( MBEDTLS_PK_ECDSA ) ) == 0 ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + mbedtls_pk_free( &pub ); +} + + opaque_mock_debug_called_correctly = 0; + TEST_ASSERT( mbedtls_pk_debug( &ctx, &opaque_mock_pk_debug_item ) == 0 ); + TEST_ASSERT( opaque_mock_debug_called_correctly ); + + opaque_mock_free_called_correctly = 0; + mbedtls_pk_free( &ctx ); + TEST_ASSERT( opaque_mock_free_called_correctly ); + return; + +exit: + mbedtls_pk_free( &ctx ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void pk_opaque_minimal( ) +{ + mbedtls_pk_info_t info = + { + MBEDTLS_PK_OPAQUE, + "mock", + opaque_mock_get_bitlen, + opaque_mock_can_do, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + opaque_mock_ctx_free_func, + NULL, + NULL, + }; + mbedtls_pk_context ctx; + + mbedtls_pk_init( &ctx ); + TEST_ASSERT( mbedtls_pk_setup( &ctx, &info ) == 0 ); + ctx.pk_ctx = &opaque_mock_fake_ctx; + + TEST_ASSERT( mbedtls_pk_get_type( &ctx ) == MBEDTLS_PK_OPAQUE ); + TEST_ASSERT( mbedtls_pk_get_name( &ctx ) == info.name ); + TEST_ASSERT( mbedtls_pk_get_bitlen( &ctx ) == OPAQUE_MOCK_BITLEN ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ) == 1 ); + TEST_ASSERT( mbedtls_pk_can_do( &ctx, OPAQUE_MOCK_CAN_DO ^ 1 ) == 0 ); + TEST_ASSERT( mbedtls_pk_signature_size( &ctx ) == + ( OPAQUE_MOCK_BITLEN + 7 ) / 8 ); + + TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, + NULL, 0, NULL, 0 ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + TEST_ASSERT( mbedtls_pk_sign( &ctx, OPAQUE_MOCK_MD_ALG, NULL, 0, + NULL, NULL, NULL, NULL ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + TEST_ASSERT( mbedtls_pk_encrypt( &ctx, NULL, 0, + NULL, NULL, 0, NULL, NULL ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH); + TEST_ASSERT( mbedtls_pk_decrypt( &ctx, NULL, 0, + NULL, NULL, 0, NULL, NULL ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH); + + TEST_ASSERT( mbedtls_pk_check_pair( NULL, &ctx ) == + MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + TEST_ASSERT( mbedtls_pk_check_pair( &ctx, &ctx ) == 0 ); + { + mbedtls_pk_context pub; + mbedtls_pk_init( &pub ); + TEST_ASSERT( mbedtls_pk_setup( &pub, + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 ); + TEST_ASSERT( mbedtls_pk_check_pair( &pub, &ctx ) == + MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + mbedtls_pk_free( &pub ); +} + + TEST_ASSERT( mbedtls_pk_debug( &ctx, &opaque_mock_pk_debug_item ) == + MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + opaque_mock_free_called_correctly = 0; + mbedtls_pk_free( &ctx ); + TEST_ASSERT( opaque_mock_free_called_correctly ); + return; + +exit: + mbedtls_pk_free( &ctx ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void pk_opaque_fail_allocation( ) +{ + mbedtls_pk_info_t info = + { + MBEDTLS_PK_OPAQUE, + "mock", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + opaque_mock_ctx_alloc_fail, + NULL, + NULL, + NULL, + }; + mbedtls_pk_context ctx; + mbedtls_pk_init( &ctx ); + TEST_ASSERT( mbedtls_pk_setup( &ctx, &info ) == + MBEDTLS_ERR_PK_ALLOC_FAILED ); + TEST_ASSERT( ctx.pk_info == NULL ); + TEST_ASSERT( ctx.pk_ctx == NULL ); +exit: + mbedtls_pk_free( &ctx ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_PK_RSA_ALT_SUPPORT */ +void pk_opaque_wrapper( ) +{ + /* Test an opaque context that's a wrapper around the usual RSA + implementation against an independent raw RSA context. */ + mbedtls_pk_context opaque; + mbedtls_rsa_context raw; + const mbedtls_pk_info_t *mbedtls_rsa_info = + mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); + mbedtls_pk_info_t pk_rsa_opaque_info = + { + MBEDTLS_PK_OPAQUE, + "RSA-opaque-wrapper", + mbedtls_rsa_info->get_bitlen, + mbedtls_rsa_info->can_do, + mbedtls_rsa_info->verify_func, + mbedtls_rsa_info->sign_func, + mbedtls_rsa_info->decrypt_func, + mbedtls_rsa_info->encrypt_func, + NULL, // we don't test check_pair here + mbedtls_rsa_info->ctx_alloc_func, + mbedtls_rsa_info->ctx_free_func, + mbedtls_rsa_info->debug_func, + NULL, // signature_size_func: the fallback implementation is fine + }; + + /* Generate an RSA key to use in both contexts */ + pk_rsa_prepare( &raw ); + + /* Set up the opaque context with the generated key */ + mbedtls_pk_init( &opaque ); + TEST_ASSERT( mbedtls_pk_setup( &opaque, &pk_rsa_opaque_info ) == 0 ); + mbedtls_rsa_copy( opaque.pk_ctx, &raw ); + + /* Check the metadata in the opaque context */ + TEST_ASSERT( mbedtls_pk_get_type( &opaque ) == MBEDTLS_PK_OPAQUE ); + TEST_ASSERT( strcmp( mbedtls_pk_get_name( &opaque ), + "RSA-opaque-wrapper" ) == 0 ); + + /* Exercise the opaque context */ + pk_rsa_match( &raw, &opaque, 0, 0, 0, 0, 0 ); + +exit: + mbedtls_rsa_free( &raw ); + mbedtls_pk_free( &opaque ); } /* END_CASE */