summaryrefslogtreecommitdiffstats
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)
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);