DHM: new functions to query the length of the modulus

Add two functions mbedtls_dhm_get_len() and mbedtls_dhm_get_bitlen() to
query the length of the modulus in bytes or bits.

Remove the len field: the cost of calling mbedtls_dhm_get_len() each time
it's needed is negligible, and this improves the abstraction of the DHM
module.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/ChangeLog.d/dhm-fields.txt b/ChangeLog.d/dhm-fields.txt
new file mode 100644
index 0000000..620e3dc
--- /dev/null
+++ b/ChangeLog.d/dhm-fields.txt
@@ -0,0 +1,7 @@
+Features
+   * The new functions mbedtls_dhm_get_len() and mbedtls_dhm_get_bitlen()
+     query the size of the modulus in a Diffie-Hellman context.
+
+API changes
+   * Instead of accessing the len field of a DHM context, which is no longer
+     supported, use the new function mbedtls_dhm_get_len() .
diff --git a/include/mbedtls/dhm.h b/include/mbedtls/dhm.h
index 6c8ca03..3f7206e 100644
--- a/include/mbedtls/dhm.h
+++ b/include/mbedtls/dhm.h
@@ -96,7 +96,6 @@
  */
 typedef struct mbedtls_dhm_context
 {
-    size_t MBEDTLS_PRIVATE(len);         /*!<  The size of \p P in Bytes. */
     mbedtls_mpi MBEDTLS_PRIVATE(P);      /*!<  The prime modulus. */
     mbedtls_mpi MBEDTLS_PRIVATE(G);      /*!<  The generator. */
     mbedtls_mpi MBEDTLS_PRIVATE(X);      /*!<  Our secret value. */
@@ -283,6 +282,26 @@
                      void *p_rng );
 
 /**
+ * \brief          This function returns the size of the prime modulus in bits.
+ *
+ * \param ctx      The DHM context to query.
+ *
+ * \return         The size of the prime modulus in bits,
+ *                 i.e. the number n such that 2^(n-1) <= P < 2^n.
+ */
+size_t mbedtls_dhm_get_bitlen( const mbedtls_dhm_context *ctx );
+
+/**
+ * \brief          This function returns the size of the prime modulus in bytes.
+ *
+ * \param ctx      The DHM context to query.
+ *
+ * \return         The size of the prime modulus in bytes,
+ *                 i.e. the number n such that 2^(8*(n-1)) <= P < 2^(8*n).
+ */
+size_t mbedtls_dhm_get_len( const mbedtls_dhm_context *ctx );
+
+/**
  * \brief          This function frees and clears the components
  *                 of a DHM context.
  *
diff --git a/library/dhm.c b/library/dhm.c
index accd5a8..2543be1 100644
--- a/library/dhm.c
+++ b/library/dhm.c
@@ -124,6 +124,16 @@
     memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
 }
 
+size_t mbedtls_dhm_get_bitlen( const mbedtls_dhm_context *ctx )
+{
+    return( mbedtls_mpi_bitlen( &ctx->P ) );
+}
+
+size_t mbedtls_dhm_get_len( const mbedtls_dhm_context *ctx )
+{
+    return( mbedtls_mpi_size( &ctx->P ) );
+}
+
 /*
  * Parse the ServerKeyExchange parameters
  */
@@ -144,8 +154,6 @@
     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
         return( ret );
 
-    ctx->len = mbedtls_mpi_size( &ctx->P );
-
     return( 0 );
 }
 
@@ -247,8 +255,6 @@
 
     *olen = p - output;
 
-    ctx->len = n1;
-
 cleanup:
     if( ret != 0 && ret > -128 )
         ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED, ret );
@@ -273,7 +279,6 @@
         return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_SET_GROUP_FAILED, ret ) );
     }
 
-    ctx->len = mbedtls_mpi_size( &ctx->P );
     return( 0 );
 }
 
@@ -287,7 +292,7 @@
     DHM_VALIDATE_RET( ctx != NULL );
     DHM_VALIDATE_RET( input != NULL );
 
-    if( ilen < 1 || ilen > ctx->len )
+    if( ilen < 1 || ilen > mbedtls_dhm_get_len( ctx ) )
         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
     if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
@@ -309,7 +314,7 @@
     DHM_VALIDATE_RET( output != NULL );
     DHM_VALIDATE_RET( f_rng != NULL );
 
-    if( olen < 1 || olen > ctx->len )
+    if( olen < 1 || olen > mbedtls_dhm_get_len( ctx ) )
         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
     ret = dhm_make_common( ctx, x_size, f_rng, p_rng );
@@ -408,7 +413,7 @@
     DHM_VALIDATE_RET( output != NULL );
     DHM_VALIDATE_RET( olen != NULL );
 
-    if( output_size < ctx->len )
+    if( output_size < mbedtls_dhm_get_len( ctx ) )
         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
@@ -564,8 +569,6 @@
 
     ret = 0;
 
-    dhm->len = mbedtls_mpi_size( &dhm->P );
-
 exit:
 #if defined(MBEDTLS_PEM_PARSE_C)
     mbedtls_pem_free( &pem );
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 12ed0fb..1bacd64 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -2553,7 +2553,7 @@
         return( ret );
     }
 
-    dhm_actual_bitlen = mbedtls_mpi_bitlen( &ssl->handshake->dhm_ctx.P );
+    dhm_actual_bitlen = mbedtls_dhm_get_bitlen( &ssl->handshake->dhm_ctx );
     if( dhm_actual_bitlen < ssl->conf->dhm_min_bitlen )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "DHM prime too short: %" MBEDTLS_PRINTF_SIZET " < %u",
@@ -3588,14 +3588,14 @@
         /*
          * DHM key exchange -- send G^X mod P
          */
-        content_len = ssl->handshake->dhm_ctx.len;
+        content_len = mbedtls_dhm_get_len( &ssl->handshake->dhm_ctx );
 
         ssl->out_msg[4] = (unsigned char)( content_len >> 8 );
         ssl->out_msg[5] = (unsigned char)( content_len      );
         header_len = 6;
 
         ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx,
-                          (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
+                          (int) mbedtls_dhm_get_len( &ssl->handshake->dhm_ctx ),
                           &ssl->out_msg[header_len], content_len,
                           ssl->conf->f_rng, ssl->conf->p_rng );
         if( ret != 0 )
@@ -3848,7 +3848,7 @@
             /*
              * ClientDiffieHellmanPublic public (DHM send G^X mod P)
              */
-            content_len = ssl->handshake->dhm_ctx.len;
+            content_len = mbedtls_dhm_get_len( &ssl->handshake->dhm_ctx );
 
             if( header_len + 2 + content_len >
                 MBEDTLS_SSL_OUT_CONTENT_LEN )
@@ -3862,7 +3862,7 @@
             ssl->out_msg[header_len++] = (unsigned char)( content_len      );
 
             ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx,
-                    (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
+                    (int) mbedtls_dhm_get_len( &ssl->handshake->dhm_ctx ),
                     &ssl->out_msg[header_len], content_len,
                     ssl->conf->f_rng, ssl->conf->p_rng );
             if( ret != 0 )
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 4fe6b02..cf4b7c5 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -3049,7 +3049,7 @@
 
         if( ( ret = mbedtls_dhm_make_params(
                   &ssl->handshake->dhm_ctx,
-                  (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
+                  (int) mbedtls_dhm_get_len( &ssl->handshake->dhm_ctx ),
                   ssl->out_msg + ssl->out_msglen, &len,
                   ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
         {
diff --git a/programs/pkey/dh_client.c b/programs/pkey/dh_client.c
index 101b0bb..d68dc24 100644
--- a/programs/pkey/dh_client.c
+++ b/programs/pkey/dh_client.c
@@ -192,7 +192,8 @@
         goto exit;
     }
 
-    if( dhm.MBEDTLS_PRIVATE(len) < 64 || dhm.MBEDTLS_PRIVATE(len) > 512 )
+    n = mbedtls_dhm_get_len( &dhm );
+    if( n < 64 || n > 512 )
     {
         mbedtls_printf( " failed\n  ! Invalid DHM modulus size\n\n" );
         goto exit;
@@ -232,8 +233,8 @@
     mbedtls_printf( "\n  . Sending own public value to server" );
     fflush( stdout );
 
-    n = dhm.MBEDTLS_PRIVATE(len);
-    if( ( ret = mbedtls_dhm_make_public( &dhm, (int) dhm.MBEDTLS_PRIVATE(len), buf, n,
+    n = mbedtls_dhm_get_len( &dhm );
+    if( ( ret = mbedtls_dhm_make_public( &dhm, (int) n, buf, n,
                                  mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
     {
         mbedtls_printf( " failed\n  ! mbedtls_dhm_make_public returned %d\n\n", ret );
diff --git a/programs/pkey/dh_server.c b/programs/pkey/dh_server.c
index 745e68a..9d51c14 100644
--- a/programs/pkey/dh_server.c
+++ b/programs/pkey/dh_server.c
@@ -254,14 +254,14 @@
 
     memset( buf, 0, sizeof( buf ) );
 
-    n = dhm.MBEDTLS_PRIVATE(len);
+    n = mbedtls_dhm_get_len( &dhm );
     if( ( ret = mbedtls_net_recv( &client_fd, buf, n ) ) != (int) n )
     {
         mbedtls_printf( " failed\n  ! mbedtls_net_recv returned %d\n\n", ret );
         goto exit;
     }
 
-    if( ( ret = mbedtls_dhm_read_public( &dhm, buf, dhm.MBEDTLS_PRIVATE(len) ) ) != 0 )
+    if( ( ret = mbedtls_dhm_read_public( &dhm, buf, n ) ) != 0 )
     {
         mbedtls_printf( " failed\n  ! mbedtls_dhm_read_public returned %d\n\n", ret );
         goto exit;
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
index e580fb2..148e6da 100644
--- a/programs/test/benchmark.c
+++ b/programs/test/benchmark.c
@@ -827,6 +827,7 @@
 
         mbedtls_dhm_context dhm;
         size_t olen;
+        size_t n;
         for( i = 0; (size_t) i < sizeof( dhm_sizes ) / sizeof( dhm_sizes[0] ); i++ )
         {
             mbedtls_dhm_init( &dhm );
@@ -839,14 +840,14 @@
                 mbedtls_exit( 1 );
             }
 
-            dhm.len = mbedtls_mpi_size( &dhm.P );
-            mbedtls_dhm_make_public( &dhm, (int) dhm.len, buf, dhm.len, myrand, NULL );
+            n = mbedtls_mpi_size( &dhm.P );
+            mbedtls_dhm_make_public( &dhm, (int) n, buf, n, myrand, NULL );
             if( mbedtls_mpi_copy( &dhm.GY, &dhm.GX ) != 0 )
                 mbedtls_exit( 1 );
 
             mbedtls_snprintf( title, sizeof( title ), "DHE-%d", dhm_sizes[i] );
             TIME_PUBLIC( title, "handshake",
-                    ret |= mbedtls_dhm_make_public( &dhm, (int) dhm.len, buf, dhm.len,
+                    ret |= mbedtls_dhm_make_public( &dhm, (int) n, buf, n,
                                             myrand, NULL );
                     ret |= mbedtls_dhm_calc_secret( &dhm, buf, sizeof( buf ), &olen, myrand, NULL ) );
 
diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function
index c4d78de..7e01eb7 100644
--- a/tests/suites/test_suite_dhm.function
+++ b/tests/suites/test_suite_dhm.function
@@ -229,7 +229,8 @@
 
     TEST_ASSERT( mbedtls_dhm_parse_dhmfile( &ctx, filename ) == 0 );
 
-    TEST_ASSERT( ctx.len == (size_t) len );
+    TEST_EQUAL( mbedtls_dhm_get_len( &ctx ), (size_t) len );
+    TEST_EQUAL( mbedtls_dhm_get_bitlen( &ctx ), mbedtls_mpi_bitlen( &P ) );
     TEST_ASSERT( mbedtls_mpi_cmp_mpi( &ctx.P, &P ) == 0 );
     TEST_ASSERT( mbedtls_mpi_cmp_mpi( &ctx.G, &G ) == 0 );