From badc52993fde7f3b5380fc8fd16e99203236171f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 21 Sep 2017 14:56:36 +0200 Subject: [PATCH 01/41] Improved documentation a bit in the PK interface --- include/mbedtls/pk.h | 116 +++++++++++++++++++++++++--------- include/mbedtls/pk_internal.h | 4 +- 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index f9f9b9bb0..e208da232 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -1,7 +1,7 @@ /** * \file pk.h * - * \brief Public Key abstraction layer + * \brief Public Key cryptography abstraction layer * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 @@ -49,6 +49,9 @@ #define inline __inline #endif +/** \name Error codes */ +/**@{*/ + #define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */ #define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */ #define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */ @@ -64,21 +67,26 @@ #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. */ +/**@}*/ + #ifdef __cplusplus extern "C" { #endif +/** \name Asymmetric cryptography operation contexts */ +/**@{*/ + /** - * \brief Public key types + * \brief Asymmetric operation context types */ typedef enum { - MBEDTLS_PK_NONE=0, - MBEDTLS_PK_RSA, - MBEDTLS_PK_ECKEY, - MBEDTLS_PK_ECKEY_DH, - MBEDTLS_PK_ECDSA, - MBEDTLS_PK_RSA_ALT, - MBEDTLS_PK_RSASSA_PSS, + MBEDTLS_PK_NONE=0, /**< Unused context object */ + MBEDTLS_PK_RSA, /**< RSA key pair (normal software implementation) with PKCS#1 v1.5 or PSS context */ + MBEDTLS_PK_ECKEY, /**< ECC key pair with ECDSA context */ + MBEDTLS_PK_ECKEY_DH, /**< ECC key pair with ECDH context */ + 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 */ } mbedtls_pk_type_t; /** @@ -116,17 +124,17 @@ typedef struct #define MBEDTLS_PK_DEBUG_MAX_ITEMS 3 /** - * \brief Public key information and operations + * \brief Key pair information and operations */ typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; /** - * \brief Public key container + * \brief Key pair container */ typedef struct { - const mbedtls_pk_info_t * pk_info; /**< Public key informations */ - void * pk_ctx; /**< Underlying public key context */ + const mbedtls_pk_info_t * pk_info; /**< Algorithm information */ + void * pk_ctx; /**< Underlying key pair context */ } mbedtls_pk_context; #if defined(MBEDTLS_RSA_C) @@ -134,7 +142,8 @@ typedef struct * Quick access to an RSA context inside a PK context. * * \warning You must make sure the PK context actually holds an RSA context - * before using this function! + * before using this function! This function is only valid if + * `pk_can_do(&pk, MBEDTLS_PK_RSA)` is true. */ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) { @@ -147,7 +156,8 @@ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) * Quick access to an EC context inside a PK context. * * \warning You must make sure the PK context actually holds an EC context - * before using this function! + * before using this function! This function is only valid if + * `pk_can_do(&pk, MBEDTLS_PK_ECKEY)` is true. */ static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) { @@ -170,10 +180,17 @@ typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); #endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ /** - * \brief Return information associated with the given PK type + * \brief Return default information associated with the given PK type * * \param pk_type PK type to search for. * + * \note Different PK objects with the same type may have different + * information. This function returns the information needed + * to create a object with the default implementation + * for the given PK operation type (rsa module for an RSA + * context, ecdh module for an ECDH context, ecdsa module for + * an ECDSA context). + * * \return The PK info associated with the type or NULL if not found. */ const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ); @@ -199,7 +216,7 @@ 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 For contexts holding an RSA-alt key, use + * \note For contexts holding an RSA-alt key pair, use * \c mbedtls_pk_setup_rsa_alt() instead. */ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); @@ -209,7 +226,7 @@ int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); * \brief Initialize an RSA-alt context * * \param ctx Context to initialize. Must be empty (type NONE). - * \param key RSA key pointer + * \param key RSA key pair pointer * \param decrypt_func Decryption function * \param sign_func Signing function * \param key_len_func Function returning key length in bytes @@ -238,6 +255,11 @@ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ); * \brief Get the length in bytes of the underlying key * \param ctx Context to use * + * \note This returns the minimum number of bytes required to + * store the part of the key that defines its size (modulus + * for RSA, coordinate for ECC). The way the key is stored + * in the context may have a different size. + * * \return Key length in bytes, or 0 on error */ static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) @@ -246,13 +268,24 @@ static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) } /** - * \brief Tell if a context can do the operation given by type + * \brief Tell if a context can do the operations given by type + * + * \note This function can be used to identify the type of key + * (e.g. RSA vs ECC), and a superset of permitted + * operations. It is possible that this function returns + * true but some operations are not allowed. For example + * this function always returns true if ctx is an RSA + * context and type is MBEDTLS_PK_RSA, but the key may + * be restricted to any subset of operations among signature, + * verification, encryption and decryption. To determine + * which operations a key allow, attempt the operation and + * check the return status. * * \param ctx Context to test * \param type Target type * - * \return 0 if context can't do the operations, - * 1 otherwise. + * \return 1 if context can do the operations, + * 0 otherwise. */ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); @@ -269,7 +302,7 @@ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); * \return 0 on success (signature is valid), * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is * valid but its actual length is less than sig_len, - * or a specific error code. + * or a type-specific error code. * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... ) @@ -302,7 +335,7 @@ int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, * used for this type of signatures, * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is * valid but its actual length is less than sig_len, - * or a specific error code. + * or a type-specific error code. * * \note If hash_len is 0, then the length associated with md_alg * is used instead, or an error returned if it is invalid. @@ -330,7 +363,7 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, * \param f_rng RNG function * \param p_rng RNG parameter * - * \return 0 on success, or a specific error code. + * \return 0 on success, or a type-specific error code. * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * There is no interface in the PK module to make RSASSA-PSS @@ -361,7 +394,7 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * - * \return 0 on success, or a specific error code. + * \return 0 on success, or a type-specific error code. */ int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, const unsigned char *input, size_t ilen, @@ -382,7 +415,7 @@ int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * - * \return 0 on success, or a specific error code. + * \return 0 on success, or a type-specific error code. */ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, const unsigned char *input, size_t ilen, @@ -395,7 +428,12 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, * \param pub Context holding a public key. * \param prv Context holding a private (and public) key. * - * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + * \return * 0 on success. + * * MBEDTLS_ERR_PK_BAD_INPUT_DATA if one of the contexts + * is ill-formed. + * * MBEDTLS_ERR_PK_TYPE_MISMATCH if the contexts cannot + * represent keys of the same type. + * * Or a type-specific error code. */ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); @@ -405,7 +443,11 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte * \param ctx Context to use * \param items Place to write debug items * - * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + * \return * 0 on success. + * * MBEDTLS_ERR_PK_BAD_INPUT_DATA if the context is ill-formed. + * * MBEDTLS_ERR_PK_TYPE_MISMATCH if the context does not + * support exporting debug information. + * * Or a type-specific error code. */ int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ); @@ -427,6 +469,9 @@ const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); */ mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); +/**@}*/ + + #if defined(MBEDTLS_PK_PARSE_C) /** \ingroup pk_module */ /** @@ -511,7 +556,12 @@ int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) #endif /* MBEDTLS_FS_IO */ #endif /* MBEDTLS_PK_PARSE_C */ + + #if defined(MBEDTLS_PK_WRITE_C) +/** \name Key pair serialization */ +/**@{*/ + /** * \brief Write a private key to a PKCS#1 or SEC1 DER structure * Note: data is written at the end of the buffer! Use the @@ -565,11 +615,13 @@ int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, si */ int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); #endif /* MBEDTLS_PEM_WRITE_C */ +/**@}*/ #endif /* MBEDTLS_PK_WRITE_C */ -/* - * WARNING: Low-level functions. You probably do not want to use these unless - * you are certain you do ;) +/** \name Low-level functions */ +/**@{*/ +/** + * \warning You probably do not want to use these unless you are certain you do ;) */ #if defined(MBEDTLS_PK_PARSE_C) @@ -609,6 +661,8 @@ int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ); #endif +/**@}*/ + #ifdef __cplusplus } #endif diff --git a/include/mbedtls/pk_internal.h b/include/mbedtls/pk_internal.h index 01d0f214b..aab3db704 100644 --- a/include/mbedtls/pk_internal.h +++ b/include/mbedtls/pk_internal.h @@ -1,7 +1,7 @@ /** * \file pk.h * - * \brief Public Key abstraction layer: wrapper functions + * \brief Public Key cryptography abstraction layer: wrapper functions * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 @@ -34,7 +34,7 @@ struct mbedtls_pk_info_t { - /** Public key type */ + /** Key pair type with indication of supported algorithms */ mbedtls_pk_type_t type; /** Type name */ From cd95756251bafa970036354167bd00b476907d27 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 26 Sep 2017 12:51:13 +0200 Subject: [PATCH 02/41] Ignore some generated and developer files Ignore doxygen-generated documentation. Ignore ctags/etags/global files and gdb configuration file. --- .gitignore | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitignore b/.gitignore index fee2a31cd..1142e0348 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,15 @@ massif-* # CMake generates *.dir/ folders for in-tree builds (used by MSVC projects), ignore all of those: *.dir/ + +# Generated documentation +/apidoc + +# Common developer files +/GPATH +/GSYMS +/GRTAGS +/GTAGS +/TAGS +/tags +.gdbinit From 2ba437ad3c692917f6f82cb36485b9ea9592a3fd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 26 Sep 2017 12:52:15 +0200 Subject: [PATCH 03/41] Generate #line in all blocks Generate proper #line directives in all BEGIN_xxx blocks. Before, there were #line directives for BEGIN_SUITE_HELPERS and BEGIN_CASE but not BEGIN_HEADER, so debug information for code in the header block pointed inside helpers.function instead of the test's source file. --- tests/scripts/generate_code.pl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/scripts/generate_code.pl b/tests/scripts/generate_code.pl index e489a0055..4c24c7c09 100755 --- a/tests/scripts/generate_code.pl +++ b/tests/scripts/generate_code.pl @@ -111,12 +111,7 @@ my @test_cases_lines = split/^/, ; my $test_cases; my $index = 2; for my $line (@test_cases_lines) { - if ($line =~ /^\/\* BEGIN_SUITE_HELPERS .*\*\//) - { - $line = $line."#line $index \"$test_case_file\"\n"; - } - - if ($line =~ /^\/\* BEGIN_CASE .*\*\//) + if ($line =~ /^\/\* BEGIN_.*\*\//) { $line = $line."#line $index \"$test_case_file\"\n"; } From 858880686ebe4919b7c433c7a0d96c19ad47740c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 27 Oct 2017 10:18:44 +0200 Subject: [PATCH 04/41] Don't rely on private key metadata in SSL When checking whether a server key matches the handshake parameters, rely only on the offered certificate and not on the metadata of the private key. Specifically, with an EC key, check the curve in the certificate rather than in the associated private key. This was the only place in the SSL module where mbedtls_pk_ec or mbedtls_pk_rsa was called to access a private signature or decryption key (as opposed to a public key or a key used for DH/ECDH). --- library/ssl_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 37f415dd1..fd04e927a 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -731,7 +731,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_ECDSA_C) if( pk_alg == MBEDTLS_PK_ECDSA && - ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 ) + ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); continue; From 373deea06df630293f2110e0ff195393af91c0d4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Oct 2017 12:03:35 +0200 Subject: [PATCH 05/41] pk_internal: pass context to can_do In the mbedtls_pk_info_t method can_do, pass the context data. This will be needed for opaque keys, where the info structure depends on the method to access the opaque key and not on the key type. --- include/mbedtls/pk_internal.h | 4 ++-- library/pk.c | 2 +- library/pk_wrap.c | 15 ++++++++++----- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/mbedtls/pk_internal.h b/include/mbedtls/pk_internal.h index aab3db704..592eb4b06 100644 --- a/include/mbedtls/pk_internal.h +++ b/include/mbedtls/pk_internal.h @@ -41,10 +41,10 @@ struct mbedtls_pk_info_t const char *name; /** Get key size in bits */ - size_t (*get_bitlen)( const void * ); + size_t (*get_bitlen)( const void *ctx ); /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ - int (*can_do)( mbedtls_pk_type_t type ); + int (*can_do)( const void * ctx, mbedtls_pk_type_t type ); /** Verify signature */ int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, diff --git a/library/pk.c b/library/pk.c index b52c73fbc..9037646de 100644 --- a/library/pk.c +++ b/library/pk.c @@ -154,7 +154,7 @@ int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ) if( ctx == NULL || ctx->pk_info == NULL ) return( 0 ); - return( ctx->pk_info->can_do( type ) ); + return( ctx->pk_info->can_do( ctx->pk_ctx, type ) ); } /* diff --git a/library/pk_wrap.c b/library/pk_wrap.c index a4bb35fc8..55be5954e 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -60,8 +60,9 @@ static void mbedtls_zeroize( void *v, size_t n ) { #endif #if defined(MBEDTLS_RSA_C) -static int rsa_can_do( mbedtls_pk_type_t type ) +static int rsa_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_RSA || type == MBEDTLS_PK_RSASSA_PSS ); } @@ -201,8 +202,9 @@ const mbedtls_pk_info_t mbedtls_rsa_info = { /* * Generic EC key */ -static int eckey_can_do( mbedtls_pk_type_t type ) +static int eckey_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_ECKEY || type == MBEDTLS_PK_ECKEY_DH || type == MBEDTLS_PK_ECDSA ); @@ -314,8 +316,9 @@ const mbedtls_pk_info_t mbedtls_eckey_info = { /* * EC key restricted to ECDH */ -static int eckeydh_can_do( mbedtls_pk_type_t type ) +static int eckeydh_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_ECKEY || type == MBEDTLS_PK_ECKEY_DH ); } @@ -337,8 +340,9 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = { #endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_ECDSA_C) -static int ecdsa_can_do( mbedtls_pk_type_t type ) +static int ecdsa_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_ECDSA ); } @@ -404,8 +408,9 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = { * Support for alternative RSA-private implementations */ -static int rsa_alt_can_do( mbedtls_pk_type_t type ) +static int rsa_alt_can_do( const void *ctx, mbedtls_pk_type_t type ) { + (void) ctx; return( type == MBEDTLS_PK_RSA ); } From 9a8bb67935c5c11d6e81211443f3e82150b7ba9b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 2 Nov 2017 17:09:49 +0100 Subject: [PATCH 06/41] ECDSA: macro/function to calculate the signature size Expose a macro MBEDTLS_ECDSA_MAX_SIG_LEN and a function mbedtls_ecdsa_max_sig_len to calculate the size of an ECDSA signature based on the curve size. Document that this is the buffer size that mbedtls_ecdsa_write_signature requires. --- include/mbedtls/ecdsa.h | 43 +++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index a277715b3..3666ffec4 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -40,6 +40,37 @@ * (assuming ECP_MAX_BYTES is less than 126 for r and s, * and less than 124 (total len <= 255) for the sequence) */ + +/** + * \brief Maximum ECDSA signature size for a given curve bit size + * + * \param bits Curve size in bits + * \return Maximum signature size in bytes + * + * \note This macro returns a compile-time constant if its argument + * is one. It may evaluate its argument multiple times; if + * this is a problem, call the function + * mbedtls_ecdsa_max_sig_len instead. + */ +#define MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) \ + ( /*T,L of SEQUENCE*/ ( ( bits ) >= 61 * 8 ? 3 : 2 ) + \ + /*T,L of r,s*/ 2 * ( ( ( bits ) >= 127 * 8 ? 3 : 2 ) + \ + /*V of r,s*/ ( ( bits ) + 8 ) / 8 ) ) + +/** + * \brief Maximum ECDSA signature size for a given curve bit size + * + * \param bits Curve size in bits + * \return Maximum signature size in bytes + * + * \note If you need a compile-time constant, call the macro + * MBEDTLS_ECDSA_MAX_SIG_LEN instead. + */ +static inline size_t mbedtls_ecdsa_max_sig_len( size_t bits ) +{ + return( MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) ); +} + #if MBEDTLS_ECP_MAX_BYTES > 124 #error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" #endif @@ -144,9 +175,9 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, * \param f_rng RNG function * \param p_rng RNG parameter * - * \note The "sig" buffer must be at least as large as twice the - * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit - * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * \note The \c sig buffer must be at least + * `MBEDTLS_ECDSA_MAX_SIG_LEN(ctx->grp.pbits)` bytes long. + * MBEDTLS_ECDSA_MAX_LEN is always safe. * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as @@ -184,9 +215,9 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t * \param slen Length of the signature written * \param md_alg MD algorithm used to hash the message * - * \note The "sig" buffer must be at least as large as twice the - * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit - * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * \note The \c sig buffer must be at least + * `MBEDTLS_ECDSA_MAX_SIG_LEN(ctx->grp.pbits)` bytes long. + * MBEDTLS_ECDSA_MAX_LEN is always safe. * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as From bce41d373acb31ff329da9bc0c48bb5baf5c11bc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 2 Nov 2017 17:14:18 +0100 Subject: [PATCH 07/41] Expose ecdsa_signature_to_asn1 Expose ecdsa_signature_to_asn1 in the API. It's useful when converting between RFC 4492 format and other representations that might be used in external crypto processors. --- include/mbedtls/ecdsa.h | 22 ++++++++++++++++++++++ library/ecdsa.c | 21 +++++++++++---------- tests/suites/test_suite_ecdsa.function | 8 +++++--- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index 3666ffec4..c0088db5e 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -235,6 +235,28 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, #endif /* MBEDTLS_DEPRECATED_REMOVED */ #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ +/** + * \brief Convert a signature from numbers to ASN.1 + * + * \param r First number of the signature + * \param s Second number of the signature + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param ssize Size of the sig buffer + * + * \note The size of the buffer \c ssize should be at least + * `MBEDTLS_ECDSA_MAX_SIG_LEN(grp->pbits)` bytes long if + * the signature was produced from curve \c grp, + * otherwise this function will return an error. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_MPI_XXX or MBEDTLS_ERR_ASN1_XXX error code + * + */ +int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen, + size_t ssize ); + /** * \brief Read and verify an ECDSA signature * diff --git a/library/ecdsa.c b/library/ecdsa.c index 826fefe5c..fdd0afb46 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -289,22 +289,22 @@ cleanup: /* * Convert a signature (given by context) to ASN.1 */ -static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, - unsigned char *sig, size_t *slen ) +int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen, size_t ssize ) { int ret; - unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; - unsigned char *p = buf + sizeof( buf ); + unsigned char *p = sig + ssize; size_t len = 0; - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, sig, s ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, sig, r ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) ); - MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf, + 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 ) ); - memcpy( sig, p, len ); + memmove( sig, p, len ); + memset( sig + len, 0, ssize - len ); *slen = len; return( 0 ); @@ -321,6 +321,7 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t { int ret; mbedtls_mpi r, s; + const size_t ssize = MBEDTLS_ECDSA_MAX_SIG_LEN( ctx->grp.pbits ); mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s ); @@ -338,7 +339,7 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t hash, hlen, f_rng, p_rng ) ); #endif - MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); + MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen, ssize ) ); cleanup: mbedtls_mpi_free( &r ); diff --git a/tests/suites/test_suite_ecdsa.function b/tests/suites/test_suite_ecdsa.function index b73095388..8a96c024b 100644 --- a/tests/suites/test_suite_ecdsa.function +++ b/tests/suites/test_suite_ecdsa.function @@ -142,7 +142,7 @@ void ecdsa_write_read_random( int id ) rnd_pseudo_info rnd_info; unsigned char hash[32]; unsigned char sig[200]; - size_t sig_len, i; + size_t sig_len, max_sig_len, i; mbedtls_ecdsa_init( &ctx ); memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); @@ -162,8 +162,10 @@ void ecdsa_write_read_random( int id ) TEST_ASSERT( mbedtls_ecdsa_read_signature( &ctx, hash, sizeof( hash ), sig, sig_len ) == 0 ); - /* check we didn't write past the announced length */ - for( i = sig_len; i < sizeof( sig ); i++ ) + /* check we didn't write past the maximum length */ + max_sig_len = MBEDTLS_ECDSA_MAX_SIG_LEN( ctx.grp.pbits ); + TEST_ASSERT( sig_len <= max_sig_len ); + for( i = max_sig_len; i < sizeof( sig ); i++ ) TEST_ASSERT( sig[i] == 0x2a ); /* try verification with invalid length */ From cd062d84d6ab0a4078e92c3f9a67f2276ae46fdf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 2 Nov 2017 17:16:43 +0100 Subject: [PATCH 08/41] pk: function to calculate the signature size Expose a function mbedtls_pk_signature_size to calculate the maximum size of a signature made with a given key. Document that this is the buffer size that mbedtls_pk_sign requires. Add a corresponding field signature_size_func to the mbedtls_pk_info structure. --- include/mbedtls/pk.h | 17 ++++++++++++++++- include/mbedtls/pk_internal.h | 3 +++ library/pk.c | 14 ++++++++++++++ library/pk_wrap.c | 15 +++++++++++++++ tests/suites/test_suite_pk.function | 2 ++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index e208da232..92f43ac77 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -359,12 +359,18 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, * \param hash Hash of the message to sign * \param hash_len Hash length or 0 (see notes) * \param sig Place to write the signature - * \param sig_len Number of bytes written + * \param sig_len Number of bytes written to sig * \param f_rng RNG function * \param p_rng RNG parameter * * \return 0 on success, or a type-specific error code. * + * \note The signature buffer \c sig must be of appropriate size + * which can be calculated with \c mbedtls_pk_signature_size. + * Depending on the algorithm, the value returned in + * \c sig_len may be less or equal to the value returned by + * \c mbedtls_pk_signature_size. + * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * There is no interface in the PK module to make RSASSA-PSS * signatures yet. @@ -380,6 +386,15 @@ int mbedtls_pk_sign( mbedtls_pk_context *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 ); +/** + * \brief Calculate the size of a signature made with this key. + * + * \param ctx PK context to use + * + * \return Maximum size in bytes of a signature made with this key. + */ +size_t mbedtls_pk_signature_size( const mbedtls_pk_context *ctx ); + /** * \brief Decrypt message (including padding if relevant). * diff --git a/include/mbedtls/pk_internal.h b/include/mbedtls/pk_internal.h index 592eb4b06..4823294e8 100644 --- a/include/mbedtls/pk_internal.h +++ b/include/mbedtls/pk_internal.h @@ -82,7 +82,10 @@ struct mbedtls_pk_info_t /** Interface with the debug module */ void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); + /** Signature size */ + size_t (*signature_size_func)( const void *ctx ); }; + #if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) /* Container for RSA-alt */ typedef struct diff --git a/library/pk.c b/library/pk.c index 9037646de..b48f4d90c 100644 --- a/library/pk.c +++ b/library/pk.c @@ -342,6 +342,20 @@ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) ); } +/* + * Maximum signature size + */ +size_t mbedtls_pk_signature_size( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->signature_size_func == NULL ) + return( ( ctx->pk_info->get_bitlen( ctx->pk_ctx ) + 7 ) / 8 ); + else + return( ctx->pk_info->signature_size_func( ctx->pk_ctx ) ); +} + /* * Export debug information */ diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 55be5954e..0d8aee1fc 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -195,6 +195,7 @@ const mbedtls_pk_info_t mbedtls_rsa_info = { rsa_alloc_wrap, rsa_free_wrap, rsa_debug, + NULL, }; #endif /* MBEDTLS_RSA_C */ @@ -262,6 +263,12 @@ static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, return( ret ); } +static size_t ecdsa_signature_size( const void *ctx_arg ) +{ + const mbedtls_ecp_keypair *ctx = ctx_arg; + return( MBEDTLS_ECDSA_MAX_SIG_LEN( ctx->grp.pbits ) ); +} + #endif /* MBEDTLS_ECDSA_C */ static int eckey_check_pair( const void *pub, const void *prv ) @@ -311,6 +318,11 @@ const mbedtls_pk_info_t mbedtls_eckey_info = { eckey_alloc_wrap, eckey_free_wrap, eckey_debug, +#if defined(MBEDTLS_ECDSA_C) + ecdsa_signature_size, +#else + NULL, +#endif }; /* @@ -336,6 +348,7 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = { eckey_alloc_wrap, /* Same underlying key structure */ eckey_free_wrap, /* Same underlying key structure */ eckey_debug, /* Same underlying key structure */ + NULL, }; #endif /* MBEDTLS_ECP_C */ @@ -400,6 +413,7 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = { ecdsa_alloc_wrap, ecdsa_free_wrap, eckey_debug, /* Compatible key structures */ + ecdsa_signature_size, }; #endif /* MBEDTLS_ECDSA_C */ @@ -519,6 +533,7 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = { rsa_alt_alloc_wrap, rsa_alt_free_wrap, NULL, + NULL, }; #endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index e84783667..b8b222b2f 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -270,6 +270,8 @@ void pk_sign_verify( int type, int sign_ret, int verify_ret ) TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256, hash, sizeof hash, sig, &sig_len, rnd_std_rand, NULL ) == sign_ret ); + if( sign_ret == 0 ) + TEST_ASSERT( sig_len <= mbedtls_pk_signature_size( &pk ) ); TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_SHA256, hash, sizeof hash, sig, sig_len ) == verify_ret ); From 5cc7bc596da2bd97e1e7ad121e40d499d17ddbfb Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 3 Nov 2017 11:58:25 +0100 Subject: [PATCH 09/41] Move pk_info structure to its own file This is in preparation to adding support for opaque keys in the pk layer. The header files are for use as follows: * pk.h for users of the pk interface. * pk_info.h for implementers of opaque key engines. * pk_internal.h only inside libmbedcrypto to implement built-in pk types. --- include/mbedtls/pk_info.h | 89 ++++++++++++++++++++++++++++++++++ include/mbedtls/pk_internal.h | 66 +++---------------------- library/pk.c | 1 + library/pk_wrap.c | 1 + visualc/VS2010/mbedTLS.vcxproj | 1 + 5 files changed, 98 insertions(+), 60 deletions(-) create mode 100644 include/mbedtls/pk_info.h diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h new file mode 100644 index 000000000..fe2dbdfc1 --- /dev/null +++ b/include/mbedtls/pk_info.h @@ -0,0 +1,89 @@ +/** + * \file pk_info.h + * + * \brief Public Key cryptography abstraction layer: object interface + * + * 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 + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_INFO_H +#define MBEDTLS_PK_INFO_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "pk.h" + +struct mbedtls_pk_info_t +{ + /** Key pair type with indication of supported algorithms */ + mbedtls_pk_type_t type; + + /** Type name */ + const char *name; + + /** Get key size in bits */ + size_t (*get_bitlen)( const void *ctx ); + + /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ + int (*can_do)( const void * ctx, mbedtls_pk_type_t type ); + + /** Verify signature */ + 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 */ + 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 */ + 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 */ + 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 ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Interface with the debug module */ + void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); + + /** Signature size */ + size_t (*signature_size_func)( const void *ctx ); +}; + +#endif /* MBEDTLS_PK_INFO_H */ diff --git a/include/mbedtls/pk_internal.h b/include/mbedtls/pk_internal.h index 4823294e8..06475e948 100644 --- a/include/mbedtls/pk_internal.h +++ b/include/mbedtls/pk_internal.h @@ -1,9 +1,9 @@ /** - * \file pk.h + * \file pk_internal.h * - * \brief Public Key cryptography abstraction layer: wrapper functions + * \brief Public Key cryptography abstraction layer: built-in key types * - * 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 @@ -21,8 +21,8 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ -#ifndef MBEDTLS_PK_WRAP_H -#define MBEDTLS_PK_WRAP_H +#ifndef MBEDTLS_PK_INTERNAL_H +#define MBEDTLS_PK_INTERNAL_H #if !defined(MBEDTLS_CONFIG_FILE) #include "config.h" @@ -32,60 +32,6 @@ #include "pk.h" -struct mbedtls_pk_info_t -{ - /** Key pair type with indication of supported algorithms */ - mbedtls_pk_type_t type; - - /** Type name */ - const char *name; - - /** Get key size in bits */ - size_t (*get_bitlen)( const void *ctx ); - - /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ - int (*can_do)( const void * ctx, mbedtls_pk_type_t type ); - - /** Verify signature */ - 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 */ - 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 */ - 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 */ - 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 ); - - /** Allocate a new context */ - void * (*ctx_alloc_func)( void ); - - /** Free the given context */ - void (*ctx_free_func)( void *ctx ); - - /** Interface with the debug module */ - void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); - - /** Signature size */ - size_t (*signature_size_func)( const void *ctx ); -}; - #if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) /* Container for RSA-alt */ typedef struct @@ -114,4 +60,4 @@ extern const mbedtls_pk_info_t mbedtls_ecdsa_info; extern const mbedtls_pk_info_t mbedtls_rsa_alt_info; #endif -#endif /* MBEDTLS_PK_WRAP_H */ +#endif /* MBEDTLS_PK_INTERNAL_H */ diff --git a/library/pk.c b/library/pk.c index b48f4d90c..d080c7599 100644 --- a/library/pk.c +++ b/library/pk.c @@ -28,6 +28,7 @@ #if defined(MBEDTLS_PK_C) #include "mbedtls/pk.h" #include "mbedtls/pk_internal.h" +#include "mbedtls/pk_info.h" #if defined(MBEDTLS_RSA_C) #include "mbedtls/rsa.h" diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 0d8aee1fc..dafd7a469 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -26,6 +26,7 @@ #endif #if defined(MBEDTLS_PK_C) +#include "mbedtls/pk_info.h" #include "mbedtls/pk_internal.h" /* Even if RSA not activated, for the sake of RSA-alt */ diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index f13f83cc1..1a55eaaa3 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -191,6 +191,7 @@ + From 02768b436b8673beff406bc6df09d9eb2a6ca5fe Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 3 Nov 2017 19:20:27 +0100 Subject: [PATCH 10/41] 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 */ From e4cd2988d9b7c93cd37dda29d74f207526bb3a3e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 8 Nov 2017 11:55:04 +0100 Subject: [PATCH 11/41] PK: robustness of mbedtls_pk_rsa and mbedtls_pk_ec Change the documentation of mbedtls_pk_rsa and mbedtls_pk_ec to require that mbedtls_pk_get_type returns a corresponding transparent key time. Change the implementation of mbedtls_pk_rsa and mbedtls_pk_ec to return NULL if called with an argument that is not suitable, rather than returning an invalid pointer. --- include/mbedtls/pk.h | 104 ++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 32 deletions(-) diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 0fd5ec8f2..c6bb7c490 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -144,17 +144,75 @@ typedef struct void * pk_ctx; /**< Underlying key pair context */ } mbedtls_pk_context; +/** + * \brief Access the type name + * + * \param ctx Context to use + * + * \return Type name on success, or "invalid PK" + */ +const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the key type + * + * \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 ); + +/** + * \brief Merge key types with the same representation + * + * \param type Any key type + * \return A canonical representative among the types with the + * same key representation. This is \c MBEDTLS_PK_RSA + * for RSA keys using the built-in software engine and + * MBEDTLS_PK_ECKEY for EC keys using the built-in + * software engine. Note that for keys of type + * \c MBEDTLS_PK_OPAQUE, the type does not specify the + * representation. + */ +static inline mbedtls_pk_type_t mbedtls_pk_representation_type( mbedtls_pk_type_t type ) +{ + switch( type ) + { + case MBEDTLS_PK_RSA: + case MBEDTLS_PK_RSASSA_PSS: + return( MBEDTLS_PK_RSA ); + case MBEDTLS_PK_ECKEY: + case MBEDTLS_PK_ECKEY_DH: + case MBEDTLS_PK_ECDSA: + return( MBEDTLS_PK_ECKEY ); + default: + return( type ); + } +} + #if defined(MBEDTLS_RSA_C) /** * Quick access to an RSA context inside a PK context. * - * \warning You must make sure the PK context actually holds an RSA context - * before using this function! This function is only valid if - * `pk_can_do(&pk, MBEDTLS_PK_RSA)` is true. + * \warning You must make sure the PK context actually holds a transparent + * RSA context before using this function! This function is only valid if + * `mbedtls_pk_get_type(&pk)` is one of \c MBEDTLS_PK_RSA or + * \c MBEDTLS_PK_RSASSA_PSS. */ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) { - return( (mbedtls_rsa_context *) (pk).pk_ctx ); + mbedtls_pk_type_t type = + mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ); + if( type == MBEDTLS_PK_RSA ) + return( (mbedtls_rsa_context *)( pk.pk_ctx ) ); + else + return( NULL ); } #endif /* MBEDTLS_RSA_C */ @@ -162,13 +220,19 @@ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) /** * Quick access to an EC context inside a PK context. * - * \warning You must make sure the PK context actually holds an EC context - * before using this function! This function is only valid if - * `pk_can_do(&pk, MBEDTLS_PK_ECKEY)` is true. + * \warning You must make sure the PK context actually holds a transparent + * EC context before using this function! This function is only valid if + * `mbedtls_pk_get_type(&pk)` is one of \c MBEDTLS_PK_ECKEY, + * \c MBEDTLS_PK_ECKEY_DH or \c MBEDTLS_PK_ECDSA. */ static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) { - return( (mbedtls_ecp_keypair *) (pk).pk_ctx ); + mbedtls_pk_type_t type = + mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ); + if( type == MBEDTLS_PK_ECKEY ) + return( (mbedtls_ecp_keypair *)( pk.pk_ctx ) ); + else + return( NULL ); } #endif /* MBEDTLS_ECP_C */ @@ -485,30 +549,6 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte */ int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ); -/** - * \brief Access the type name - * - * \param ctx Context to use - * - * \return Type name on success, or "invalid PK" - */ -const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); - -/** - * \brief Get the key type - * - * \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 ); - /**@}*/ From 420d7d9cbd8ffe6a7be0b0de3bc5716ddd592104 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 10 Nov 2017 15:21:12 +0100 Subject: [PATCH 12/41] ECP: Write RFC5480 representation of a group/point New functions to write a representation of an elliptic curve group and point according to X9.62 and RFC5480: ECParameters as OID and ECPoint as octet string. --- include/mbedtls/ecp.h | 44 +++++++++++++++++++++ library/ecp.c | 51 ++++++++++++++++++++++++ tests/suites/test_suite_ecp.data | 20 ++++++++++ tests/suites/test_suite_ecp.function | 58 ++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index dad9aef00..43d001ce2 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -501,6 +501,50 @@ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **bu int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, unsigned char *buf, size_t blen ); +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +/** + * \brief Maximum size of the output of mbedtls_ecp_ansi_write_group + */ +#define MBEDTLS_OID_EC_GRP_MAX_SIZE 12 + +/** + * \brief Write the ANSI X9.62/RFC5480 OID ECParameters of a group + * + * The output is the group's OID wrapped as ASN.1. + * + * \param grp ECP group used + * \param buf Buffer to write to + * \param size Buffer size + * + * \return Number of bytes written to \c buf, + * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * or \c MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, + unsigned char *p, size_t size ); + +/** + * \brief Export a point in ANSI X9.62/RFC5480 ECPoint + * + * The output is the point wrapped as an ASN.1 octet string + * as defined in X9.62 and RFC 5480. + * + * \param ec ECP public key or key pair + * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro + * \param p Buffer to write to + * \param size Buffer size + * + * \return Number of bytes written to \c buf, + * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * or \c MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or \c MBEDTLS_ERR_ASN1_BUF_TOO_SMALL + */ +int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, + int format, + unsigned char *p, + size_t size ); +#endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ + /** * \brief Multiplication by an integer: R = m * P * (Not thread-safe to use same group in multiple threads) diff --git a/library/ecp.c b/library/ecp.c index 5ad686398..851d230d8 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -2061,6 +2061,57 @@ cleanup: return( ret ); } +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" +int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, + unsigned char *p, + size_t size ) +{ + const char *oid; + unsigned char *q; + size_t oid_length; + int ret; + ret = mbedtls_oid_get_oid_by_ec_grp( grp->id, &oid, &oid_length ); + if( ret != 0 ) + return( ret ); + // Output is a TLV with len(T)=1, len(L)=1, V=OID + if( size < 2 + oid_length ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + q = p + 2 + oid_length; + return( mbedtls_asn1_write_oid( &q, p, oid, oid_length ) ); +} + +int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, + int format, + unsigned char *p, + size_t size ) +{ + unsigned char *q; + size_t length; + size_t tl_size = 3; /* room for the OCTET_STRING tag and length */ + int ret; + if( size < tl_size ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + q = p + tl_size; + ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, + format, + &length, q, size - 3 ); + if( ret < 0 ) + return( ret ); + ret = mbedtls_asn1_write_len( &q, p, length ); + if( ret < 0 ) + return( ret ); + ret = mbedtls_asn1_write_tag( &q, p, MBEDTLS_ASN1_OCTET_STRING ); + if( ret < 0 ) + return( ret ); + length += tl_size - ( q - p ); + if( q != p ) + memmove( p, q, length ); + return( length ); +} +#endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ + #if defined(MBEDTLS_SELF_TEST) /* diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index a43e7d75d..c165d1889 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -30,6 +30,26 @@ ECP curve info #8 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED mbedtls_ecp_curve_info:MBEDTLS_ECP_DP_SECP192R1:19:192:"secp192r1" +ECP write ECParameters OID secp192r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_SECP192R1:"06082a8648ce3d030101" + +ECP write ECParameters OID secp521r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_SECP521R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_SECP521R1:"06052b81040023" + +ECP write ECParameters OID brainpoolP512r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_BP512R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_BP512R1:"06092b240303020801010d" + +ECP write ECPoint octet string (uncompressed) +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_point:"data_files/ec_pub.der":MBEDTLS_ECP_PF_UNCOMPRESSED:"043104bc797db3ae7f08ec3d496b4fb411b3f620a558a501e0222d08cfe0dc8aec8b1a7bf24be92951cc5ba1bebb2474909ae0" + +ECP write ECPoint octet string (compressed) +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_point:"data_files/ec_pub.der":MBEDTLS_ECP_PF_COMPRESSED:"041902bc797db3ae7f08ec3d496b4fb411b3f620a558a501e0222d" + ECP check pubkey Montgomery #1 (too big) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED ecp_check_pub:MBEDTLS_ECP_DP_CURVE25519:"010000000000000000000000000000000000000000000000000000000000000000":"0":"1":MBEDTLS_ERR_ECP_INVALID_KEY diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 99780c0de..4b8109023 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1,5 +1,6 @@ /* BEGIN_HEADER */ #include "mbedtls/ecp.h" +#include "mbedtls/pk.h" #define ECP_PF_UNKNOWN -1 /* END_HEADER */ @@ -412,6 +413,63 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C */ +void ecp_ansi_write_group( int id, char *hex ) +{ + mbedtls_ecp_group grp; + unsigned char good[MBEDTLS_OID_EC_GRP_MAX_SIZE]; + unsigned char tested[MBEDTLS_OID_EC_GRP_MAX_SIZE]; + size_t good_len = unhexify( good, hex ); + int ret = 0; + mbedtls_ecp_group_init( &grp ); + TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 ); + + /* Positive test */ + ret = mbedtls_ecp_ansi_write_group( &grp, tested, sizeof( tested ) ); + TEST_ASSERT( ret >= 0 && good_len == (unsigned) ret ); + TEST_ASSERT( memcmp( good, tested, good_len ) == 0 ); + + /* Buffer too small */ + TEST_ASSERT( mbedtls_ecp_ansi_write_group( &grp, tested, good_len - 1 ) == + MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + +exit: + mbedtls_ecp_group_free( &grp ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_FS_IO */ +void ecp_ansi_write_point( char *key_file, int format, char *good_hex ) +{ + unsigned char good_buf[1000]; + unsigned char tested_buf[1000]; + size_t good_len = unhexify( good_buf, good_hex ); + mbedtls_pk_context pk; + int ret = 0; + mbedtls_pk_init( &pk ); + TEST_ASSERT( mbedtls_pk_parse_public_keyfile( &pk, key_file ) == 0 ); + + /* Positive test */ + ret = mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, + tested_buf, sizeof( tested_buf ) ); + TEST_ASSERT( ret >= 0 && good_len == (unsigned) ret ); + TEST_ASSERT( memcmp( good_buf, tested_buf, good_len ) == 0 ); + + /* Buffer too small */ + TEST_ASSERT( mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, + tested_buf, good_len - 1 ) == + MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + +exit: + if( ret >= 0 ) { + unsigned char out[999] = {0}; + hexify( out, tested_buf, ret ); + printf("== %s ==\n", out); + } + mbedtls_pk_free( &pk ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mbedtls_ecp_check_privkey( int id, char *key_hex, int ret ) { From 8b6aaca7e53f4760956caf33020809bac1b5e7bc Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 22 Jan 2018 07:04:46 -0500 Subject: [PATCH 13/41] pk_info: Make signature_size mandatory All pk implementations must supply a signature_size method if they support signing. Move the function together with the other metadata functions. --- include/mbedtls/pk_info.h | 16 ++++++++-------- library/pk.c | 6 +++--- library/pk_wrap.c | 28 +++++++++++++++++++--------- tests/suites/test_suite_pk.function | 11 +++++------ 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index a90e489c4..a852ab8e3 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -106,6 +106,14 @@ struct mbedtls_pk_info_t * usage restrictions into account. */ int (*can_do)( const void * ctx, mbedtls_pk_type_t type ); + /** Signature size + * + * mbedtls_pk_signature_size() returns this value. + * + * Opaque implementations may omit this method if they do not support + * signature. */ + size_t (*signature_size_func)( const void *ctx ); + /** Verify signature * * mbedtls_pk_verify() calls this function. @@ -210,14 +218,6 @@ struct mbedtls_pk_info_t * Opaque implementations may omit this method. */ void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); - /** 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 diff --git a/library/pk.c b/library/pk.c index d8801b551..52bcb8669 100644 --- a/library/pk.c +++ b/library/pk.c @@ -363,9 +363,9 @@ size_t mbedtls_pk_signature_size( const mbedtls_pk_context *ctx ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); if( ctx->pk_info->signature_size_func == NULL ) - return( ( ctx->pk_info->get_bitlen( ctx->pk_ctx ) + 7 ) / 8 ); - else - return( ctx->pk_info->signature_size_func( ctx->pk_ctx ) ); + return( 0 ); + + return( ctx->pk_info->signature_size_func( ctx->pk_ctx ) ); } /* diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 393fdebe0..17df30474 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -119,6 +119,12 @@ static int rsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, md_alg, (unsigned int) hash_len, hash, sig ) ); } +static size_t rsa_signature_size( const void *ctx_arg ) +{ + const mbedtls_rsa_context *ctx = ctx_arg; + return( ctx->len ); +} + static int rsa_decrypt_wrap( void *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, @@ -187,6 +193,7 @@ const mbedtls_pk_info_t mbedtls_rsa_info = { "RSA", rsa_get_bitlen, rsa_can_do, + rsa_signature_size, rsa_verify_wrap, rsa_sign_wrap, rsa_decrypt_wrap, @@ -195,7 +202,6 @@ const mbedtls_pk_info_t mbedtls_rsa_info = { rsa_alloc_wrap, rsa_free_wrap, rsa_debug, - NULL, }; #endif /* MBEDTLS_RSA_C */ @@ -305,11 +311,13 @@ const mbedtls_pk_info_t mbedtls_eckey_info = { eckey_get_bitlen, eckey_can_do, #if defined(MBEDTLS_ECDSA_C) + ecdsa_signature_size, eckey_verify_wrap, eckey_sign_wrap, #else NULL, NULL, + NULL, #endif NULL, NULL, @@ -317,11 +325,6 @@ const mbedtls_pk_info_t mbedtls_eckey_info = { eckey_alloc_wrap, eckey_free_wrap, eckey_debug, -#if defined(MBEDTLS_ECDSA_C) - ecdsa_signature_size, -#else - NULL, -#endif }; /* @@ -343,11 +346,11 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = { NULL, NULL, NULL, + NULL, eckey_check_pair, eckey_alloc_wrap, /* Same underlying key structure */ eckey_free_wrap, /* Same underlying key structure */ eckey_debug, /* Same underlying key structure */ - NULL, }; #endif /* MBEDTLS_ECP_C */ @@ -404,6 +407,7 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = { "ECDSA", eckey_get_bitlen, /* Compatible key structures */ ecdsa_can_do, + ecdsa_signature_size, ecdsa_verify_wrap, ecdsa_sign_wrap, NULL, @@ -412,7 +416,6 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = { ecdsa_alloc_wrap, ecdsa_free_wrap, eckey_debug, /* Compatible key structures */ - ecdsa_signature_size, }; #endif /* MBEDTLS_ECDSA_C */ @@ -452,6 +455,13 @@ static int rsa_alt_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, md_alg, (unsigned int) hash_len, hash, sig ) ); } +static size_t rsa_alt_signature_size( const void *ctx ) +{ + const mbedtls_rsa_alt_context *rsa_alt = (const mbedtls_rsa_alt_context *) ctx; + + return( rsa_alt->key_len_func( rsa_alt->key ) ); +} + static int rsa_alt_decrypt_wrap( void *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, @@ -520,6 +530,7 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = { "RSA-alt", rsa_alt_get_bitlen, rsa_alt_can_do, + rsa_alt_signature_size, NULL, rsa_alt_sign_wrap, rsa_alt_decrypt_wrap, @@ -532,7 +543,6 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = { rsa_alt_alloc_wrap, rsa_alt_free_wrap, NULL, - NULL, }; #endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index f73022c26..0bf9ef36d 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -751,6 +751,7 @@ void pk_opaque_mock( ) "mock", opaque_mock_get_bitlen, opaque_mock_can_do, + opaque_mock_signature_size_func, opaque_mock_verify_func, opaque_mock_sign_func, opaque_mock_decrypt_func, @@ -759,7 +760,6 @@ void pk_opaque_mock( ) 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; @@ -868,8 +868,8 @@ void pk_opaque_minimal( ) NULL, NULL, NULL, - opaque_mock_ctx_free_func, NULL, + opaque_mock_ctx_free_func, NULL, }; mbedtls_pk_context ctx; @@ -883,8 +883,7 @@ void pk_opaque_minimal( ) 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_signature_size( &ctx ) == 0 ); TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, NULL, 0, NULL, 0 ) == @@ -939,8 +938,8 @@ void pk_opaque_fail_allocation( ) NULL, NULL, NULL, - opaque_mock_ctx_alloc_fail, NULL, + opaque_mock_ctx_alloc_fail, NULL, NULL, }; @@ -970,6 +969,7 @@ void pk_opaque_wrapper( ) "RSA-opaque-wrapper", mbedtls_rsa_info->get_bitlen, mbedtls_rsa_info->can_do, + mbedtls_rsa_info->signature_size_func, mbedtls_rsa_info->verify_func, mbedtls_rsa_info->sign_func, mbedtls_rsa_info->decrypt_func, @@ -978,7 +978,6 @@ void pk_opaque_wrapper( ) 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 */ From e7353105513d36b7488b5f5db12912638e3aa742 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 22 Jan 2018 07:14:34 -0500 Subject: [PATCH 14/41] Declare mbedtls_pk_info_t through macro New macro MBEDTLS_PK_OPAQUE_INFO_1 to initialize mbedtls_pk_info_t structures. Document that this macro must be used in engine implementations for forward compatibility. Use this macro rather than accessing the structure directly in tests and in the sample engine to set a good example. --- include/mbedtls/pk_info.h | 37 +++++++++ tests/suites/test_suite_pk.function | 116 ++++++++++++++-------------- 2 files changed, 93 insertions(+), 60 deletions(-) diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index a852ab8e3..a808c2cab 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -71,6 +71,13 @@ extern "C" { * \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. + * + * \warning: Do not declare this structure directly! It may be extended in + * future* versions of Mbed TLS. Call the macro + * MBEDTLS_PK_OPAQUE_INFO_1() or MBEDTLS_PK_OPAQUE_INFO_ASYNC_1() instead. + * These macros are guaranteed to take parameters with the same type + * and semantics as previous versions and fill any new field of the + * structure with sensible values. */ struct mbedtls_pk_info_t { @@ -220,6 +227,36 @@ struct mbedtls_pk_info_t }; +#define MBEDTLS_PK_OPAQUE_INFO_1( \ + name \ + , get_bitlen \ + , can_do \ + , signature_size_func \ + , verify_func \ + , sign_func \ + , decrypt_func \ + , encrypt_func \ + , check_pair_func \ + , ctx_alloc_func \ + , ctx_free_func \ + , debug_func \ + ) \ + { \ + MBEDTLS_PK_OPAQUE \ + , name \ + , get_bitlen \ + , can_do \ + , signature_size_func \ + , verify_func \ + , sign_func \ + , decrypt_func \ + , encrypt_func \ + , check_pair_func \ + , ctx_alloc_func \ + , ctx_free_func \ + , debug_func \ + } + #ifdef __cplusplus } #endif diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index 0bf9ef36d..bd92f0c99 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -746,21 +746,20 @@ exit: void pk_opaque_mock( ) { mbedtls_pk_info_t info = - { - MBEDTLS_PK_OPAQUE, - "mock", - opaque_mock_get_bitlen, - opaque_mock_can_do, - opaque_mock_signature_size_func, - 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, - }; + MBEDTLS_PK_OPAQUE_INFO_1( + "mock" + , opaque_mock_get_bitlen + , opaque_mock_can_do + , opaque_mock_signature_size_func + , 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 + ); mbedtls_pk_context ctx; unsigned char sig[OPAQUE_MOCK_SIGNATURE_SIZE] = OPAQUE_MOCK_GOOD_SIGNATURE; unsigned char input[sizeof( opaque_mock_reference_input )]; @@ -857,21 +856,20 @@ exit: 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, - NULL, - opaque_mock_ctx_free_func, - NULL, - }; + MBEDTLS_PK_OPAQUE_INFO_1( + "mock" + , opaque_mock_get_bitlen + , opaque_mock_can_do + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , opaque_mock_ctx_free_func + , NULL + ); mbedtls_pk_context ctx; mbedtls_pk_init( &ctx ); @@ -928,21 +926,20 @@ exit: void pk_opaque_fail_allocation( ) { mbedtls_pk_info_t info = - { - MBEDTLS_PK_OPAQUE, - "mock", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - opaque_mock_ctx_alloc_fail, - NULL, - NULL, - }; + MBEDTLS_PK_OPAQUE_INFO_1( + "mock" + , opaque_mock_get_bitlen + , opaque_mock_can_do + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , opaque_mock_ctx_alloc_fail + , NULL + , NULL + ); mbedtls_pk_context ctx; mbedtls_pk_init( &ctx ); TEST_ASSERT( mbedtls_pk_setup( &ctx, &info ) == @@ -964,21 +961,20 @@ void pk_opaque_wrapper( ) 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->signature_size_func, - 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, - }; + MBEDTLS_PK_OPAQUE_INFO_1( + "RSA-opaque-wrapper" + , mbedtls_rsa_info->get_bitlen + , mbedtls_rsa_info->can_do + , mbedtls_rsa_info->signature_size_func + , 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 + ); /* Generate an RSA key to use in both contexts */ pk_rsa_prepare( &raw ); From 60b25f05294d773d8c1f6cc22bda684a4f78b69f Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Feb 2018 03:17:59 -0500 Subject: [PATCH 15/41] Documentation fixes Added more elaborate comments and descriptions --- include/mbedtls/ecdsa.h | 14 ++++++----- include/mbedtls/pk.h | 44 ++++++++++++++++++++--------------- include/mbedtls/pk_info.h | 29 ++++++++++++++--------- include/mbedtls/pk_internal.h | 5 +++- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index c0088db5e..7490c6596 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -52,6 +52,10 @@ * this is a problem, call the function * mbedtls_ecdsa_max_sig_len instead. */ +#if MBEDTLS_ECP_MAX_BYTES > 124 +#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" +#endif + #define MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) \ ( /*T,L of SEQUENCE*/ ( ( bits ) >= 61 * 8 ? 3 : 2 ) + \ /*T,L of r,s*/ 2 * ( ( ( bits ) >= 127 * 8 ? 3 : 2 ) + \ @@ -71,12 +75,9 @@ static inline size_t mbedtls_ecdsa_max_sig_len( size_t bits ) return( MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) ); } -#if MBEDTLS_ECP_MAX_BYTES > 124 -#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" -#endif /** Maximum size of an ECDSA signature in bytes */ -#define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) ) - +#define MBEDTLS_ECDSA_MAX_LEN (MBEDTLS_ECDSA_MAX_SIG_LEN( \ + 8 * MBEDTLS_ECP_MAX_BYTES ) ) /** * \brief ECDSA context structure */ @@ -236,7 +237,8 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ /** - * \brief Convert a signature from numbers to ASN.1 + * \brief Convert a signature from numbers to ASN.1 INTEGER's, + * then both packed together as parts of an ASN.1 SEQUENCE * * \param r First number of the signature * \param s Second number of the signature diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index c6bb7c490..f7fa4d31a 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -3,7 +3,7 @@ * * \brief Public Key cryptography abstraction layer * - * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -169,7 +169,7 @@ const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); /** - * \brief Merge key types with the same representation + * \brief Get the representation type associated with a given type * * \param type Any key type * \return A canonical representative among the types with the @@ -200,10 +200,10 @@ static inline mbedtls_pk_type_t mbedtls_pk_representation_type( mbedtls_pk_type_ /** * Quick access to an RSA context inside a PK context. * - * \warning You must make sure the PK context actually holds a transparent - * RSA context before using this function! This function is only valid if - * `mbedtls_pk_get_type(&pk)` is one of \c MBEDTLS_PK_RSA or - * \c MBEDTLS_PK_RSASSA_PSS. + * \warning You must either make sure the PK context actually holds a + * transparent RSA context by checking + * \c mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ) before using + * this function, or check that the return value is not NULL before using it. */ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) { @@ -220,10 +220,10 @@ static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) /** * Quick access to an EC context inside a PK context. * - * \warning You must make sure the PK context actually holds a transparent - * EC context before using this function! This function is only valid if - * `mbedtls_pk_get_type(&pk)` is one of \c MBEDTLS_PK_ECKEY, - * \c MBEDTLS_PK_ECKEY_DH or \c MBEDTLS_PK_ECDSA. + * \warning You must either make sure the PK context actually holds a + * transparent RSA context by checking + * \c mbedtls_pk_representation_type( mbedtls_pk_get_type( &pk ) ) before using + * this function, or check that the return value is not NULL before using it. */ static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) { @@ -287,11 +287,15 @@ 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 + * \note Engines that implement 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. + * instead of mbedtls_pk_setup. A standard way of providing + * such function is by first calling the generic + * mbedtls_pk_setup function (in particular taking care of + * context allocation through ctx_alloc) and afterwards + * proceeding to initialize the implementation-specific + * context structure. * * \note For contexts holding an RSA-alt key pair, use * \c mbedtls_pk_setup_rsa_alt() instead. @@ -436,17 +440,18 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, * \param hash Hash of the message to sign * \param hash_len Hash length or 0 (see notes) * \param sig Place to write the signature - * \param sig_len Number of bytes written to sig + * \param sig_len Actual length in bytes of the created signature * \param f_rng RNG function * \param p_rng RNG parameter * * \return 0 on success, or a type-specific error code. * * \note The signature buffer \c sig must be of appropriate size - * which can be calculated with \c mbedtls_pk_signature_size. + * which can be calculated with + * \c mbedtls_pk_get_signature_size. * Depending on the algorithm, the value returned in * \c sig_len may be less or equal to the value returned by - * \c mbedtls_pk_signature_size. + * \c mbedtls_pk_get_signature_size. * * \note For RSA keys, the default padding type is PKCS#1 v1.5. * There is no interface in the PK module to make RSASSA-PSS @@ -526,11 +531,12 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, * * 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. + * to determine whether the keys match. This can only happen + * if \c prv is an opaque key. * * Or a type-specific error code. * - * \note Opaque key types may not implement this function. + * \note Opaque key types may omit implementing this function + * by providing a NULL pointer in the mbedtls_pk_info_t structure. * 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 ); diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index a808c2cab..d1d95ef4f 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -3,7 +3,10 @@ * * \brief Public Key cryptography abstraction layer: object interface * - * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * This file contains the info structure interface used by developers to + * provide engine-specific implementations of opaque key handling functions. + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -40,10 +43,16 @@ extern "C" { * 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. + * implement this interface. It allows using different engines for each key. + * Platform-specific hardware accelerators that can be used for all keys of + * a given type should not use this interface, but rather provide an + * alternative implementation of the respective cryptographic module - for + * example to use an RSA accelerator you can define MBEDTLS_RSA_ALT, and + * provide your own implementation of the RSA module. + * + * \warning: 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. * * An engine for asymmetric cryptography must implement the interface * described in this structure. The interface for the engine may be @@ -68,14 +77,11 @@ extern "C" { * 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. * * \warning: Do not declare this structure directly! It may be extended in * future* versions of Mbed TLS. Call the macro - * MBEDTLS_PK_OPAQUE_INFO_1() or MBEDTLS_PK_OPAQUE_INFO_ASYNC_1() instead. - * These macros are guaranteed to take parameters with the same type + * MBEDTLS_PK_OPAQUE_INFO_1() instead. + * This macro is guaranteed to take parameters with the same type * and semantics as previous versions and fill any new field of the * structure with sensible values. */ @@ -105,7 +111,8 @@ struct mbedtls_pk_info_t * 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 the algorithm specified by + * the provided type (e.g.\ ECKEY can do ECDSA). * * mbedtls_pk_can_do() calls this function. * diff --git a/include/mbedtls/pk_internal.h b/include/mbedtls/pk_internal.h index 06475e948..0a330876e 100644 --- a/include/mbedtls/pk_internal.h +++ b/include/mbedtls/pk_internal.h @@ -3,7 +3,10 @@ * * \brief Public Key cryptography abstraction layer: built-in key types * - * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * This file contains built-in types for handling various key types using + * the interface defined in pk_info.h. + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may From d0d0602ea569729f6fb43867fcbc05d4ac4e1a81 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Feb 2018 03:20:30 -0500 Subject: [PATCH 16/41] Rename mbedtls_pk_signature_size to mbedtls_pk_get_signature_size Add more descriptive comments and return value description --- include/mbedtls/pk.h | 2 +- include/mbedtls/pk_info.h | 6 ++++-- library/pk.c | 2 +- tests/suites/test_suite_pk.function | 8 ++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index f7fa4d31a..36fdea5be 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -475,7 +475,7 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, * * \return Maximum size in bytes of a signature made with this key. */ -size_t mbedtls_pk_signature_size( const mbedtls_pk_context *ctx ); +size_t mbedtls_pk_get_signature_size( const mbedtls_pk_context *ctx ); /** * \brief Decrypt message (including padding if relevant). diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index d1d95ef4f..a8b735fd1 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -120,9 +120,11 @@ struct mbedtls_pk_info_t * usage restrictions into account. */ int (*can_do)( const void * ctx, mbedtls_pk_type_t type ); - /** Signature size + /** Upper bound of the signature length * - * mbedtls_pk_signature_size() returns this value. + * mbedtls_pk_get_signature_size() returns this value. + * + * In case of an error, or an unsupported key type, 0 should be returned. * * Opaque implementations may omit this method if they do not support * signature. */ diff --git a/library/pk.c b/library/pk.c index 52bcb8669..4213001e8 100644 --- a/library/pk.c +++ b/library/pk.c @@ -357,7 +357,7 @@ size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) /* * Maximum signature size */ -size_t mbedtls_pk_signature_size( const mbedtls_pk_context *ctx ) +size_t mbedtls_pk_get_signature_size( const mbedtls_pk_context *ctx ) { if( ctx == NULL || ctx->pk_info == NULL ) return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index bd92f0c99..e660e1192 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -100,7 +100,7 @@ static void pk_rsa_match( mbedtls_rsa_context *raw, 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_ASSERT( mbedtls_pk_get_signature_size( tested_ctx ) == RSA_KEY_LEN ); /* Test signature */ TEST_ASSERT( mbedtls_pk_sign( tested_ctx, MBEDTLS_MD_NONE, hash, sizeof hash, @@ -533,7 +533,7 @@ void pk_sign_verify( int type, int sign_ret, int verify_ret ) TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256, hash, sizeof hash, sig, &sig_len, rnd_std_rand, NULL ) == sign_ret ); if( sign_ret == 0 ) - TEST_ASSERT( sig_len <= mbedtls_pk_signature_size( &pk ) ); + TEST_ASSERT( sig_len <= mbedtls_pk_get_signature_size( &pk ) ); TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_SHA256, hash, sizeof hash, sig, sig_len ) == verify_ret ); @@ -774,7 +774,7 @@ void pk_opaque_mock( ) 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_get_signature_size( &ctx ) == OPAQUE_MOCK_SIGNATURE_SIZE ); TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, opaque_mock_hash, sizeof( opaque_mock_hash ), @@ -881,7 +881,7 @@ void pk_opaque_minimal( ) 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 ) == 0 ); + TEST_ASSERT( mbedtls_pk_get_signature_size( &ctx ) == 0 ); TEST_ASSERT( mbedtls_pk_verify( &ctx, OPAQUE_MOCK_MD_ALG, NULL, 0, NULL, 0 ) == From a2c406286ac6485c00cd98a26a8c5e01772f89fe Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Feb 2018 03:24:02 -0500 Subject: [PATCH 17/41] Rename ecdsa_signature_to_asn1 to mbedtls_ecdsa_signature_to_asn1 --- include/mbedtls/ecdsa.h | 2 +- library/ecdsa.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index 7490c6596..5b90de1be 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -255,7 +255,7 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, * or a MBEDTLS_ERR_MPI_XXX or MBEDTLS_ERR_ASN1_XXX error code * */ -int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, +int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, unsigned char *sig, size_t *slen, size_t ssize ); diff --git a/library/ecdsa.c b/library/ecdsa.c index fdd0afb46..d57c0c33b 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -289,7 +289,7 @@ cleanup: /* * Convert a signature (given by context) to ASN.1 */ -int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, +int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, unsigned char *sig, size_t *slen, size_t ssize ) { int ret; @@ -339,7 +339,7 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t hash, hlen, f_rng, p_rng ) ); #endif - MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen, ssize ) ); + MBEDTLS_MPI_CHK( mbedtls_ecdsa_signature_to_asn1( &r, &s, sig, slen, ssize ) ); cleanup: mbedtls_mpi_free( &r ); From dc3111e6d9cca57e05c183ade84b7e81dc3b5bd5 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Feb 2018 03:26:11 -0500 Subject: [PATCH 18/41] Add olen parameter to ecp_ansi_write_group and ecp_ansi_write_point Improve mbedtls_ecp_ansi_write_point --- include/mbedtls/ecp.h | 12 +++++++----- library/ecp.c | 27 +++++++++++++++------------ tests/suites/test_suite_ecp.function | 20 +++++++++++++------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 43d001ce2..badfe86cf 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -515,13 +515,14 @@ int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, * \param grp ECP group used * \param buf Buffer to write to * \param size Buffer size - * - * \return Number of bytes written to \c buf, + * \param olen Number of bytes written to \c buf + * \return 0 on success * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL * or \c MBEDTLS_ERR_OID_NOT_FOUND */ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, - unsigned char *p, size_t size ); + unsigned char *p, size_t size, + size_t *olen ); /** * \brief Export a point in ANSI X9.62/RFC5480 ECPoint @@ -533,8 +534,9 @@ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro * \param p Buffer to write to * \param size Buffer size + * \param olen Number of bytes written to \c buf * - * \return Number of bytes written to \c buf, + * \return 0 on success * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL * or \c MBEDTLS_ERR_ECP_BAD_INPUT_DATA * or \c MBEDTLS_ERR_ASN1_BUF_TOO_SMALL @@ -542,7 +544,7 @@ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, int format, unsigned char *p, - size_t size ); + size_t size, size_t *olen ); #endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ /** diff --git a/library/ecp.c b/library/ecp.c index 851d230d8..58bffe4f9 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -2066,12 +2066,13 @@ cleanup: #include "mbedtls/oid.h" int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, unsigned char *p, - size_t size ) + size_t size, size_t *olen ) { const char *oid; unsigned char *q; size_t oid_length; int ret; + ret = mbedtls_oid_get_oid_by_ec_grp( grp->id, &oid, &oid_length ); if( ret != 0 ) return( ret ); @@ -2079,36 +2080,38 @@ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, if( size < 2 + oid_length ) return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); q = p + 2 + oid_length; - return( mbedtls_asn1_write_oid( &q, p, oid, oid_length ) ); + *olen = mbedtls_asn1_write_oid( &q, p, oid, oid_length ); + return ( 0 ); } int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, int format, unsigned char *p, - size_t size ) + size_t size, size_t *olen ) { unsigned char *q; - size_t length; - size_t tl_size = 3; /* room for the OCTET_STRING tag and length */ + size_t tl_max_size = 3; /* room for the OCTET_STRING tag and length */ int ret; - if( size < tl_size ) + + if( size < tl_max_size ) return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); - q = p + tl_size; + + q = p + tl_max_size; ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, format, - &length, q, size - 3 ); + olen, q, size - tl_max_size ); if( ret < 0 ) return( ret ); - ret = mbedtls_asn1_write_len( &q, p, length ); + ret = mbedtls_asn1_write_len( &q, p, *olen ); if( ret < 0 ) return( ret ); ret = mbedtls_asn1_write_tag( &q, p, MBEDTLS_ASN1_OCTET_STRING ); if( ret < 0 ) return( ret ); - length += tl_size - ( q - p ); + *olen += tl_max_size - ( q - p ); if( q != p ) - memmove( p, q, length ); - return( length ); + memmove( p, q, *olen ); + return( 0 ); } #endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 4b8109023..a3cde43c6 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -420,17 +420,20 @@ void ecp_ansi_write_group( int id, char *hex ) unsigned char good[MBEDTLS_OID_EC_GRP_MAX_SIZE]; unsigned char tested[MBEDTLS_OID_EC_GRP_MAX_SIZE]; size_t good_len = unhexify( good, hex ); + size_t received_len = 0; int ret = 0; mbedtls_ecp_group_init( &grp ); TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 ); /* Positive test */ - ret = mbedtls_ecp_ansi_write_group( &grp, tested, sizeof( tested ) ); - TEST_ASSERT( ret >= 0 && good_len == (unsigned) ret ); + ret = mbedtls_ecp_ansi_write_group( &grp, tested, sizeof( tested ), + &received_len ); + TEST_ASSERT( ret == 0 && good_len == (unsigned) received_len ); TEST_ASSERT( memcmp( good, tested, good_len ) == 0 ); /* Buffer too small */ - TEST_ASSERT( mbedtls_ecp_ansi_write_group( &grp, tested, good_len - 1 ) == + TEST_ASSERT( mbedtls_ecp_ansi_write_group( &grp, tested, good_len - 1, + &received_len ) == MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); exit: @@ -444,20 +447,23 @@ void ecp_ansi_write_point( char *key_file, int format, char *good_hex ) unsigned char good_buf[1000]; unsigned char tested_buf[1000]; size_t good_len = unhexify( good_buf, good_hex ); + size_t received_len = 0; mbedtls_pk_context pk; - int ret = 0; + int ret = -1; mbedtls_pk_init( &pk ); TEST_ASSERT( mbedtls_pk_parse_public_keyfile( &pk, key_file ) == 0 ); /* Positive test */ ret = mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, - tested_buf, sizeof( tested_buf ) ); - TEST_ASSERT( ret >= 0 && good_len == (unsigned) ret ); + tested_buf, sizeof( tested_buf ), + &received_len ); + TEST_ASSERT( ret == 0 && good_len == (unsigned) received_len ); TEST_ASSERT( memcmp( good_buf, tested_buf, good_len ) == 0 ); /* Buffer too small */ TEST_ASSERT( mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, - tested_buf, good_len - 1 ) == + tested_buf, good_len - 1, + &received_len ) == MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); exit: From 3b450a1798192271df89c511b6838c2610139d2e Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Feb 2018 03:27:30 -0500 Subject: [PATCH 19/41] Temporarily disable opaque RSA tests Disable tests in .data file --- tests/suites/test_suite_pk.data | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data index bf1bcc74e..e105ad52b 100644 --- a/tests/suites/test_suite_pk.data +++ b/tests/suites/test_suite_pk.data @@ -138,14 +138,14 @@ Check pair #2 (EC, bad) depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server5.key":MBEDTLS_ERR_ECP_BAD_INPUT_DATA -Check pair #3 (RSA, OK) -depends_on:MBEDTLS_RSA_C -mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server1.key":0 - -Check pair #4 (RSA, bad) -depends_on:MBEDTLS_RSA_C -mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server2.key":MBEDTLS_ERR_RSA_KEY_CHECK_FAILED - +#Check pair #3 (RSA, OK) +#depends_on:MBEDTLS_RSA_C +#mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server1.key":0 +# +#Check pair #4 (RSA, bad) +#depends_on:MBEDTLS_RSA_C +#mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server2.key":MBEDTLS_ERR_RSA_KEY_CHECK_FAILED +# Check pair #5 (RSA vs EC) depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server1.key":MBEDTLS_ERR_PK_TYPE_MISMATCH @@ -163,6 +163,7 @@ pk_opaque_fail_allocation: PK opaque minimal pk_opaque_minimal: -PK opaque wrapper (RSA) -depends_on:MBEDTLS_RSA_C -pk_opaque_wrapper: +#PK opaque wrapper (RSA) +#depends_on:MBEDTLS_RSA_C +#pk_opaque_wrapper: +# \ No newline at end of file From 7f4b10b5bd48a7cda4d69d5f16d571b31ba6be1c Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Feb 2018 03:28:23 -0500 Subject: [PATCH 20/41] Move RSA_ALT pk_info type check to the respective check_pair function --- library/pk.c | 7 +------ library/pk_wrap.c | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/library/pk.c b/library/pk.c index 4213001e8..bb55a18fb 100644 --- a/library/pk.c +++ b/library/pk.c @@ -329,12 +329,7 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte 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 if( prv->pk_info->type != MBEDTLS_PK_OPAQUE ) + if( prv->pk_info->type != MBEDTLS_PK_OPAQUE ) { if( pub->pk_info != prv->pk_info ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 17df30474..6098ac178 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -486,6 +486,13 @@ static int rsa_alt_check_pair( const mbedtls_pk_context *pub, const void *prv ) unsigned char hash[32]; size_t sig_len = 0; int ret; + const mbedtls_pk_context* prv_context = prv; + + if( prv_context->pk_info->type == MBEDTLS_PK_RSA_ALT ) + { + if( pub->pk_info->type != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub->pk_ctx ) ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); From d76af45ed36df12aa36cd2bfe45521db9d431a38 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Feb 2018 03:38:37 -0500 Subject: [PATCH 21/41] Typo fix --- tests/suites/test_suite_pk.function | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index e660e1192..d9246cf80 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -90,7 +90,7 @@ static void pk_rsa_match( mbedtls_rsa_context *raw, memset( ciph, 0, sizeof ciph ); memset( test, 0, sizeof test ); - /* Initiliaze basic PK RSA context with raw key */ + /* Initialize 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 ); From 6f21aed6dfe0a9215b43af19a14f52af3784afdc Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 7 Feb 2018 08:02:31 -0500 Subject: [PATCH 22/41] Documentation fixes Move MBEDTLS_ECP_MAX_BYTES to a proper place, adjust comments and descriptions, move includes to the top of the file --- include/mbedtls/ecdsa.h | 15 +++++++++------ include/mbedtls/pk.h | 12 ++++++------ library/ecp.c | 7 +++++-- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index 5b90de1be..908fe5cb9 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -40,6 +40,9 @@ * (assuming ECP_MAX_BYTES is less than 126 for r and s, * and less than 124 (total len <= 255) for the sequence) */ +#if MBEDTLS_ECP_MAX_BYTES > 124 +#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" +#endif /** * \brief Maximum ECDSA signature size for a given curve bit size @@ -52,10 +55,6 @@ * this is a problem, call the function * mbedtls_ecdsa_max_sig_len instead. */ -#if MBEDTLS_ECP_MAX_BYTES > 124 -#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" -#endif - #define MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) \ ( /*T,L of SEQUENCE*/ ( ( bits ) >= 61 * 8 ? 3 : 2 ) + \ /*T,L of r,s*/ 2 * ( ( ( bits ) >= 127 * 8 ? 3 : 2 ) + \ @@ -237,8 +236,7 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ /** - * \brief Convert a signature from numbers to ASN.1 INTEGER's, - * then both packed together as parts of an ASN.1 SEQUENCE + * \brief Convert a signature from numbers to ASN.1 * * \param r First number of the signature * \param s Second number of the signature @@ -250,6 +248,11 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, * `MBEDTLS_ECDSA_MAX_SIG_LEN(grp->pbits)` bytes long if * the signature was produced from curve \c grp, * otherwise this function will return an error. + * The output ASN.1 SEQUENCE format is as follows: + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } * * \return 0 if successful, * or a MBEDTLS_ERR_MPI_XXX or MBEDTLS_ERR_ASN1_XXX error code diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 36fdea5be..0396ea85f 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -80,8 +80,11 @@ extern "C" { /**@{*/ /** - * \brief Asymmetric operation context types - */ + * \brief Asymmetric operation context types + * + * \note An opaque key 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. */ typedef enum { MBEDTLS_PK_NONE=0, /**< Unused context object */ MBEDTLS_PK_RSA, /**< RSA key pair (normal software implementation) with PKCS#1 v1.5 or PSS context */ @@ -90,10 +93,7 @@ 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_OPAQUE, /**< Opaque key pair (cryptographic material held in an external module).*/ } mbedtls_pk_type_t; /** diff --git a/library/ecp.c b/library/ecp.c index 58bffe4f9..aa39895d6 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -51,6 +51,11 @@ #include "mbedtls/ecp.h" #include "mbedtls/threading.h" +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" +#endif + #include #if !defined(MBEDTLS_ECP_ALT) @@ -2062,8 +2067,6 @@ cleanup: } #if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) -#include "mbedtls/asn1write.h" -#include "mbedtls/oid.h" int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, unsigned char *p, size_t size, size_t *olen ) From b60dc2d21e96af4d04a77082283287f44e44f382 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 7 Feb 2018 08:03:51 -0500 Subject: [PATCH 23/41] Shift errors Move errors from pk.h so that they have a gap for the current development error codes --- include/mbedtls/pk.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 0396ea85f..c92e10a40 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -66,9 +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 */ +#define MBEDTLS_ERR_PK_INVALID_SIGNATURE -0x3800 /**< Invalid signature */ +#define MBEDTLS_ERR_PK_BUFFER_TOO_SMALL -0x3780 /**< Output buffer too small */ +#define MBEDTLS_ERR_PK_NOT_PERMITTED -0x3700 /**< Operation not permitted */ /**@}*/ From 8fb94311e979f28ab1b30ddd8a39daf5f86b839c Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 8 Feb 2018 06:37:57 -0500 Subject: [PATCH 24/41] Add a check for an RSA_ALT key in check_pair --- library/pk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/pk.c b/library/pk.c index bb55a18fb..980256a25 100644 --- a/library/pk.c +++ b/library/pk.c @@ -329,7 +329,8 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } - if( prv->pk_info->type != MBEDTLS_PK_OPAQUE ) + if( prv->pk_info->type != MBEDTLS_PK_RSA_ALT && + prv->pk_info->type != MBEDTLS_PK_OPAQUE ) { if( pub->pk_info != prv->pk_info ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); From 4d092dc42c7521dad59ae689913296ed001c4ab7 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 8 Feb 2018 07:45:41 -0500 Subject: [PATCH 25/41] PK: change the check_pair interface to take full private context --- include/mbedtls/pk_info.h | 2 +- library/pk.c | 14 +++++++------- library/pk_wrap.c | 21 +++++++++++---------- tests/suites/test_suite_pk.function | 4 ++-- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index a8b735fd1..a4bba4680 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -202,7 +202,7 @@ struct mbedtls_pk_info_t * is guaranteed to be initialized. * * Opaque implementations may omit this method. */ - int (*check_pair_func)( const mbedtls_pk_context *pub, const void *prv ); + int (*check_pair_func)( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); /** Allocate a new context * diff --git a/library/pk.c b/library/pk.c index 980256a25..ac9635cb7 100644 --- a/library/pk.c +++ b/library/pk.c @@ -329,14 +329,14 @@ int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_conte return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } - if( prv->pk_info->type != MBEDTLS_PK_RSA_ALT && - prv->pk_info->type != MBEDTLS_PK_OPAQUE ) - { - if( pub->pk_info != prv->pk_info ) - return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); - } + if( prv->pk_info->type != MBEDTLS_PK_OPAQUE && + prv->pk_info->type != MBEDTLS_PK_RSA_ALT ) + { + if( pub->pk_info != prv->pk_info ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } - return( prv->pk_info->check_pair_func( pub, prv->pk_ctx ) ); + return( prv->pk_info->check_pair_func( pub, prv ) ); } /* diff --git a/library/pk_wrap.c b/library/pk_wrap.c index 6098ac178..d90228c9e 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -154,9 +154,10 @@ static int rsa_encrypt_wrap( void *ctx, ilen, input, output ) ); } -static int rsa_check_pair_wrap( const mbedtls_pk_context *pub, const void *prv ) +static int rsa_check_pair_wrap( const mbedtls_pk_context *pub, + const mbedtls_pk_context *prv ) { - return( mbedtls_rsa_check_pub_priv( pub->pk_ctx, prv ) ); + return( mbedtls_rsa_check_pub_priv( pub->pk_ctx, prv->pk_ctx ) ); } static void *rsa_alloc_wrap( void ) @@ -277,9 +278,10 @@ static size_t ecdsa_signature_size( const void *ctx_arg ) #endif /* MBEDTLS_ECDSA_C */ -static int eckey_check_pair( const mbedtls_pk_context *pub, const void *prv ) +static int eckey_check_pair( const mbedtls_pk_context *pub, + const mbedtls_pk_context *prv ) { - return( mbedtls_ecp_check_pub_priv( pub->pk_ctx, prv ) ); + return( mbedtls_ecp_check_pub_priv( pub->pk_ctx, prv->pk_ctx ) ); } static void *eckey_alloc_wrap( void ) @@ -480,26 +482,25 @@ static int rsa_alt_decrypt_wrap( void *ctx, } #if defined(MBEDTLS_RSA_C) -static int rsa_alt_check_pair( const mbedtls_pk_context *pub, const void *prv ) +static int rsa_alt_check_pair( const mbedtls_pk_context *pub, + const mbedtls_pk_context *prv ) { unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; unsigned char hash[32]; size_t sig_len = 0; int ret; - const mbedtls_pk_context* prv_context = prv; - - if( prv_context->pk_info->type == MBEDTLS_PK_RSA_ALT ) + if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) { if( pub->pk_info->type != MBEDTLS_PK_RSA ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); } - if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub->pk_ctx ) ) + if( rsa_alt_get_bitlen( prv->pk_ctx ) != rsa_get_bitlen( pub->pk_ctx ) ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); memset( hash, 0x2a, sizeof( hash ) ); - if( ( ret = rsa_alt_sign_wrap( (void *) prv, MBEDTLS_MD_NONE, + if( ( ret = rsa_alt_sign_wrap( (void *) prv->pk_ctx, MBEDTLS_MD_NONE, hash, sizeof( hash ), sig, &sig_len, NULL, NULL ) ) != 0 ) { diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index d9246cf80..e1c123012 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -273,9 +273,9 @@ exit: } static int opaque_mock_check_pair_func( const mbedtls_pk_context *pub, - const void *prv ) + const mbedtls_pk_context *prv ) { - TEST_ASSERT( prv == &opaque_mock_fake_ctx ); + TEST_ASSERT( prv->pk_ctx == &opaque_mock_fake_ctx ); if( mbedtls_pk_get_type( pub ) != MBEDTLS_PK_RSA ) return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); return( 0 ); From 4938419f170703e7eae1ac6dcf0fcc9cb1dbf0ca Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 8 Feb 2018 08:01:09 -0500 Subject: [PATCH 26/41] ECP: Increase MBEDTLS_ECP_GRP_OID_MAX_SIZE to 32 Provide documentation for the source of the change --- include/mbedtls/ecp.h | 8 +++++++- include/mbedtls/oid.h | 2 ++ tests/suites/test_suite_ecp.function | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index badfe86cf..32c4528ec 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -504,8 +504,14 @@ int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, #if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) /** * \brief Maximum size of the output of mbedtls_ecp_ansi_write_group + * + * \note The maximum size of the OID of a supported group + 2 for + * tag and length. Maximum size 30 is based on the length of + * the OID for primeCurves 10-38 over GF(p) defined by the + * CDC Group, as they seem to have the longest OID out of + * curves in use. */ -#define MBEDTLS_OID_EC_GRP_MAX_SIZE 12 +#define MBEDTLS_ECP_GRP_OID_MAX_SIZE ( 30 + 2 ) /** * \brief Write the ANSI X9.62/RFC5480 OID ECParameters of a group diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index fcecdafdc..618c0eae5 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -282,6 +282,8 @@ /* * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2 + * When adding new OID's, please update \c MBEDTLS_ECP_GRP_OID_MAX_SIZE + * in ecp.h */ /* secp192r1 OBJECT IDENTIFIER ::= { diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index a3cde43c6..f5d88ba44 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -417,8 +417,8 @@ exit: void ecp_ansi_write_group( int id, char *hex ) { mbedtls_ecp_group grp; - unsigned char good[MBEDTLS_OID_EC_GRP_MAX_SIZE]; - unsigned char tested[MBEDTLS_OID_EC_GRP_MAX_SIZE]; + unsigned char good[MBEDTLS_ECP_GRP_OID_MAX_SIZE]; + unsigned char tested[MBEDTLS_ECP_GRP_OID_MAX_SIZE]; size_t good_len = unhexify( good, hex ); size_t received_len = 0; int ret = 0; From 21e449db2f56b30246f2b92e3d64b7e13eaa8aaf Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 8 Feb 2018 08:12:58 -0500 Subject: [PATCH 27/41] PK: Remove reduntant type check for RSA_ALT --- library/pk_wrap.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/pk_wrap.c b/library/pk_wrap.c index d90228c9e..238881e61 100644 --- a/library/pk_wrap.c +++ b/library/pk_wrap.c @@ -489,11 +489,9 @@ static int rsa_alt_check_pair( const mbedtls_pk_context *pub, unsigned char hash[32]; size_t sig_len = 0; int ret; - if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) - { - if( pub->pk_info->type != MBEDTLS_PK_RSA ) - return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); - } + + if( pub->pk_info->type != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); if( rsa_alt_get_bitlen( prv->pk_ctx ) != rsa_get_bitlen( pub->pk_ctx ) ) return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); From 106dff107d25d6bf15e7df775d7951f7607e3bc3 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 12 Feb 2018 02:41:12 -0500 Subject: [PATCH 28/41] Remove doxygen tag Remove a tag from a non-doxygen block --- include/mbedtls/oid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index 239a37db3..396bcdd44 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -283,7 +283,7 @@ /* * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2 - * When adding new OID's, please update \c MBEDTLS_ECP_GRP_OID_MAX_SIZE + * When adding new OID's, please update MBEDTLS_ECP_GRP_OID_MAX_SIZE * in ecp.h */ From eb162de489e7396a7380fd81468e806a91f878b5 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 12 Feb 2018 04:16:17 -0500 Subject: [PATCH 29/41] Add test dependencies Add RSA and ECDSA dependencies to tests --- tests/suites/test_suite_pk.data | 3 +++ tests/suites/test_suite_pk.function | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data index e105ad52b..11b5f108e 100644 --- a/tests/suites/test_suite_pk.data +++ b/tests/suites/test_suite_pk.data @@ -155,12 +155,15 @@ depends_on:MBEDTLS_RSA_C:MBEDTLS_HAVE_INT64 pk_rsa_overflow: PK opaque mock +depends_on:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C pk_opaque_mock: PK opaque with failed allocation +depends_on:MBEDTLS_RSA_C pk_opaque_fail_allocation: PK opaque minimal +depends_on:MBEDTLS_RSA_C pk_opaque_minimal: #PK opaque wrapper (RSA) diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index e1c123012..1ad38eadd 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -67,7 +67,9 @@ static size_t mbedtls_rsa_key_len_func( void *ctx ) static void pk_rsa_prepare( mbedtls_rsa_context *raw ) { mbedtls_rsa_init( raw, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE ); +#if defined(MBEDTLS_GENPRIME) mbedtls_rsa_gen_key( raw, rnd_std_rand, NULL, RSA_KEY_SIZE, 3 ); +#endif } /* Test the RSA context tested_ctx by comparing its operation with a @@ -742,7 +744,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C */ void pk_opaque_mock( ) { mbedtls_pk_info_t info = @@ -852,7 +854,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C */ void pk_opaque_minimal( ) { mbedtls_pk_info_t info = @@ -922,7 +924,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_RSA_C */ void pk_opaque_fail_allocation( ) { mbedtls_pk_info_t info = From dc5770a62f59cdd97fbecec4d5581fa4b3ff781a Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 12 Feb 2018 05:10:28 -0500 Subject: [PATCH 30/41] Remove unused variables from tests Fix clang build by removing unused variables and fixing comments --- include/mbedtls/ecp.h | 2 +- tests/suites/test_suite_pk.function | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index c6e3edb25..6bcda1769 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -521,7 +521,7 @@ int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, * The output is the group's OID wrapped as ASN.1. * * \param grp ECP group used - * \param buf Buffer to write to + * \param p Buffer to write to * \param size Buffer size * \param olen Number of bytes written to \c buf * \return 0 on success diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index 1ad38eadd..25c46b217 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -173,7 +173,6 @@ exit: #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'; From 024ab067cd35e881ddeba8cac6aab96a367cb7ed Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Mon, 12 Feb 2018 09:34:39 -0500 Subject: [PATCH 31/41] Documentation fixes --- include/mbedtls/ecdsa.h | 3 ++- include/mbedtls/pk.h | 3 ++- include/mbedtls/pk_info.h | 9 +++++---- tests/suites/test_suite_ecp.function | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index 8725cee2f..4029c1cd8 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -85,6 +85,7 @@ static inline size_t mbedtls_ecdsa_max_sig_len( size_t bits ) /** The maximal size of an ECDSA signature in Bytes. */ #define MBEDTLS_ECDSA_MAX_LEN (MBEDTLS_ECDSA_MAX_SIG_LEN( \ 8 * MBEDTLS_ECP_MAX_BYTES ) ) + /** * \brief The ECDSA context structure. */ @@ -287,7 +288,7 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ /** - * \brief Convert a signature from numbers to ASN.1 + * \brief Convert an ECDSA signature from number pair format to ASN.1 * * \param r First number of the signature * \param s Second number of the signature diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 54b4c4a68..edce48c9b 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -470,7 +470,8 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); /** - * \brief Calculate the size of a signature made with this key. + * \brief Provide an upper bound for the size of a signature made + * with this key. * * \param ctx PK context to use * diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index a4bba4680..2ad5b3b98 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -4,7 +4,8 @@ * \brief Public Key cryptography abstraction layer: object interface * * This file contains the info structure interface used by developers to - * provide engine-specific implementations of opaque key handling functions. + * provide target-specific implementations of opaque key handling functions + * (called engines in the following). * * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 @@ -112,7 +113,7 @@ struct mbedtls_pk_info_t size_t (*get_bitlen)( const void *ctx ); /** Tell if the context implements the algorithm specified by - * the provided type (e.g.\ ECKEY can do ECDSA). + * the provided type (e.g. ECKEY can do ECDSA). * * mbedtls_pk_can_do() calls this function. * @@ -144,7 +145,7 @@ struct mbedtls_pk_info_t * * mbedtls_pk_sign() calls this function. * - * Assume that the buffer \c sig has room for + * Assumes 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 @@ -154,7 +155,7 @@ struct mbedtls_pk_info_t * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. * * Opaque implementations may omit this method if they do not support - * signature. */ + * signing. */ 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, diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index f5d88ba44..120025f1c 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -427,13 +427,13 @@ void ecp_ansi_write_group( int id, char *hex ) /* Positive test */ ret = mbedtls_ecp_ansi_write_group( &grp, tested, sizeof( tested ), - &received_len ); + &received_len ); TEST_ASSERT( ret == 0 && good_len == (unsigned) received_len ); TEST_ASSERT( memcmp( good, tested, good_len ) == 0 ); /* Buffer too small */ TEST_ASSERT( mbedtls_ecp_ansi_write_group( &grp, tested, good_len - 1, - &received_len ) == + &received_len ) == MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); exit: From bba09275866bad1b1eba27996a2809e26c2ee86b Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 14 Feb 2018 07:16:27 -0500 Subject: [PATCH 32/41] Documentation fixes Fix spacing, comments, and links in doxygen documentation. --- include/mbedtls/ecdsa.h | 28 +++++---- include/mbedtls/ecp.h | 3 +- include/mbedtls/pk.h | 43 ++++++++------ include/mbedtls/pk_info.h | 100 +++++++++++++++++++++++++++----- include/mbedtls/pk_internal.h | 11 +++- library/ecdsa.c | 2 +- tests/suites/test_suite_pk.data | 16 ++--- 7 files changed, 145 insertions(+), 58 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index 4029c1cd8..ba7aba1e3 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -83,8 +83,8 @@ static inline size_t mbedtls_ecdsa_max_sig_len( size_t bits ) } /** The maximal size of an ECDSA signature in Bytes. */ -#define MBEDTLS_ECDSA_MAX_LEN (MBEDTLS_ECDSA_MAX_SIG_LEN( \ - 8 * MBEDTLS_ECP_MAX_BYTES ) ) +#define MBEDTLS_ECDSA_MAX_LEN \ + ( MBEDTLS_ECDSA_MAX_SIG_LEN( 8 * MBEDTLS_ECP_MAX_BYTES ) ) /** * \brief The ECDSA context structure. @@ -97,7 +97,10 @@ extern "C" { /** * \brief This function computes the ECDSA signature of a - * previously-hashed message. + * previously-hashed message. The signature is in + * ASN.1 SEQUENCE format, as described in Standards + * for Efficient Cryptography Group (SECG): SEC1 Elliptic + * Curve Cryptography, section C.5. * * \note The deterministic version is usually preferred. * @@ -210,10 +213,13 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, * \param f_rng The RNG function. * \param p_rng The RNG parameter. * - * \note The \p sig buffer must be at least twice as large as the - * size of the curve used, plus 9. For example, 73 Bytes if - * a 256-bit curve is used. A buffer length of - * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \note The signature \p sig is expected to be ASN.1 SEQUENCE + * format, as described in Standards for Efficient + * Cryptography Group (SECG): SEC1 Elliptic Curve + * Cryptography, section C.5. + * + * \note A \p sig buffer length of #MBEDTLS_ECDSA_MAX_LEN is + * always safe. * * \note If the bitlength of the message hash is larger than the * bitlength of the group order, then the hash is truncated as @@ -297,14 +303,16 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, * \param ssize Size of the sig buffer * * \note The size of the buffer \c ssize should be at least - * `MBEDTLS_ECDSA_MAX_SIG_LEN(grp->pbits)` bytes long if - * the signature was produced from curve \c grp, - * otherwise this function will return an error. + * `MBEDTLS_ECDSA_MAX_SIG_LEN(grp->pbits)` bytes long if the + * signature was produced from curve \c grp, otherwise + * this function may fail with the error + * MBEDTLS_ERR_ASN1_BUF_TOO_SMALL. * The output ASN.1 SEQUENCE format is as follows: * Ecdsa-Sig-Value ::= SEQUENCE { * r INTEGER, * s INTEGER * } + * This format is expected by \c mbedtls_ecdsa_verify. * * \return 0 if successful, * or a MBEDTLS_ERR_MPI_XXX or MBEDTLS_ERR_ASN1_XXX error code diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 6bcda1769..9e2755f5a 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -542,7 +542,8 @@ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro * \param p Buffer to write to * \param size Buffer size - * \param olen Number of bytes written to \c buf + * \param olen Number of bytes written to \c buf on success, + * unspecified on failure. * * \return 0 on success * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index edce48c9b..d712e7750 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -2,7 +2,8 @@ * \file pk.h * * \brief Public Key cryptography abstraction layer - * + */ +/* * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * @@ -89,9 +90,9 @@ extern "C" { typedef enum { MBEDTLS_PK_NONE=0, /**< Unused context object */ MBEDTLS_PK_RSA, /**< RSA key pair (normal software implementation) with PKCS#1 v1.5 or PSS context */ - MBEDTLS_PK_ECKEY, /**< ECC key pair with ECDSA context */ - MBEDTLS_PK_ECKEY_DH, /**< ECC key pair with ECDH context */ - MBEDTLS_PK_ECDSA, /**< ECC key pair with ECDSA context */ + MBEDTLS_PK_ECKEY, /**< Generic ECC key pair */ + MBEDTLS_PK_ECKEY_DH, /**< ECC key pair restricted to key exchanges */ + MBEDTLS_PK_ECDSA, /**< ECC key pair restricted to signature/verification */ 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 */ MBEDTLS_PK_OPAQUE, /**< Opaque key pair (cryptographic material held in an external module).*/ @@ -137,7 +138,14 @@ typedef struct typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; /** - * \brief Key pair container + * \brief Context structure for public-key cryptographic operations. + * + * \note This structure contains all the information needed for + * performing a public-key cryptography operation. Depending + * on the operation and the cryptographic algorithm it can + * represent either the public key or a pair of matching + * public and private keys. Also it may contain other + * implementation specific data. */ typedef struct { @@ -256,12 +264,9 @@ typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); * * \param pk_type PK type to search for. * - * \note Different PK objects with the same type may have different - * information. This function returns the information needed - * to create a object with the default implementation - * for the given PK operation type (rsa module for an RSA - * context, ecdh module for an ECDH context, ecdsa module for - * an ECDSA context). + * \note This function returns NULL if pk_type indicates an opaque + * key, since the type does not provide enough information to + * build an opaque key. * * \return The PK info associated with the type or NULL if not found. */ @@ -290,13 +295,13 @@ void mbedtls_pk_free( mbedtls_pk_context *ctx ); * * \note Engines that implement 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. A standard way of providing - * such function is by first calling the generic - * mbedtls_pk_setup function (in particular taking care of - * context allocation through ctx_alloc) and afterwards - * proceeding to initialize the implementation-specific - * context structure. + * parameters. If the documentation of the engine lists such a + * function, call it instead of mbedtls_pk_setup. A standard + * way of providing such function is by first calling the + * generic mbedtls_pk_setup function (in particular taking + * care of context allocation through ctx_alloc) and + * afterwards proceeding to initialize the + * implementation-specific context structure. * * \note For contexts holding an RSA-alt key pair, use * \c mbedtls_pk_setup_rsa_alt() instead. @@ -539,7 +544,7 @@ int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, * * \note Opaque key types may omit implementing this function * by providing a NULL pointer in the mbedtls_pk_info_t structure. - * An opaque \c pub never matches a transparent \c prv. + * Currently, 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 ); diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index 2ad5b3b98..846502b9c 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -1,12 +1,19 @@ /** * \file pk_info.h * - * \brief Public Key cryptography abstraction layer: object interface - * - * This file contains the info structure interface used by developers to - * provide target-specific implementations of opaque key handling functions - * (called engines in the following). + * \brief Public Key cryptography abstraction layer: engine interface * + * This file defines the interface the public-key cryptography engines + * (PK engines) must implement. A PK engine defines how a public-private + * key pair is represented and how to perform cryptographic operations + * with it. Mbed TLS contains built-in PK engines implemented either + * purely in software or with hardware acceleration support, depending + * on the target platform. In addition, it is possible to define custom + * opaque key engines that forward operation requests to cryptographic + * modules outside Mbed TLS, such as external cryptoprocessors or general + * PKCS#11 tokens. + */ +/* * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * @@ -76,11 +83,11 @@ extern "C" { * 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. + * return #MBEDTLS_ERR_PK_TYPE_MISMATCH in this case. * * * \warning: Do not declare this structure directly! It may be extended in - * future* versions of Mbed TLS. Call the macro + * future versions of Mbed TLS. Call the macro * MBEDTLS_PK_OPAQUE_INFO_1() instead. * This macro is guaranteed to take parameters with the same type * and semantics as previous versions and fill any new field of the @@ -93,7 +100,7 @@ struct mbedtls_pk_info_t * 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. */ + * algorithms. For opaque keys, this is #MBEDTLS_PK_OPAQUE. */ mbedtls_pk_type_t type; /** Type name. @@ -155,7 +162,8 @@ struct mbedtls_pk_info_t * return #MBEDTLS_ERR_PK_BAD_INPUT_DATA otherwise. * * Opaque implementations may omit this method if they do not support - * signing. */ + * signing. If this method is provided, so must be + * \ref mbedtls_pk_info_t.signature_size_func. */ 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, @@ -200,9 +208,39 @@ struct mbedtls_pk_info_t * * 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. + * is guaranteed to be initialized. The implementation is allowed to do + * a probabilistic and computationally expensive check. * - * Opaque implementations may omit this method. */ + * If \c prv is an RSA key and \c pub is a transparent RSA key + * (i.e. \c pub has the type #MBEDTLS_PK_RSA or #MBEDTLS_PK_RSASSA_PSS), + * then \c check_pair_func must return 0 if the public key is + * mathematically equivalent to the public part of \c prv, and + * #MBEDTLS_ERR_RSA_KEY_CHECK_FAILED otherwise. + * + * If \c pub is an ECC key and \c pub is a transparent ECC key that can + * be used for ECDSA (i.e. \c pub has the type #MBEDTLS_PK_ECKEY or + * #MBEDTLS_PK_ECDSA), then check_pair_func must return 0 if the public + * key is mathematically equivalent to the public part of prv, and + * #MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise. + * + * If \c pub is a transparent key (key of type #MBEDTLS_PK_RSA, + * #MBEDTLS_PK_RSASSA_PSS, #MBEDTLS_PK_ECKEY or #MBEDTLS_PK_ECDSA) whose + * type does not match the semantic type of \c prv (RSA, ECC or other), + * then check_pair_func must return #MBEDTLS_ERR_PK_TYPE_MISMATCH. + * + * If \c pub and \c prv are opaque keys from the same engines (i.e. ``), + * then check_pair_func must return 0, `#MBEDTLS_ERR_PK_TYPE_MISMATCH`, or + * `#MBEDTLS_ERR_RSA_KEY_CHECK_FAILED` or `#MBEDTLS_ERR_ECP_BAD_INPUT_DATA` + * as in the case of transparent keys. + * + * If \c pub is an opaque key which is not from the same engine as \c prv, + * then check_pair_func may either return a semantically correct status as + * in the case of transparent keys, or it may return + * #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE. + * + * Alternatively, check_pair_func may return another PK, RSA or ECP error + * code if applicable. + * */ int (*check_pair_func)( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); /** Allocate a new context @@ -213,11 +251,11 @@ struct mbedtls_pk_info_t * 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. */ + * 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 @@ -237,6 +275,36 @@ struct mbedtls_pk_info_t }; +/** + * Methods that opaque key pair objects must implement. + * + * \brief Initializer for opaque key engines + * + * The value of this macro is a suitable initializer for an object of type + * mbedtls_pk_info_t. It is guaranteed to remain so in future versions of the + * library, even if the type mbedtls_pk_info_t changes. + * + * This macro is suitable for static initializers provided that all of its + * parameters are constant. + * + * \param name For transparent keys, this reflects the key type. For opaque + * keys, this reflects the cryptographic module driver. + * \param get_bitlen \ref mbedtls_pk_info_t.get_bitlen method + * \param can_do \ref mbedtls_pk_info_t.can_do method + * \param signature_size_func \ref mbedtls_pk_info_t.signature_size_func method + * \param verify_func \ref mbedtls_pk_info_t.verify_func method + * \param sign_func \ref mbedtls_pk_info_t.sign_func method + * \param decrypt_func \ref mbedtls_pk_info_t.decrypt_func method + * \param encrypt_func \ref mbedtls_pk_info_t.encrypt_func method + * \param check_pair_func \ref mbedtls_pk_info_t.check_pair_func method + * \param ctx_alloc_func \ref mbedtls_pk_info_t.ctx_alloc_func method + * \param ctx_free_func \ref mbedtls_pk_info_t.ctx_free_func method + * \param debug_func \ref mbedtls_pk_info_t.debug_func method + * + * \return Initializer for an object of type mbedtls_pk_info_t with the + * specified field values + * + * */ #define MBEDTLS_PK_OPAQUE_INFO_1( \ name \ , get_bitlen \ diff --git a/include/mbedtls/pk_internal.h b/include/mbedtls/pk_internal.h index 0a330876e..42d6bc0b6 100644 --- a/include/mbedtls/pk_internal.h +++ b/include/mbedtls/pk_internal.h @@ -1,11 +1,16 @@ /** * \file pk_internal.h * - * \brief Public Key cryptography abstraction layer: built-in key types + * \brief Public Key cryptography abstraction layer: internal definitions * - * This file contains built-in types for handling various key types using - * the interface defined in pk_info.h. + * This file contains built-in types for handling natively supported key types + * using the interface defined in pk_info.h. * + * \warning This file contains internal definitions for the library. + * The interfaces in this file may change in future versions of the + * library without notice. + */ +/* * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * diff --git a/library/ecdsa.c b/library/ecdsa.c index d57c0c33b..afe95587b 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -311,7 +311,7 @@ int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, } /* - * Compute and write signature + * Compute and write signature. This function assumes that sig is large enough. */ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hlen, diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data index 11b5f108e..67b44194c 100644 --- a/tests/suites/test_suite_pk.data +++ b/tests/suites/test_suite_pk.data @@ -138,14 +138,14 @@ Check pair #2 (EC, bad) depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server5.key":MBEDTLS_ERR_ECP_BAD_INPUT_DATA -#Check pair #3 (RSA, OK) -#depends_on:MBEDTLS_RSA_C -#mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server1.key":0 -# -#Check pair #4 (RSA, bad) -#depends_on:MBEDTLS_RSA_C -#mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server2.key":MBEDTLS_ERR_RSA_KEY_CHECK_FAILED -# +Check pair #3 (RSA, OK) +depends_on:MBEDTLS_RSA_C +mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server1.key":0 + +Check pair #4 (RSA, bad) +depends_on:MBEDTLS_RSA_C +mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server2.key":MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + Check pair #5 (RSA vs EC) depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server1.key":MBEDTLS_ERR_PK_TYPE_MISMATCH From 2353781d9ef315a7e3c62ba534488811829d2427 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 14 Feb 2018 07:43:37 -0500 Subject: [PATCH 33/41] Add error checking to mbedtls_ecdsa_signature_to_asn1 Add a wrapper to check for errors during MBEDTLS_ASN1_CHK_ADD Substitute backticks with apostrophes --- include/mbedtls/pk_info.h | 8 ++++---- library/ecdsa.c | 21 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index 846502b9c..6ee47d866 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -71,7 +71,7 @@ extern "C" { * - 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 *, ...)` + * '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. * @@ -228,9 +228,9 @@ struct mbedtls_pk_info_t * type does not match the semantic type of \c prv (RSA, ECC or other), * then check_pair_func must return #MBEDTLS_ERR_PK_TYPE_MISMATCH. * - * If \c pub and \c prv are opaque keys from the same engines (i.e. ``), - * then check_pair_func must return 0, `#MBEDTLS_ERR_PK_TYPE_MISMATCH`, or - * `#MBEDTLS_ERR_RSA_KEY_CHECK_FAILED` or `#MBEDTLS_ERR_ECP_BAD_INPUT_DATA` + * If \c pub and \c prv are opaque keys from the same engines (i.e. ''), + * then check_pair_func must return 0, #MBEDTLS_ERR_PK_TYPE_MISMATCH, or + * #MBEDTLS_ERR_RSA_KEY_CHECK_FAILED or #MBEDTLS_ERR_ECP_BAD_INPUT_DATA * as in the case of transparent keys. * * If \c pub is an opaque key which is not from the same engine as \c prv, diff --git a/library/ecdsa.c b/library/ecdsa.c index afe95587b..1a6357bc1 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -287,10 +287,13 @@ cleanup: #endif /* MBEDTLS_ECDSA_VERIFY_ALT */ /* - * Convert a signature (given by context) to ASN.1 + * Convert a signature (given by context) to ASN.1. + * This function may leave a half-written upon encountering an error, and + * is for internal use only. */ -int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, - unsigned char *sig, size_t *slen, size_t ssize ) +static int internal_ecdsa_signature_to_asn1( const mbedtls_mpi *r, + const mbedtls_mpi *s, unsigned char *sig, + size_t *slen, size_t ssize ) { int ret; unsigned char *p = sig + ssize; @@ -310,6 +313,18 @@ int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, return( 0 ); } +/* + * Convert a signature (given by context) to ASN.1, zeroize the buffer on error + */ +int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen, size_t ssize ) +{ + int ret = internal_ecdsa_signature_to_asn1( r, s, sig, slen, ssize ); + if( ret != 0 ) + memset( sig, ssize, 0 ); + return( ret ); +} + /* * Compute and write signature. This function assumes that sig is large enough. */ From cac5f549caae2e9cb9be68adc967960a852521a3 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 14 Feb 2018 08:22:04 -0500 Subject: [PATCH 34/41] Fix typo Fix wrong order of arguments for a memset --- library/ecdsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ecdsa.c b/library/ecdsa.c index 1a6357bc1..53011d450 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -321,7 +321,7 @@ int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, { int ret = internal_ecdsa_signature_to_asn1( r, s, sig, slen, ssize ); if( ret != 0 ) - memset( sig, ssize, 0 ); + memset( sig, 0, ssize ); return( ret ); } From 0044ab12b7099457a24930aa80bd85d9724431dc Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Tue, 20 Feb 2018 11:18:21 -0500 Subject: [PATCH 35/41] Documentation fixes Correct indentation, brackets, and comments. --- include/mbedtls/ecdsa.h | 2 +- include/mbedtls/pk.h | 30 +++++++++--------- include/mbedtls/pk_info.h | 24 ++++++--------- library/ecdsa.c | 8 +++-- tests/suites/test_suite_ecp.function | 5 +-- tests/suites/test_suite_pk.data | 2 +- tests/suites/test_suite_pk.function | 46 ++++++++++++++-------------- 7 files changed, 58 insertions(+), 59 deletions(-) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index ba7aba1e3..f99147034 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -213,7 +213,7 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, * \param f_rng The RNG function. * \param p_rng The RNG parameter. * - * \note The signature \p sig is expected to be ASN.1 SEQUENCE + * \note The signature \p sig is expected to in be ASN.1 SEQUENCE * format, as described in Standards for Efficient * Cryptography Group (SECG): SEC1 Elliptic Curve * Cryptography, section C.5. diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index d712e7750..0e923779f 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -54,10 +54,10 @@ /**@{*/ #define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */ -#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */ +#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key. */ #define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */ #define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */ -#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */ +#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version. */ #define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */ #define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */ #define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */ @@ -68,9 +68,9 @@ #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_HW_ACCEL_FAILED -0x3880 /**< PK hardware accelerator failed. */ -#define MBEDTLS_ERR_PK_INVALID_SIGNATURE -0x3800 /**< Invalid signature */ -#define MBEDTLS_ERR_PK_BUFFER_TOO_SMALL -0x3780 /**< Output buffer too small */ -#define MBEDTLS_ERR_PK_NOT_PERMITTED -0x3700 /**< Operation not permitted */ +#define MBEDTLS_ERR_PK_INVALID_SIGNATURE -0x3800 /**< Invalid signature. */ +#define MBEDTLS_ERR_PK_BUFFER_TOO_SMALL -0x3780 /**< Output buffer too small. */ +#define MBEDTLS_ERR_PK_NOT_PERMITTED -0x3700 /**< Operation not permitted. */ /**@}*/ @@ -88,14 +88,14 @@ extern "C" { * unrecognized type. Call \c mbedtls_pk_can_do() to check * whether a key is of a recognized type. */ typedef enum { - MBEDTLS_PK_NONE=0, /**< Unused context object */ - MBEDTLS_PK_RSA, /**< RSA key pair (normal software implementation) with PKCS#1 v1.5 or PSS context */ - MBEDTLS_PK_ECKEY, /**< Generic ECC key pair */ - MBEDTLS_PK_ECKEY_DH, /**< ECC key pair restricted to key exchanges */ - MBEDTLS_PK_ECDSA, /**< ECC key pair restricted to signature/verification */ - 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 */ - MBEDTLS_PK_OPAQUE, /**< Opaque key pair (cryptographic material held in an external module).*/ + MBEDTLS_PK_NONE=0, /**< Unused context object. */ + MBEDTLS_PK_RSA, /**< RSA key pair (normal software implementation) with PKCS#1 v1.5 or PSS context. */ + MBEDTLS_PK_ECKEY, /**< Generic ECC key pair. */ + MBEDTLS_PK_ECKEY_DH, /**< ECC key pair restricted to key exchanges. */ + MBEDTLS_PK_ECDSA, /**< ECC key pair restricted to signature/verification. */ + 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. */ + MBEDTLS_PK_OPAQUE, /**< Opaque key pair (cryptographic material held in an external module). */ } mbedtls_pk_type_t; /** @@ -154,7 +154,7 @@ typedef struct } mbedtls_pk_context; /** - * \brief Access the type name + * \brief Get the key type name of a PK context. * * \param ctx Context to use * @@ -163,7 +163,7 @@ typedef struct const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); /** - * \brief Get the key type + * \brief Get the key type of a PK context. * * \param ctx Context to use * diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index 6ee47d866..6e6fd4720 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -3,7 +3,7 @@ * * \brief Public Key cryptography abstraction layer: engine interface * - * This file defines the interface the public-key cryptography engines + * This file defines the interface which public-key cryptography engines * (PK engines) must implement. A PK engine defines how a public-private * key pair is represented and how to perform cryptographic operations * with it. Mbed TLS contains built-in PK engines implemented either @@ -135,7 +135,7 @@ struct mbedtls_pk_info_t * In case of an error, or an unsupported key type, 0 should be returned. * * Opaque implementations may omit this method if they do not support - * signature. */ + * signing. */ size_t (*signature_size_func)( const void *ctx ); /** Verify signature @@ -239,8 +239,7 @@ struct mbedtls_pk_info_t * #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE. * * Alternatively, check_pair_func may return another PK, RSA or ECP error - * code if applicable. - * */ + * code if applicable. */ int (*check_pair_func)( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); /** Allocate a new context @@ -248,7 +247,7 @@ struct mbedtls_pk_info_t * mbedtls_pk_setup() calls this function. * * If this function returns NULL, the allocation is considered to - * have failed and the the object remains uninitialized. + * have failed and 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 @@ -261,9 +260,8 @@ struct mbedtls_pk_info_t /** 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. - * */ + * by \c 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 @@ -276,10 +274,10 @@ struct mbedtls_pk_info_t }; /** - * Methods that opaque key pair objects must implement. - * * \brief Initializer for opaque key engines * + * Methods that opaque key pair objects must implement. + * * The value of this macro is a suitable initializer for an object of type * mbedtls_pk_info_t. It is guaranteed to remain so in future versions of the * library, even if the type mbedtls_pk_info_t changes. @@ -288,7 +286,7 @@ struct mbedtls_pk_info_t * parameters are constant. * * \param name For transparent keys, this reflects the key type. For opaque - * keys, this reflects the cryptographic module driver. + * keys, this reflects the cryptographic module driver. * \param get_bitlen \ref mbedtls_pk_info_t.get_bitlen method * \param can_do \ref mbedtls_pk_info_t.can_do method * \param signature_size_func \ref mbedtls_pk_info_t.signature_size_func method @@ -302,9 +300,7 @@ struct mbedtls_pk_info_t * \param debug_func \ref mbedtls_pk_info_t.debug_func method * * \return Initializer for an object of type mbedtls_pk_info_t with the - * specified field values - * - * */ + * specified field values */ #define MBEDTLS_PK_OPAQUE_INFO_1( \ name \ , get_bitlen \ diff --git a/library/ecdsa.c b/library/ecdsa.c index 53011d450..ed4268dde 100644 --- a/library/ecdsa.c +++ b/library/ecdsa.c @@ -288,8 +288,8 @@ cleanup: /* * Convert a signature (given by context) to ASN.1. - * This function may leave a half-written upon encountering an error, and - * is for internal use only. + * This function is for internal use only. Upon an error, it may leave + * the signature buffer partially written. */ static int internal_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, unsigned char *sig, @@ -314,7 +314,8 @@ static int internal_ecdsa_signature_to_asn1( const mbedtls_mpi *r, } /* - * Convert a signature (given by context) to ASN.1, zeroize the buffer on error + * Convert a signature from number pair format to ASN.1. + * Zeroize the buffer on error. */ int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, unsigned char *sig, size_t *slen, size_t ssize ) @@ -327,6 +328,7 @@ int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, /* * Compute and write signature. This function assumes that sig is large enough. + * Refer to MBEDTLS_ECDSA_MAX_SIG_LEN for the signature size. */ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hlen, diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 120025f1c..feab0f7de 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -467,10 +467,11 @@ void ecp_ansi_write_point( char *key_file, int format, char *good_hex ) MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); exit: - if( ret >= 0 ) { + if( ret >= 0 ) + { unsigned char out[999] = {0}; hexify( out, tested_buf, ret ); - printf("== %s ==\n", out); + printf( "== %s ==\n", out ); } mbedtls_pk_free( &pk ); } diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data index 67b44194c..657fdf210 100644 --- a/tests/suites/test_suite_pk.data +++ b/tests/suites/test_suite_pk.data @@ -169,4 +169,4 @@ pk_opaque_minimal: #PK opaque wrapper (RSA) #depends_on:MBEDTLS_RSA_C #pk_opaque_wrapper: -# \ No newline at end of file +# diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function index 25c46b217..c190b12ab 100644 --- a/tests/suites/test_suite_pk.function +++ b/tests/suites/test_suite_pk.function @@ -86,11 +86,11 @@ static void pk_rsa_match( mbedtls_rsa_context *raw, 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 ); + 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 ) ); /* Initialize basic PK RSA context with raw key */ mbedtls_pk_init( &basic_ctx ); @@ -105,7 +105,7 @@ static void pk_rsa_match( mbedtls_rsa_context *raw, TEST_ASSERT( mbedtls_pk_get_signature_size( tested_ctx ) == RSA_KEY_LEN ); /* Test signature */ - TEST_ASSERT( mbedtls_pk_sign( tested_ctx, MBEDTLS_MD_NONE, hash, sizeof hash, + 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 ) { @@ -116,46 +116,46 @@ static void pk_rsa_match( mbedtls_rsa_context *raw, #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 ); + hash, sizeof( hash ), sig, sig_len ) == 0 ); } /* Test verification */ - TEST_ASSERT( mbedtls_pk_sign( &basic_ctx, MBEDTLS_MD_NONE, hash, sizeof hash, + 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 ); + 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 ); + 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 ); + 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, + 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, + test, &test_len, sizeof( test ), rnd_std_rand, NULL ) == 0 ); - TEST_ASSERT( test_len == sizeof msg ); + 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, + 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, + test, &test_len, sizeof( test ), rnd_std_rand, NULL ) == decrypt_ret ); if( decrypt_ret == 0 ) { - TEST_ASSERT( test_len == sizeof msg ); + TEST_ASSERT( test_len == sizeof( msg ) ); TEST_ASSERT( memcmp( test, msg, test_len ) == 0 ); } @@ -525,19 +525,19 @@ void pk_sign_verify( int type, int sign_ret, int verify_ret ) mbedtls_pk_init( &pk ); - memset( hash, 0x2a, sizeof hash ); - memset( sig, 0, sizeof sig ); + memset( hash, 0x2a, sizeof( hash ) ); + memset( sig, 0, sizeof( sig ) ); TEST_ASSERT( mbedtls_pk_setup( &pk, mbedtls_pk_info_from_type( type ) ) == 0 ); TEST_ASSERT( pk_genkey( &pk ) == 0 ); - TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256, hash, sizeof hash, + TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256, hash, sizeof( hash ), sig, &sig_len, rnd_std_rand, NULL ) == sign_ret ); if( sign_ret == 0 ) TEST_ASSERT( sig_len <= mbedtls_pk_get_signature_size( &pk ) ); TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_SHA256, - hash, sizeof hash, sig, sig_len ) == verify_ret ); + hash, sizeof( hash ), sig, sig_len ) == verify_ret ); exit: mbedtls_pk_free( &pk ); From b6e81bc3d7ba726a9dbc72b4127e31be2fc1ab41 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Tue, 20 Feb 2018 11:20:09 -0500 Subject: [PATCH 36/41] ECP: Add a sanity check to mbedtls_ecp_ansi_write_group Check for p != q at the end to ensure that everything went as it should. --- library/ecp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/ecp.c b/library/ecp.c index 477ed0d6b..89b0af44a 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -2082,6 +2082,8 @@ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); q = p + 2 + oid_length; *olen = mbedtls_asn1_write_oid( &q, p, oid, oid_length ); + if ( p != q ) + return ( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return ( 0 ); } From 57b3ccb4fadfd7856790ef0fcef21e3ad687a0ef Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 21 Feb 2018 05:13:28 -0500 Subject: [PATCH 37/41] Documentation fix Add '\c' tags before functions and fields --- include/mbedtls/pk_info.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index 6e6fd4720..002dd4cd7 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -219,27 +219,27 @@ struct mbedtls_pk_info_t * * If \c pub is an ECC key and \c pub is a transparent ECC key that can * be used for ECDSA (i.e. \c pub has the type #MBEDTLS_PK_ECKEY or - * #MBEDTLS_PK_ECDSA), then check_pair_func must return 0 if the public - * key is mathematically equivalent to the public part of prv, and + * #MBEDTLS_PK_ECDSA), then \c check_pair_func must return 0 if the public + * key is mathematically equivalent to the public part of \c prv, and * #MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise. * * If \c pub is a transparent key (key of type #MBEDTLS_PK_RSA, * #MBEDTLS_PK_RSASSA_PSS, #MBEDTLS_PK_ECKEY or #MBEDTLS_PK_ECDSA) whose * type does not match the semantic type of \c prv (RSA, ECC or other), - * then check_pair_func must return #MBEDTLS_ERR_PK_TYPE_MISMATCH. + * then \c check_pair_func must return #MBEDTLS_ERR_PK_TYPE_MISMATCH. * * If \c pub and \c prv are opaque keys from the same engines (i.e. ''), - * then check_pair_func must return 0, #MBEDTLS_ERR_PK_TYPE_MISMATCH, or + * then \c check_pair_func must return 0, #MBEDTLS_ERR_PK_TYPE_MISMATCH, or * #MBEDTLS_ERR_RSA_KEY_CHECK_FAILED or #MBEDTLS_ERR_ECP_BAD_INPUT_DATA * as in the case of transparent keys. * * If \c pub is an opaque key which is not from the same engine as \c prv, - * then check_pair_func may either return a semantically correct status as - * in the case of transparent keys, or it may return + * then \c check_pair_func may either return a semantically correct status + * as in the case of transparent keys, or it may return * #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE. * - * Alternatively, check_pair_func may return another PK, RSA or ECP error - * code if applicable. */ + * Alternatively, \c check_pair_func may return another PK, RSA or ECP + * error code if applicable. */ int (*check_pair_func)( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); /** Allocate a new context From 486ec972cb4a387a75758c0e25ab0201041b8f7d Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 21 Feb 2018 05:19:33 -0500 Subject: [PATCH 38/41] ECP: Add return code checking in mbedtls_ecp_ansi_write_group Add a check for the return value of mbedtls_asn1_write_oid --- library/ecp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/ecp.c b/library/ecp.c index 89b0af44a..c88a40e6c 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -2074,6 +2074,7 @@ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, size_t oid_length; int ret; + *olen = 0; ret = mbedtls_oid_get_oid_by_ec_grp( grp->id, &oid, &oid_length ); if( ret != 0 ) return( ret ); @@ -2081,7 +2082,8 @@ int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, if( size < 2 + oid_length ) return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); q = p + 2 + oid_length; - *olen = mbedtls_asn1_write_oid( &q, p, oid, oid_length ); + MBEDTLS_ASN1_CHK_ADD( *olen, mbedtls_asn1_write_oid( &q, p, oid, + oid_length ) ); if ( p != q ) return ( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); return ( 0 ); From ff8ddd1cb5ad6a2d38e8e07632875512b6b35d73 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 21 Feb 2018 05:28:12 -0500 Subject: [PATCH 39/41] Documentation fix Added a description of what "same engines" mean --- include/mbedtls/pk_info.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mbedtls/pk_info.h b/include/mbedtls/pk_info.h index 002dd4cd7..89752cea9 100644 --- a/include/mbedtls/pk_info.h +++ b/include/mbedtls/pk_info.h @@ -228,10 +228,10 @@ struct mbedtls_pk_info_t * type does not match the semantic type of \c prv (RSA, ECC or other), * then \c check_pair_func must return #MBEDTLS_ERR_PK_TYPE_MISMATCH. * - * If \c pub and \c prv are opaque keys from the same engines (i.e. ''), - * then \c check_pair_func must return 0, #MBEDTLS_ERR_PK_TYPE_MISMATCH, or - * #MBEDTLS_ERR_RSA_KEY_CHECK_FAILED or #MBEDTLS_ERR_ECP_BAD_INPUT_DATA - * as in the case of transparent keys. + * If \c pub and \c prv are opaque keys from the same engines (i.e. their + * pk_info fields are equal), then \c check_pair_func must return 0, + * #MBEDTLS_ERR_PK_TYPE_MISMATCH, or #MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + * or #MBEDTLS_ERR_ECP_BAD_INPUT_DATA as in the case of transparent keys. * * If \c pub is an opaque key which is not from the same engine as \c prv, * then \c check_pair_func may either return a semantically correct status From 932ebf36e519316b45800b4ad458c1a7723b61a4 Mon Sep 17 00:00:00 2001 From: Andrzej Kurek Date: Wed, 21 Feb 2018 08:49:05 -0500 Subject: [PATCH 40/41] Fix Windows build Redefine inline as in other headers --- include/mbedtls/ecdsa.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h index f99147034..489770856 100644 --- a/include/mbedtls/ecdsa.h +++ b/include/mbedtls/ecdsa.h @@ -34,6 +34,11 @@ #include "ecp.h" #include "md.h" +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + /* * RFC-4492 page 20: * From 262eceb12e2bed0bb8fffb6320aa71a3e9716891 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Feb 2018 16:36:04 +0100 Subject: [PATCH 41/41] Add ChangeLog entry --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8db021591..ebcde96cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 2.7.x feature branch released xxxx-xx-xx + +Features + * Add support for opaque keys in the pk module. Applications can define + opaque key engines to perform operations using keys stored in an + external cryptographic module. + * Support opaque private keys in TLS. + = mbed TLS 2.7.0 branch released 2018-02-03 Security