Use a dynamic curve enumerator to list/convert TLS named curves
authorMartin Willi <martin@revosec.ch>
Fri, 3 Sep 2010 15:05:39 +0000 (17:05 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 3 Sep 2010 15:24:23 +0000 (17:24 +0200)
src/libtls/tls_crypto.c
src/libtls/tls_crypto.h
src/libtls/tls_peer.c
src/libtls/tls_server.c

index 89cf1a5..46e177c 100644 (file)
@@ -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,
index b92af1b..cc83df3 100644 (file)
@@ -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.
index 17d5264..d6d6976 100644 (file)
@@ -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);
index 62a3d1d..aa371c3 100644 (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
  */
-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
        {