diff options
author | Martin Willi <martin@revosec.ch> | 2010-02-05 11:27:52 +0000 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2010-08-03 15:39:25 +0200 |
commit | 110364b042bc05e1dce88555e2c5c4b31a47b9f2 (patch) | |
tree | 907e115ea40410264d2dfc9fc00a6656da685f19 /src | |
parent | f139b5786fb386adab5f82c59fb9ace0b3b4a4db (diff) | |
download | strongswan-110364b042bc05e1dce88555e2c5c4b31a47b9f2.tar.bz2 strongswan-110364b042bc05e1dce88555e2c5c4b31a47b9f2.tar.xz |
Verify Server Finished message
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_peer.c | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/src/charon/plugins/eap_tls/tls/tls_peer.c b/src/charon/plugins/eap_tls/tls/tls_peer.c index 97052b556..2c96d0267 100644 --- a/src/charon/plugins/eap_tls/tls/tls_peer.c +++ b/src/charon/plugins/eap_tls/tls/tls_peer.c @@ -31,6 +31,7 @@ typedef enum { STATE_CIPHERSPEC_CHANGED_OUT, STATE_FINISHED_SENT, STATE_CIPHERSPEC_CHANGED_IN, + STATE_COMPLETE, } peer_state_t; /** @@ -276,7 +277,62 @@ static status_t process_hello_done(private_tls_peer_t *this, */ static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader) { - return FAILED; + chunk_t seed, received; + tls_prf_t *prf; + char data[12]; + + if (!reader->read_data(reader, sizeof(data), &received)) + { + DBG1(DBG_IKE, "received server finished too short"); + return FAILED; + } + + if (this->tls->get_version(this->tls) >= TLS_1_2) + { + /* TODO: use hash of cipher suite only */ + seed = chunk_empty; + } + else + { + hasher_t *md5, *sha1; + char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1]; + + md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5); + if (!md5) + { + DBG1(DBG_IKE, "unable to create %N Finished, MD5 not supported", + tls_version_names, this->tls->get_version(this->tls)); + return FAILED; + } + md5->get_hash(md5, this->handshake, buf); + md5->destroy(md5); + sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!sha1) + { + DBG1(DBG_IKE, "unable to sign %N Finished, SHA1 not supported", + tls_version_names, this->tls->get_version(this->tls)); + return FAILED; + } + sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5); + sha1->destroy(sha1); + + seed = chunk_clonea(chunk_from_thing(buf)); + } + + prf = this->crypto->get_prf(this->crypto); + if (!prf) + { + return FAILED; + } + prf->get_bytes(prf, "server finished", seed, sizeof(data), data); + + if (!chunk_equals(received, chunk_from_thing(data))) + { + DBG1(DBG_IKE, "received server finished invalid"); + return FAILED; + } + this->state = STATE_COMPLETE; + return NEED_MORE; } METHOD(tls_handshake_t, process, status_t, @@ -605,6 +661,8 @@ METHOD(tls_handshake_t, build, status_t, return send_certificate_verify(this, type, writer); case STATE_CIPHERSPEC_CHANGED_OUT: return send_finished(this, type, writer); + case STATE_COMPLETE: + return INVALID_STATE; default: return INVALID_STATE; } |