diff options
author | Martin Willi <martin@revosec.ch> | 2010-09-02 19:27:13 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2010-09-02 19:33:08 +0200 |
commit | f14358a9b52768f1eae36bf71b22af8d321c9795 (patch) | |
tree | b32c22eb006e8f99d69b0831e8bd6140318943b4 /src/libtls/tls_server.c | |
parent | da3f4a9fd01ce7069e6d9ac1d9d77b462675b170 (diff) | |
download | strongswan-f14358a9b52768f1eae36bf71b22af8d321c9795.tar.bz2 strongswan-f14358a9b52768f1eae36bf71b22af8d321c9795.tar.xz |
Added TLS server side support for DHE suites
Diffstat (limited to 'src/libtls/tls_server.c')
-rw-r--r-- | src/libtls/tls_server.c | 119 |
1 files changed, 116 insertions, 3 deletions
diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c index ab0d80630..88e0326b0 100644 --- a/src/libtls/tls_server.c +++ b/src/libtls/tls_server.c @@ -28,6 +28,7 @@ typedef enum { STATE_HELLO_RECEIVED, STATE_HELLO_SENT, STATE_CERT_SENT, + STATE_KEY_EXCHANGE_SENT, STATE_CERTREQ_SENT, STATE_HELLO_DONE, STATE_CERT_RECEIVED, @@ -105,6 +106,11 @@ struct private_tls_server_t { private_key_t *private; /** + * DHE exchange + */ + diffie_hellman_t *dh; + + /** * Selected TLS cipher suite */ tls_cipher_suite_t suite; @@ -269,10 +275,10 @@ static status_t process_certificate(private_tls_server_t *this, } /** - * Process Client Key Exchange + * Process Client Key Exchange, using premaster encryption */ -static status_t process_key_exchange(private_tls_server_t *this, - tls_reader_t *reader) +static status_t process_key_exchange_encrypted(private_tls_server_t *this, + tls_reader_t *reader) { chunk_t encrypted, decrypted; char premaster[48]; @@ -329,6 +335,53 @@ static status_t process_key_exchange(private_tls_server_t *this, } /** + * Process client key exchange, using DHE exchange + */ +static status_t process_key_exchange_dhe(private_tls_server_t *this, + tls_reader_t *reader) +{ + chunk_t premaster, pub; + + this->crypto->append_handshake(this->crypto, + TLS_CLIENT_KEY_EXCHANGE, reader->peek(reader)); + + if (!reader->read_data16(reader, &pub)) + { + DBG1(DBG_TLS, "received invalid Client Key Exchange"); + this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); + return NEED_MORE; + } + this->dh->set_other_public_value(this->dh, pub); + if (this->dh->get_shared_secret(this->dh, &premaster) != SUCCESS) + { + DBG1(DBG_TLS, "calculating premaster from DH failed"); + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + return NEED_MORE; + } + + this->crypto->derive_secrets(this->crypto, premaster, + chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random)); + chunk_clear(&premaster); + + this->state = STATE_KEY_EXCHANGE_RECEIVED; + return NEED_MORE; +} + +/** + * Process Client Key Exchange + */ +static status_t process_key_exchange(private_tls_server_t *this, + tls_reader_t *reader) +{ + if (this->dh) + { + return process_key_exchange_dhe(this, reader); + } + return process_key_exchange_encrypted(this, reader); +} + +/** * Process Certificate verify */ static status_t process_cert_verify(private_tls_server_t *this, @@ -613,6 +666,56 @@ static status_t send_certificate_request(private_tls_server_t *this, } /** + * Send Server key Exchange + */ +static status_t send_server_key_exchange(private_tls_server_t *this, + tls_handshake_type_t *type, tls_writer_t *writer, + diffie_hellman_group_t group) +{ + diffie_hellman_params_t *params; + chunk_t chunk; + + params = diffie_hellman_get_params(group); + if (!params) + { + DBG1(DBG_TLS, "no parameters found for DH group %N", + diffie_hellman_group_names, group); + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + return NEED_MORE; + } + 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; + } + + writer->write_data16(writer, params->prime); + writer->write_data16(writer, params->generator); + this->dh->get_my_public_value(this->dh, &chunk); + writer->write_data16(writer, chunk); + free(chunk.ptr); + + chunk = chunk_cat("ccc", chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random), writer->get_buf(writer)); + if (!this->private || !this->crypto->sign(this->crypto, this->private, + writer, chunk, this->hashsig)) + { + DBG1(DBG_TLS, "signing DH parameters failed"); + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + free(chunk.ptr); + return NEED_MORE; + } + free(chunk.ptr); + *type = TLS_SERVER_KEY_EXCHANGE; + this->state = STATE_KEY_EXCHANGE_SENT; + this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer)); + return NEED_MORE; +} + +/** * Send Hello Done */ static status_t send_hello_done(private_tls_server_t *this, @@ -652,6 +755,8 @@ static status_t send_finished(private_tls_server_t *this, METHOD(tls_handshake_t, build, status_t, private_tls_server_t *this, tls_handshake_type_t *type, tls_writer_t *writer) { + diffie_hellman_group_t group; + switch (this->state) { case STATE_HELLO_RECEIVED: @@ -659,6 +764,13 @@ METHOD(tls_handshake_t, build, status_t, case STATE_HELLO_SENT: return send_certificate(this, type, writer); case STATE_CERT_SENT: + group = this->crypto->get_dh_group(this->crypto); + if (group) + { + return send_server_key_exchange(this, type, writer, group); + } + /* otherwise fall through to next state */ + case STATE_KEY_EXCHANGE_SENT: if (this->peer) { return send_certificate_request(this, type, writer); @@ -710,6 +822,7 @@ METHOD(tls_handshake_t, destroy, void, private_tls_server_t *this) { DESTROY_IF(this->private); + DESTROY_IF(this->dh); this->peer_auth->destroy(this->peer_auth); this->server_auth->destroy(this->server_auth); free(this->hashsig.ptr); |