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>
This commit is contained in:
parent
94836de2ae
commit
c130dd8ea4
@ -1929,6 +1929,7 @@ void ERR_load_SSL_strings(void);
|
||||
# define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE 267
|
||||
# define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268
|
||||
# define SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC 371
|
||||
# define SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST 385
|
||||
# define SSL_F_DTLS_GET_REASSEMBLED_MESSAGE 370
|
||||
# define SSL_F_READ_STATE_MACHINE 352
|
||||
# define SSL_F_SSL3_ACCEPT 128
|
||||
|
@ -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;
|
||||
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;
|
||||
}
|
||||
|
||||
len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
|
||||
s->d1->cookie, s->d1->cookie_len);
|
||||
|
||||
dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
|
||||
len);
|
||||
len += DTLS1_HM_HEADER_LENGTH;
|
||||
|
||||
s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
|
||||
/* number of bytes to write */
|
||||
s->init_num = len;
|
||||
s->init_off = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
|
||||
return (dtls1_do_write(s, SSL3_RT_HANDSHAKE));
|
||||
len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
|
||||
s->d1->cookie, s->d1->cookie_len);
|
||||
|
||||
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;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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"},
|
||||
|
@ -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);
|
||||
|
147
ssl/statem.c
147
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user