diff --git a/.travis.yml b/.travis.yml index 4d23652c6..4fc31c923 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,13 @@ compiler: - gcc sudo: false cache: ccache + +# blocklist +branches: + except: + - development-psa + - coverity_scan + script: - tests/scripts/recursion.pl library/*.c - tests/scripts/check-generated-files.sh @@ -34,7 +41,7 @@ addons: coverity_scan: project: name: "ARMmbed/mbedtls" - notification_email: p.j.bakker@polarssl.org + notification_email: simon.butcher@arm.com build_command_prepend: build_command: make branch_pattern: coverity_scan diff --git a/ChangeLog b/ChangeLog index f4bb41613..b37cf7ea8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,58 @@ Changes * Add unit tests for AES-GCM when called through mbedtls_cipher_auth_xxx() from the cipher abstraction layer. Fixes #2198. += mbed TLS 2.14.0+01b34fb316a5 branch released xxxx-xx-xx + +Security + * Fix timing variations and memory access variations in RSA PKCS#1 v1.5 + decryption that could lead to a Bleichenbacher-style padding oracle + attack. In TLS, this affects servers that accept ciphersuites based on + RSA decryption (i.e. ciphersuites whose name contains RSA but not + (EC)DH(E)). Discovered by Eyal Ronen (Weizmann Institute), Robert Gillham + (University of Adelaide), Daniel Genkin (University of Michigan), + Adi Shamir (Weizmann Institute), David Wong (NCC Group), and Yuval Yarom + (University of Adelaide, Data61). The attack is described in more detail + in the paper available here: http://cat.eyalro.net/cat.pdf CVE-2018-19608 + * In mbedtls_mpi_write_binary(), don't leak the exact size of the number + via branching and memory access patterns. An attacker who could submit + a plaintext for RSA PKCS#1 v1.5 decryption but only observe the timing + of the decryption and not its result could nonetheless decrypt RSA + plaintexts and forge RSA signatures. Other asymmetric algorithms may + have been similarly vulnerable. Reported by Eyal Ronen, Robert Gillham, + Daniel Genkin, Adi Shamir, David Wong and Yuval Yarom. + * Wipe sensitive buffers on the stack in the CTR_DRBG and HMAC_DRBG + modules. + +API Changes + * The following functions in the random generator modules have been + deprecated and replaced as shown below. The new functions change + the return type from void to int to allow returning error codes when + using MBEDTLS__ALT for the underlying AES or message digest + primitive. Fixes #1798. + mbedtls_ctr_drbg_update() -> mbedtls_ctr_drbg_update_ret() + mbedtls_hmac_drbg_update() -> mbedtls_hmac_drbg_update_ret() + * Extend ECDH interface to enable alternative implementations. + +New deprecations + * Deprecate mbedtls_ctr_drbg_update and mbedtls_hmac_drbg_update + in favor of functions that can return an error code. + +Bugfix + * Fix for Clang, which was reporting a warning for the bignum.c inline + assembly for AMD64 targets creating string literals greater than those + permitted by the ISO C99 standard. Found by Aaron Jones. Fixes #482. + * Fix runtime error in `mbedtls_platform_entropy_poll()` when run + through qemu user emulation. Reported and fix suggested by randombit + in #1212. Fixes #1212. + * Fix an unsafe bounds check when restoring an SSL session from a ticket. + This could lead to a buffer overflow, but only in case ticket authentication + was broken. Reported and fix suggested by Guido Vranken in #659. + * Add explicit integer to enumeration type casts to example program + programs/pkey/gen_key which previously led to compilation failure + on some toolchains. Reported by phoenixmcallister. Fixes #2170. + * Fix double initialization of ECC hardware that made some accelerators + hang. + = mbed TLS 2.14.0 branch released 2018-11-19 Security diff --git a/include/mbedtls/bn_mul.h b/include/mbedtls/bn_mul.h index 0af694c7c..2f7b72fe4 100644 --- a/include/mbedtls/bn_mul.h +++ b/include/mbedtls/bn_mul.h @@ -170,19 +170,19 @@ #define MULADDC_INIT \ asm( \ - "xorq %%r8, %%r8 \n\t" + "xorq %%r8, %%r8\n" #define MULADDC_CORE \ - "movq (%%rsi), %%rax \n\t" \ - "mulq %%rbx \n\t" \ - "addq $8, %%rsi \n\t" \ - "addq %%rcx, %%rax \n\t" \ - "movq %%r8, %%rcx \n\t" \ - "adcq $0, %%rdx \n\t" \ - "nop \n\t" \ - "addq %%rax, (%%rdi) \n\t" \ - "adcq %%rdx, %%rcx \n\t" \ - "addq $8, %%rdi \n\t" + "movq (%%rsi), %%rax\n" \ + "mulq %%rbx\n" \ + "addq $8, %%rsi\n" \ + "addq %%rcx, %%rax\n" \ + "movq %%r8, %%rcx\n" \ + "adcq $0, %%rdx\n" \ + "nop \n" \ + "addq %%rax, (%%rdi)\n" \ + "adcq %%rdx, %%rcx\n" \ + "addq $8, %%rdi\n" #define MULADDC_STOP \ : "+c" (c), "+D" (d), "+S" (s) \ diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index 508c00a8a..9e7aa3820 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -114,6 +114,7 @@ defined(MBEDTLS_ECDSA_SIGN_ALT) || \ defined(MBEDTLS_ECDSA_VERIFY_ALT) || \ defined(MBEDTLS_ECDSA_GENKEY_ALT) || \ + defined(MBEDTLS_ECP_INTERNAL_ALT) || \ defined(MBEDTLS_ECP_ALT) ) #error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation" #endif @@ -137,6 +138,10 @@ #error "MBEDTLS_ECP_C defined, but not all prerequisites" #endif +#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_ASN1_PARSE_C) +#error "MBEDTLS_PK_PARSE_C defined, but not all prerequesites" +#endif + #if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \ !defined(MBEDTLS_SHA256_C)) #error "MBEDTLS_ENTROPY_C defined, but not all prerequisites" diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 1f37d0843..fde1c5692 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -414,11 +414,11 @@ * unsigned char mbedtls_internal_ecp_grp_capable( * const mbedtls_ecp_group *grp ) * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) - * void mbedtls_internal_ecp_deinit( const mbedtls_ecp_group *grp ) + * void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ) * The mbedtls_internal_ecp_grp_capable function should return 1 if the * replacement functions implement arithmetic for the given group and 0 * otherwise. - * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_deinit are + * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_free are * called before and after each point operation and provide an opportunity to * implement optimized set up and tear down instructions. * diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h index c91ca58b3..10f9389d9 100644 --- a/include/mbedtls/ctr_drbg.h +++ b/include/mbedtls/ctr_drbg.h @@ -239,18 +239,20 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, /** * \brief This function updates the state of the CTR_DRBG context. * - * \note If \p add_len is greater than - * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first - * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. - * The remaining Bytes are silently discarded. - * * \param ctx The CTR_DRBG context. * \param additional The data to update the state with. - * \param add_len Length of \p additional data. + * \param add_len Length of \p additional in bytes. This must be at + * most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if + * \p add_len is more than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * \return An error from the underlying AES cipher on failure. */ -void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, - const unsigned char *additional, size_t add_len ); +int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ); /** * \brief This function updates a CTR_DRBG instance with additional @@ -290,6 +292,35 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function updates the state of the CTR_DRBG context. + * + * \deprecated Superseded by mbedtls_ctr_drbg_update_ret() + * in 2.16.0. + * + * \note If \p add_len is greater than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. + * The remaining Bytes are silently discarded. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. + * \param add_len Length of \p additional data. + */ +MBEDTLS_DEPRECATED void mbedtls_ctr_drbg_update( + mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + #if defined(MBEDTLS_FS_IO) /** * \brief This function writes a seed file. diff --git a/include/mbedtls/debug.h b/include/mbedtls/debug.h index ef8db67ff..736444bb7 100644 --- a/include/mbedtls/debug.h +++ b/include/mbedtls/debug.h @@ -65,6 +65,11 @@ mbedtls_debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ) #endif +#if defined(MBEDTLS_ECDH_C) +#define MBEDTLS_SSL_DEBUG_ECDH( level, ecdh, attr ) \ + mbedtls_debug_printf_ecdh( ssl, level, __FILE__, __LINE__, ecdh, attr ) +#endif + #else /* MBEDTLS_DEBUG_C */ #define MBEDTLS_SSL_DEBUG_MSG( level, args ) do { } while( 0 ) @@ -73,6 +78,7 @@ #define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) #define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) do { } while( 0 ) #define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_ECDH( level, ecdh, attr ) do { } while( 0 ) #endif /* MBEDTLS_DEBUG_C */ @@ -221,6 +227,36 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, const char *text, const mbedtls_x509_crt *crt ); #endif +#if defined(MBEDTLS_ECDH_C) +typedef enum +{ + MBEDTLS_DEBUG_ECDH_Q, + MBEDTLS_DEBUG_ECDH_QP, + MBEDTLS_DEBUG_ECDH_Z, +} mbedtls_debug_ecdh_attr; + +/** + * \brief Print a field of the ECDH structure in the SSL context to the debug + * output. This function is always used through the + * MBEDTLS_SSL_DEBUG_ECDH() macro, which supplies the ssl context, file + * and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param ecdh the ECDH context + * \param attr the identifier of the attribute being output + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_printf_ecdh( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ); +#endif + #ifdef __cplusplus } #endif diff --git a/include/mbedtls/ecdh.h b/include/mbedtls/ecdh.h index 27f2ffc6a..cbd48414a 100644 --- a/include/mbedtls/ecdh.h +++ b/include/mbedtls/ecdh.h @@ -36,6 +36,18 @@ #include "ecp.h" +/* + * Use a backward compatible ECDH context. + * + * This flag is always enabled for now and future versions might add a + * configuration option that conditionally undefines this flag. + * The configuration option in question may have a different name. + * + * Features undefining this flag, must have a warning in their description in + * config.h stating that the feature breaks backward compatibility. + */ +#define MBEDTLS_ECDH_LEGACY_CONTEXT + #ifdef __cplusplus extern "C" { #endif @@ -49,6 +61,39 @@ typedef enum MBEDTLS_ECDH_THEIRS, /**< The key of the peer. */ } mbedtls_ecdh_side; +#if !defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +/** + * Defines the ECDH implementation used. + * + * Later versions of the library may add new variants, therefore users should + * not make any assumptions about them. + */ +typedef enum +{ + MBEDTLS_ECDH_VARIANT_NONE = 0, /*!< Implementation not defined. */ + MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0,/*!< The default Mbed TLS implementation */ +} mbedtls_ecdh_variant; + +/** + * The context used by the default ECDH implementation. + * + * Later versions might change the structure of this context, therefore users + * should not make any assumptions about the structure of + * mbedtls_ecdh_context_mbed. + */ +typedef struct mbedtls_ecdh_context_mbed +{ + mbedtls_ecp_group grp; /*!< The elliptic curve used. */ + mbedtls_mpi d; /*!< The private key. */ + mbedtls_ecp_point Q; /*!< The public key. */ + mbedtls_ecp_point Qp; /*!< The value of the public key of the peer. */ + mbedtls_mpi z; /*!< The shared secret. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx rs; /*!< The restart context for EC computations. */ +#endif +} mbedtls_ecdh_context_mbed; +#endif + /** * * \warning Performing multiple operations concurrently on the same @@ -58,6 +103,7 @@ typedef enum */ typedef struct mbedtls_ecdh_context { +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) mbedtls_ecp_group grp; /*!< The elliptic curve used. */ mbedtls_mpi d; /*!< The private key. */ mbedtls_ecp_point Q; /*!< The public key. */ @@ -70,7 +116,26 @@ typedef struct mbedtls_ecdh_context #if defined(MBEDTLS_ECP_RESTARTABLE) int restart_enabled; /*!< The flag for restartable mode. */ mbedtls_ecp_restart_ctx rs; /*!< The restart context for EC computations. */ -#endif +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#else + uint8_t point_format; /*!< The format of point export in TLS messages + as defined in RFC 4492. */ + mbedtls_ecp_group_id grp_id;/*!< The elliptic curve used. */ + mbedtls_ecdh_variant var; /*!< The ECDH implementation/structure used. */ + union + { + mbedtls_ecdh_context_mbed mbed_ecdh; + } ctx; /*!< Implementation-specific context. The + context in use is specified by the \c var + field. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + uint8_t restart_enabled; /*!< The flag for restartable mode. Functions of + an alternative implementation not supporting + restartable mode must return + MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED error + if this flag is set. */ +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */ } mbedtls_ecdh_context; @@ -134,6 +199,24 @@ int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, */ void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ); +/** + * \brief This function sets up the ECDH context with the information + * given. + * + * This function should be called after mbedtls_ecdh_init() but + * before mbedtls_ecdh_make_params(). There is no need to call + * this function before mbedtls_ecdh_read_params(). + * + * This is the first function used by a TLS server for ECDHE + * ciphersuites. + * + * \param ctx The ECDH context to set up. + * \param grp_id The group id of the group to set up the context for. + * + * \return \c 0 on success. + */ +int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id ); + /** * \brief This function frees a context. * @@ -145,8 +228,8 @@ void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ); * \brief This function generates a public key and a TLS * ServerKeyExchange payload. * - * This is the first function used by a TLS server for ECDHE - * ciphersuites. + * This is the second function used by a TLS server for ECDHE + * ciphersuites. (It is called after mbedtls_ecdh_setup().) * * \note This function assumes that the ECP group (grp) of the * \p ctx context has already been properly set, @@ -242,8 +325,9 @@ int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, * \brief This function parses and processes a TLS ClientKeyExchange * payload. * - * This is the second function used by a TLS server for ECDH(E) - * ciphersuites. + * This is the third function used by a TLS server for ECDH(E) + * ciphersuites. (It is called after mbedtls_ecdh_setup() and + * mbedtls_ecdh_make_params().) * * \see ecp.h * diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 2fb1af49a..1c372980e 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -159,6 +159,10 @@ mbedtls_ecp_point; * additions or subtractions. Therefore, it is only an approximative modular * reduction. It must return 0 on success and non-zero on failure. * + * \note Alternative implementations must keep the group IDs distinct. If + * two group structures have the same ID, then they must be + * identical. + * */ typedef struct mbedtls_ecp_group { @@ -632,7 +636,7 @@ int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_poi /** * \brief This function imports a point from a TLS ECPoint record. * - * \note On function return, \p buf is updated to point to immediately + * \note On function return, \p *buf is updated to point immediately * after the ECPoint record. * * \param grp The ECP group used. @@ -641,7 +645,8 @@ int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_poi * \param len The length of the buffer. * * \return \c 0 on success. - * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization + * failure. * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. */ int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, @@ -687,19 +692,39 @@ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ); /** * \brief This function sets a group from a TLS ECParameters record. * - * \note \p buf is updated to point right after the ECParameters record - * on exit. + * \note \p buf is updated to point right after the ECParameters + * record on exit. * * \param grp The destination group. * \param buf The address of the pointer to the start of the input buffer. * \param len The length of the buffer. * * \return \c 0 on success. - * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization + * failure. * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognised. */ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ); +/** + * \brief This function reads a group from a TLS ECParameters record. + * + * \note \p buf is updated to point right after the ECParameters + * record on exit. + * + * \param grp Output parameter to hold the group id. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognised. + */ +int mbedtls_ecp_tls_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, size_t len ); /** * \brief This function writes the TLS ECParameters record for a group. * diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h index 3bc675ec7..146367b9d 100644 --- a/include/mbedtls/hmac_drbg.h +++ b/include/mbedtls/hmac_drbg.h @@ -195,10 +195,13 @@ void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, * \param additional Additional data to update state with, or NULL * \param add_len Length of additional data, or 0 * + * \return \c 0 on success, or an error from the underlying + * hash calculation. + * * \note Additional data is optional, pass NULL and 0 as second * third argument if no additional data is being used. */ -void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, +int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t add_len ); /** @@ -257,6 +260,31 @@ int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len */ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ); +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief HMAC_DRBG update state + * + * \deprecated Superseded by mbedtls_hmac_drbg_update_ret() + * in 2.16.0. + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to update state with, or NULL + * \param add_len Length of additional data, or 0 + * + * \note Additional data is optional, pass NULL and 0 as second + * third argument if no additional data is being used. + */ +MBEDTLS_DEPRECATED void mbedtls_hmac_drbg_update( + mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + #if defined(MBEDTLS_FS_IO) /** * \brief Write a seed file diff --git a/include/mbedtls/pkcs12.h b/include/mbedtls/pkcs12.h index a621ef5b1..69f04177c 100644 --- a/include/mbedtls/pkcs12.h +++ b/include/mbedtls/pkcs12.h @@ -46,6 +46,8 @@ extern "C" { #endif +#if defined(MBEDTLS_ASN1_PARSE_C) + /** * \brief PKCS12 Password Based function (encryption / decryption) * for pbeWithSHAAnd128BitRC4 @@ -87,6 +89,8 @@ int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, const unsigned char *input, size_t len, unsigned char *output ); +#endif /* MBEDTLS_ASN1_PARSE_C */ + /** * \brief The PKCS#12 derivation function uses a password and a salt * to produce pseudo-random bits for a particular "purpose". diff --git a/include/mbedtls/pkcs5.h b/include/mbedtls/pkcs5.h index 9a3c9fddc..d4bb36dfa 100644 --- a/include/mbedtls/pkcs5.h +++ b/include/mbedtls/pkcs5.h @@ -44,6 +44,8 @@ extern "C" { #endif +#if defined(MBEDTLS_ASN1_PARSE_C) + /** * \brief PKCS#5 PBES2 function * @@ -62,6 +64,8 @@ int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, const unsigned char *data, size_t datalen, unsigned char *output ); +#endif /* MBEDTLS_ASN1_PARSE_C */ + /** * \brief PKCS#5 PBKDF2 using HMAC * diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index afeefca60..3dd592248 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -232,19 +232,34 @@ int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *bu size_t buflen ); /** - * \brief Parse one or more certificates and add them - * to the chained list. Parses permissively. If some - * certificates can be parsed, the result is the number - * of failed certificates it encountered. If none complete - * correctly, the first error is returned. + * \brief Parse one DER-encoded or one or more concatenated PEM-encoded + * certificates and add them to the chained list. * - * \param chain points to the start of the chain - * \param buf buffer holding the certificate data in PEM or DER format - * \param buflen size of the buffer - * (including the terminating null byte for PEM data) + * For CRTs in PEM encoding, the function parses permissively: + * if at least one certificate can be parsed, the function + * returns the number of certificates for which parsing failed + * (hence \c 0 if all certificates were parsed successfully). + * If no certificate could be parsed, the function returns + * the first (negative) error encountered during parsing. + * + * PEM encoded certificates may be interleaved by other data + * such as human readable descriptions of their content, as + * long as the certificates are enclosed in the PEM specific + * '-----{BEGIN/END} CERTIFICATE-----' delimiters. + * + * \param chain The chain to which to add the parsed certificates. + * \param buf The buffer holding the certificate data in PEM or DER format. + * For certificates in PEM encoding, this may be a concatenation + * of multiple certificates; for DER encoding, the buffer must + * comprise exactly one certificate. + * \param buflen The size of \p buf, including the terminating \c NULL byte + * in case of PEM encoded data. + * + * \return \c 0 if all certificates were parsed successfully. + * \return The (positive) number of certificates that couldn't + * be parsed if parsing was partly successful (see above). + * \return A negative X509 or PEM error code otherwise. * - * \return 0 if all certificates parsed successfully, a positive number - * if partly successful or a specific X509 or PEM error code */ int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ); diff --git a/library/asn1write.c b/library/asn1write.c index d617de5b0..a4d23f619 100644 --- a/library/asn1write.c +++ b/library/asn1write.c @@ -331,14 +331,36 @@ int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, return( (int) len ); } -mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **head, + +/* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(), + * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */ +static mbedtls_asn1_named_data *asn1_find_named_data( + mbedtls_asn1_named_data *list, + const char *oid, size_t len ) +{ + while( list != NULL ) + { + if( list->oid.len == len && + memcmp( list->oid.p, oid, len ) == 0 ) + { + break; + } + + list = list->next; + } + + return( list ); +} + +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( + mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, const unsigned char *val, size_t val_len ) { mbedtls_asn1_named_data *cur; - if( ( cur = mbedtls_asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) + if( ( cur = asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) { // Add new entry if not present yet based on OID // diff --git a/library/bignum.c b/library/bignum.c index ae5e7cfa0..be4df2fe7 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -321,6 +321,10 @@ int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ) return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); } +/* Get a specific byte, without range checks. */ +#define GET_BYTE( X, i ) \ + ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff ) + /* * Set a bit to a specific value of 0 or 1 */ @@ -704,19 +708,40 @@ cleanup: /* * Export X into unsigned binary data, big endian */ -int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ) +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, + unsigned char *buf, size_t buflen ) { - size_t i, j, n; + size_t stored_bytes = X->n * ciL; + size_t bytes_to_copy; + unsigned char *p; + size_t i; - n = mbedtls_mpi_size( X ); + if( stored_bytes < buflen ) + { + /* There is enough space in the output buffer. Write initial + * null bytes and record the position at which to start + * writing the significant bytes. In this case, the execution + * trace of this function does not depend on the value of the + * number. */ + bytes_to_copy = stored_bytes; + p = buf + buflen - stored_bytes; + memset( buf, 0, buflen - stored_bytes ); + } + else + { + /* The output buffer is smaller than the allocated size of X. + * However X may fit if its leading bytes are zero. */ + bytes_to_copy = buflen; + p = buf; + for( i = bytes_to_copy; i < stored_bytes; i++ ) + { + if( GET_BYTE( X, i ) != 0 ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + } - if( buflen < n ) - return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); - - memset( buf, 0, buflen ); - - for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) - buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + for( i = 0; i < bytes_to_copy; i++ ) + p[bytes_to_copy - i - 1] = GET_BYTE( X, i ); return( 0 ); } diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c index fead18f72..fb121575b 100644 --- a/library/ctr_drbg.c +++ b/library/ctr_drbg.c @@ -299,9 +299,7 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, * Crypt counter block */ if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ) ) != 0 ) - { - return( ret ); - } + goto exit; p += MBEDTLS_CTR_DRBG_BLOCKSIZE; } @@ -313,12 +311,12 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, * Update key and counter */ if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) - { - return( ret ); - } + goto exit; memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE ); - return( 0 ); +exit: + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + return( ret ); } /* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) @@ -333,23 +331,39 @@ static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, * and with outputs * ctx = initial_working_state */ -void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, - const unsigned char *additional, size_t add_len ) +int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) { unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + int ret; - if( add_len > 0 ) - { - /* MAX_INPUT would be more logical here, but we have to match - * block_cipher_df()'s limits since we can't propagate errors */ - if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) - add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + if( add_len == 0 ) + return( 0 ); - block_cipher_df( add_input, additional, add_len ); - ctr_drbg_update_internal( ctx, add_input ); - } + if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 ) + goto exit; + if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) + goto exit; + +exit: + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); + return( ret ); } +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + /* MAX_INPUT would be more logical here, but we have to match + * block_cipher_df()'s limits since we can't propagate errors */ + if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + (void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len ); +} +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + /* CTR_DRBG_Reseed with derivation function (SP 800-90A §10.2.1.4.2) * mbedtls_ctr_drbg_reseed(ctx, additional, len) * implements @@ -399,20 +413,18 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, * Reduce to 384 bits */ if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 ) - { - return( ret ); - } + goto exit; /* * Update state */ if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 ) - { - return( ret ); - } + goto exit; ctx->reseed_counter = 1; - return( 0 ); +exit: + mbedtls_platform_zeroize( seed, sizeof( seed ) ); + return( ret ); } /* CTR_DRBG_Generate with derivation function (SP 800-90A §10.2.1.5.2) @@ -467,13 +479,9 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, if( add_len > 0 ) { if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 ) - { - return( ret ); - } + goto exit; if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) - { - return( ret ); - } + goto exit; } while( output_len > 0 ) @@ -489,9 +497,7 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, * Crypt counter block */ if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ) ) != 0 ) - { - return( ret ); - } + goto exit; use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len; @@ -504,12 +510,13 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng, } if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) - { - return( ret ); - } + goto exit; ctx->reseed_counter++; +exit: + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); return( 0 ); } @@ -561,35 +568,36 @@ exit: int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) { int ret = 0; - FILE *f; + FILE *f = NULL; size_t n; unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + unsigned char c; if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); - fseek( f, 0, SEEK_END ); - n = (size_t) ftell( f ); - fseek( f, 0, SEEK_SET ); - - if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) { - fclose( f ); - return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + goto exit; } - - if( fread( buf, 1, n, f ) != n ) + if( n == 0 || ferror( f ) ) + { ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; - else - mbedtls_ctr_drbg_update( ctx, buf, n ); - + goto exit; + } fclose( f ); + f = NULL; + ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n ); + +exit: mbedtls_platform_zeroize( buf, sizeof( buf ) ); - + if( f != NULL ) + fclose( f ); if( ret != 0 ) return( ret ); - return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); } #endif /* MBEDTLS_FS_IO */ diff --git a/library/debug.c b/library/debug.c index db3924ac5..824cd0236 100644 --- a/library/debug.c +++ b/library/debug.c @@ -365,4 +365,54 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, } #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_ECDH_C) +static void mbedtls_debug_printf_ecdh_internal( const mbedtls_ssl_context *ssl, + int level, const char *file, + int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + const mbedtls_ecdh_context* ctx = ecdh; +#else + const mbedtls_ecdh_context_mbed* ctx = &ecdh->ctx.mbed_ecdh; +#endif + + switch( attr ) + { + case MBEDTLS_DEBUG_ECDH_Q: + mbedtls_debug_print_ecp( ssl, level, file, line, "ECDH: Q", + &ctx->Q ); + break; + case MBEDTLS_DEBUG_ECDH_QP: + mbedtls_debug_print_ecp( ssl, level, file, line, "ECDH: Qp", + &ctx->Qp ); + break; + case MBEDTLS_DEBUG_ECDH_Z: + mbedtls_debug_print_mpi( ssl, level, file, line, "ECDH: z", + &ctx->z ); + break; + default: + break; + } +} + +void mbedtls_debug_printf_ecdh( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + mbedtls_debug_printf_ecdh_internal( ssl, level, file, line, ecdh, attr ); +#else + switch( ecdh->var ) + { + default: + mbedtls_debug_printf_ecdh_internal( ssl, level, file, line, ecdh, + attr ); + } +#endif +} +#endif /* MBEDTLS_ECDH_C */ + #endif /* MBEDTLS_DEBUG_C */ diff --git a/library/ecdh.c b/library/ecdh.c index e6ae99994..d68db8ac7 100644 --- a/library/ecdh.c +++ b/library/ecdh.c @@ -38,6 +38,10 @@ #include +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed; +#endif + #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) /* * Generate public key (restartable version) @@ -124,43 +128,84 @@ int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, } #endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ -/* - * Initialize context - */ -void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) +static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx ) { mbedtls_ecp_group_init( &ctx->grp ); mbedtls_mpi_init( &ctx->d ); mbedtls_ecp_point_init( &ctx->Q ); mbedtls_ecp_point_init( &ctx->Qp ); mbedtls_mpi_init( &ctx->z ); - ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; - mbedtls_ecp_point_init( &ctx->Vi ); - mbedtls_ecp_point_init( &ctx->Vf ); - mbedtls_mpi_init( &ctx->_d ); #if defined(MBEDTLS_ECP_RESTARTABLE) - ctx->restart_enabled = 0; mbedtls_ecp_restart_init( &ctx->rs ); #endif } /* - * Free context + * Initialize context */ -void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + ecdh_init_internal( ctx ); + mbedtls_ecp_point_init( &ctx->Vi ); + mbedtls_ecp_point_init( &ctx->Vf ); + mbedtls_mpi_init( &ctx->_d ); +#else + memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); + + ctx->var = MBEDTLS_ECDH_VARIANT_NONE; +#endif + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; +#if defined(MBEDTLS_ECP_RESTARTABLE) + ctx->restart_enabled = 0; +#endif +} + +static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx, + mbedtls_ecp_group_id grp_id ) +{ + int ret; + + ret = mbedtls_ecp_group_load( &ctx->grp, grp_id ); + if( ret != 0 ) + { + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} + +/* + * Setup context + */ +int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id ) { if( ctx == NULL ) - return; + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_setup_internal( ctx, grp_id ) ); +#else + switch( grp_id ) + { + default: + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0; + ctx->grp_id = grp_id; + ecdh_init_internal( &ctx->ctx.mbed_ecdh ); + return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) ); + } +#endif +} + +static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx ) +{ mbedtls_ecp_group_free( &ctx->grp ); mbedtls_mpi_free( &ctx->d ); mbedtls_ecp_point_free( &ctx->Q ); mbedtls_ecp_point_free( &ctx->Qp ); mbedtls_mpi_free( &ctx->z ); - mbedtls_ecp_point_free( &ctx->Vi ); - mbedtls_ecp_point_free( &ctx->Vf ); - mbedtls_mpi_free( &ctx->_d ); #if defined(MBEDTLS_ECP_RESTARTABLE) mbedtls_ecp_restart_free( &ctx->rs ); @@ -173,21 +218,50 @@ void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) */ void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx ) { + if( ctx == NULL ) + return; + ctx->restart_enabled = 1; } #endif /* - * Setup and write the ServerKeyExhange parameters (RFC 4492) - * struct { - * ECParameters curve_params; - * ECPoint public; - * } ServerECDHParams; + * Free context */ -int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + mbedtls_ecp_point_free( &ctx->Vi ); + mbedtls_ecp_point_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->_d ); + ecdh_free_internal( ctx ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + ecdh_free_internal( &ctx->ctx.mbed_ecdh ); + break; + default: + break; + } + + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + ctx->var = MBEDTLS_ECDH_VARIANT_NONE; + ctx->grp_id = MBEDTLS_ECP_DP_NONE; +#endif +} + +static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) { int ret; size_t grp_len, pt_len; @@ -195,12 +269,14 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, mbedtls_ecp_restart_ctx *rs_ctx = NULL; #endif - if( ctx == NULL || ctx->grp.pbits == 0 ) + if( ctx->grp.pbits == 0 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); #if defined(MBEDTLS_ECP_RESTARTABLE) - if( ctx->restart_enabled ) + if( restart_enabled ) rs_ctx = &ctx->rs; +#else + (void) restart_enabled; #endif @@ -214,14 +290,14 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, return( ret ); #endif /* MBEDTLS_ECP_RESTARTABLE */ - if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) ) - != 0 ) + if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, + blen ) ) != 0 ) return( ret ); buf += grp_len; blen -= grp_len; - if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, + if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, &pt_len, buf, blen ) ) != 0 ) return( ret ); @@ -229,6 +305,54 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, return( 0 ); } +/* + * Setup and write the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, + end - *buf ) ); +} + /* * Read the ServerKeyExhange parameters (RFC 4492) * struct { @@ -237,31 +361,42 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, * } ServerECDHParams; */ int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, - const unsigned char **buf, const unsigned char *end ) + const unsigned char **buf, + const unsigned char *end ) { int ret; + mbedtls_ecp_group_id grp_id; - if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) ) + != 0 ) return( ret ); - if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) - != 0 ) + if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 ) return( ret ); - return( 0 ); +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_params_internal( ctx, buf, end ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh, + buf, end ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif } -/* - * Get parameters from a keypair - */ -int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, - mbedtls_ecdh_side side ) +static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) { int ret; - if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ) - return( ret ); - /* If it's not our key, just import the public part as Qp */ if( side == MBEDTLS_ECDH_THEIRS ) return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); @@ -278,29 +413,61 @@ int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypai } /* - * Setup and export the client public value + * Get parameters from a keypair */ -int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) +{ + int ret; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_get_params_internal( ctx, key, side ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh, + key, side ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) { int ret; #if defined(MBEDTLS_ECP_RESTARTABLE) mbedtls_ecp_restart_ctx *rs_ctx = NULL; #endif - if( ctx == NULL || ctx->grp.pbits == 0 ) + if( ctx->grp.pbits == 0 ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); #if defined(MBEDTLS_ECP_RESTARTABLE) - if( ctx->restart_enabled ) + if( restart_enabled ) rs_ctx = &ctx->rs; +#else + (void) restart_enabled; #endif #if defined(MBEDTLS_ECP_RESTARTABLE) if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, - f_rng, p_rng, rs_ctx ) ) != 0 ) + f_rng, p_rng, rs_ctx ) ) != 0 ) return( ret ); #else if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, @@ -308,23 +475,52 @@ int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, return( ret ); #endif /* MBEDTLS_ECP_RESTARTABLE */ - return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, - olen, buf, blen ); + return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen, + buf, blen ); } /* - * Parse and import the client's public value + * Setup and export the client public value */ -int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, - const unsigned char *buf, size_t blen ) +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { - int ret; - const unsigned char *p = buf; + int restart_enabled = 0; if( ctx == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); - if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, blen ) ) != 0 ) +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char *buf, size_t blen ) +{ + int ret; + const unsigned char *p = buf; + + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, + blen ) ) != 0 ) return( ret ); if( (size_t)( p - buf ) != blen ) @@ -334,12 +530,36 @@ int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, } /* - * Derive and export the shared secret + * Parse and import the client's public value */ -int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, - unsigned char *buf, size_t blen, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_public_internal( ctx, buf, blen ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh, + buf, blen ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, unsigned char *buf, + size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) { int ret; #if defined(MBEDTLS_ECP_RESTARTABLE) @@ -350,13 +570,16 @@ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); #if defined(MBEDTLS_ECP_RESTARTABLE) - if( ctx->restart_enabled ) + if( restart_enabled ) rs_ctx = &ctx->rs; +#else + (void) restart_enabled; #endif #if defined(MBEDTLS_ECP_RESTARTABLE) - if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, - &ctx->z, &ctx->Qp, &ctx->d, f_rng, p_rng, rs_ctx ) ) != 0 ) + if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp, + &ctx->d, f_rng, p_rng, + rs_ctx ) ) != 0 ) { return( ret ); } @@ -375,4 +598,37 @@ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); } +/* + * Derive and export the shared secret + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng, + restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf, + blen, f_rng, p_rng, + restart_enabled ) ); + default: + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } +#endif +} + #endif /* MBEDTLS_ECDH_C */ diff --git a/library/ecp.c b/library/ecp.c index de5725c70..7fefb4c16 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -47,6 +47,35 @@ #include MBEDTLS_CONFIG_FILE #endif +/** + * \brief Function level alternative implementation. + * + * The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to + * replace certain functions in this module. The alternative implementations are + * typically hardware accelerators and need to activate the hardware before the + * computation starts and deactivate it after it finishes. The + * mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve + * this purpose. + * + * To preserve the correct functionality the following conditions must hold: + * + * - The alternative implementation must be activated by + * mbedtls_internal_ecp_init() before any of the replaceable functions is + * called. + * - mbedtls_internal_ecp_free() must \b only be called when the alternative + * implementation is activated. + * - mbedtls_internal_ecp_init() must \b not be called when the alternative + * implementation is activated. + * - Public functions must not return while the alternative implementation is + * activated. + * - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and + * before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) ) + * \endcode ensures that the alternative implementation supports the current + * group. + */ +#if defined(MBEDTLS_ECP_INTERNAL_ALT) +#endif + #if defined(MBEDTLS_ECP_C) #include "mbedtls/ecp.h" @@ -645,7 +674,7 @@ int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) } /* - * Compare two points lazyly + * Compare two points lazily */ int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) @@ -833,7 +862,24 @@ int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp /* * Set a group from an ECParameters record (RFC 4492) */ -int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ) +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, + const unsigned char **buf, size_t len ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + + if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, len ) ) != 0 ) + return( ret ); + + return mbedtls_ecp_group_load( grp, grp_id ); +} + +/* + * Read a group id from an ECParameters record (RFC 4492) and convert it to + * mbedtls_ecp_group_id. + */ +int mbedtls_ecp_tls_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, size_t len ) { uint16_t tls_id; const mbedtls_ecp_curve_info *curve_info; @@ -860,7 +906,9 @@ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **bu if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); - return mbedtls_ecp_group_load( grp, curve_info->grp_id ); + *grp = curve_info->grp_id; + + return( 0 ); } /* @@ -2393,11 +2441,6 @@ int mbedtls_ecp_muladd_restartable( mbedtls_ecp_point_init( &mP ); -#if defined(MBEDTLS_ECP_INTERNAL_ALT) - if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) ) - MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); -#endif /* MBEDTLS_ECP_INTERNAL_ALT */ - ECP_RS_ENTER( ma ); #if defined(MBEDTLS_ECP_RESTARTABLE) @@ -2425,6 +2468,12 @@ int mbedtls_ecp_muladd_restartable( mul2: #endif MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pR, n, Q, rs_ctx ) ); + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) ) + MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->ma != NULL ) rs_ctx->ma->state = ecp_rsma_add; diff --git a/library/entropy_poll.c b/library/entropy_poll.c index 040aa117d..4556f88a5 100644 --- a/library/entropy_poll.c +++ b/library/entropy_poll.c @@ -99,6 +99,7 @@ int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len #include #if defined(SYS_getrandom) #define HAVE_GETRANDOM +#include static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) { @@ -108,47 +109,8 @@ static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) memset( buf, 0, buflen ); #endif #endif - return( syscall( SYS_getrandom, buf, buflen, flags ) ); } - -#include -/* Check if version is at least 3.17.0 */ -static int check_version_3_17_plus( void ) -{ - int minor; - struct utsname un; - const char *ver; - - /* Get version information */ - uname(&un); - ver = un.release; - - /* Check major version; assume a single digit */ - if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) - return( -1 ); - - if( ver[0] - '0' > 3 ) - return( 0 ); - - /* Ok, so now we know major == 3, check minor. - * Assume 1 or 2 digits. */ - if( ver[2] < '0' || ver[2] > '9' ) - return( -1 ); - - minor = ver[2] - '0'; - - if( ver[3] >= '0' && ver[3] <= '9' ) - minor = 10 * minor + ver[3] - '0'; - else if( ver [3] != '.' ) - return( -1 ); - - if( minor < 17 ) - return( -1 ); - - return( 0 ); -} -static int has_getrandom = -1; #endif /* SYS_getrandom */ #endif /* __linux__ */ @@ -159,22 +121,21 @@ int mbedtls_platform_entropy_poll( void *data, { FILE *file; size_t read_len; + int ret; ((void) data); #if defined(HAVE_GETRANDOM) - if( has_getrandom == -1 ) - has_getrandom = ( check_version_3_17_plus() == 0 ); - - if( has_getrandom ) + ret = getrandom_wrapper( output, len, 0 ); + if( ret >= 0 ) { - int ret; - - if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) - return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); - *olen = ret; return( 0 ); } + else if( errno != ENOSYS ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + /* Fall through if the system call isn't known. */ +#else + ((void) ret); #endif /* HAVE_GETRANDOM */ *olen = 0; diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c index dad55ff86..c50330e7d 100644 --- a/library/hmac_drbg.c +++ b/library/hmac_drbg.c @@ -66,31 +66,60 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ) /* * HMAC_DRBG update, using optional additional data (10.1.2.2) */ -void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, - const unsigned char *additional, size_t add_len ) +int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) { size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1; unsigned char sep[1]; unsigned char K[MBEDTLS_MD_MAX_SIZE]; + int ret; for( sep[0] = 0; sep[0] < rounds; sep[0]++ ) { /* Step 1 or 4 */ - mbedtls_md_hmac_reset( &ctx->md_ctx ); - mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); - mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 ); + if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + sep, 1 ) ) != 0 ) + goto exit; if( rounds == 2 ) - mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len ); - mbedtls_md_hmac_finish( &ctx->md_ctx, K ); + { + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + additional, add_len ) ) != 0 ) + goto exit; + } + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, K ) ) != 0 ) + goto exit; /* Step 2 or 5 */ - mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ); - mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); - mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 ) + goto exit; } + +exit: + mbedtls_platform_zeroize( K, sizeof( K ) ); + return( ret ); } +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + (void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len ); +} +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + /* * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) */ @@ -108,10 +137,13 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, * Use the V memory location, which is currently all 0, to initialize the * MD context with an all-zero key. Then set V to its initial value. */ - mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) ); + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, + mbedtls_md_get_size( md_info ) ) ) != 0 ) + return( ret ); memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) ); - mbedtls_hmac_drbg_update( ctx, data, data_len ); + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 ) + return( ret ); return( 0 ); } @@ -124,6 +156,7 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, { unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; size_t seedlen; + int ret; /* III. Check input length */ if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || @@ -135,7 +168,8 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); /* IV. Gather entropy_len bytes of entropy for the seed */ - if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 ) + if( ( ret = ctx->f_entropy( ctx->p_entropy, + seed, ctx->entropy_len ) ) != 0 ) return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); seedlen = ctx->entropy_len; @@ -148,13 +182,16 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, } /* 2. Update state */ - mbedtls_hmac_drbg_update( ctx, seed, seedlen ); + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, seed, seedlen ) ) != 0 ) + goto exit; /* 3. Reset reseed_counter */ ctx->reseed_counter = 1; +exit: /* 4. Done */ - return( 0 ); + mbedtls_platform_zeroize( seed, seedlen ); + return( ret ); } /* @@ -180,7 +217,8 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, * Use the V memory location, which is currently all 0, to initialize the * MD context with an all-zero key. Then set V to its initial value. */ - mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ); + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ) ) != 0 ) + return( ret ); memset( ctx->V, 0x01, md_size ); ctx->f_entropy = f_entropy; @@ -273,16 +311,24 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng, /* 2. Use additional data if any */ if( additional != NULL && add_len != 0 ) - mbedtls_hmac_drbg_update( ctx, additional, add_len ); + { + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, + additional, add_len ) ) != 0 ) + goto exit; + } /* 3, 4, 5. Generate bytes */ while( left != 0 ) { size_t use_len = left > md_len ? md_len : left; - mbedtls_md_hmac_reset( &ctx->md_ctx ); - mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); - mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 ) + goto exit; memcpy( out, ctx->V, use_len ); out += use_len; @@ -290,13 +336,16 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng, } /* 6. Update */ - mbedtls_hmac_drbg_update( ctx, additional, add_len ); + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, + additional, add_len ) ) != 0 ) + goto exit; /* 7. Update reseed counter */ ctx->reseed_counter++; +exit: /* 8. Done */ - return( 0 ); + return( ret ); } /* @@ -368,35 +417,36 @@ exit: int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) { int ret = 0; - FILE *f; + FILE *f = NULL; size_t n; unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + unsigned char c; if( ( f = fopen( path, "rb" ) ) == NULL ) return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); - fseek( f, 0, SEEK_END ); - n = (size_t) ftell( f ); - fseek( f, 0, SEEK_SET ); - - if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) { - fclose( f ); - return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; + goto exit; } - - if( fread( buf, 1, n, f ) != n ) + if( n == 0 || ferror( f ) ) + { ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; - else - mbedtls_hmac_drbg_update( ctx, buf, n ); - + goto exit; + } fclose( f ); + f = NULL; + ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); + +exit: mbedtls_platform_zeroize( buf, sizeof( buf ) ); - + if( f != NULL ) + fclose( f ); if( ret != 0 ) return( ret ); - return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); } #endif /* MBEDTLS_FS_IO */ diff --git a/library/pkcs12.c b/library/pkcs12.c index 16a15cb63..7edf064c1 100644 --- a/library/pkcs12.c +++ b/library/pkcs12.c @@ -48,6 +48,8 @@ #include "mbedtls/des.h" #endif +#if defined(MBEDTLS_ASN1_PARSE_C) + static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params, mbedtls_asn1_buf *salt, int *iterations ) { @@ -226,6 +228,8 @@ exit: return( ret ); } +#endif /* MBEDTLS_ASN1_PARSE_C */ + static void pkcs12_fill_buffer( unsigned char *data, size_t data_len, const unsigned char *filler, size_t fill_len ) { diff --git a/library/pkcs5.c b/library/pkcs5.c index f04f0ab25..50133435c 100644 --- a/library/pkcs5.c +++ b/library/pkcs5.c @@ -54,22 +54,7 @@ #define mbedtls_printf printf #endif -#if !defined(MBEDTLS_ASN1_PARSE_C) -int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, - const unsigned char *pwd, size_t pwdlen, - const unsigned char *data, size_t datalen, - unsigned char *output ) -{ - ((void) pbe_params); - ((void) mode); - ((void) pwd); - ((void) pwdlen); - ((void) data); - ((void) datalen); - ((void) output); - return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); -} -#else +#if defined(MBEDTLS_ASN1_PARSE_C) static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params, mbedtls_asn1_buf *salt, int *iterations, int *keylen, mbedtls_md_type_t *md_type ) diff --git a/library/rsa.c b/library/rsa.c index c64f14895..b68018829 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1392,6 +1392,97 @@ cleanup: #endif /* MBEDTLS_PKCS1_V21 */ #if defined(MBEDTLS_PKCS1_V15) +/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches. + * + * \param value The value to analyze. + * \return Zero if \p value is zero, otherwise all-bits-one. + */ +static unsigned all_or_nothing_int( unsigned value ) +{ + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif +} + +/** Check whether a size is out of bounds, without branches. + * + * This is equivalent to `size > max`, but is likely to be compiled to + * to code using bitwise operation rather than a branch. + * + * \param size Size to check. + * \param max Maximum desired value for \p size. + * \return \c 0 if `size <= max`. + * \return \c 1 if `size > max`. + */ +static unsigned size_greater_than( size_t size, size_t max ) +{ + /* Return the sign bit (1 for negative) of (max - size). */ + return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); +} + +/** Choose between two integer values, without branches. + * + * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled + * to code using bitwise operation rather than a branch. + * + * \param cond Condition to test. + * \param if1 Value to use if \p cond is nonzero. + * \param if0 Value to use if \p cond is zero. + * \return \c if1 if \p cond is nonzero, otherwise \c if0. + */ +static unsigned if_int( unsigned cond, unsigned if1, unsigned if0 ) +{ + unsigned mask = all_or_nothing_int( cond ); + return( ( mask & if1 ) | (~mask & if0 ) ); +} + +/** Shift some data towards the left inside a buffer without leaking + * the length of the data through side channels. + * + * `mem_move_to_left(start, total, offset)` is functionally equivalent to + * ``` + * memmove(start, start + offset, total - offset); + * memset(start + offset, 0, total - offset); + * ``` + * but it strives to use a memory access pattern (and thus total timing) + * that does not depend on \p offset. This timing independence comes at + * the expense of performance. + * + * \param start Pointer to the start of the buffer. + * \param total Total size of the buffer. + * \param offset Offset from which to copy \p total - \p offset bytes. + */ +static void mem_move_to_left( void *start, + size_t total, + size_t offset ) +{ + volatile unsigned char *buf = start; + size_t i, n; + if( total == 0 ) + return; + for( i = 0; i < total; i++ ) + { + unsigned no_op = size_greater_than( total - offset, i ); + /* The first `total - offset` passes are a no-op. The last + * `offset` passes shift the data one byte to the left and + * zero out the last byte. */ + for( n = 0; n < total - 1; n++ ) + { + unsigned char current = buf[n]; + unsigned char next = buf[n+1]; + buf[n] = if_int( no_op, current, next ); + } + buf[total-1] = if_int( no_op, buf[total-1], 0 ); + } +} + /* * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function */ @@ -1401,18 +1492,34 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, int mode, size_t *olen, const unsigned char *input, unsigned char *output, - size_t output_max_len) + size_t output_max_len ) { int ret; - size_t ilen, pad_count = 0, i; - unsigned char *p, bad, pad_done = 0; + size_t ilen = ctx->len; + size_t i; + size_t plaintext_max_size = ( output_max_len > ilen - 11 ? + ilen - 11 : + output_max_len ); unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + /* The following variables take sensitive values: their value must + * not leak into the observable behavior of the function other than + * the designated outputs (output, olen, return value). Otherwise + * this would open the execution of the function to + * side-channel-based variants of the Bleichenbacher padding oracle + * attack. Potential side channels include overall timing, memory + * access patterns (especially visible to an adversary who has access + * to a shared memory cache), and branches (especially visible to + * an adversary who has access to a shared code cache or to a shared + * branch predictor). */ + size_t pad_count = 0; + unsigned bad = 0; + unsigned char pad_done = 0; + size_t plaintext_size = 0; + unsigned output_too_large; if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - ilen = ctx->len; - if( ilen < 16 || ilen > sizeof( buf ) ) return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); @@ -1423,64 +1530,109 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, if( ret != 0 ) goto cleanup; - p = buf; - bad = 0; + /* Check and get padding length in constant time and constant + * memory trace. The first byte must be 0. */ + bad |= buf[0]; - /* - * Check and get padding len in "constant-time" - */ - bad |= *p++; /* First byte must be 0 */ - - /* This test does not depend on secret data */ if( mode == MBEDTLS_RSA_PRIVATE ) { - bad |= *p++ ^ MBEDTLS_RSA_CRYPT; + /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 + * where PS must be at least 8 nonzero bytes. */ + bad |= buf[1] ^ MBEDTLS_RSA_CRYPT; - /* Get padding len, but always read till end of buffer - * (minus one, for the 00 byte) */ - for( i = 0; i < ilen - 3; i++ ) + /* Read the whole buffer. Set pad_done to nonzero if we find + * the 0x00 byte and remember the padding length in pad_count. */ + for( i = 2; i < ilen; i++ ) { - pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1; + pad_done |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1; pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; } - - p += pad_count; - bad |= *p++; /* Must be zero */ } else { - bad |= *p++ ^ MBEDTLS_RSA_SIGN; + /* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00 + * where PS must be at least 8 bytes with the value 0xFF. */ + bad |= buf[1] ^ MBEDTLS_RSA_SIGN; - /* Get padding len, but always read till end of buffer - * (minus one, for the 00 byte) */ - for( i = 0; i < ilen - 3; i++ ) + /* Read the whole buffer. Set pad_done to nonzero if we find + * the 0x00 byte and remember the padding length in pad_count. + * If there's a non-0xff byte in the padding, the padding is bad. */ + for( i = 2; i < ilen; i++ ) { - pad_done |= ( p[i] != 0xFF ); - pad_count += ( pad_done == 0 ); + pad_done |= if_int( buf[i], 0, 1 ); + pad_count += if_int( pad_done, 0, 1 ); + bad |= if_int( pad_done, 0, buf[i] ^ 0xFF ); } - - p += pad_count; - bad |= *p++; /* Must be zero */ } - bad |= ( pad_count < 8 ); + /* If pad_done is still zero, there's no data, only unfinished padding. */ + bad |= if_int( pad_done, 0, 1 ); - if( bad ) - { - ret = MBEDTLS_ERR_RSA_INVALID_PADDING; - goto cleanup; - } + /* There must be at least 8 bytes of padding. */ + bad |= size_greater_than( 8, pad_count ); - if( ilen - ( p - buf ) > output_max_len ) - { - ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE; - goto cleanup; - } + /* If the padding is valid, set plaintext_size to the number of + * remaining bytes after stripping the padding. If the padding + * is invalid, avoid leaking this fact through the size of the + * output: use the maximum message size that fits in the output + * buffer. Do it without branches to avoid leaking the padding + * validity through timing. RSA keys are small enough that all the + * size_t values involved fit in unsigned int. */ + plaintext_size = if_int( bad, + (unsigned) plaintext_max_size, + (unsigned) ( ilen - pad_count - 3 ) ); - *olen = ilen - (p - buf); - if( *olen != 0 ) - memcpy( output, p, *olen ); - ret = 0; + /* Set output_too_large to 0 if the plaintext fits in the output + * buffer and to 1 otherwise. */ + output_too_large = size_greater_than( plaintext_size, + plaintext_max_size ); + + /* Set ret without branches to avoid timing attacks. Return: + * - INVALID_PADDING if the padding is bad (bad != 0). + * - OUTPUT_TOO_LARGE if the padding is good but the decrypted + * plaintext does not fit in the output buffer. + * - 0 if the padding is correct. */ + ret = - (int) if_int( bad, - MBEDTLS_ERR_RSA_INVALID_PADDING, + if_int( output_too_large, - MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, + 0 ) ); + + /* If the padding is bad or the plaintext is too large, zero the + * data that we're about to copy to the output buffer. + * We need to copy the same amount of data + * from the same buffer whether the padding is good or not to + * avoid leaking the padding validity through overall timing or + * through memory or cache access patterns. */ + bad = all_or_nothing_int( bad | output_too_large ); + for( i = 11; i < ilen; i++ ) + buf[i] &= ~bad; + + /* If the plaintext is too large, truncate it to the buffer size. + * Copy anyway to avoid revealing the length through timing, because + * revealing the length is as bad as revealing the padding validity + * for a Bleichenbacher attack. */ + plaintext_size = if_int( output_too_large, + (unsigned) plaintext_max_size, + (unsigned) plaintext_size ); + + /* Move the plaintext to the leftmost position where it can start in + * the working buffer, i.e. make it start plaintext_max_size from + * the end of the buffer. Do this with a memory access trace that + * does not depend on the plaintext size. After this move, the + * starting location of the plaintext is no longer sensitive + * information. */ + mem_move_to_left( buf + ilen - plaintext_max_size, + plaintext_max_size, + plaintext_max_size - plaintext_size ); + + /* Finally copy the decrypted plaintext plus trailing zeros + * into the output buffer. */ + memcpy( output, buf + ilen - plaintext_max_size, plaintext_max_size ); + + /* Report the amount of data we copied to the output buffer. In case + * of errors (bad padding or output too large), the value of *olen + * when this function returns is not specified. Making it equivalent + * to the good case limits the risks of leaking the padding validity. */ + *olen = plaintext_size; cleanup: mbedtls_platform_zeroize( buf, sizeof( buf ) ); diff --git a/library/ssl_cli.c b/library/ssl_cli.c index cd25dca91..06bcc731f 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -2074,8 +2074,14 @@ static int ssl_parse_server_dh_params( mbedtls_ssl_context *ssl, unsigned char * static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) { const mbedtls_ecp_curve_info *curve_info; + mbedtls_ecp_group_id grp_id; +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + grp_id = ssl->handshake->ecdh_ctx.grp.id; +#else + grp_id = ssl->handshake->ecdh_ctx.grp_id; +#endif - curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + curve_info = mbedtls_ecp_curve_info_from_grp_id( grp_id ); if( curve_info == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); @@ -2085,14 +2091,15 @@ static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); #if defined(MBEDTLS_ECP_C) - if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) + if( mbedtls_ssl_check_curve( ssl, grp_id ) != 0 ) #else if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || ssl->handshake->ecdh_ctx.grp.nbits > 521 ) #endif return( -1 ); - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); return( 0 ); } @@ -3014,7 +3021,8 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) return( ret ); } - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); #if defined(MBEDTLS_SSL__ECP_RESTARTABLE) if( ssl->handshake->ecrs_enabled ) @@ -3041,7 +3049,8 @@ ecdh_calc_secret: return( ret ); } - MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || @@ -3156,7 +3165,8 @@ ecdh_calc_secret: return( ret ); } - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 4d99f884d..8a90288ea 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3088,8 +3088,8 @@ curve_matching_done: MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", (*curve)->name ) ); - if( ( ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, - (*curve)->grp_id ) ) != 0 ) + if( ( ret = mbedtls_ecdh_setup( &ssl->handshake->ecdh_ctx, + (*curve)->grp_id ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); return( ret ); @@ -3111,7 +3111,8 @@ curve_matching_done: ssl->out_msglen += len; - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); } #endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ @@ -3832,7 +3833,8 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); } - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &ssl->handshake->pmslen, @@ -3844,7 +3846,8 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); } - MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z ", &ssl->handshake->ecdh_ctx.z ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || @@ -3982,7 +3985,8 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); #endif - MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, ciphersuite_info->key_exchange ) ) != 0 ) diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c index 9fc690f4c..7de4e66b1 100644 --- a/library/ssl_ticket.c +++ b/library/ssl_ticket.c @@ -217,9 +217,9 @@ static int ssl_save_session( const mbedtls_ssl_session *session, if( left < 3 + cert_len ) return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); - *p++ = (unsigned char)( cert_len >> 16 & 0xFF ); - *p++ = (unsigned char)( cert_len >> 8 & 0xFF ); - *p++ = (unsigned char)( cert_len & 0xFF ); + *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( cert_len ) & 0xFF ); if( session->peer_cert != NULL ) memcpy( p, session->peer_cert->raw.p, cert_len ); @@ -244,14 +244,14 @@ static int ssl_load_session( mbedtls_ssl_session *session, size_t cert_len; #endif /* MBEDTLS_X509_CRT_PARSE_C */ - if( p + sizeof( mbedtls_ssl_session ) > end ) + if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); memcpy( session, p, sizeof( mbedtls_ssl_session ) ); p += sizeof( mbedtls_ssl_session ); #if defined(MBEDTLS_X509_CRT_PARSE_C) - if( p + 3 > end ) + if( 3 > (size_t)( end - p ) ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; @@ -265,7 +265,7 @@ static int ssl_load_session( mbedtls_ssl_session *session, { int ret; - if( p + cert_len > end ) + if( cert_len > (size_t)( end - p ) ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); @@ -276,7 +276,7 @@ static int ssl_load_session( mbedtls_ssl_session *session, mbedtls_x509_crt_init( session->peer_cert ); if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert, - p, cert_len ) ) != 0 ) + p, cert_len ) ) != 0 ) { mbedtls_x509_crt_free( session->peer_cert ); mbedtls_free( session->peer_cert ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 8fe93141f..cf44ed506 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1499,7 +1499,8 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exch *(p++) = (unsigned char)( zlen ); p += zlen; - MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); } else #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ @@ -3366,8 +3367,10 @@ int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) } } - if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && - hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST && + /* Whenever we send anything different from a + * HelloRequest we should be in a handshake - double check. */ + if( ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) && ssl->handshake == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); @@ -3461,8 +3464,8 @@ int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) /* Either send now, or just save to be sent (and resent) later */ #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && - ( ssl->out_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || - hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) ) + ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) ) { if( ( ret = ssl_flight_append( ssl ) ) != 0 ) { diff --git a/library/x509_crt.c b/library/x509_crt.c index c5b6a1248..3a3c0a0a4 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2203,7 +2203,7 @@ static int x509_crt_find_parent( } /* extra precaution against mistakes in the caller */ - if( parent == NULL ) + if( *parent == NULL ) { *parent_is_trusted = 0; *signature_is_good = 0; diff --git a/programs/pkey/ecdh_curve25519.c b/programs/pkey/ecdh_curve25519.c index 5db04088f..7fbf1678f 100644 --- a/programs/pkey/ecdh_curve25519.c +++ b/programs/pkey/ecdh_curve25519.c @@ -35,12 +35,12 @@ #define MBEDTLS_EXIT_FAILURE EXIT_FAILURE #endif /* MBEDTLS_PLATFORM_C */ -#if !defined(MBEDTLS_ECDH_C) || \ +#if !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDH_LEGACY_CONTEXT) || \ !defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \ !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) int main( void ) { - mbedtls_printf( "MBEDTLS_ECDH_C and/or " + mbedtls_printf( "MBEDTLS_ECDH_C and/or MBEDTLS_ECDH_LEGACY_CONTEXT and/or " "MBEDTLS_ECP_DP_CURVE25519_ENABLED and/or " "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C " "not defined\n" ); diff --git a/programs/pkey/gen_key.c b/programs/pkey/gen_key.c index f01bf5fcd..31abb0cb8 100644 --- a/programs/pkey/gen_key.c +++ b/programs/pkey/gen_key.c @@ -322,7 +322,8 @@ int main( int argc, char *argv[] ) mbedtls_printf( "\n . Generating the private key ..." ); fflush( stdout ); - if( ( ret = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( opt.type ) ) ) != 0 ) + if( ( ret = mbedtls_pk_setup( &key, + mbedtls_pk_info_from_type( (mbedtls_pk_type_t) opt.type ) ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_pk_setup returned -0x%04x", -ret ); goto exit; @@ -344,7 +345,8 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_ECP_C) if( opt.type == MBEDTLS_PK_ECKEY ) { - ret = mbedtls_ecp_gen_key( opt.ec_curve, mbedtls_pk_ec( key ), + ret = mbedtls_ecp_gen_key( (mbedtls_ecp_group_id) opt.ec_curve, + mbedtls_pk_ec( key ), mbedtls_ctr_drbg_random, &ctr_drbg ); if( ret != 0 ) { diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c index 13602c2e5..cd0c23064 100644 --- a/programs/pkey/key_app_writer.c +++ b/programs/pkey/key_app_writer.c @@ -87,10 +87,12 @@ USAGE_OUT \ "\n" -#if !defined(MBEDTLS_PK_WRITE_C) || !defined(MBEDTLS_FS_IO) +#if !defined(MBEDTLS_PK_PARSE_C) || \ + !defined(MBEDTLS_PK_WRITE_C) || \ + !defined(MBEDTLS_FS_IO) int main( void ) { - mbedtls_printf( "MBEDTLS_PK_WRITE_C and/or MBEDTLS_FS_IO not defined.\n" ); + mbedtls_printf( "MBEDTLS_PK_PARSE_C and/or MBEDTLS_PK_WRITE_C and/or MBEDTLS_FS_IO not defined.\n" ); return( 0 ); } #else @@ -433,4 +435,4 @@ exit: return( exit_code ); } -#endif /* MBEDTLS_PK_WRITE_C && MBEDTLS_FS_IO */ +#endif /* MBEDTLS_PK_PARSE_C && MBEDTLS_PK_WRITE_C && MBEDTLS_FS_IO */ diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c index e7d29c396..dd4303b89 100644 --- a/programs/test/benchmark.c +++ b/programs/test/benchmark.c @@ -862,7 +862,7 @@ int main( int argc, char *argv[] ) } #endif -#if defined(MBEDTLS_ECDH_C) +#if defined(MBEDTLS_ECDH_C) && defined(MBEDTLS_ECDH_LEGACY_CONTEXT) if( todo.ecdh ) { mbedtls_ecdh_context ecdh; diff --git a/tests/git-scripts/pre-push.sh b/tests/git-scripts/pre-push.sh index 7407f44b9..86edf5a30 100755 --- a/tests/git-scripts/pre-push.sh +++ b/tests/git-scripts/pre-push.sh @@ -46,3 +46,4 @@ run_test ./tests/scripts/check-doxy-blocks.pl run_test ./tests/scripts/check-names.sh run_test ./tests/scripts/check-generated-files.sh run_test ./tests/scripts/check-files.py +run_test ./tests/scripts/doxygen.sh diff --git a/tests/scripts/basic-build-test.sh b/tests/scripts/basic-build-test.sh index b4058718a..fbe757d9e 100755 --- a/tests/scripts/basic-build-test.sh +++ b/tests/scripts/basic-build-test.sh @@ -76,7 +76,7 @@ TEST_OUTPUT=out_${PPID} cd tests # Step 2a - Unit Tests -perl scripts/run-test-suites.pl -v |tee unit-test-$TEST_OUTPUT +perl scripts/run-test-suites.pl -v 2 |tee unit-test-$TEST_OUTPUT echo # Step 2b - System Tests diff --git a/tests/scripts/check-files.py b/tests/scripts/check-files.py index ed6787289..005a077c7 100755 --- a/tests/scripts/check-files.py +++ b/tests/scripts/check-files.py @@ -43,11 +43,14 @@ class IssueTracker(object): for i, line in enumerate(iter(f.readline, b"")): self.check_file_line(filepath, line, i + 1) + def record_issue(self, filepath, line_number): + if filepath not in self.files_with_issues.keys(): + self.files_with_issues[filepath] = [] + self.files_with_issues[filepath].append(line_number) + def check_file_line(self, filepath, line, line_number): if self.issue_with_line(line): - if filepath not in self.files_with_issues.keys(): - self.files_with_issues[filepath] = [] - self.files_with_issues[filepath].append(line_number) + self.record_issue(filepath, line_number) def output_file_issues(self, logger): if self.files_with_issues.values(): @@ -132,13 +135,36 @@ class TabIssueTracker(IssueTracker): return b"\t" in line +class MergeArtifactIssueTracker(IssueTracker): + + def __init__(self): + super().__init__() + self.heading = "Merge artifact:" + + def issue_with_line(self, filepath, line): + # Detect leftover git conflict markers. + if line.startswith(b'<<<<<<< ') or line.startswith(b'>>>>>>> '): + return True + if line.startswith(b'||||||| '): # from merge.conflictStyle=diff3 + return True + if line.rstrip(b'\r\n') == b'=======' and \ + not filepath.endswith('.md'): + return True + return False + + def check_file_line(self, filepath, line, line_number): + if self.issue_with_line(filepath, line): + self.record_issue(filepath, line_number) + class TodoIssueTracker(IssueTracker): def __init__(self): super().__init__() self.heading = "TODO present:" self.files_exemptions = [ - __file__, "benchmark.c", "pull_request_template.md" + os.path.basename(__file__), + "benchmark.c", + "pull_request_template.md", ] def issue_with_line(self, line): @@ -167,6 +193,7 @@ class IntegrityChecker(object): LineEndingIssueTracker(), TrailingWhitespaceIssueTracker(), TabIssueTracker(), + MergeArtifactIssueTracker(), TodoIssueTracker(), ] diff --git a/tests/scripts/mbedtls_test.py b/tests/scripts/mbedtls_test.py index 8e8a89ba9..f9e88cf99 100755 --- a/tests/scripts/mbedtls_test.py +++ b/tests/scripts/mbedtls_test.py @@ -185,7 +185,7 @@ class MbedTlsTest(BaseHostTest): binary_path = self.get_config_item('image_path') script_dir = os.path.split(os.path.abspath(__file__))[0] suite_name = os.path.splitext(os.path.basename(binary_path))[0] - data_file = ".".join((suite_name, 'data')) + data_file = ".".join((suite_name, 'datax')) data_file = os.path.join(script_dir, '..', 'mbedtls', suite_name, data_file) if os.path.exists(data_file): diff --git a/tests/scripts/run-test-suites.pl b/tests/scripts/run-test-suites.pl index 6fe6abfa5..d0d404621 100755 --- a/tests/scripts/run-test-suites.pl +++ b/tests/scripts/run-test-suites.pl @@ -24,14 +24,10 @@ use strict; use utf8; use open qw(:std utf8); -use constant FALSE => 0; -use constant TRUE => 1; +use Getopt::Long; -my $verbose; -my $switch = shift; -if ( defined($switch) && ( $switch eq "-v" || $switch eq "--verbose" ) ) { - $verbose = TRUE; -} +my $verbose = 0; +GetOptions( "verbose|v:1" => \$verbose ); # All test suites = executable files, excluding source files, debug # and profiling information, etc. We can't just grep {! /\./} because @@ -50,10 +46,20 @@ my ($failed_suites, $total_tests_run, $failed, $suite_cases_passed, $suite_cases_failed, $suite_cases_skipped, $total_cases_passed, $total_cases_failed, $total_cases_skipped ); +sub pad_print_center { + my( $width, $padchar, $string ) = @_; + my $padlen = ( $width - length( $string ) - 2 ) / 2; + print $padchar x( $padlen ), " $string ", $padchar x( $padlen ), "\n"; +} + for my $suite (@suites) { print "$suite ", "." x ( 72 - length($suite) - 2 - 4 ), " "; - my $result = `$prefix$suite`; + my $command = "$prefix$suite"; + if( $verbose ) { + $command .= ' -v'; + } + my $result = `$command`; $suite_cases_passed = () = $result =~ /.. PASS/g; $suite_cases_failed = () = $result =~ /.. FAILED/g; @@ -61,15 +67,25 @@ for my $suite (@suites) if( $result =~ /PASSED/ ) { print "PASS\n"; + if( $verbose > 2 ) { + pad_print_center( 72, '-', "Begin $suite" ); + print $result; + pad_print_center( 72, '-', "End $suite" ); + } } else { $failed_suites++; print "FAIL\n"; + if( $verbose ) { + pad_print_center( 72, '-', "Begin $suite" ); + print $result; + pad_print_center( 72, '-', "End $suite" ); + } } my ($passed, $tests, $skipped) = $result =~ /([0-9]*) \/ ([0-9]*) tests.*?([0-9]*) skipped/; $total_tests_run += $tests - $skipped; - if ( $verbose ) { + if( $verbose > 1 ) { print "(test cases passed:", $suite_cases_passed, " failed:", $suite_cases_failed, " skipped:", $suite_cases_skipped, @@ -87,7 +103,7 @@ print "-" x 72, "\n"; print $failed_suites ? "FAILED" : "PASSED"; printf " (%d suites, %d tests run)\n", scalar @suites, $total_tests_run; -if ( $verbose ) { +if( $verbose > 1 ) { print " test cases passed :", $total_cases_passed, "\n"; print " failed :", $total_cases_failed, "\n"; print " skipped :", $total_cases_skipped, "\n"; diff --git a/tests/suites/test_suite_asn1write.function b/tests/suites/test_suite_asn1write.function index aae44a8c6..57a974125 100644 --- a/tests/suites/test_suite_asn1write.function +++ b/tests/suites/test_suite_asn1write.function @@ -78,7 +78,7 @@ void mbedtls_asn1_write_ia5_string( char * str, data_t * asn1, } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_ASN1PARSE_C */ void mbedtls_asn1_write_len( int len, data_t * asn1, int buf_len, int result ) { diff --git a/tests/suites/test_suite_ctr_drbg.function b/tests/suites/test_suite_ctr_drbg.function index f10e98aa5..4a97826f6 100644 --- a/tests/suites/test_suite_ctr_drbg.function +++ b/tests/suites/test_suite_ctr_drbg.function @@ -244,9 +244,11 @@ void ctr_drbg_entropy_usage( ) } TEST_ASSERT( last_idx == test_offset_idx ); - /* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT) - * (just make sure it doesn't cause memory corruption) */ - mbedtls_ctr_drbg_update( &ctx, entropy, sizeof( entropy ) ); + /* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT). + * Make sure it's detected as an error and doesn't cause memory + * corruption. */ + TEST_ASSERT( mbedtls_ctr_drbg_update_ret( + &ctx, entropy, sizeof( entropy ) ) != 0 ); /* Now enable PR, so the next few calls should all reseed */ mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); diff --git a/tests/suites/test_suite_ecdh.data b/tests/suites/test_suite_ecdh.data index 0165a7e0a..89e5e3a80 100644 --- a/tests/suites/test_suite_ecdh.data +++ b/tests/suites/test_suite_ecdh.data @@ -69,3 +69,7 @@ ecdh_restart:MBEDTLS_ECP_DP_SECP256R1:"C88F01F510D9AC3F70A292DAA2316DE544E9AAB8A ECDH restartable rfc 5903 p256 restart disabled max_ops=250 depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED ecdh_restart:MBEDTLS_ECP_DP_SECP256R1:"C88F01F510D9AC3F70A292DAA2316DE544E9AAB8AFE84049C62A9C57862D1433":"C6EF9C5D78AE012A011164ACB397CE2088685D8F06BF9BE0B283AB46476BEE53":"D6840F6B42F6EDAFD13116E0E12565202FEF8E9ECE7DCE03812464D04B9442DE":0:250:0:0 + +ECDH exchange legacy context +depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecdh_exchange_legacy:MBEDTLS_ECP_DP_SECP192R1 diff --git a/tests/suites/test_suite_ecdh.function b/tests/suites/test_suite_ecdh.function index 965230885..7144763a2 100644 --- a/tests/suites/test_suite_ecdh.function +++ b/tests/suites/test_suite_ecdh.function @@ -129,27 +129,31 @@ void ecdh_exchange( int id ) const unsigned char *vbuf; size_t len; rnd_pseudo_info rnd_info; + unsigned char res_buf[1000]; + size_t res_len; mbedtls_ecdh_init( &srv ); mbedtls_ecdh_init( &cli ); memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); - TEST_ASSERT( mbedtls_ecp_group_load( &srv.grp, id ) == 0 ); + TEST_ASSERT( mbedtls_ecdh_setup( &srv, id ) == 0 ); memset( buf, 0x00, sizeof( buf ) ); vbuf = buf; TEST_ASSERT( mbedtls_ecdh_make_params( &srv, &len, buf, 1000, - &rnd_pseudo_rand, &rnd_info ) == 0 ); + &rnd_pseudo_rand, &rnd_info ) == 0 ); TEST_ASSERT( mbedtls_ecdh_read_params( &cli, &vbuf, buf + len ) == 0 ); memset( buf, 0x00, sizeof( buf ) ); TEST_ASSERT( mbedtls_ecdh_make_public( &cli, &len, buf, 1000, - &rnd_pseudo_rand, &rnd_info ) == 0 ); + &rnd_pseudo_rand, &rnd_info ) == 0 ); TEST_ASSERT( mbedtls_ecdh_read_public( &srv, buf, len ) == 0 ); TEST_ASSERT( mbedtls_ecdh_calc_secret( &srv, &len, buf, 1000, - &rnd_pseudo_rand, &rnd_info ) == 0 ); - TEST_ASSERT( mbedtls_ecdh_calc_secret( &cli, &len, buf, 1000, NULL, NULL ) == 0 ); - TEST_ASSERT( mbedtls_mpi_cmp_mpi( &srv.z, &cli.z ) == 0 ); + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( mbedtls_ecdh_calc_secret( &cli, &res_len, res_buf, 1000, + NULL, NULL ) == 0 ); + TEST_ASSERT( len == res_len ); + TEST_ASSERT( memcmp( buf, res_buf, len ) == 0 ); exit: mbedtls_ecdh_free( &srv ); @@ -172,7 +176,9 @@ void ecdh_restart( int id, char *dA_str, char *dB_str, char *z_str, unsigned char rnd_buf_B[MBEDTLS_ECP_MAX_BYTES]; rnd_buf_info rnd_info_A, rnd_info_B; int cnt_restart; + mbedtls_ecp_group grp; + mbedtls_ecp_group_init( &grp ); mbedtls_ecdh_init( &srv ); mbedtls_ecdh_init( &cli ); @@ -184,16 +190,20 @@ void ecdh_restart( int id, char *dA_str, char *dB_str, char *z_str, rnd_info_B.buf = rnd_buf_B; rnd_info_B.length = unhexify( rnd_buf_B, dB_str ); - TEST_ASSERT( mbedtls_ecp_group_load( &srv.grp, id ) == 0 ); + /* The ECDH context is not guaranteed ot have an mbedtls_ecp_group structure + * in every configuration, therefore we load it separately. */ + TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 ); - /* otherwise we would have to fix the random buffer, - * as in ecdh_primitive_test_vec */ - TEST_ASSERT( srv.grp.nbits % 8 == 0 ); + /* Otherwise we would have to fix the random buffer, + * as in ecdh_primitive_testvec. */ + TEST_ASSERT( grp.nbits % 8 == 0 ); + + TEST_ASSERT( mbedtls_ecdh_setup( &srv, id ) == 0 ); /* set up restart parameters */ mbedtls_ecp_set_max_ops( max_ops ); - if( enable) + if( enable ) { mbedtls_ecdh_enable_restart( &srv ); mbedtls_ecdh_enable_restart( &cli ); @@ -268,6 +278,45 @@ void ecdh_restart( int id, char *dA_str, char *dB_str, char *z_str, TEST_ASSERT( len == z_len ); TEST_ASSERT( memcmp( buf, z, len ) == 0 ); +exit: + mbedtls_ecp_group_free( &grp ); + mbedtls_ecdh_free( &srv ); + mbedtls_ecdh_free( &cli ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ECDH_LEGACY_CONTEXT */ +void ecdh_exchange_legacy( int id ) +{ + mbedtls_ecdh_context srv, cli; + unsigned char buf[1000]; + const unsigned char *vbuf; + size_t len; + + rnd_pseudo_info rnd_info; + + mbedtls_ecdh_init( &srv ); + mbedtls_ecdh_init( &cli ); + memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) ); + + TEST_ASSERT( mbedtls_ecp_group_load( &srv.grp, id ) == 0 ); + + memset( buf, 0x00, sizeof( buf ) ); vbuf = buf; + TEST_ASSERT( mbedtls_ecdh_make_params( &srv, &len, buf, 1000, + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( mbedtls_ecdh_read_params( &cli, &vbuf, buf + len ) == 0 ); + + memset( buf, 0x00, sizeof( buf ) ); + TEST_ASSERT( mbedtls_ecdh_make_public( &cli, &len, buf, 1000, + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( mbedtls_ecdh_read_public( &srv, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecdh_calc_secret( &srv, &len, buf, 1000, + &rnd_pseudo_rand, &rnd_info ) == 0 ); + TEST_ASSERT( mbedtls_ecdh_calc_secret( &cli, &len, buf, 1000, NULL, + NULL ) == 0 ); + TEST_ASSERT( mbedtls_mpi_cmp_mpi( &srv.z, &cli.z ) == 0 ); + exit: mbedtls_ecdh_free( &srv ); mbedtls_ecdh_free( &cli ); diff --git a/tests/suites/test_suite_ecdsa.function b/tests/suites/test_suite_ecdsa.function index 7f8995294..71078329b 100644 --- a/tests/suites/test_suite_ecdsa.function +++ b/tests/suites/test_suite_ecdsa.function @@ -14,7 +14,7 @@ void ecdsa_prim_random( int id ) mbedtls_ecp_point Q; mbedtls_mpi d, r, s; rnd_pseudo_info rnd_info; - unsigned char buf[66]; + unsigned char buf[MBEDTLS_MD_MAX_SIZE]; mbedtls_ecp_group_init( &grp ); mbedtls_ecp_point_init( &Q ); diff --git a/tests/suites/test_suite_pkcs1_v15.data b/tests/suites/test_suite_pkcs1_v15.data index 030940007..a4d6eb545 100644 --- a/tests/suites/test_suite_pkcs1_v15.data +++ b/tests/suites/test_suite_pkcs1_v15.data @@ -33,3 +33,93 @@ pkcs1_rsassa_v15_sign:1024:16:"d17f655bf27c8b16d35462c905cc04a26f37e2a67fa9c0ce0 RSASSA-V15 Verification Test Vector Int pkcs1_rsassa_v15_verify:1024:16:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":16:"010001":MBEDTLS_MD_SHA1:MBEDTLS_MD_SHA1:"859eef2fd78aca00308bdc471193bf55bf9d78db8f8a672b484634f3c9c26e6478ae10260fe0dd8c082e53a5293af2173cd50c6d5d354febf78b26021c25c02712e78cd4694c9f469777e451e7f8e9e04cd3739c6bbfedae487fb55644e9ca74ff77a53cb729802f6ed4a5ffa8ba159890fc":"e3b5d5d002c1bce50c2b65ef88a188d83bce7e61":"2154f928615e5101fcdeb57bc08fc2f35c3d5996403861ae3efb1d0712f8bb05cc21f7f5f11f62e5b6ea9f0f2b62180e5cbe7ba535032d6ac8068fff7f362f73d2c3bf5eca6062a1723d7cfd5abb6dcf7e405f2dc560ffe6fc37d38bee4dc9e24fe2bece3e3b4a3f032701d3f0947b42930083dd4ad241b3309b514595482d42":0 + +RSAES-V15 decoding: good, payload=max, tight output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505152535455565700":117:117:0 + +RSAES-V15 decoding: good, payload=max, larger output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505152535455565700":117:128:0 + +RSAES-V15 decoding: good, payload=max-1, tight output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000250515253545556575800":116:116:0 + +RSAES-V15 decoding: good, payload=max-1, larger output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000250515253545556575800":116:117:0 + +RSAES-V15 decoding: good, payload=1 +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"00025050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":1:1:0 + +RSAES-V15 decoding: good, empty payload +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505000":0:0:0 + +RSAES-V15 decoding: payload=max, output too large +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505152535455565700":117:116:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE + +RSAES-V15 decoding: payload=max-1, output too large +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000250515253545556575800":116:115:MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE + +RSAES-V15 decoding: bad first byte +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0102505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSAES-V15 decoding: bad second byte (0 instead of 2) +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0000505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSAES-V15 decoding: bad second byte (1 instead of 2) +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0001505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSAES-V15 decoding: padding too short (0) +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"000200":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSAES-V15 decoding: padding too short (7) +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505050505050500000ffffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +RSAES-V15 decoding: unfinished padding +pkcs1_v15_decode:MBEDTLS_RSA_PRIVATE:"0002505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: good, payload=max, tight output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffff00":117:117:0 + +EMSA-V15 decoding: good, payload=max, larger output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffff00":117:128:0 + +EMSA-V15 decoding: good, payload=max-1, tight output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffff00":116:116:0 + +EMSA-V15 decoding: good, payload=max-1, larger output buffer +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffff00":116:117:0 + +EMSA-V15 decoding: good, payload=1 +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00":1:1:0 + +EMSA-V15 decoding: good, empty payload +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00":0:0:0 + +EMSA-V15 decoding: bad first byte +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0101ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: bad second byte (0 instead of 1) +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0000ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: bad second byte (2 instead of 1) +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0002ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: padding too short (0) +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"000100":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: padding too short (7) +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffff0000ffffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: invalid padding at first byte +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001fffffffffffffffe00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: invalid padding at last byte +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001feffffffffffffff00":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: unfinished padding +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: unfinished padding with invalid first byte +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING + +EMSA-V15 decoding: unfinished padding with invalid last byte +pkcs1_v15_decode:MBEDTLS_RSA_PUBLIC:"0001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe":0:42:MBEDTLS_ERR_RSA_INVALID_PADDING diff --git a/tests/suites/test_suite_pkcs1_v15.function b/tests/suites/test_suite_pkcs1_v15.function index 83f417ca8..0723623a5 100644 --- a/tests/suites/test_suite_pkcs1_v15.function +++ b/tests/suites/test_suite_pkcs1_v15.function @@ -93,6 +93,154 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void pkcs1_v15_decode( int mode, + data_t *input, + int expected_plaintext_length_arg, + int output_size_arg, + int expected_result ) +{ + size_t expected_plaintext_length = expected_plaintext_length_arg; + size_t output_size = output_size_arg; + rnd_pseudo_info rnd_info; + mbedtls_mpi Nmpi, Empi, Pmpi, Qmpi; + mbedtls_rsa_context ctx; + static unsigned char N[128] = { + 0xc4, 0x79, 0x4c, 0x6d, 0xb2, 0xe9, 0xdf, 0xc5, + 0xe5, 0xd7, 0x55, 0x4b, 0xfb, 0x6c, 0x2e, 0xec, + 0x84, 0xd0, 0x88, 0x12, 0xaf, 0xbf, 0xb4, 0xf5, + 0x47, 0x3c, 0x7e, 0x92, 0x4c, 0x58, 0xc8, 0x73, + 0xfe, 0x8f, 0x2b, 0x8f, 0x8e, 0xc8, 0x5c, 0xf5, + 0x05, 0xeb, 0xfb, 0x0d, 0x7b, 0x2a, 0x93, 0xde, + 0x15, 0x0d, 0xc8, 0x13, 0xcf, 0xd2, 0x6f, 0x0d, + 0x9d, 0xad, 0x30, 0xe5, 0x70, 0x20, 0x92, 0x9e, + 0xb3, 0x6b, 0xba, 0x5c, 0x50, 0x0f, 0xc3, 0xb2, + 0x7e, 0x64, 0x07, 0x94, 0x7e, 0xc9, 0x4e, 0xc1, + 0x65, 0x04, 0xaf, 0xb3, 0x9f, 0xde, 0xa8, 0x46, + 0xfa, 0x6c, 0xf3, 0x03, 0xaf, 0x1c, 0x1b, 0xec, + 0x75, 0x44, 0x66, 0x77, 0xc9, 0xde, 0x51, 0x33, + 0x64, 0x27, 0xb0, 0xd4, 0x8d, 0x31, 0x6a, 0x11, + 0x27, 0x3c, 0x99, 0xd4, 0x22, 0xc0, 0x9d, 0x12, + 0x01, 0xc7, 0x4a, 0x73, 0xac, 0xbf, 0xc2, 0xbb + }; + static unsigned char E[1] = { 0x03 }; + static unsigned char P[64] = { + 0xe5, 0x53, 0x1f, 0x88, 0x51, 0xee, 0x59, 0xf8, + 0xc1, 0xe4, 0xcc, 0x5b, 0xb3, 0x75, 0x8d, 0xc8, + 0xe8, 0x95, 0x2f, 0xd0, 0xef, 0x37, 0xb4, 0xcd, + 0xd3, 0x9e, 0x48, 0x8b, 0x81, 0x58, 0x60, 0xb9, + 0x27, 0x1d, 0xb6, 0x28, 0x92, 0x64, 0xa3, 0xa5, + 0x64, 0xbd, 0xcc, 0x53, 0x68, 0xdd, 0x3e, 0x55, + 0xea, 0x9d, 0x5e, 0xcd, 0x1f, 0x96, 0x87, 0xf1, + 0x29, 0x75, 0x92, 0x70, 0x8f, 0x28, 0xfb, 0x2b + }; + static unsigned char Q[64] = { + 0xdb, 0x53, 0xef, 0x74, 0x61, 0xb4, 0x20, 0x3b, + 0x3b, 0x87, 0x76, 0x75, 0x81, 0x56, 0x11, 0x03, + 0x59, 0x31, 0xe3, 0x38, 0x4b, 0x8c, 0x7a, 0x9c, + 0x05, 0xd6, 0x7f, 0x1e, 0x5e, 0x60, 0xf0, 0x4e, + 0x0b, 0xdc, 0x34, 0x54, 0x1c, 0x2e, 0x90, 0x83, + 0x14, 0xef, 0xc0, 0x96, 0x5c, 0x30, 0x10, 0xcc, + 0xc1, 0xba, 0xa0, 0x54, 0x3f, 0x96, 0x24, 0xca, + 0xa3, 0xfb, 0x55, 0xbc, 0x71, 0x29, 0x4e, 0xb1 + }; + unsigned char original[128]; + unsigned char intermediate[128]; + static unsigned char default_content[128] = { + /* A randomly generated pattern. */ + 0x4c, 0x27, 0x54, 0xa0, 0xce, 0x0d, 0x09, 0x4a, + 0x1c, 0x38, 0x8e, 0x2d, 0xa3, 0xc4, 0xe0, 0x19, + 0x4c, 0x99, 0xb2, 0xbf, 0xe6, 0x65, 0x7e, 0x58, + 0xd7, 0xb6, 0x8a, 0x05, 0x2f, 0xa5, 0xec, 0xa4, + 0x35, 0xad, 0x10, 0x36, 0xff, 0x0d, 0x08, 0x50, + 0x74, 0x47, 0xc9, 0x9c, 0x4a, 0xe7, 0xfd, 0xfa, + 0x83, 0x5f, 0x14, 0x5a, 0x1e, 0xe7, 0x35, 0x08, + 0xad, 0xf7, 0x0d, 0x86, 0xdf, 0xb8, 0xd4, 0xcf, + 0x32, 0xb9, 0x5c, 0xbe, 0xa3, 0xd2, 0x89, 0x70, + 0x7b, 0xc6, 0x48, 0x7e, 0x58, 0x4d, 0xf3, 0xef, + 0x34, 0xb7, 0x57, 0x54, 0x79, 0xc5, 0x8e, 0x0a, + 0xa3, 0xbf, 0x6d, 0x42, 0x83, 0x25, 0x13, 0xa2, + 0x95, 0xc0, 0x0d, 0x32, 0xec, 0x77, 0x91, 0x2b, + 0x68, 0xb6, 0x8c, 0x79, 0x15, 0xfb, 0x94, 0xde, + 0xb9, 0x2b, 0x94, 0xb3, 0x28, 0x23, 0x86, 0x3d, + 0x37, 0x00, 0xe6, 0xf1, 0x1f, 0x4e, 0xd4, 0x42 + }; + unsigned char final[128]; + size_t output_length = 0x7EA0; + + memset( &rnd_info, 0, sizeof( rnd_pseudo_info ) ); + mbedtls_mpi_init( &Nmpi ); mbedtls_mpi_init( &Empi ); + mbedtls_mpi_init( &Pmpi ); mbedtls_mpi_init( &Qmpi ); + mbedtls_rsa_init( &ctx, MBEDTLS_RSA_PKCS_V15, 0 ); + + TEST_ASSERT( mbedtls_mpi_read_binary( &Nmpi, N, sizeof( N ) ) == 0 ); + TEST_ASSERT( mbedtls_mpi_read_binary( &Empi, E, sizeof( E ) ) == 0 ); + TEST_ASSERT( mbedtls_mpi_read_binary( &Pmpi, P, sizeof( P ) ) == 0 ); + TEST_ASSERT( mbedtls_mpi_read_binary( &Qmpi, Q, sizeof( Q ) ) == 0 ); + + TEST_ASSERT( mbedtls_rsa_import( &ctx, &Nmpi, &Pmpi, &Qmpi, + NULL, &Empi ) == 0 ); + TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 ); + + TEST_ASSERT( input->len <= sizeof( N ) ); + memcpy( original, input->x, input->len ); + memset( original + input->len, 'd', sizeof( original ) - input->len ); + if( mode == MBEDTLS_RSA_PRIVATE ) + TEST_ASSERT( mbedtls_rsa_public( &ctx, original, intermediate ) == 0 ); + else + TEST_ASSERT( mbedtls_rsa_private( &ctx, &rnd_pseudo_rand, &rnd_info, + original, intermediate ) == 0 ); + + memcpy( final, default_content, sizeof( final ) ); + TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, + &rnd_pseudo_rand, &rnd_info, + mode, + &output_length, + intermediate, + final, + output_size ) == expected_result ); + if( expected_result == 0 ) + { + TEST_ASSERT( output_length == expected_plaintext_length ); + TEST_ASSERT( memcmp( original + sizeof( N ) - output_length, + final, + output_length ) == 0 ); + } + else if( expected_result == MBEDTLS_ERR_RSA_INVALID_PADDING || + expected_result == MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ) + { + size_t max_payload_length = + output_size > sizeof( N ) - 11 ? sizeof( N ) - 11 : output_size; + size_t i; + size_t count = 0; + +#if !defined(MBEDTLS_RSA_ALT) + /* Check that the output in invalid cases is what the default + * implementation currently does. Alternative implementations + * may produce different output, so we only perform these precise + * checks when using the default implementation. */ + TEST_ASSERT( output_length == max_payload_length ); + for( i = 0; i < max_payload_length; i++ ) + TEST_ASSERT( final[i] == 0 ); +#endif + /* Even in alternative implementations, the outputs must have + * changed, otherwise it indicates at least a timing vulnerability + * because no write to the outputs is performed in the bad case. */ + TEST_ASSERT( output_length != 0x7EA0 ); + for( i = 0; i < max_payload_length; i++ ) + count += ( final[i] == default_content[i] ); + /* If more than 16 bytes are unchanged in final, that's evidence + * that final wasn't overwritten. */ + TEST_ASSERT( count < 16 ); + } + +exit: + mbedtls_mpi_free( &Nmpi ); mbedtls_mpi_free( &Empi ); + mbedtls_mpi_free( &Pmpi ); mbedtls_mpi_free( &Qmpi ); + mbedtls_rsa_free( &ctx ); +} +/* END_CASE */ + /* BEGIN_CASE */ void pkcs1_rsassa_v15_sign( int mod, int radix_P, char * input_P, int radix_Q, char * input_Q, int radix_N, char * input_N, diff --git a/tests/suites/test_suite_pkwrite.function b/tests/suites/test_suite_pkwrite.function index 3ad782d33..43c275ef2 100644 --- a/tests/suites/test_suite_pkwrite.function +++ b/tests/suites/test_suite_pkwrite.function @@ -5,7 +5,7 @@ /* END_HEADER */ /* BEGIN_DEPENDENCIES - * depends_on:MBEDTLS_PK_WRITE_C:MBEDTLS_BIGNUM_C:MBEDTLS_FS_IO + * depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_BIGNUM_C:MBEDTLS_FS_IO * END_DEPENDENCIES */