提交 c130dd8e 编写于 作者: M Matt Caswell

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: NTim Hudson <tjh@openssl.org>
Reviewed-by: NRichard Levitte <levitte@openssl.org>
上级 94836de2
......@@ -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;
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;
}
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册