summaryrefslogtreecommitdiffstats
path: root/ssl/record
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2015-09-14 22:49:35 +0100
committerMatt Caswell <matt@openssl.org>2015-09-23 13:53:26 +0100
commite3d0dae7cf8363ca462ac425b72c7bb31c3b4b7a (patch)
tree5324d0001be54ed135b4ff8d60fd0a4ea6ccf1ef /ssl/record
parent01b7851aa27aa144372f5484da916be042d9aa4f (diff)
DTLSv1_listen rewrite
The existing implementation of DTLSv1_listen() is fundamentally flawed. This function is used in DTLS solutions to listen for new incoming connections from DTLS clients. A client will send an initial ClientHello. The server will respond with a HelloVerifyRequest containing a unique cookie. The client the responds with a second ClientHello - which this time contains the cookie. Once the cookie has been verified then DTLSv1_listen() returns to user code, which is typically expected to continue the handshake with a call to (for example) SSL_accept(). Whilst listening for incoming ClientHellos, the underlying BIO is usually in an unconnected state. Therefore ClientHellos can come in from *any* peer. The arrival of the first ClientHello without the cookie, and the second one with it, could be interspersed with other intervening messages from different clients. The whole purpose of this mechanism is as a defence against DoS attacks. The idea is to avoid allocating state on the server until the client has verified that it is capable of receiving messages at the address it claims to come from. However the existing DTLSv1_listen() implementation completely fails to do this. It attempts to super-impose itself on the standard state machine and reuses all of this code. However the standard state machine expects to operate in a stateful manner with a single client, and this can cause various problems. A second more minor issue is that the return codes from this function are quite confused, with no distinction made between fatal and non-fatal errors. Most user code treats all errors as non-fatal, and simply retries the call to DTLSv1_listen(). This commit completely rewrites the implementation of DTLSv1_listen() and provides a stand alone implementation that does not rely on the existing state machine. It also provides more consistent return codes. Reviewed-by: Andy Polyakov <appro@openssl.org>
Diffstat (limited to 'ssl/record')
-rw-r--r--ssl/record/rec_layer_d1.c6
-rw-r--r--ssl/record/record.h5
2 files changed, 9 insertions, 2 deletions
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index 74796bed6f..b5548e626a 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -226,6 +226,12 @@ void DTLS_RECORD_LAYER_resync_write(RECORD_LAYER *rl)
memcpy(rl->write_sequence, rl->read_sequence, sizeof(rl->write_sequence));
}
+
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq)
+{
+ memcpy(rl->write_sequence, seq, SEQ_NUM_SIZE);
+}
+
static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
int len, int peek);
diff --git a/ssl/record/record.h b/ssl/record/record.h
index 5c8fead869..96370710c4 100644
--- a/ssl/record/record.h
+++ b/ssl/record/record.h
@@ -288,8 +288,8 @@ typedef struct record_layer_st {
int wpend_ret;
const unsigned char *wpend_buf;
- unsigned char read_sequence[8];
- unsigned char write_sequence[8];
+ unsigned char read_sequence[SEQ_NUM_SIZE];
+ unsigned char write_sequence[SEQ_NUM_SIZE];
DTLS_RECORD_LAYER *d;
} RECORD_LAYER;
@@ -346,6 +346,7 @@ void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_set_saved_w_epoch(RECORD_LAYER *rl, unsigned short e);
void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_resync_write(RECORD_LAYER *rl);
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq);
__owur int dtls1_read_bytes(SSL *s, int type, int *recvd_type,
unsigned char *buf, int len, int peek);
__owur int dtls1_write_bytes(SSL *s, int type, const void *buf, int len);