aboutsummaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2015-09-04 13:51:49 +0100
committerMatt Caswell <matt@openssl.org>2015-10-30 08:38:18 +0000
commitc130dd8ea4d09cb708aac9e41bd25c2f5fa7ea38 (patch)
tree6466c850736d62f8fd90b31defdde4d93cc5ac39 /ssl
parent94836de2aeab65869caf2aa9a260114a309aaf0a (diff)
downloadopenssl-c130dd8ea4d09cb708aac9e41bd25c2f5fa7ea38.tar.gz
Move server side DTLS to new state machine
Implement all of the necessary changes to make DTLS on the server work with the new state machine code. Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'ssl')
-rw-r--r--ssl/d1_srvr.c49
-rw-r--r--ssl/s3_srvr.c56
-rw-r--r--ssl/ssl_err.c2
-rw-r--r--ssl/ssl_locl.h1
-rw-r--r--ssl/statem.c147
5 files changed, 210 insertions, 45 deletions
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index 22dbbfe3d3..02a944d86e 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -127,7 +127,6 @@
#endif
static const SSL_METHOD *dtls1_get_server_method(int ver);
-static int dtls1_send_hello_verify_request(SSL *s);
static const SSL_METHOD *dtls1_get_server_method(int ver)
{
@@ -157,6 +156,7 @@ IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
ssl_undefined_function,
dtls1_get_server_method, DTLSv1_2_enc_data)
+#if 0
int dtls1_accept(SSL *s)
{
BUF_MEM *buf;
@@ -857,6 +857,7 @@ int dtls1_accept(SSL *s)
cb(s, SSL_CB_ACCEPT_EXIT, ret);
return (ret);
}
+#endif
unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
unsigned char *cookie,
@@ -879,37 +880,33 @@ unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
}
-int dtls1_send_hello_verify_request(SSL *s)
+int dtls_construct_hello_verify_request(SSL *s)
{
unsigned int len;
unsigned char *buf;
- if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A) {
- buf = (unsigned char *)s->init_buf->data;
-
- if (s->ctx->app_gen_cookie_cb == NULL ||
- s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
- &(s->d1->cookie_len)) == 0 ||
- s->d1->cookie_len > 255) {
- SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,
- SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
- s->state = SSL_ST_ERR;
- return 0;
- }
+ buf = (unsigned char *)s->init_buf->data;
- len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
- s->d1->cookie, s->d1->cookie_len);
+ if (s->ctx->app_gen_cookie_cb == NULL ||
+ s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+ &(s->d1->cookie_len)) == 0 ||
+ s->d1->cookie_len > 255) {
+ SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,
+ SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+ statem_set_error(s);
+ return 0;
+ }
- dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
- len);
- len += DTLS1_HM_HEADER_LENGTH;
+ len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
+ s->d1->cookie, s->d1->cookie_len);
- s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
- /* number of bytes to write */
- s->init_num = len;
- s->init_off = 0;
- }
+ dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
+ len);
+ len += DTLS1_HM_HEADER_LENGTH;
+
+ /* number of bytes to write */
+ s->init_num = len;
+ s->init_off = 0;
- /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
- return (dtls1_do_write(s, SSL3_RT_HANDSHAKE));
+ return 1;
}
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 992df70f4c..d390f149a2 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -2876,27 +2876,47 @@ enum MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, long n)
enum WORK_STATE tls_post_process_client_key_exchange(SSL *s,
enum WORK_STATE wst)
{
-
#ifndef OPENSSL_NO_SCTP
- if (SSL_IS_DTLS(s)) {
- unsigned char sctpauthkey[64];
- char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
- /*
- * Add new shared key for SCTP-Auth, will be ignored if no SCTP
- * used.
- */
- snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
- DTLS1_SCTP_AUTH_LABEL);
+ if (wst == WORK_MORE_A) {
+ if (SSL_IS_DTLS(s)) {
+ unsigned char sctpauthkey[64];
+ char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+ /*
+ * Add new shared key for SCTP-Auth, will be ignored if no SCTP
+ * used.
+ */
+ snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
+ DTLS1_SCTP_AUTH_LABEL);
+
+ if (SSL_export_keying_material(s, sctpauthkey,
+ sizeof(sctpauthkey), labelbuffer,
+ sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+ statem_set_error(s);
+ return WORK_ERROR;;
+ }
- if (SSL_export_keying_material(s, sctpauthkey,
- sizeof(sctpauthkey), labelbuffer,
- sizeof(labelbuffer), NULL, 0, 0) <= 0) {
- statem_set_error(s);
- return WORK_ERROR;;
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+ sizeof(sctpauthkey), sctpauthkey);
}
+ wst = WORK_MORE_B;
+ }
- BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
- sizeof(sctpauthkey), sctpauthkey);
+ if ((wst == WORK_MORE_B)
+ /* Is this SCTP? */
+ && BIO_dgram_is_sctp(SSL_get_wbio(s))
+ /* Are we renegotiating? */
+ && s->renegotiate
+ /* Are we going to skip the CertificateVerify? */
+ && (s->session->peer == NULL || s->no_cert_verify)
+ && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+ s->s3->in_read_app_data = 2;
+ s->rwstate = SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ statem_set_sctp_read_sock(s, 1);
+ return WORK_MORE_B;
+ } else {
+ statem_set_sctp_read_sock(s, 0);
}
#endif
@@ -3169,7 +3189,7 @@ enum MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, long n)
goto f_err;
}
- ret = MSG_PROCESS_CONTINUE_READING;
+ ret = MSG_PROCESS_CONTINUE_PROCESSING;
if (0) {
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index fe4201ba66..faee32fa5f 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -114,6 +114,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_DTLS1_WRITE_APP_DATA_BYTES), "dtls1_write_app_data_bytes"},
{ERR_FUNC(SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC),
"dtls_construct_change_cipher_spec"},
+ {ERR_FUNC(SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST),
+ "dtls_construct_hello_verify_request"},
{ERR_FUNC(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE),
"DTLS_GET_REASSEMBLED_MESSAGE"},
{ERR_FUNC(SSL_F_READ_STATE_MACHINE), "READ_STATE_MACHINE"},
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 425d3956a0..891030c7c3 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -2201,6 +2201,7 @@ __owur int tls_construct_server_hello(SSL *s);
__owur int ssl3_send_hello_request(SSL *s);
__owur int tls_construct_hello_request(SSL *s);
__owur int ssl3_send_server_key_exchange(SSL *s);
+__owur int dtls_construct_hello_verify_request(SSL *s);
__owur int tls_construct_server_key_exchange(SSL *s);
__owur int ssl3_send_certificate_request(SSL *s);
__owur int tls_construct_certificate_request(SSL *s);
diff --git a/ssl/statem.c b/ssl/statem.c
index e2cf11e114..2fe3df4b7e 100644
--- a/ssl/statem.c
+++ b/ssl/statem.c
@@ -171,6 +171,11 @@ int ssl3_accept(SSL *s)
return state_machine(s, 1);
}
+int dtls1_accept(SSL *s)
+{
+ return state_machine(s, 1);
+}
+
/*
* The main message flow state machine. We start in the MSG_FLOW_UNINITED or
* MSG_FLOW_RENEGOTIATE state and finish in MSG_FLOW_FINISHED. Valid states and
@@ -1490,6 +1495,7 @@ static int server_read_transition(SSL *s, int mt)
switch(st->hand_state) {
case TLS_ST_BEFORE:
+ case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
if (mt == SSL3_MT_CLIENT_HELLO) {
st->hand_state = TLS_ST_SR_CLNT_HELLO;
return 1;
@@ -1726,9 +1732,16 @@ static enum WRITE_TRAN server_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
case TLS_ST_SR_CLNT_HELLO:
- st->hand_state = TLS_ST_SW_SRVR_HELLO;
+ if (SSL_IS_DTLS(s) && !s->d1->cookie_verified
+ && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
+ st->hand_state = DTLS_ST_SW_HELLO_VERIFY_REQUEST;
+ else
+ st->hand_state = TLS_ST_SW_SRVR_HELLO;
return WRITE_TRAN_CONTINUE;
+ case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+ return WRITE_TRAN_FINISHED;
+
case TLS_ST_SW_SRVR_HELLO:
if (s->hit) {
if (s->tlsext_ticket_expected)
@@ -1826,6 +1839,44 @@ static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst)
switch(st->hand_state) {
case TLS_ST_SW_HELLO_REQ:
s->shutdown = 0;
+ if (SSL_IS_DTLS(s))
+ dtls1_clear_record_buffer(s);
+ break;
+
+ case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+ s->shutdown = 0;
+ if (SSL_IS_DTLS(s)) {
+ dtls1_clear_record_buffer(s);
+ /* We don't buffer this message so don't use the timer */
+ st->use_timer = 0;
+ }
+ break;
+
+ case TLS_ST_SW_SRVR_HELLO:
+ if (SSL_IS_DTLS(s)) {
+ /*
+ * Messages we write from now on should be bufferred and
+ * retransmitted if necessary, so we need to use the timer now
+ */
+ st->use_timer = 1;
+ }
+ break;
+
+ case TLS_ST_SW_SRVR_DONE:
+#ifndef OPENSSL_NO_SCTP
+ if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s)))
+ return dtls_wait_for_dry(s);
+#endif
+ return WORK_FINISHED_CONTINUE;
+
+ case TLS_ST_SW_SESSION_TICKET:
+ if (SSL_IS_DTLS(s)) {
+ /*
+ * We're into the last flight. We don't retransmit the last flight
+ * unless we need to, so we don't use the timer
+ */
+ st->use_timer = 0;
+ }
break;
case TLS_ST_SW_CHANGE:
@@ -1834,6 +1885,15 @@ static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst)
statem_set_error(s);
return WORK_ERROR;
}
+ if (SSL_IS_DTLS(s)) {
+ /*
+ * We're into the last flight. We don't retransmit the last flight
+ * unless we need to, so we don't use the timer. This might have
+ * already been set to 0 if we sent a NewSessionTicket message,
+ * but we'll set it again here in case we didn't.
+ */
+ st->use_timer = 0;
+ }
return WORK_FINISHED_CONTINUE;
case TLS_ST_OK:
@@ -1864,12 +1924,64 @@ static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst)
ssl3_init_finished_mac(s);
break;
+ case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+ if (statem_flush(s) != 1)
+ return WORK_MORE_A;
+ /* HelloVerifyRequest resets Finished MAC */
+ if (s->version != DTLS1_BAD_VER)
+ ssl3_init_finished_mac(s);
+ /*
+ * The next message should be another ClientHello which we need to
+ * treat like it was the first packet
+ */
+ s->first_packet = 1;
+ break;
+
+ case TLS_ST_SW_SRVR_HELLO:
+#ifndef OPENSSL_NO_SCTP
+ if (SSL_IS_DTLS(s) && s->hit) {
+ unsigned char sctpauthkey[64];
+ char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+
+ /*
+ * Add new shared key for SCTP-Auth, will be ignored if no
+ * SCTP used.
+ */
+ snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
+ DTLS1_SCTP_AUTH_LABEL);
+
+ if (SSL_export_keying_material(s, sctpauthkey,
+ sizeof(sctpauthkey), labelbuffer,
+ sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+ statem_set_error(s);
+ return WORK_ERROR;
+ }
+
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+ sizeof(sctpauthkey), sctpauthkey);
+ }
+#endif
+ break;
+
case TLS_ST_SW_CHANGE:
+#ifndef OPENSSL_NO_SCTP
+ if (SSL_IS_DTLS(s) && !s->hit) {
+ /*
+ * Change to new shared key of SCTP-Auth, will be ignored if
+ * no SCTP used.
+ */
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+ 0, NULL);
+ }
+#endif
if (!s->method->ssl3_enc->change_cipher_state(s,
SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
statem_set_error(s);
return WORK_ERROR;
}
+
+ if (SSL_IS_DTLS(s))
+ dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
break;
case TLS_ST_SW_SRVR_DONE:
@@ -1880,6 +1992,16 @@ static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst)
case TLS_ST_SW_FINISHED:
if (statem_flush(s) != 1)
return WORK_MORE_A;
+#ifndef OPENSSL_NO_SCTP
+ if (SSL_IS_DTLS(s) && s->hit) {
+ /*
+ * Change to new shared key of SCTP-Auth, will be ignored if
+ * no SCTP used.
+ */
+ BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+ 0, NULL);
+ }
+#endif
break;
default:
@@ -1902,6 +2024,9 @@ static int server_construct_message(SSL *s)
STATEM *st = &s->statem;
switch(st->hand_state) {
+ case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+ return dtls_construct_hello_verify_request(s);
+
case TLS_ST_SW_HELLO_REQ:
return tls_construct_hello_request(s);
@@ -2045,6 +2170,26 @@ static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst)
case TLS_ST_SR_KEY_EXCH:
return tls_post_process_client_key_exchange(s, wst);
+ case TLS_ST_SR_CERT_VRFY:
+#ifndef OPENSSL_NO_SCTP
+ if ( /* Is this SCTP? */
+ BIO_dgram_is_sctp(SSL_get_wbio(s))
+ /* Are we renegotiating? */
+ && s->renegotiate
+ && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+ s->s3->in_read_app_data = 2;
+ s->rwstate = SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ statem_set_sctp_read_sock(s, 1);
+ return WORK_MORE_A;
+ } else {
+ statem_set_sctp_read_sock(s, 0);
+ }
+#endif
+ return WORK_FINISHED_CONTINUE;
+
+
case TLS_ST_SR_FINISHED:
if (s->hit)
return tls_finish_handshake(s, wst);