diff options
author | Martin Willi <martin@revosec.ch> | 2010-09-03 11:45:55 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2010-09-03 14:54:43 +0200 |
commit | 37a59a8fbfc6f3203ecf79d9294fc10af981baf0 (patch) | |
tree | d191131092609f749d3e49ee5311ae261e46d55d | |
parent | 141d7f7abd179fbc3f5c46e2f66fb75b01342886 (diff) | |
download | strongswan-37a59a8fbfc6f3203ecf79d9294fc10af981baf0.tar.bz2 strongswan-37a59a8fbfc6f3203ecf79d9294fc10af981baf0.tar.xz |
Support for EC curve Hello extension, EC curve fallback
-rw-r--r-- | src/libtls/tls.c | 5 | ||||
-rw-r--r-- | src/libtls/tls.h | 4 | ||||
-rw-r--r-- | src/libtls/tls_crypto.c | 14 | ||||
-rw-r--r-- | src/libtls/tls_crypto.h | 7 | ||||
-rw-r--r-- | src/libtls/tls_peer.c | 6 | ||||
-rw-r--r-- | src/libtls/tls_server.c | 130 |
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, ¤t)) + { + 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); } |