Support for EC curve Hello extension, EC curve fallback

This commit is contained in:
Martin Willi
2010-09-03 14:54:43 +02:00
parent 141d7f7abd
commit 37a59a8fbf
6 changed files with 143 additions and 23 deletions
+4 -1
View File
@@ -55,7 +55,10 @@ ENUM_NEXT(tls_handshake_type_names, TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_E
"Finished");
ENUM_END(tls_handshake_type_names, TLS_FINISHED);
ENUM(tls_extension_names, TLS_EXT_SIGNATURE_ALGORITHMS, TLS_EXT_SIGNATURE_ALGORITHMS,
ENUM(tls_extension_names, TLS_EXT_ELLIPTIC_CURVES, TLS_EXT_SIGNATURE_ALGORITHMS,
"elliptic curves",
"ec point formats",
"(12)",
"signature algorithms",
);
+4
View File
@@ -104,6 +104,10 @@ enum tls_purpose_t {
* TLS Hello extension types.
*/
enum tls_extension_t {
/** supported elliptic curves */
TLS_EXT_ELLIPTIC_CURVES = 10,
/** supported point formats */
TLS_EXT_EC_POINT_FORMATS = 11,
/** supported signature algorithms */
TLS_EXT_SIGNATURE_ALGORITHMS = 13,
};
+14
View File
@@ -757,6 +757,19 @@ METHOD(tls_crypto_t, get_signature_algorithms, void,
supported->destroy(supported);
}
METHOD(tls_crypto_t, get_curves, void,
private_tls_crypto_t *this, tls_writer_t *writer)
{
u_int16_t curves[] = {
htons(TLS_SECP256R1),
htons(TLS_SECP384R1),
htons(TLS_SECP521R1),
htons(TLS_SECP192R1),
htons(TLS_SECP224R1),
};
writer->write_data16(writer, chunk_from_thing(curves));
}
METHOD(tls_crypto_t, set_protection, void,
private_tls_crypto_t *this, tls_protection_t *protection)
{
@@ -1215,6 +1228,7 @@ tls_crypto_t *tls_crypto_create(tls_t *tls)
.select_cipher_suite = _select_cipher_suite,
.get_dh_group = _get_dh_group,
.get_signature_algorithms = _get_signature_algorithms,
.get_curves = _get_curves,
.set_protection = _set_protection,
.append_handshake = _append_handshake,
.sign = _sign,
+7
View File
@@ -395,6 +395,13 @@ struct tls_crypto_t {
*/
void (*get_signature_algorithms)(tls_crypto_t *this, tls_writer_t *writer);
/**
* Write the list of supported elliptic curves to writer.
*
* @param writer writer to write elliptic curves to
*/
void (*get_curves)(tls_crypto_t *this, tls_writer_t *writer);
/**
* Set the protection layer of the TLS stack to control it.
*
+5 -1
View File
@@ -709,10 +709,14 @@ static status_t send_client_hello(private_tls_peer_t *this,
writer->write_uint8(writer, 1);
writer->write_uint8(writer, 0);
/* signature algorithms extension */
extensions = tls_writer_create(32);
extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
this->crypto->get_signature_algorithms(this->crypto, extensions);
extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
this->crypto->get_curves(this->crypto, extensions);
writer->write_data16(writer, extensions->get_buf(extensions));
extensions->destroy(extensions);
+109 -21
View File
@@ -124,6 +124,16 @@ struct private_tls_server_t {
* Hash and signature algorithms supported by peer
*/
chunk_t hashsig;
/**
* Elliptic curves supported by peer
*/
chunk_t curves;
/**
* Did we receive the curves from the client?
*/
bool curves_received;
};
/**
@@ -175,6 +185,13 @@ static status_t process_client_hello(private_tls_server_t *this,
this->hashsig = chunk_clone(ext);
}
break;
case TLS_EXT_ELLIPTIC_CURVES:
this->curves_received = TRUE;
if (extensions->read_data16(extensions, &ext))
{
this->curves = chunk_clone(ext);
}
break;
default:
break;
}
@@ -679,6 +696,81 @@ static status_t send_certificate_request(private_tls_server_t *this,
return NEED_MORE;
}
/**
* Get the TLS curve of a given EC DH group
*/
static tls_named_curve_t ec_group_to_curve(diffie_hellman_group_t group)
{
switch (group)
{
case ECP_256_BIT:
return TLS_SECP256R1;
case ECP_384_BIT:
return TLS_SECP384R1;
case ECP_521_BIT:
return TLS_SECP521R1;
case ECP_192_BIT:
return TLS_SECP192R1;
case ECP_224_BIT:
return TLS_SECP224R1;
default:
return 0;
}
}
/**
* Check if the peer supports a given TLS EC group
*/
bool peer_supports_ec_group(private_tls_server_t *this,
diffie_hellman_group_t group)
{
tls_reader_t *reader;
u_int16_t curve, current;
if (!this->curves_received)
{ /* none received, assume yes */
return TRUE;
}
curve = ec_group_to_curve(group);
reader = tls_reader_create(this->curves);
while (reader->remaining(reader) && reader->read_uint16(reader, &current))
{
if (current == curve)
{
reader->destroy(reader);
return TRUE;
}
}
reader->destroy(reader);
return FALSE;
}
/**
* Try to find a group supported by both, client and server
*/
static bool find_supported_group(private_tls_server_t *this,
diffie_hellman_group_t *group)
{
diffie_hellman_group_t groups[] = {
ECP_256_BIT,
ECP_384_BIT,
ECP_521_BIT,
ECP_224_BIT,
ECP_192_BIT,
};
int i;
for (i = 0; i < countof(groups); i++)
{
if (peer_supports_ec_group(this, groups[i]))
{
*group = groups[i];
return TRUE;
}
}
return FALSE;
}
/**
* Send Server key Exchange
*/
@@ -689,35 +781,22 @@ static status_t send_server_key_exchange(private_tls_server_t *this,
diffie_hellman_params_t *params = NULL;
chunk_t chunk;
this->dh = lib->crypto->create_dh(lib->crypto, group);
if (!this->dh)
{
DBG1(DBG_TLS, "DH group %N not supported",
diffie_hellman_group_names, group);
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
return NEED_MORE;
}
switch (group)
{
case ECP_256_BIT:
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
writer->write_uint16(writer, TLS_SECP256R1);
break;
case ECP_384_BIT:
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
writer->write_uint16(writer, TLS_SECP384R1);
break;
case ECP_521_BIT:
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
writer->write_uint16(writer, TLS_SECP521R1);
break;
case ECP_192_BIT:
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
writer->write_uint16(writer, TLS_SECP192R1);
break;
case ECP_224_BIT:
if (!peer_supports_ec_group(this, group) &&
!find_supported_group(this, &group))
{
DBG1(DBG_TLS, "no EC group supported by client and server");
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
return NEED_MORE;
}
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
writer->write_uint16(writer, TLS_SECP224R1);
writer->write_uint16(writer, ec_group_to_curve(group));
break;
default:
/* MODP groups */
@@ -733,6 +812,14 @@ static status_t send_server_key_exchange(private_tls_server_t *this,
writer->write_data16(writer, params->generator);
break;
}
this->dh = lib->crypto->create_dh(lib->crypto, group);
if (!this->dh)
{
DBG1(DBG_TLS, "DH group %N not supported",
diffie_hellman_group_names, group);
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
return NEED_MORE;
}
this->dh->get_my_public_value(this->dh, &chunk);
if (params)
{
@@ -872,6 +959,7 @@ METHOD(tls_handshake_t, destroy, void,
this->peer_auth->destroy(this->peer_auth);
this->server_auth->destroy(this->server_auth);
free(this->hashsig.ptr);
free(this->curves.ptr);
free(this);
}