Use a dynamic curve enumerator to list/convert TLS named curves

This commit is contained in:
Martin Willi
2010-09-03 17:24:23 +02:00
parent f4c98ae664
commit 3f7bb88ba3
4 changed files with 135 additions and 74 deletions
+47 -11
View File
@@ -839,17 +839,53 @@ METHOD(tls_crypto_t, get_signature_algorithms, void,
supported->destroy(supported); supported->destroy(supported);
} }
METHOD(tls_crypto_t, get_curves, void, /**
private_tls_crypto_t *this, tls_writer_t *writer) * Mapping groups to TLS named curves
*/
static struct {
diffie_hellman_group_t group;
tls_named_curve_t curve;
} curves[] = {
{ ECP_256_BIT, TLS_SECP256R1},
{ ECP_384_BIT, TLS_SECP384R1},
{ ECP_521_BIT, TLS_SECP521R1},
{ ECP_224_BIT, TLS_SECP224R1},
{ ECP_192_BIT, TLS_SECP192R1},
};
/**
* Filter EC groups, add TLS curve
*/
static bool group_filter(void *null,
diffie_hellman_group_t *in, diffie_hellman_group_t *out,
void* dummy1, tls_named_curve_t *curve)
{ {
u_int16_t curves[] = { int i;
htons(TLS_SECP256R1),
htons(TLS_SECP384R1), for (i = 0; i < countof(curves); i++)
htons(TLS_SECP521R1), {
htons(TLS_SECP192R1), if (curves[i].group == *in)
htons(TLS_SECP224R1), {
}; if (out)
writer->write_data16(writer, chunk_from_thing(curves)); {
*out = curves[i].group;
}
if (curve)
{
*curve = curves[i].curve;
}
return TRUE;
}
}
return FALSE;
}
METHOD(tls_crypto_t, create_ec_enumerator, enumerator_t*,
private_tls_crypto_t *this)
{
return enumerator_create_filter(
lib->crypto->create_dh_enumerator(lib->crypto),
(void*)group_filter, NULL, NULL);
} }
METHOD(tls_crypto_t, set_protection, void, METHOD(tls_crypto_t, set_protection, void,
@@ -1310,7 +1346,7 @@ tls_crypto_t *tls_crypto_create(tls_t *tls)
.select_cipher_suite = _select_cipher_suite, .select_cipher_suite = _select_cipher_suite,
.get_dh_group = _get_dh_group, .get_dh_group = _get_dh_group,
.get_signature_algorithms = _get_signature_algorithms, .get_signature_algorithms = _get_signature_algorithms,
.get_curves = _get_curves, .create_ec_enumerator = _create_ec_enumerator,
.set_protection = _set_protection, .set_protection = _set_protection,
.append_handshake = _append_handshake, .append_handshake = _append_handshake,
.sign = _sign, .sign = _sign,
+5 -3
View File
@@ -398,11 +398,13 @@ struct tls_crypto_t {
void (*get_signature_algorithms)(tls_crypto_t *this, tls_writer_t *writer); void (*get_signature_algorithms)(tls_crypto_t *this, tls_writer_t *writer);
/** /**
* Write the list of supported elliptic curves to writer. * Create an enumerator over supported ECDH groups.
* *
* @param writer writer to write elliptic curves to * Enumerates over (diffie_hellman_group_t, tls_named_curve_t)
*
* @return enumerator
*/ */
void (*get_curves)(tls_crypto_t *this, tls_writer_t *writer); enumerator_t* (*create_ec_enumerator)(tls_crypto_t *this);
/** /**
* Set the protection layer of the TLS stack to control it. * Set the protection layer of the TLS stack to control it.
+49 -24
View File
@@ -352,6 +352,28 @@ static status_t process_modp_key_exchange(private_tls_peer_t *this,
return NEED_MORE; return NEED_MORE;
} }
/**
* Get the EC group for a TLS named curve
*/
static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this,
tls_named_curve_t curve)
{
diffie_hellman_group_t group;
tls_named_curve_t current;
enumerator_t *enumerator;
enumerator = this->crypto->create_ec_enumerator(this->crypto);
while (enumerator->enumerate(enumerator, &group, &current))
{
if (current == curve)
{
enumerator->destroy(enumerator);
return group;
}
}
enumerator->destroy(enumerator);
return 0;
}
/** /**
* Process a Key Exchange message using EC Diffie Hellman * Process a Key Exchange message using EC Diffie Hellman
@@ -386,28 +408,14 @@ static status_t process_ec_key_exchange(private_tls_peer_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE; return NEED_MORE;
} }
switch (curve)
group = curve_to_ec_group(this, curve);
if (!group)
{ {
case TLS_SECP256R1: DBG1(DBG_TLS, "ECDH curve %N not supported",
group = ECP_256_BIT; tls_named_curve_names, curve);
break; this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
case TLS_SECP384R1: return NEED_MORE;
group = ECP_384_BIT;
break;
case TLS_SECP521R1:
group = ECP_521_BIT;
break;
case TLS_SECP192R1:
group = ECP_192_BIT;
break;
case TLS_SECP224R1:
group = ECP_224_BIT;
break;
default:
DBG1(DBG_TLS, "ECDH curve %N not supported",
tls_named_curve_names, curve);
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
return NEED_MORE;
} }
public = find_public_key(this); public = find_public_key(this);
@@ -656,8 +664,10 @@ static status_t send_client_hello(private_tls_peer_t *this,
tls_handshake_type_t *type, tls_writer_t *writer) tls_handshake_type_t *type, tls_writer_t *writer)
{ {
tls_cipher_suite_t *suites; tls_cipher_suite_t *suites;
tls_writer_t *extensions; tls_writer_t *extensions, *curves = NULL;
tls_version_t version; tls_version_t version;
tls_named_curve_t curve;
enumerator_t *enumerator;
int count, i; int count, i;
rng_t *rng; rng_t *rng;
@@ -697,8 +707,23 @@ static status_t send_client_hello(private_tls_peer_t *this,
extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS); extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
this->crypto->get_signature_algorithms(this->crypto, extensions); this->crypto->get_signature_algorithms(this->crypto, extensions);
extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES); /* add supported Elliptic Curves, if any */
this->crypto->get_curves(this->crypto, extensions); enumerator = this->crypto->create_ec_enumerator(this->crypto);
while (enumerator->enumerate(enumerator, NULL, &curve))
{
if (!curves)
{
extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
curves = tls_writer_create(16);
}
curves->write_uint16(curves, curve);
}
enumerator->destroy(enumerator);
if (curves)
{
extensions->write_data16(extensions, curves->get_buf(curves));
curves->destroy(curves);
}
writer->write_data16(writer, extensions->get_buf(extensions)); writer->write_data16(writer, extensions->get_buf(extensions));
extensions->destroy(extensions); extensions->destroy(extensions);
+34 -36
View File
@@ -730,39 +730,38 @@ static status_t send_certificate_request(private_tls_server_t *this,
/** /**
* Get the TLS curve of a given EC DH group * Get the TLS curve of a given EC DH group
*/ */
static tls_named_curve_t ec_group_to_curve(diffie_hellman_group_t group) static tls_named_curve_t ec_group_to_curve(private_tls_server_t *this,
diffie_hellman_group_t group)
{ {
switch (group) diffie_hellman_group_t current;
tls_named_curve_t curve;
enumerator_t *enumerator;
enumerator = this->crypto->create_ec_enumerator(this->crypto);
while (enumerator->enumerate(enumerator, &current, &curve))
{ {
case ECP_256_BIT: if (current == group)
return TLS_SECP256R1; {
case ECP_384_BIT: enumerator->destroy(enumerator);
return TLS_SECP384R1; return curve;
case ECP_521_BIT: }
return TLS_SECP521R1;
case ECP_192_BIT:
return TLS_SECP192R1;
case ECP_224_BIT:
return TLS_SECP224R1;
default:
return 0;
} }
enumerator->destroy(enumerator);
return 0;
} }
/** /**
* Check if the peer supports a given TLS EC group * Check if the peer supports a given TLS curve
*/ */
bool peer_supports_ec_group(private_tls_server_t *this, bool peer_supports_curve(private_tls_server_t *this, tls_named_curve_t curve)
diffie_hellman_group_t group)
{ {
tls_reader_t *reader; tls_reader_t *reader;
u_int16_t curve, current; u_int16_t current;
if (!this->curves_received) if (!this->curves_received)
{ /* none received, assume yes */ { /* none received, assume yes */
return TRUE; return TRUE;
} }
curve = ec_group_to_curve(group);
reader = tls_reader_create(this->curves); reader = tls_reader_create(this->curves);
while (reader->remaining(reader) && reader->read_uint16(reader, &current)) while (reader->remaining(reader) && reader->read_uint16(reader, &current))
{ {
@@ -777,28 +776,25 @@ bool peer_supports_ec_group(private_tls_server_t *this,
} }
/** /**
* Try to find a group supported by both, client and server * Try to find a curve supported by both, client and server
*/ */
static bool find_supported_group(private_tls_server_t *this, static bool find_supported_curve(private_tls_server_t *this,
diffie_hellman_group_t *group) tls_named_curve_t *curve)
{ {
diffie_hellman_group_t groups[] = { tls_named_curve_t current;
ECP_256_BIT, enumerator_t *enumerator;
ECP_384_BIT,
ECP_521_BIT,
ECP_224_BIT,
ECP_192_BIT,
};
int i;
for (i = 0; i < countof(groups); i++) enumerator = this->crypto->create_ec_enumerator(this->crypto);
while (enumerator->enumerate(enumerator, NULL, &current))
{ {
if (peer_supports_ec_group(this, groups[i])) if (peer_supports_curve(this, current))
{ {
*group = groups[i]; *curve = current;
enumerator->destroy(enumerator);
return TRUE; return TRUE;
} }
} }
enumerator->destroy(enumerator);
return FALSE; return FALSE;
} }
@@ -810,19 +806,21 @@ static status_t send_server_key_exchange(private_tls_server_t *this,
diffie_hellman_group_t group) diffie_hellman_group_t group)
{ {
diffie_hellman_params_t *params = NULL; diffie_hellman_params_t *params = NULL;
tls_named_curve_t curve;
chunk_t chunk; chunk_t chunk;
if (diffie_hellman_group_is_ec(group)) if (diffie_hellman_group_is_ec(group))
{ {
if (!peer_supports_ec_group(this, group) && curve = ec_group_to_curve(this, group);
!find_supported_group(this, &group)) if (!curve || (!peer_supports_curve(this, curve) &&
!find_supported_curve(this, &curve)))
{ {
DBG1(DBG_TLS, "no EC group supported by client and server"); DBG1(DBG_TLS, "no EC group supported by client and server");
this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE); this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
return NEED_MORE; return NEED_MORE;
} }
writer->write_uint8(writer, TLS_ECC_NAMED_CURVE); writer->write_uint8(writer, TLS_ECC_NAMED_CURVE);
writer->write_uint16(writer, ec_group_to_curve(group)); writer->write_uint16(writer, curve);
} }
else else
{ {