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 )