aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/plugins/eap_tls/tls/tls_peer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/eap_tls/tls/tls_peer.c')
-rw-r--r--src/libcharon/plugins/eap_tls/tls/tls_peer.c625
1 files changed, 0 insertions, 625 deletions
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_peer.c b/src/libcharon/plugins/eap_tls/tls/tls_peer.c
deleted file mode 100644
index 95973598b..000000000
--- a/src/libcharon/plugins/eap_tls/tls/tls_peer.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * Copyright (C) 2010 Martin Willi
- * Copyright (C) 2010 revosec AG
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "tls_peer.h"
-
-#include <daemon.h>
-
-#include <time.h>
-
-typedef struct private_tls_peer_t private_tls_peer_t;
-
-typedef enum {
- STATE_INIT,
- STATE_HELLO_SENT,
- STATE_HELLO_RECEIVED,
- STATE_HELLO_DONE,
- STATE_CERT_SENT,
- STATE_CERT_RECEIVED,
- STATE_CERTREQ_RECEIVED,
- STATE_KEY_EXCHANGE_SENT,
- STATE_VERIFY_SENT,
- STATE_CIPHERSPEC_CHANGED_OUT,
- STATE_FINISHED_SENT,
- STATE_CIPHERSPEC_CHANGED_IN,
- STATE_COMPLETE,
-} peer_state_t;
-
-/**
- * Private data of an tls_peer_t object.
- */
-struct private_tls_peer_t {
-
- /**
- * Public tls_peer_t interface.
- */
- tls_peer_t public;
-
- /**
- * TLS stack
- */
- tls_t *tls;
-
- /**
- * TLS crypto context
- */
- tls_crypto_t *crypto;
-
- /**
- * Peer identity
- */
- identification_t *peer;
-
- /**
- * Server identity
- */
- identification_t *server;
-
- /**
- * State we are in
- */
- peer_state_t state;
-
- /**
- * Hello random data selected by client
- */
- char client_random[32];
-
- /**
- * Hello random data selected by server
- */
- char server_random[32];
-
- /**
- * Auth helper for peer authentication
- */
- auth_cfg_t *peer_auth;
-
- /**
- * Auth helper for server authentication
- */
- auth_cfg_t *server_auth;
-
- /**
- * Peer private key
- */
- private_key_t *private;
-};
-
-/**
- * Process a server hello message
- */
-static status_t process_server_hello(private_tls_peer_t *this,
- tls_reader_t *reader)
-{
- u_int8_t compression;
- u_int16_t version, cipher;
- chunk_t random, session, ext = chunk_empty;
- tls_cipher_suite_t suite;
-
- this->crypto->append_handshake(this->crypto,
- TLS_SERVER_HELLO, reader->peek(reader));
-
- if (!reader->read_uint16(reader, &version) ||
- !reader->read_data(reader, sizeof(this->server_random), &random) ||
- !reader->read_data8(reader, &session) ||
- !reader->read_uint16(reader, &cipher) ||
- !reader->read_uint8(reader, &compression) ||
- (reader->remaining(reader) && !reader->read_data16(reader, &ext)))
- {
- DBG1(DBG_IKE, "received invalid ServerHello");
- return FAILED;
- }
-
- memcpy(this->server_random, random.ptr, sizeof(this->server_random));
-
- if (version < this->tls->get_version(this->tls))
- {
- this->tls->set_version(this->tls, version);
- }
- suite = cipher;
- if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1))
- {
- DBG1(DBG_IKE, "received cipher suite inacceptable");
- return FAILED;
- }
- this->state = STATE_HELLO_RECEIVED;
- return NEED_MORE;
-}
-
-/**
- * Process a Certificate message
- */
-static status_t process_certificate(private_tls_peer_t *this,
- tls_reader_t *reader)
-{
- certificate_t *cert;
- tls_reader_t *certs;
- chunk_t data;
- bool first = TRUE;
-
- this->crypto->append_handshake(this->crypto,
- TLS_CERTIFICATE, reader->peek(reader));
-
- if (!reader->read_data24(reader, &data))
- {
- return FAILED;
- }
- certs = tls_reader_create(data);
- while (certs->remaining(certs))
- {
- if (!certs->read_data24(certs, &data))
- {
- certs->destroy(certs);
- return FAILED;
- }
- cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
- BUILD_BLOB_ASN1_DER, data, BUILD_END);
- if (cert)
- {
- if (first)
- {
- this->server_auth->add(this->server_auth,
- AUTH_HELPER_SUBJECT_CERT, cert);
- DBG1(DBG_IKE, "received TLS server certificate '%Y'",
- cert->get_subject(cert));
- first = FALSE;
- }
- else
- {
- DBG1(DBG_IKE, "received TLS intermediate certificate '%Y'",
- cert->get_subject(cert));
- this->server_auth->add(this->server_auth,
- AUTH_HELPER_IM_CERT, cert);
- }
- }
- else
- {
- DBG1(DBG_IKE, "parsing TLS certificate failed, skipped");
- }
- }
- certs->destroy(certs);
- this->state = STATE_CERT_RECEIVED;
- return NEED_MORE;
-}
-
-/**
- * Process a Certificate message
- */
-static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
-{
- chunk_t types, hashsig, data;
- tls_reader_t *authorities;
- identification_t *id;
- certificate_t *cert;
-
- this->crypto->append_handshake(this->crypto,
- TLS_CERTIFICATE_REQUEST, reader->peek(reader));
-
- if (!reader->read_data8(reader, &types))
- {
- return FAILED;
- }
- if (this->tls->get_version(this->tls) >= TLS_1_2)
- {
- if (!reader->read_data16(reader, &hashsig))
- {
- return FAILED;
- }
- /* TODO: store supported hashsig algorithms */
- }
- if (!reader->read_data16(reader, &data))
- {
- return FAILED;
- }
- authorities = tls_reader_create(data);
- while (authorities->remaining(authorities))
- {
- if (!authorities->read_data16(authorities, &data))
- {
- authorities->destroy(authorities);
- return FAILED;
- }
- id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
- cert = lib->credmgr->get_cert(lib->credmgr,
- CERT_X509, KEY_ANY, id, TRUE);
- if (cert)
- {
- DBG1(DBG_IKE, "received cert request for '%Y", id);
- this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
- }
- else
- {
- DBG1(DBG_IKE, "received cert request for unknown CA '%Y'", id);
- }
- id->destroy(id);
- }
- authorities->destroy(authorities);
- this->state = STATE_CERTREQ_RECEIVED;
- return NEED_MORE;
-}
-
-/**
- * Process Hello Done message
- */
-static status_t process_hello_done(private_tls_peer_t *this,
- tls_reader_t *reader)
-{
- this->crypto->append_handshake(this->crypto,
- TLS_SERVER_HELLO_DONE, reader->peek(reader));
- this->state = STATE_HELLO_DONE;
- return NEED_MORE;
-}
-
-/**
- * Process finished message
- */
-static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
-{
- chunk_t received;
- char buf[12];
-
- if (!reader->read_data(reader, sizeof(buf), &received))
- {
- DBG1(DBG_IKE, "received server finished too short");
- return FAILED;
- }
- if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
- {
- DBG1(DBG_IKE, "calculating server finished failed");
- return FAILED;
- }
- if (!chunk_equals(received, chunk_from_thing(buf)))
- {
- DBG1(DBG_IKE, "received server finished invalid");
- return FAILED;
- }
- this->state = STATE_COMPLETE;
- this->crypto->derive_eap_msk(this->crypto,
- chunk_from_thing(this->client_random),
- chunk_from_thing(this->server_random));
- return NEED_MORE;
-}
-
-METHOD(tls_handshake_t, process, status_t,
- private_tls_peer_t *this, tls_handshake_type_t type, tls_reader_t *reader)
-{
- tls_handshake_type_t expected;
-
- switch (this->state)
- {
- case STATE_HELLO_SENT:
- if (type == TLS_SERVER_HELLO)
- {
- return process_server_hello(this, reader);
- }
- expected = TLS_SERVER_HELLO;
- break;
- case STATE_HELLO_RECEIVED:
- if (type == TLS_CERTIFICATE)
- {
- return process_certificate(this, reader);
- }
- expected = TLS_CERTIFICATE;
- break;
- case STATE_CERT_RECEIVED:
- if (type == TLS_CERTIFICATE_REQUEST)
- {
- return process_certreq(this, reader);
- }
- expected = TLS_CERTIFICATE_REQUEST;
- break;
- case STATE_CERTREQ_RECEIVED:
- if (type == TLS_SERVER_HELLO_DONE)
- {
- return process_hello_done(this, reader);
- }
- expected = TLS_SERVER_HELLO_DONE;
- break;
- case STATE_CIPHERSPEC_CHANGED_IN:
- if (type == TLS_FINISHED)
- {
- return process_finished(this, reader);
- }
- expected = TLS_FINISHED;
- break;
- default:
- DBG1(DBG_IKE, "TLS %N not expected in current state",
- tls_handshake_type_names, type);
- return FAILED;
- }
- DBG1(DBG_IKE, "TLS %N expected, but received %N",
- tls_handshake_type_names, expected, tls_handshake_type_names, type);
- return FAILED;
-}
-
-/**
- * Send a client hello
- */
-static status_t send_client_hello(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
-{
- tls_cipher_suite_t *suite;
- int count, i;
- rng_t *rng;
-
- htoun32(&this->client_random, time(NULL));
- rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
- if (!rng)
- {
- return FAILED;
- }
- rng->get_bytes(rng, sizeof(this->client_random) - 4, this->client_random + 4);
- rng->destroy(rng);
-
- writer->write_uint16(writer, this->tls->get_version(this->tls));
- writer->write_data(writer, chunk_from_thing(this->client_random));
- /* session identifier => none */
- writer->write_data8(writer, chunk_empty);
-
- count = this->crypto->get_cipher_suites(this->crypto, &suite);
- writer->write_uint16(writer, count * 2);
- for (i = 0; i < count; i++)
- {
- writer->write_uint16(writer, suite[i]);
- }
- /* NULL compression only */
- writer->write_uint8(writer, 1);
- writer->write_uint8(writer, 0);
-
- *type = TLS_CLIENT_HELLO;
- this->state = STATE_HELLO_SENT;
- this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
- return NEED_MORE;
-}
-
-/**
- * Send Certificate
- */
-static status_t send_certificate(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
-{
- enumerator_t *enumerator;
- certificate_t *cert;
- auth_rule_t rule;
- tls_writer_t *certs;
- chunk_t data;
-
- this->private = lib->credmgr->get_private(lib->credmgr,
- KEY_ANY, this->peer, this->peer_auth);
- if (!this->private)
- {
- DBG1(DBG_IKE, "no TLS peer certificate found for '%Y'", this->peer);
- return FAILED;
- }
-
- /* generate certificate payload */
- certs = tls_writer_create(256);
- cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
- if (cert)
- {
- if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
- {
- DBG1(DBG_IKE, "sending TLS peer certificate '%Y'",
- cert->get_subject(cert));
- certs->write_data24(certs, data);
- free(data.ptr);
- }
- }
- enumerator = this->peer_auth->create_enumerator(this->peer_auth);
- while (enumerator->enumerate(enumerator, &rule, &cert))
- {
- if (rule == AUTH_RULE_IM_CERT)
- {
- if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
- {
- DBG1(DBG_IKE, "sending TLS intermediate certificate '%Y'",
- cert->get_subject(cert));
- certs->write_data24(certs, data);
- free(data.ptr);
- }
- }
- }
- enumerator->destroy(enumerator);
-
- writer->write_data24(writer, certs->get_buf(certs));
- certs->destroy(certs);
-
- *type = TLS_CERTIFICATE;
- this->state = STATE_CERT_SENT;
- this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
- return NEED_MORE;
-}
-
-/**
- * Send client key exchange
- */
-static status_t send_key_exchange(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
-{
- public_key_t *public = NULL, *current;
- enumerator_t *enumerator;
- auth_cfg_t *auth;
- rng_t *rng;
- char premaster[48];
- chunk_t encrypted;
-
- rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
- if (!rng)
- {
- DBG1(DBG_IKE, "no suitable RNG found for TLS premaster secret");
- return FAILED;
- }
- rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2);
- rng->destroy(rng);
- htoun16(premaster, TLS_1_2);
-
- this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
- chunk_from_thing(this->client_random),
- chunk_from_thing(this->server_random));
-
- enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
- KEY_ANY, this->server, this->server_auth);
- while (enumerator->enumerate(enumerator, &current, &auth))
- {
- public = current->get_ref(current);
- break;
- }
- enumerator->destroy(enumerator);
-
- if (!public)
- {
- DBG1(DBG_IKE, "no TLS public key found for server '%Y'", this->server);
- return FAILED;
- }
- if (!public->encrypt(public, chunk_from_thing(premaster), &encrypted))
- {
- public->destroy(public);
- DBG1(DBG_IKE, "encrypting TLS premaster secret failed");
- return FAILED;
- }
-
- public->destroy(public);
-
- writer->write_data16(writer, encrypted);
- free(encrypted.ptr);
-
- *type = TLS_CLIENT_KEY_EXCHANGE;
- this->state = STATE_KEY_EXCHANGE_SENT;
- this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
- return NEED_MORE;
-}
-
-/**
- * Send certificate verify
- */
-static status_t send_certificate_verify(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
-{
- if (!this->private ||
- !this->crypto->sign_handshake(this->crypto, this->private, writer))
- {
- DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
- return FAILED;
- }
-
- *type = TLS_CERTIFICATE_VERIFY;
- this->state = STATE_VERIFY_SENT;
- this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
- return NEED_MORE;
-}
-
-/**
- * Send Finished
- */
-static status_t send_finished(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
-{
- char buf[12];
-
- if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
- {
- DBG1(DBG_IKE, "calculating client finished data failed");
- return FAILED;
- }
-
- writer->write_data(writer, chunk_from_thing(buf));
-
- *type = TLS_FINISHED;
- this->state = STATE_FINISHED_SENT;
- this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
- return NEED_MORE;
-}
-
-METHOD(tls_handshake_t, build, status_t,
- private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
-{
- switch (this->state)
- {
- case STATE_INIT:
- return send_client_hello(this, type, writer);
- case STATE_HELLO_DONE:
- return send_certificate(this, type, writer);
- case STATE_CERT_SENT:
- return send_key_exchange(this, type, writer);
- case STATE_KEY_EXCHANGE_SENT:
- return send_certificate_verify(this, type, writer);
- case STATE_CIPHERSPEC_CHANGED_OUT:
- return send_finished(this, type, writer);
- default:
- return INVALID_STATE;
- }
-}
-
-METHOD(tls_handshake_t, cipherspec_changed, bool,
- private_tls_peer_t *this)
-{
- if (this->state == STATE_VERIFY_SENT)
- {
- this->crypto->change_cipher(this->crypto, FALSE);
- this->state = STATE_CIPHERSPEC_CHANGED_OUT;
- return TRUE;
- }
- return FALSE;
-}
-
-METHOD(tls_handshake_t, change_cipherspec, bool,
- private_tls_peer_t *this)
-{
- if (this->state == STATE_FINISHED_SENT)
- {
- this->crypto->change_cipher(this->crypto, TRUE);
- this->state = STATE_CIPHERSPEC_CHANGED_IN;
- return TRUE;
- }
- return FALSE;
-}
-
-METHOD(tls_handshake_t, destroy, void,
- private_tls_peer_t *this)
-{
- DESTROY_IF(this->private);
- this->peer_auth->destroy(this->peer_auth);
- this->server_auth->destroy(this->server_auth);
- free(this);
-}
-
-/**
- * See header
- */
-tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto,
- identification_t *peer, identification_t *server)
-{
- private_tls_peer_t *this;
-
- INIT(this,
- .public.handshake = {
- .process = _process,
- .build = _build,
- .cipherspec_changed = _cipherspec_changed,
- .change_cipherspec = _change_cipherspec,
- .destroy = _destroy,
- },
- .state = STATE_INIT,
- .tls = tls,
- .crypto = crypto,
- .peer = peer,
- .server = server,
- .peer_auth = auth_cfg_create(),
- .server_auth = auth_cfg_create(),
- );
-
- return &this->public;
-}