aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2010-09-03 11:45:55 +0200
committerMartin Willi <martin@revosec.ch>2010-09-03 14:54:43 +0200
commit37a59a8fbfc6f3203ecf79d9294fc10af981baf0 (patch)
treed191131092609f749d3e49ee5311ae261e46d55d
parent141d7f7abd179fbc3f5c46e2f66fb75b01342886 (diff)
downloadstrongswan-37a59a8fbfc6f3203ecf79d9294fc10af981baf0.tar.bz2
strongswan-37a59a8fbfc6f3203ecf79d9294fc10af981baf0.tar.xz
Support for EC curve Hello extension, EC curve fallback
-rw-r--r--src/libtls/tls.c5
-rw-r--r--src/libtls/tls.h4
-rw-r--r--src/libtls/tls_crypto.c14
-rw-r--r--src/libtls/tls_crypto.h7
-rw-r--r--src/libtls/tls_peer.c6
-rw-r--r--src/libtls/tls_server.c130
6 files changed, 143 insertions, 23 deletions
diff --git a/src/libtls/tls.c b/src/libtls/tls.c
index 87b81f1d1..0d40211eb 100644
--- a/src/libtls/tls.c
+++ b/src/libtls/tls.c
@@ -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",
);
diff --git a/src/libtls/tls.h b/src/libtls/tls.h
index 2bed4cb36..de0d922bb 100644
--- a/src/libtls/tls.h
+++ b/src/libtls/tls.h
@@ -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,
};
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c
index e38bf83cf..d2d8885ca 100644
--- a/src/libtls/tls_crypto.c
+++ b/src/libtls/tls_crypto.c
@@ -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,
diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h
index a17e93fb1..24d1a23a2 100644
--- a/src/libtls/tls_crypto.h
+++ b/src/libtls/tls_crypto.h
@@ -396,6 +396,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.
*
* @param protection protection layer to work on
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index b31b41188..7cfbe144c 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -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);
diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
index 48ab58b9b..1c1c962f1 100644
--- a/src/libtls/tls_server.c
+++ b/src/libtls/tls_server.c
@@ -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;
}
@@ -680,6 +697,81 @@ 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)
+{
+ 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
*/
static status_t send_server_key_exchange(private_tls_server_t *this,
@@ -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);
}