aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libtls/tls_crypto.c58
-rw-r--r--src/libtls/tls_crypto.h8
-rw-r--r--src/libtls/tls_peer.c73
-rw-r--r--src/libtls/tls_server.c76
4 files changed, 138 insertions, 77 deletions
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c
index 89cf1a54c..46e177cdc 100644
--- a/src/libtls/tls_crypto.c
+++ b/src/libtls/tls_crypto.c
@@ -839,17 +839,53 @@ 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)
+/**
+ * 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)
+{
+ int i;
+
+ for (i = 0; i < countof(curves); i++)
+ {
+ if (curves[i].group == *in)
+ {
+ if (out)
+ {
+ *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)
{
- 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));
+ return enumerator_create_filter(
+ lib->crypto->create_dh_enumerator(lib->crypto),
+ (void*)group_filter, NULL, NULL);
}
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,
.get_dh_group = _get_dh_group,
.get_signature_algorithms = _get_signature_algorithms,
- .get_curves = _get_curves,
+ .create_ec_enumerator = _create_ec_enumerator,
.set_protection = _set_protection,
.append_handshake = _append_handshake,
.sign = _sign,
diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h
index b92af1bf6..cc83df300 100644
--- a/src/libtls/tls_crypto.h
+++ b/src/libtls/tls_crypto.h
@@ -398,11 +398,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.
+ * 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.
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index 17d526428..d6d697644 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -352,6 +352,28 @@ static status_t process_modp_key_exchange(private_tls_peer_t *this,
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
@@ -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);
return NEED_MORE;
}
- switch (curve)
+
+ group = curve_to_ec_group(this, curve);
+ if (!group)
{
- case TLS_SECP256R1:
- group = ECP_256_BIT;
- break;
- case TLS_SECP384R1:
- 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;
+ 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);
@@ -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_cipher_suite_t *suites;
- tls_writer_t *extensions;
+ tls_writer_t *extensions, *curves = NULL;
tls_version_t version;
+ tls_named_curve_t curve;
+ enumerator_t *enumerator;
int count, i;
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);
this->crypto->get_signature_algorithms(this->crypto, extensions);
- extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
- this->crypto->get_curves(this->crypto, extensions);
+ /* add supported Elliptic Curves, if any */
+ 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));
extensions->destroy(extensions);
diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
index 62a3d1d5c..aa371c30a 100644
--- a/src/libtls/tls_server.c
+++ b/src/libtls/tls_server.c
@@ -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
*/
-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)
- {
- 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;
+ 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))
+ {
+ if (current == group)
+ {
+ enumerator->destroy(enumerator);
+ return curve;
+ }
}
+ 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,
- diffie_hellman_group_t group)
+bool peer_supports_curve(private_tls_server_t *this, tls_named_curve_t curve)
{
tls_reader_t *reader;
- u_int16_t curve, current;
+ u_int16_t 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))
{
@@ -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,
- diffie_hellman_group_t *group)
+static bool find_supported_curve(private_tls_server_t *this,
+ tls_named_curve_t *curve)
{
- 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]))
+ tls_named_curve_t current;
+ enumerator_t *enumerator;
+
+ enumerator = this->crypto->create_ec_enumerator(this->crypto);
+ while (enumerator->enumerate(enumerator, NULL, &current))
+ {
+ if (peer_supports_curve(this, current))
{
- *group = groups[i];
+ *curve = current;
+ enumerator->destroy(enumerator);
return TRUE;
}
}
+ enumerator->destroy(enumerator);
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_params_t *params = NULL;
+ tls_named_curve_t curve;
chunk_t chunk;
if (diffie_hellman_group_is_ec(group))
{
- if (!peer_supports_ec_group(this, group) &&
- !find_supported_group(this, &group))
+ curve = ec_group_to_curve(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");
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, ec_group_to_curve(group));
+ writer->write_uint16(writer, curve);
}
else
{