diff options
author | Martin Willi <martin@revosec.ch> | 2010-08-23 14:22:38 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2010-08-23 15:13:37 +0200 |
commit | e6f3ef13303313ce4a87983fe640f958e07cc676 (patch) | |
tree | 7dd486d439e7b7975be96d5160a5ceaf5550a2ea /src/libtls/tls_fragmentation.c | |
parent | 908e752201cc5cfc7f663e724f0ab3dc76c72d0a (diff) | |
download | strongswan-e6f3ef13303313ce4a87983fe640f958e07cc676.tar.bz2 strongswan-e6f3ef13303313ce4a87983fe640f958e07cc676.tar.xz |
Implemented TLS Alert handling
Diffstat (limited to 'src/libtls/tls_fragmentation.c')
-rw-r--r-- | src/libtls/tls_fragmentation.c | 124 |
1 files changed, 115 insertions, 9 deletions
diff --git a/src/libtls/tls_fragmentation.c b/src/libtls/tls_fragmentation.c index 06e1bcb53..d69ef3901 100644 --- a/src/libtls/tls_fragmentation.c +++ b/src/libtls/tls_fragmentation.c @@ -22,6 +22,18 @@ typedef struct private_tls_fragmentation_t private_tls_fragmentation_t; /** + * Alert state + */ +typedef enum { + /* no alert received/sent */ + ALERT_NONE, + /* currently sending an alert */ + ALERT_SENDING, + /* alert sent and out */ + ALERT_SENT, +} alert_state_t; + +/** * Private data of an tls_fragmentation_t object. */ struct private_tls_fragmentation_t { @@ -37,6 +49,16 @@ struct private_tls_fragmentation_t { tls_handshake_t *handshake; /** + * TLS alert handler + */ + tls_alert_t *alert; + + /** + * State of alert handling + */ + alert_state_t state; + + /** * Handshake input buffer */ chunk_t input; @@ -73,6 +95,23 @@ struct private_tls_fragmentation_t { #define MAX_TLS_HANDSHAKE_LEN 65536 /** + * Process a TLS alert + */ +static status_t process_alert(private_tls_fragmentation_t *this, + tls_reader_t *reader) +{ + u_int8_t level, description; + + if (!reader->read_uint8(reader, &level) || + !reader->read_uint8(reader, &description)) + { + this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); + return NEED_MORE; + } + return this->alert->process(this->alert, level, description); +} + +/** * Process TLS handshake protocol data */ static status_t process_handshake(private_tls_fragmentation_t *this, @@ -89,7 +128,8 @@ static status_t process_handshake(private_tls_fragmentation_t *this, if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN) { DBG1(DBG_TLS, "TLS fragment has invalid length"); - return FAILED; + this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); + return NEED_MORE; } if (this->input.len == 0) @@ -97,13 +137,16 @@ static status_t process_handshake(private_tls_fragmentation_t *this, if (!reader->read_uint8(reader, &type) || !reader->read_uint24(reader, &len)) { - return FAILED; + DBG1(DBG_TLS, "TLS handshake header invalid"); + this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); + return NEED_MORE; } this->type = type; if (len > MAX_TLS_HANDSHAKE_LEN) { DBG1(DBG_TLS, "TLS handshake message exceeds maximum length"); - return FAILED; + this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); + return NEED_MORE; } chunk_free(&this->input); this->inpos = 0; @@ -116,7 +159,9 @@ static status_t process_handshake(private_tls_fragmentation_t *this, len = min(this->input.len - this->inpos, reader->remaining(reader)); if (!reader->read_data(reader, len, &data)) { - return FAILED; + DBG1(DBG_TLS, "TLS fragment has invalid length"); + this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); + return NEED_MORE; } memcpy(this->input.ptr + this->inpos, data.ptr, len); this->inpos += len; @@ -151,12 +196,14 @@ static status_t process_application(private_tls_fragmentation_t *this, if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN) { DBG1(DBG_TLS, "TLS fragment has invalid length"); - return FAILED; + this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); + return NEED_MORE; } status = this->application->process(this->application, reader); if (status != NEED_MORE) { - return status; + this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY); + return NEED_MORE; } } return NEED_MORE; @@ -168,6 +215,15 @@ METHOD(tls_fragmentation_t, process, status_t, tls_reader_t *reader; status_t status; + switch (this->state) + { + case ALERT_SENDING: + case ALERT_SENT: + /* don't accept more input, fatal error ocurred */ + return NEED_MORE; + case ALERT_NONE: + break; + } reader = tls_reader_create(data); switch (type) { @@ -180,8 +236,7 @@ METHOD(tls_fragmentation_t, process, status_t, status = FAILED; break; case TLS_ALERT: - /* TODO: handle Alert */ - status = FAILED; + status = process_alert(this, reader); break; case TLS_HANDSHAKE: status = process_handshake(this, reader); @@ -198,6 +253,29 @@ METHOD(tls_fragmentation_t, process, status_t, return status; } +/** + * Check if alerts are pending + */ +static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data) +{ + tls_alert_level_t level; + tls_alert_desc_t desc; + tls_writer_t *writer; + + if (this->alert->get(this->alert, &level, &desc)) + { + writer = tls_writer_create(2); + + writer->write_uint8(writer, level); + writer->write_uint8(writer, desc); + + *data = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); + return TRUE; + } + return FALSE; +} + METHOD(tls_fragmentation_t, build, status_t, private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data) { @@ -206,6 +284,22 @@ METHOD(tls_fragmentation_t, build, status_t, tls_writer_t *writer, *msg; status_t status = INVALID_STATE; + switch (this->state) + { + case ALERT_SENDING: + this->state = ALERT_SENT; + return INVALID_STATE; + case ALERT_SENT: + return FAILED; + case ALERT_NONE: + break; + } + if (check_alerts(this, data)) + { + this->state = ALERT_SENDING; + *type = TLS_ALERT; + return NEED_MORE; + } if (this->handshake->cipherspec_changed(this->handshake)) { *type = TLS_CHANGE_CIPHER_SPEC; @@ -227,6 +321,16 @@ METHOD(tls_fragmentation_t, build, status_t, *type = TLS_APPLICATION_DATA; this->output = chunk_clone(msg->get_buf(msg)); } + else if (status != NEED_MORE) + { + this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY); + if (check_alerts(this, data)) + { + this->state = ALERT_SENDING; + *type = TLS_ALERT; + return NEED_MORE; + } + } } } else @@ -290,7 +394,7 @@ METHOD(tls_fragmentation_t, destroy, void, * See header */ tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake, - tls_application_t *application) + tls_alert_t *alert, tls_application_t *application) { private_tls_fragmentation_t *this; @@ -301,6 +405,8 @@ tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake, .destroy = _destroy, }, .handshake = handshake, + .alert = alert, + .state = ALERT_NONE, .application = application, ); |