diff options
-rw-r--r-- | src/libtls/tls_crypto.c | 58 | ||||
-rw-r--r-- | src/libtls/tls_crypto.h | 8 | ||||
-rw-r--r-- | src/libtls/tls_peer.c | 73 | ||||
-rw-r--r-- | src/libtls/tls_server.c | 76 |
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, ¤t)) + { + 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, ¤t, &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, ¤t)) { @@ -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, ¤t)) + { + 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 { |