Added Ephemeral Elliptic Curve Diffie Hellman ciphersuites to SSL/TLS
Made all modifications to include Ephemeral Elliptic Curve Diffie
Hellman ciphersuites into the existing SSL/TLS modules. All basic
handling of the ECDHE-ciphersuites (TLS_ECDHE_RSA_WITH_NULL_SHA,
TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
has been included.
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index c5788ac..bab0aa8 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -29,6 +29,9 @@
#include "polarssl/debug.h"
#include "polarssl/ssl.h"
+#if defined(POLARSSL_ECP_C)
+#include "polarssl/ecp.h"
+#endif
#include <stdlib.h>
#include <stdio.h>
@@ -191,6 +194,75 @@
return( 0 );
}
+#if defined(POLARSSL_ECP_C)
+int ssl_parse_supported_elliptic_curves( ssl_context *ssl,
+ const unsigned char *buf,
+ size_t len )
+{
+ size_t list_size;
+ const unsigned char *p;
+
+ list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
+ if( list_size + 2 != len ||
+ list_size % 2 != 0 )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ p = buf + 2;
+ while( list_size > 0 )
+ {
+ if( p[0] == 0x00 && (
+ p[1] == POLARSSL_ECP_DP_SECP192R1 ||
+ p[1] == POLARSSL_ECP_DP_SECP224R1 ||
+ p[1] == POLARSSL_ECP_DP_SECP256R1 ||
+ p[1] == POLARSSL_ECP_DP_SECP384R1 ||
+ p[1] == POLARSSL_ECP_DP_SECP521R1 ) )
+ {
+ ssl->handshake->ec_curve = p[1];
+ return( 0 );
+ }
+
+ list_size -= 2;
+ p += 2;
+ }
+
+ return( 0 );
+}
+
+int ssl_parse_supported_point_formats( ssl_context *ssl,
+ const unsigned char *buf,
+ size_t len )
+{
+ size_t list_size;
+ const unsigned char *p;
+
+ list_size = buf[0];
+ if( list_size + 1 != len )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ p = buf + 2;
+ while( list_size > 0 )
+ {
+ if( p[0] == POLARSSL_ECP_PF_UNCOMPRESSED ||
+ p[0] == POLARSSL_ECP_PF_COMPRESSED )
+ {
+ ssl->handshake->ec_point_format = p[0];
+ return( 0 );
+ }
+
+ list_size--;
+ p++;
+ }
+
+ return( 0 );
+}
+#endif /* POLARSSL_ECP_C */
+
#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
static int ssl_parse_client_hello_v2( ssl_context *ssl )
{
@@ -363,9 +435,12 @@
{
for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
{
+ // Only allow non-ECC ciphersuites as we do not have extensions
+ //
if( p[0] == 0 &&
p[1] == 0 &&
- p[2] == ssl->ciphersuites[i] )
+ ( ( ssl->ciphersuites[i] >> 8 ) & 0xFF ) == 0 &&
+ p[2] == ( ssl->ciphersuites[i] & 0xFF ) )
goto have_ciphersuite_v2;
}
}
@@ -376,7 +451,7 @@
have_ciphersuite_v2:
ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i];
- ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite );
+ ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info );
/*
* SSLv2 Client Hello relevant renegotiation security checks
@@ -412,6 +487,7 @@
unsigned char *buf, *p, *ext;
int renegotiation_info_seen = 0;
int handshake_failure = 0;
+ const ssl_ciphersuite_t *ciphersuite_info;
SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) );
@@ -639,37 +715,6 @@
}
}
- /*
- * Search for a matching ciphersuite
- */
- for( i = 0; ssl->ciphersuites[i] != 0; i++ )
- {
- for( j = 0, p = buf + 41 + sess_len; j < ciph_len;
- j += 2, p += 2 )
- {
- if( p[0] == 0 && p[1] == ssl->ciphersuites[i] )
- goto have_ciphersuite;
- }
- }
-
- SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
-
- return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
-
-have_ciphersuite:
- ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i];
- ssl->transform_negotiate->ciphersuite_info =
- ssl_ciphersuite_from_id( ssl->ciphersuites[i] );
-
- if( ssl->transform_negotiate->ciphersuite_info == NULL )
- {
- SSL_DEBUG_MSG( 1, ( "ciphersuite info for %02x not found",
- ssl->ciphersuites[i] ) );
- return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
- }
-
- ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite );
-
ext = buf + 44 + sess_len + ciph_len + comp_len;
while( ext_len )
@@ -715,6 +760,24 @@
return( ret );
break;
+#if defined(POLARSSL_ECP_C)
+ case TLS_EXT_SUPPORTED_ELLIPTIC_CURVES:
+ SSL_DEBUG_MSG( 3, ( "found supported elliptic curves extension" ) );
+
+ ret = ssl_parse_supported_elliptic_curves( ssl, ext + 4, ext_size );
+ if( ret != 0 )
+ return( ret );
+ break;
+
+ case TLS_EXT_SUPPORTED_POINT_FORMATS:
+ SSL_DEBUG_MSG( 3, ( "found supported point formats extension" ) );
+
+ ret = ssl_parse_supported_point_formats( ssl, ext + 4, ext_size );
+ if( ret != 0 )
+ return( ret );
+ break;
+#endif /* POLARSSL_ECP_C */
+
default:
SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
ext_id ) );
@@ -769,6 +832,48 @@
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
}
+ /*
+ * Search for a matching ciphersuite
+ * (At the end because we need information from the EC-based extensions)
+ */
+ for( i = 0; ssl->ciphersuites[i] != 0; i++ )
+ {
+ for( j = 0, p = buf + 41 + sess_len; j < ciph_len;
+ j += 2, p += 2 )
+ {
+ if( p[0] == ( ( ssl->ciphersuites[i] >> 8 ) & 0xFF ) &&
+ p[1] == ( ( ssl->ciphersuites[i] ) & 0xFF ) )
+ {
+ ciphersuite_info = ssl_ciphersuite_from_id( ssl->ciphersuites[i] );
+
+ if( ciphersuite_info == NULL )
+ {
+ SSL_DEBUG_MSG( 1, ( "ciphersuite info for %02x not found",
+ ssl->ciphersuites[i] ) );
+ return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
+ }
+
+ if( ( ciphersuite_info->flags & POLARSSL_CIPHERSUITE_EC ) &&
+ ssl->handshake->ec_curve == 0 )
+ continue;
+
+ goto have_ciphersuite;
+ }
+ }
+ }
+
+ SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
+
+ if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+ return( ret );
+
+ return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
+
+have_ciphersuite:
+ ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i];
+ ssl->transform_negotiate->ciphersuite_info = ciphersuite_info;
+ ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info );
+
ssl->in_left = 0;
ssl->state++;
@@ -963,8 +1068,8 @@
*p++ = 0;
*p++ = 2;
- if( ssl->session_negotiate->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 ||
- ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
+ if( ssl->transform_negotiate->ciphersuite_info->cipher ==
+ POLARSSL_CIPHER_AES_256_GCM )
{
ssl->handshake->verify_sig_alg = SSL_HASH_SHA384;
}
@@ -1009,30 +1114,36 @@
return( ret );
}
+#if !defined(POLARSSL_DHM_C) && !defined(POLARSSL_ECDH_C)
static int ssl_write_server_key_exchange( ssl_context *ssl )
{
-#if defined(POLARSSL_DHM_C)
+ SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
+ SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
+ ssl->state++;
+ return( 0 );
+}
+#else
+static int ssl_write_server_key_exchange( ssl_context *ssl )
+{
int ret;
size_t n, rsa_key_len = 0;
unsigned char hash[64];
int hash_id = 0;
unsigned int hashlen = 0;
-#endif
+
+ const ssl_ciphersuite_t *ciphersuite_info;
+ ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
- if( ssl->transform_negotiate->ciphersuite_info->key_exchange !=
- POLARSSL_KEY_EXCHANGE_DHE_RSA )
+ if( ciphersuite_info->key_exchange != POLARSSL_KEY_EXCHANGE_DHE_RSA &&
+ ciphersuite_info->key_exchange != POLARSSL_KEY_EXCHANGE_ECDHE_RSA )
{
SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
ssl->state++;
return( 0 );
}
-#if !defined(POLARSSL_DHM_C)
- SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) );
- return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
-#else
if( ssl->rsa_key == NULL )
{
@@ -1040,35 +1151,72 @@
return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED );
}
- /*
- * Ephemeral DH parameters:
- *
- * struct {
- * opaque dh_p<1..2^16-1>;
- * opaque dh_g<1..2^16-1>;
- * opaque dh_Ys<1..2^16-1>;
- * } ServerDHParams;
- */
- if( ( ret = mpi_copy( &ssl->handshake->dhm_ctx.P, &ssl->dhm_P ) ) != 0 ||
- ( ret = mpi_copy( &ssl->handshake->dhm_ctx.G, &ssl->dhm_G ) ) != 0 )
+#if defined(POLARSSL_DHM_C)
+ if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_DHE_RSA )
{
- SSL_DEBUG_RET( 1, "mpi_copy", ret );
- return( ret );
- }
+ /*
+ * Ephemeral DH parameters:
+ *
+ * struct {
+ * opaque dh_p<1..2^16-1>;
+ * opaque dh_g<1..2^16-1>;
+ * opaque dh_Ys<1..2^16-1>;
+ * } ServerDHParams;
+ */
+ if( ( ret = mpi_copy( &ssl->handshake->dhm_ctx.P, &ssl->dhm_P ) ) != 0 ||
+ ( ret = mpi_copy( &ssl->handshake->dhm_ctx.G, &ssl->dhm_G ) ) != 0 )
+ {
+ SSL_DEBUG_RET( 1, "mpi_copy", ret );
+ return( ret );
+ }
- if( ( ret = dhm_make_params( &ssl->handshake->dhm_ctx,
- mpi_size( &ssl->handshake->dhm_ctx.P ),
- ssl->out_msg + 4,
- &n, ssl->f_rng, ssl->p_rng ) ) != 0 )
+ if( ( ret = dhm_make_params( &ssl->handshake->dhm_ctx,
+ mpi_size( &ssl->handshake->dhm_ctx.P ),
+ ssl->out_msg + 4,
+ &n, ssl->f_rng, ssl->p_rng ) ) != 0 )
+ {
+ SSL_DEBUG_RET( 1, "dhm_make_params", ret );
+ return( ret );
+ }
+
+ SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X );
+ SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P );
+ SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G );
+ SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX );
+ }
+#endif /* POLARSSL_DHM_C */
+
+#if defined(POLARSSL_ECDH_C)
+ if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_RSA )
{
- SSL_DEBUG_RET( 1, "dhm_make_params", ret );
- return( ret );
- }
+ /*
+ * Ephemeral ECDH parameters:
+ *
+ * struct {
+ * ECParameters curve_params;
+ * ECPoint public;
+ * } ServerECDHParams;
+ */
+ ecdh_init( &ssl->handshake->ecdh_ctx );
+ if( ( ret = ecp_use_known_dp( &ssl->handshake->ecdh_ctx.grp,
+ ssl->handshake->ec_curve ) ) != 0 )
+ {
+ SSL_DEBUG_RET( 1, "ecp_use_known_dp", ret );
+ return( ret );
+ }
- SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X );
- SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P );
- SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G );
- SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX );
+ if( ( ret = ecdh_make_params( &ssl->handshake->ecdh_ctx,
+ &n,
+ ssl->out_msg + 4,
+ 1000, ssl->f_rng, ssl->p_rng ) ) != 0 )
+ {
+ SSL_DEBUG_RET( 1, "ecdh_make_params", ret );
+ return( ret );
+ }
+
+ SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q );
+ }
+#endif /* POLARSSL_ECDH_INIT */
if( ssl->minor_ver != SSL_MINOR_VERSION_3 )
{
@@ -1237,8 +1385,8 @@
SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) );
return( 0 );
-#endif
}
+#endif /* POLARSSL_DHM_C || POLARSSL_ECDH_C */
static int ssl_write_server_hello_done( ssl_context *ssl )
{
@@ -1267,6 +1415,10 @@
{
int ret;
size_t i, n = 0;
+#if defined(POLARSSL_DHM_C) || defined(POLARSSL_ECDH_C)
+ const ssl_ciphersuite_t *ciphersuite_info;
+ ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
+#endif
SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) );
@@ -1288,13 +1440,9 @@
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
}
- if( ssl->transform_negotiate->ciphersuite_info->key_exchange ==
- POLARSSL_KEY_EXCHANGE_DHE_RSA )
+#if defined(POLARSSL_DHM_C)
+ if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_DHE_RSA )
{
-#if !defined(POLARSSL_DHM_C)
- SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) );
- return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
-#else
/*
* Receive G^Y mod P, premaster = (G^Y)^X mod P
*/
@@ -1311,7 +1459,7 @@
ssl->in_msg + 6, n ) ) != 0 )
{
SSL_DEBUG_RET( 1, "dhm_read_public", ret );
- return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_RP );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP );
}
SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY );
@@ -1323,13 +1471,50 @@
&ssl->handshake->pmslen ) ) != 0 )
{
SSL_DEBUG_RET( 1, "dhm_calc_secret", ret );
- return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_CS );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS );
}
SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K );
-#endif
}
else
+#endif
+#if defined(POLARSSL_ECDH_C)
+ if( ciphersuite_info->key_exchange == POLARSSL_KEY_EXCHANGE_ECDHE_RSA )
+ {
+ /*
+ * Receive client public key and calculate premaster
+ */
+ n = ssl->in_msg[3];
+
+ if( n < 1 || n > mpi_size( &ssl->handshake->ecdh_ctx.grp.P ) * 2 + 2 ||
+ n + 4 != ssl->in_hslen )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
+ }
+
+ if( ( ret = ecdh_read_public( &ssl->handshake->ecdh_ctx,
+ ssl->in_msg + 4, n ) ) != 0 )
+ {
+ SSL_DEBUG_RET( 1, "ecdh_read_public", ret );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP );
+ }
+
+ SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp );
+
+ if( ( ret = ecdh_calc_secret( &ssl->handshake->ecdh_ctx,
+ &ssl->handshake->pmslen,
+ ssl->handshake->premaster,
+ POLARSSL_MPI_MAX_SIZE ) ) != 0 )
+ {
+ SSL_DEBUG_RET( 1, "ecdh_calc_secret", ret );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS );
+ }
+
+ SSL_DEBUG_MPI( 3, "ECDH: z ", &ssl->handshake->ecdh_ctx.z );
+ }
+ else
+#endif
{
if( ssl->rsa_key == NULL )
{