aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/charon/plugins/eap_tls/eap_tls.c66
-rw-r--r--src/charon/plugins/eap_tls/tls/tls.c58
-rw-r--r--src/charon/plugins/eap_tls/tls/tls.h45
3 files changed, 158 insertions, 11 deletions
diff --git a/src/charon/plugins/eap_tls/eap_tls.c b/src/charon/plugins/eap_tls/eap_tls.c
index b24805273..2e87d8f1c 100644
--- a/src/charon/plugins/eap_tls/eap_tls.c
+++ b/src/charon/plugins/eap_tls/eap_tls.c
@@ -15,6 +15,8 @@
#include "eap_tls.h"
+#include "tls/tls.h"
+
#include <daemon.h>
#include <library.h>
@@ -46,6 +48,11 @@ struct private_eap_tls_t {
bool is_server;
/**
+ * TLS layers
+ */
+ tls_t *tls;
+
+ /**
* Allocated input buffer
*/
chunk_t input;
@@ -212,28 +219,62 @@ static eap_payload_t *read_buf(private_eap_tls_t *this, u_int8_t identifier)
*/
static status_t process_buf(private_eap_tls_t *this)
{
- tls_record_t *record;
- chunk_t input;
+ tls_record_t *in, out;
+ chunk_t data;
u_int16_t len;
+ status_t status;
- input = this->input;
- while (input.len > sizeof(tls_record_t))
+ /* pass input buffer to upper layer, record for record */
+ data = this->input;
+ while (data.len > sizeof(tls_record_t))
{
- record = (tls_record_t*)input.ptr;
- len = untoh16(&record->length);
- if (len > input.len)
+ in = (tls_record_t*)data.ptr;
+ len = untoh16(&in->length);
+ if (len > data.len - sizeof(tls_record_t))
{
DBG1(DBG_IKE, "TLS record length invalid");
break;
}
- /* TODO: pass record to next layer */
- input = chunk_skip(input, len);
+ status = this->tls->process(this->tls, in->type,
+ chunk_create(in->data, len));
+ if (status != NEED_MORE)
+ {
+ return status;
+ }
+ data = chunk_skip(data, len + sizeof(tls_record_t));
}
chunk_free(&this->input);
this->inpos = 0;
- /* TODO: read records from next layer */
- return NEED_MORE;
+ /* read in records from upper layer, append to output buffer */
+ chunk_free(&this->output);
+ while (TRUE)
+ {
+ tls_content_type_t type;
+ chunk_t header = chunk_from_thing(out);
+
+ status = this->tls->build(this->tls, &type, &data);
+ switch (status)
+ {
+ case INVALID_STATE:
+ /* invalid state means we need more input from peer first */
+ return NEED_MORE;
+ case NEED_MORE:
+ case SUCCESS:
+ break;
+ case FAILED:
+ default:
+ return FAILED;
+ }
+ out.type = type;
+ htoun16(&out.version, TLS_1_2);
+ htoun16(&out.length, data.len);
+ this->output = chunk_cat("mcm", this->output, header, data);
+ if (status == SUCCESS)
+ {
+ return SUCCESS;
+ }
+ }
}
METHOD(eap_method_t, process, status_t,
@@ -309,6 +350,8 @@ METHOD(eap_method_t, destroy, void,
free(this->input.ptr);
free(this->output.ptr);
+ this->tls->destroy(this->tls);
+
free(this);
}
@@ -332,6 +375,7 @@ static eap_tls_t *eap_tls_create(identification_t *server,
.peer = peer->clone(peer),
.server = server->clone(server),
.is_server = is_server,
+ .tls = tls_create(is_server),
);
return &this->public;
diff --git a/src/charon/plugins/eap_tls/tls/tls.c b/src/charon/plugins/eap_tls/tls/tls.c
index 930ae78b6..ddb0c81f0 100644
--- a/src/charon/plugins/eap_tls/tls/tls.c
+++ b/src/charon/plugins/eap_tls/tls/tls.c
@@ -15,6 +15,8 @@
#include "tls.h"
+#include <daemon.h>
+
ENUM(tls_version_names, SSL_2_0, TLS_1_2,
"SSLv2",
"SSLv3",
@@ -44,3 +46,59 @@ ENUM_NEXT(tls_handshake_type_names, TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TL
ENUM_NEXT(tls_handshake_type_names, TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_EXCHANGE,
"Finished");
ENUM_END(tls_handshake_type_names, TLS_FINISHED);
+
+
+typedef struct private_tls_t private_tls_t;
+
+/**
+ * Private data of an tls_protection_t object.
+ */
+struct private_tls_t {
+
+ /**
+ * Public tls_t interface.
+ */
+ tls_t public;
+
+ /**
+ * Role this TLS stack acts as.
+ */
+ bool is_server;
+};
+
+METHOD(tls_t, process, status_t,
+ private_tls_t *this, tls_content_type_t type, chunk_t data)
+{
+ return NEED_MORE;
+}
+
+METHOD(tls_t, build, status_t,
+ private_tls_t *this, tls_content_type_t *type, chunk_t *data)
+{
+ return INVALID_STATE;
+}
+
+METHOD(tls_t, destroy, void,
+ private_tls_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+tls_t *tls_create(bool is_server)
+{
+ private_tls_t *this;
+
+ INIT(this,
+ .public = {
+ .process = _process,
+ .build = _build,
+ .destroy = _destroy,
+ },
+ .is_server = is_server,
+ );
+
+ return &this->public;
+}
diff --git a/src/charon/plugins/eap_tls/tls/tls.h b/src/charon/plugins/eap_tls/tls/tls.h
index d7a331756..2e3e04691 100644
--- a/src/charon/plugins/eap_tls/tls/tls.h
+++ b/src/charon/plugins/eap_tls/tls/tls.h
@@ -28,6 +28,7 @@ typedef enum tls_version_t tls_version_t;
typedef enum tls_content_type_t tls_content_type_t;
typedef enum tls_handshake_type_t tls_handshake_type_t;
typedef enum tls_cipher_suite_t tls_cipher_suite_t;
+typedef struct tls_t tls_t;
#include <library.h>
@@ -123,4 +124,48 @@ enum tls_cipher_suite_t {
TLS_DH_ANON_WITH_AES_256_CBC_SHA256 = 0x6D,
};
+/**
+ * A bottom-up driven TLS stack, suitable for EAP implementations.
+ */
+struct tls_t {
+
+ /**
+ * Process a TLS record, pass it to upper layers.
+ *
+ * @param type type of the TLS record to process
+ * @param data associated TLS record data
+ * @return
+ * - SUCCESS if TLS negotiation complete
+ * - FAILED if TLS handshake failed
+ * - NEED_MORE if more invocations to process/build needed
+ */
+ status_t (*process)(tls_t *this, tls_content_type_t type, chunk_t data);
+
+ /**
+ * Query upper layer for TLS record, build protected record.
+ *
+ * @param type type of the built TLS record
+ * @param data allocated data of the built TLS record
+ * @return
+ * - SUCCESS if TLS negotiation complete
+ * - FAILED if TLS handshake failed
+ * - NEED_MORE if upper layers have more records to send
+ * - INVALID_STATE if more input records required
+ */
+ status_t (*build)(tls_t *this, tls_content_type_t *type, chunk_t *data);
+
+ /**
+ * Destroy a tls_t.
+ */
+ void (*destroy)(tls_t *this);
+};
+
+/**
+ * Create a tls instance.
+ *
+ * @param is_server TRUE to act as server, FALSE for client
+ * @return TLS stack
+ */
+tls_t *tls_create(bool is_server);
+
#endif /** TLS_H_ @}*/