Merge remote-tracking branch 'public/pr/2283' into development
diff --git a/include/mbedtls/dhm.h b/include/mbedtls/dhm.h
index 27e3753..a5452c1 100644
--- a/include/mbedtls/dhm.h
+++ b/include/mbedtls/dhm.h
@@ -127,9 +127,15 @@
void mbedtls_dhm_init( mbedtls_dhm_context *ctx );
/**
- * \brief This function parses the ServerKeyExchange parameters.
+ * \brief This function parses the DHM parameters in a
+ * TLS ServerKeyExchange handshake message
+ * (DHM modulus, generator, and public key).
*
- * \param ctx The DHM context.
+ * \note In a TLS handshake, this is the how the client
+ * sets up its DHM context from the server's public
+ * DHM key material.
+ *
+ * \param ctx The DHM context to use. This must be initialized.
* \param p On input, *p must be the start of the input buffer.
* On output, *p is updated to point to the end of the data
* that has been read. On success, this is the first byte
@@ -143,31 +149,37 @@
* \return An \c MBEDTLS_ERR_DHM_XXX error code on failure.
*/
int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
- unsigned char **p,
- const unsigned char *end );
+ unsigned char **p,
+ const unsigned char *end );
/**
- * \brief This function sets up and writes the ServerKeyExchange
- * parameters.
+ * \brief This function generates a DHM key pair and exports its
+ * public part together with the DHM parameters in the format
+ * used in a TLS ServerKeyExchange handshake message.
*
- * \note The destination buffer must be large enough to hold
- * the reduced binary presentation of the modulus, the generator
- * and the public key, each wrapped with a 2-byte length field.
- * It is the responsibility of the caller to ensure that enough
- * space is available. Refer to \c mbedtls_mpi_size to computing
- * the byte-size of an MPI.
- *
- * \note This function assumes that \c ctx->P and \c ctx->G
- * have already been properly set. For that, use
+ * \note This function assumes that the DHM parameters \c ctx->P
+ * and \c ctx->G have already been properly set. For that, use
* mbedtls_dhm_set_group() below in conjunction with
* mbedtls_mpi_read_binary() and mbedtls_mpi_read_string().
*
- * \param ctx The DHM context.
+ * \note In a TLS handshake, this is the how the server generates
+ * and exports its DHM key material.
+ *
+ * \param ctx The DHM context to use. This must be initialized
+ * and have the DHM parameters set. It may or may not
+ * already have imported the peer's public key.
* \param x_size The private key size in Bytes.
- * \param olen The number of characters written.
- * \param output The destination buffer.
- * \param f_rng The RNG function.
- * \param p_rng The RNG context.
+ * \param olen The address at which to store the number of Bytes
+ * written on success. This must not be \c NULL.
+ * \param output The destination buffer. This must be a writable buffer of
+ * sufficient size to hold the reduced binary presentation of
+ * the modulus, the generator and the public key, each wrapped
+ * with a 2-byte length field. It is the responsibility of the
+ * caller to ensure that enough space is available. Refer to
+ * mbedtls_mpi_size() to computing the byte-size of an MPI.
+ * \param f_rng The RNG function. Must not be \c NULL.
+ * \param p_rng The RNG context to be passed to \p f_rng. This may be
+ * \c NULL if \p f_rng doesn't need a context parameter.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_DHM_XXX error code on failure.
@@ -180,12 +192,14 @@
/**
* \brief This function sets the prime modulus and generator.
*
- * \note This function can be used to set \p P, \p G
+ * \note This function can be used to set \c ctx->P, \c ctx->G
* in preparation for mbedtls_dhm_make_params().
*
- * \param ctx The DHM context.
- * \param P The MPI holding the DHM prime modulus.
- * \param G The MPI holding the DHM generator.
+ * \param ctx The DHM context to configure. This must be initialized.
+ * \param P The MPI holding the DHM prime modulus. This must be
+ * an initialized MPI.
+ * \param G The MPI holding the DHM generator. This must be an
+ * initialized MPI.
*
* \return \c 0 if successful.
* \return An \c MBEDTLS_ERR_DHM_XXX error code on failure.
@@ -195,11 +209,17 @@
const mbedtls_mpi *G );
/**
- * \brief This function imports the public value of the peer, G^Y.
+ * \brief This function imports the raw public value of the peer.
*
- * \param ctx The DHM context.
- * \param input The input buffer containing the G^Y value of the peer.
- * \param ilen The size of the input buffer.
+ * \note In a TLS handshake, this is the how the server imports
+ * the Client's public DHM key.
+ *
+ * \param ctx The DHM context to use. This must be initialized and have
+ * its DHM parameters set, e.g. via mbedtls_dhm_set_group().
+ * It may or may not already have generated its own private key.
+ * \param input The input buffer containing the \c G^Y value of the peer.
+ * This must be a readable buffer of size \p ilen Bytes.
+ * \param ilen The size of the input buffer \p input in Bytes.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_DHM_XXX error code on failure.
@@ -208,21 +228,25 @@
const unsigned char *input, size_t ilen );
/**
- * \brief This function creates its own private key, \c X, and
- * exports \c G^X.
+ * \brief This function creates a DHM key pair and exports
+ * the raw public key in big-endian format.
*
* \note The destination buffer is always fully written
* so as to contain a big-endian representation of G^X mod P.
- * If it is larger than ctx->len, it is padded accordingly
+ * If it is larger than \c ctx->len, it is padded accordingly
* with zero-bytes at the beginning.
*
- * \param ctx The DHM context.
+ * \param ctx The DHM context to use. This must be initialized and
+ * have the DHM parameters set. It may or may not already
+ * have imported the peer's public key.
* \param x_size The private key size in Bytes.
- * \param output The destination buffer.
- * \param olen The length of the destination buffer. Must be at least
- * equal to ctx->len (the size of \c P).
- * \param f_rng The RNG function.
- * \param p_rng The RNG context.
+ * \param output The destination buffer. This must be a writable buffer of
+ * size \p olen Bytes.
+ * \param olen The length of the destination buffer. This must be at least
+ * equal to `ctx->len` (the size of \c P).
+ * \param f_rng The RNG function. This must not be \c NULL.
+ * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL
+ * if \p f_rng doesn't need a context argument.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_DHM_XXX error code on failure.
@@ -233,22 +257,27 @@
void *p_rng );
/**
- * \brief This function derives and exports the shared secret
- * \c (G^Y)^X mod \c P.
+ * \brief This function derives and exports the shared secret
+ * \c (G^Y)^X mod \c P.
*
- * \note If \p f_rng is not NULL, it is used to blind the input as
- * a countermeasure against timing attacks. Blinding is used
- * only if our private key \c X is re-used, and not used
- * otherwise. We recommend always passing a non-NULL
- * \p f_rng argument.
+ * \note If \p f_rng is not \c NULL, it is used to blind the input as
+ * a countermeasure against timing attacks. Blinding is used
+ * only if our private key \c X is re-used, and not used
+ * otherwise. We recommend always passing a non-NULL
+ * \p f_rng argument.
*
- * \param ctx The DHM context.
- * \param output The destination buffer.
- * \param output_size The size of the destination buffer. Must be at least
- * the size of ctx->len (the size of \c P).
+ * \param ctx The DHM context to use. This must be initialized
+ * and have its own private key generated and the peer's
+ * public key imported.
+ * \param output The buffer to write the generated shared key to. This
+ * must be a writable buffer of size \p output_size Bytes.
+ * \param output_size The size of the destination buffer. This must be at
+ * least the size of \c ctx->len (the size of \c P).
* \param olen On exit, holds the actual number of Bytes written.
- * \param f_rng The RNG function, for blinding purposes.
- * \param p_rng The RNG context.
+ * \param f_rng The RNG function, for blinding purposes. This may
+ * b \c NULL if blinding isn't needed.
+ * \param p_rng The RNG context. This may be \c NULL if \p f_rng
+ * doesn't need a context argument.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_DHM_XXX error code on failure.
@@ -259,9 +288,12 @@
void *p_rng );
/**
- * \brief This function frees and clears the components of a DHM context.
+ * \brief This function frees and clears the components
+ * of a DHM context.
*
- * \param ctx The DHM context to free and clear.
+ * \param ctx The DHM context to free and clear. This may be \c NULL,
+ * in which case this function is a no-op. If it is not \c NULL,
+ * it must point to an initialized DHM context.
*/
void mbedtls_dhm_free( mbedtls_dhm_context *ctx );
@@ -270,17 +302,19 @@
/**
* \brief This function parses DHM parameters in PEM or DER format.
*
- * \param dhm The DHM context to initialize.
- * \param dhmin The input buffer.
- * \param dhminlen The size of the buffer, including the terminating null
- * Byte for PEM data.
+ * \param dhm The DHM context to import the DHM parameters into.
+ * This must be initialized.
+ * \param dhmin The input buffer. This must be a readable buffer of
+ * length \p dhminlen Bytes.
+ * \param dhminlen The size of the input buffer \p dhmin, including the
+ * terminating \c NULL Byte for PEM data.
*
* \return \c 0 on success.
- * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX error code
- * error code on failure.
+ * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX error
+ * code on failure.
*/
int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
- size_t dhminlen );
+ size_t dhminlen );
#if defined(MBEDTLS_FS_IO)
/** \ingroup x509_module */
@@ -288,11 +322,13 @@
* \brief This function loads and parses DHM parameters from a file.
*
* \param dhm The DHM context to load the parameters to.
+ * This must be initialized.
* \param path The filename to read the DHM parameters from.
+ * This must not be \c NULL.
*
* \return \c 0 on success.
- * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX error code
- * error code on failure.
+ * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX
+ * error code on failure.
*/
int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path );
#endif /* MBEDTLS_FS_IO */
diff --git a/library/dhm.c b/library/dhm.c
index 82cbb0c..ee28572 100644
--- a/library/dhm.c
+++ b/library/dhm.c
@@ -60,6 +60,11 @@
#if !defined(MBEDTLS_DHM_ALT)
+#define DHM_VALIDATE_RET( cond ) \
+ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA )
+#define DHM_VALIDATE( cond ) \
+ MBEDTLS_INTERNAL_VALIDATE( cond )
+
/*
* helper to validate the mbedtls_mpi size and import it
*/
@@ -121,6 +126,7 @@
void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
{
+ DHM_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
}
@@ -132,6 +138,9 @@
const unsigned char *end )
{
int ret;
+ DHM_VALIDATE_RET( ctx != NULL );
+ DHM_VALIDATE_RET( p != NULL && *p != NULL );
+ DHM_VALIDATE_RET( end != NULL );
if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
@@ -157,6 +166,10 @@
int ret, count = 0;
size_t n1, n2, n3;
unsigned char *p;
+ DHM_VALIDATE_RET( ctx != NULL );
+ DHM_VALIDATE_RET( output != NULL );
+ DHM_VALIDATE_RET( olen != NULL );
+ DHM_VALIDATE_RET( f_rng != NULL );
if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
@@ -227,9 +240,9 @@
const mbedtls_mpi *G )
{
int ret;
-
- if( ctx == NULL || P == NULL || G == NULL )
- return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
+ DHM_VALIDATE_RET( ctx != NULL );
+ DHM_VALIDATE_RET( P != NULL );
+ DHM_VALIDATE_RET( G != NULL );
if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
@@ -248,8 +261,10 @@
const unsigned char *input, size_t ilen )
{
int ret;
+ DHM_VALIDATE_RET( ctx != NULL );
+ DHM_VALIDATE_RET( input != NULL );
- if( ctx == NULL || ilen < 1 || ilen > ctx->len )
+ if( ilen < 1 || ilen > ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
@@ -267,8 +282,11 @@
void *p_rng )
{
int ret, count = 0;
+ DHM_VALIDATE_RET( ctx != NULL );
+ DHM_VALIDATE_RET( output != NULL );
+ DHM_VALIDATE_RET( f_rng != NULL );
- if( ctx == NULL || olen < 1 || olen > ctx->len )
+ if( olen < 1 || olen > ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
@@ -380,8 +398,11 @@
{
int ret;
mbedtls_mpi GYb;
+ DHM_VALIDATE_RET( ctx != NULL );
+ DHM_VALIDATE_RET( output != NULL );
+ DHM_VALIDATE_RET( olen != NULL );
- if( ctx == NULL || output_size < ctx->len )
+ if( output_size < ctx->len )
return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
@@ -428,6 +449,9 @@
*/
void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
{
+ if( ctx == NULL )
+ return;
+
mbedtls_mpi_free( &ctx->pX ); mbedtls_mpi_free( &ctx->Vf );
mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->RP );
mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY );
@@ -449,7 +473,12 @@
unsigned char *p, *end;
#if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_context pem;
+#endif /* MBEDTLS_PEM_PARSE_C */
+ DHM_VALIDATE_RET( dhm != NULL );
+ DHM_VALIDATE_RET( dhmin != NULL );
+
+#if defined(MBEDTLS_PEM_PARSE_C)
mbedtls_pem_init( &pem );
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
@@ -596,6 +625,8 @@
int ret;
size_t n;
unsigned char *buf;
+ DHM_VALIDATE_RET( dhm != NULL );
+ DHM_VALIDATE_RET( path != NULL );
if( ( ret = load_file( path, &buf, &n ) ) != 0 )
return( ret );
diff --git a/tests/suites/test_suite_dhm.data b/tests/suites/test_suite_dhm.data
index 734fd97..edebce0 100644
--- a/tests/suites/test_suite_dhm.data
+++ b/tests/suites/test_suite_dhm.data
@@ -1,3 +1,6 @@
+Diffie-Hellman parameter validation
+dhm_invalid_params:
+
Diffie-Hellman full exchange #1
dhm_do_dhm:10:"23":10:"5":0
diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function
index 9a4c99c..8a05a38 100644
--- a/tests/suites/test_suite_dhm.function
+++ b/tests/suites/test_suite_dhm.function
@@ -7,6 +7,113 @@
* END_DEPENDENCIES
*/
+/* BEGIN_CASE depends_on:MBEDTLS_CHECK_PARAMS:!MBEDTLS_PARAM_FAILED_ALT */
+void dhm_invalid_params( )
+{
+ mbedtls_dhm_context ctx;
+ unsigned char buf[42] = { 0 };
+ unsigned char *buf_null = NULL;
+ mbedtls_mpi X;
+ size_t const buflen = sizeof( buf );
+ size_t len;
+
+ TEST_INVALID_PARAM( mbedtls_dhm_init( NULL ) );
+ TEST_VALID_PARAM( mbedtls_dhm_free( NULL ) );
+
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_read_params( NULL,
+ (unsigned char**) &buf,
+ buf ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_read_params( &ctx, &buf_null, buf ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_read_params( &ctx, NULL, buf ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_read_params( &ctx,
+ (unsigned char**) &buf,
+ NULL ) );
+
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_make_params( NULL, buflen,
+ buf, &len,
+ rnd_std_rand,
+ NULL ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_make_params( &ctx, buflen,
+ NULL, &len,
+ rnd_std_rand,
+ NULL ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_make_params( &ctx, buflen,
+ buf, NULL,
+ rnd_std_rand,
+ NULL ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_make_params( &ctx, buflen,
+ buf, &len,
+ NULL,
+ NULL ) );
+
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_set_group( NULL, &X, &X ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_set_group( &ctx, NULL, &X ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_set_group( &ctx, &X, NULL ) );
+
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_read_public( NULL, buf, buflen ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_read_public( &ctx, NULL, buflen ) );
+
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_make_public( NULL, buflen,
+ buf, buflen,
+ rnd_std_rand,
+ NULL ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_make_public( &ctx, buflen,
+ NULL, buflen,
+ rnd_std_rand,
+ NULL ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_make_public( &ctx, buflen,
+ buf, buflen,
+ NULL,
+ NULL ) );
+
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_calc_secret( NULL, buf, buflen,
+ &len, rnd_std_rand,
+ NULL ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_calc_secret( &ctx, NULL, buflen,
+ &len, rnd_std_rand,
+ NULL ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_calc_secret( &ctx, buf, buflen,
+ NULL, rnd_std_rand,
+ NULL ) );
+
+#if defined(MBEDTLS_ASN1_PARSE_C)
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_parse_dhm( NULL, buf, buflen ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_parse_dhm( &ctx, NULL, buflen ) );
+
+#if defined(MBEDTLS_FS_IO)
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_parse_dhmfile( NULL, "" ) );
+ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_DHM_BAD_INPUT_DATA,
+ mbedtls_dhm_parse_dhmfile( &ctx, NULL ) );
+#endif /* MBEDTLS_FS_IO */
+#endif /* MBEDTLS_ASN1_PARSE_C */
+
+exit:
+ return;
+}
+/* END_CASE */
+
/* BEGIN_CASE */
void dhm_do_dhm( int radix_P, char *input_P,
int radix_G, char *input_G, int result )