aboutsummaryrefslogtreecommitdiffstats
path: root/src/charon/plugins/eap_tls/tls/tls_fragmentation.c
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2010-01-25 10:44:35 +0100
committerMartin Willi <martin@revosec.ch>2010-08-03 15:39:24 +0200
commit4c0c2283a51bab1d992dc2c7337b5e81906ab9e4 (patch)
tree349b2feadc189489490480561c15807ad45d2651 /src/charon/plugins/eap_tls/tls/tls_fragmentation.c
parent4c0124a0a2bf535e741ffde067209450cb91b475 (diff)
downloadstrongswan-4c0c2283a51bab1d992dc2c7337b5e81906ab9e4.tar.bz2
strongswan-4c0c2283a51bab1d992dc2c7337b5e81906ab9e4.tar.xz
Added stubs for handshake handling, server and peer variants
Diffstat (limited to 'src/charon/plugins/eap_tls/tls/tls_fragmentation.c')
-rw-r--r--src/charon/plugins/eap_tls/tls/tls_fragmentation.c134
1 files changed, 131 insertions, 3 deletions
diff --git a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c
index c1cfa0559..0d38e4890 100644
--- a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c
+++ b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c
@@ -28,30 +28,157 @@ struct private_tls_fragmentation_t {
* Public tls_fragmentation_t interface.
*/
tls_fragmentation_t public;
+
+ /**
+ * Upper layer handshake protocol
+ */
+ tls_handshake_t *handshake;
+
+ /**
+ * Handshake input buffer
+ */
+ chunk_t input;
+
+ /**
+ * Position in input buffer
+ */
+ size_t inpos;
+
+ /**
+ * Currently processed handshake message type
+ */
+ tls_handshake_type_t type;
};
+/**
+ * Maximum size of a TLS fragment
+ */
+#define MAX_TLS_FRAGMENT_LEN 16384
+
+/**
+ * Maximum size of a TLS handshake message we accept
+ */
+#define MAX_TLS_HANDSHAKE_LEN 65536
+
+/**
+ * TLS handshake message header
+ */
+typedef union {
+ u_int8_t type;
+ /* 24bit length field */
+ u_int32_t length;
+} tls_handshake_header_t;
+
+/**
+ * Process TLS handshake protocol data
+ */
+static status_t process_handshake(private_tls_fragmentation_t *this,
+ chunk_t data)
+{
+ while (data.len)
+ {
+ u_int32_t len;
+ status_t status;
+ tls_handshake_header_t *hdr;
+
+ if (data.len == 0 || data.len > MAX_TLS_FRAGMENT_LEN)
+ {
+ DBG1(DBG_IKE, "TLS fragment has invalid length");
+ return FAILED;
+ }
+
+ if (this->input.len == 0)
+ { /* new handshake message */
+ if (data.len < sizeof(tls_handshake_header_t))
+ {
+ DBG1(DBG_IKE, "initial TLS fragment too short %B", &data);
+ return FAILED;
+ }
+ hdr = (tls_handshake_header_t*)data.ptr;
+ len = untoh32(&hdr->length) & 0x00FFFFFF;
+ this->type = hdr->type;
+ if (len > MAX_TLS_HANDSHAKE_LEN)
+ {
+ DBG1(DBG_IKE, "TLS handshake message exceeds maximum length");
+ return FAILED;
+ }
+ this->input = len ? chunk_alloc(len) : chunk_empty;
+ this->inpos = 0;
+ data = chunk_skip(data, sizeof(tls_handshake_header_t));
+ }
+
+ len = min(this->input.len - this->inpos, data.len);
+ memcpy(this->input.ptr + this->inpos, data.ptr, len);
+ this->inpos += len;
+ data = chunk_skip(data, len);
+
+ if (this->input.len == this->inpos)
+ { /* message completely defragmented, process */
+ status = this->handshake->process(this->handshake,
+ this->type, this->input);
+ chunk_free(&this->input);
+ if (status != NEED_MORE)
+ {
+ return status;
+ }
+ }
+ }
+ return NEED_MORE;
+}
+
METHOD(tls_fragmentation_t, process, status_t,
private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data)
{
- return NEED_MORE;
+ switch (type)
+ {
+ case TLS_CHANGE_CIPHER_SPEC:
+ /* TODO: handle ChangeCipherSpec */
+ return FAILED;
+ case TLS_ALERT:
+ /* TODO: handle Alert */
+ return FAILED;
+ case TLS_HANDSHAKE:
+ return process_handshake(this, data);
+ case TLS_APPLICATION_DATA:
+ /* skip application data */
+ return NEED_MORE;
+ default:
+ DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type);
+ return NEED_MORE;
+ }
}
METHOD(tls_fragmentation_t, build, status_t,
private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
{
- return INVALID_STATE;
+ tls_handshake_header_t header;
+ tls_handshake_type_t hs_type;
+ chunk_t hs_data;
+ status_t status;
+
+ status = this->handshake->build(this->handshake, &hs_type, &hs_data);
+ if (status != NEED_MORE)
+ {
+ return status;
+ }
+ htoun32(&header.length, hs_data.len);
+ header.type |= hs_type;
+ *data = chunk_cat("cm", chunk_from_thing(header), hs_data);
+ *type = TLS_HANDSHAKE;
+ return NEED_MORE;
}
METHOD(tls_fragmentation_t, destroy, void,
private_tls_fragmentation_t *this)
{
+ free(this->input.ptr);
free(this);
}
/**
* See header
*/
-tls_fragmentation_t *tls_fragmentation_create()
+tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake)
{
private_tls_fragmentation_t *this;
@@ -61,6 +188,7 @@ tls_fragmentation_t *tls_fragmentation_create()
.build = _build,
.destroy = _destroy,
},
+ .handshake = handshake,
);
return &this->public;