Implement Client TLS state machine
This swaps the implementation of the client TLS state machine to use the new state machine code instead. Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Richard Levitte <levitte@openssl.org>
This commit is contained in:
parent
b9908bf9b8
commit
8723588e1b
@ -127,8 +127,7 @@ int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
|
|||||||
*/
|
*/
|
||||||
if ((SSL_in_init(s) && !s->in_handshake) ||
|
if ((SSL_in_init(s) && !s->in_handshake) ||
|
||||||
(BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
|
(BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
|
||||||
(s->state == DTLS1_SCTP_ST_SR_READ_SOCK
|
statem_in_sctp_read_sock(s)))
|
||||||
|| s->state == DTLS1_SCTP_ST_CR_READ_SOCK)))
|
|
||||||
#else
|
#else
|
||||||
if (SSL_in_init(s) && !s->in_handshake)
|
if (SSL_in_init(s) && !s->in_handshake)
|
||||||
#endif
|
#endif
|
||||||
|
@ -440,9 +440,8 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
|
|||||||
* SCTP.
|
* SCTP.
|
||||||
*/
|
*/
|
||||||
if ((!s->in_handshake && SSL_in_init(s)) ||
|
if ((!s->in_handshake && SSL_in_init(s)) ||
|
||||||
(BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
|
(BIO_dgram_is_sctp(SSL_get_rbio(s))
|
||||||
(s->state == DTLS1_SCTP_ST_SR_READ_SOCK
|
&& statem_in_sctp_read_sock(s)
|
||||||
|| s->state == DTLS1_SCTP_ST_CR_READ_SOCK)
|
|
||||||
&& s->s3->in_read_app_data != 2))
|
&& s->s3->in_read_app_data != 2))
|
||||||
#else
|
#else
|
||||||
if (!s->in_handshake && SSL_in_init(s))
|
if (!s->in_handshake && SSL_in_init(s))
|
||||||
@ -586,8 +585,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
|
|||||||
*/
|
*/
|
||||||
if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
|
if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
|
||||||
SSL3_RECORD_get_type(rr) == SSL3_RT_APPLICATION_DATA &&
|
SSL3_RECORD_get_type(rr) == SSL3_RT_APPLICATION_DATA &&
|
||||||
(s->state == DTLS1_SCTP_ST_SR_READ_SOCK
|
statem_in_sctp_read_sock(s)) {
|
||||||
|| s->state == DTLS1_SCTP_ST_CR_READ_SOCK)) {
|
|
||||||
s->rwstate = SSL_READING;
|
s->rwstate = SSL_READING;
|
||||||
BIO_clear_retry_flags(SSL_get_rbio(s));
|
BIO_clear_retry_flags(SSL_get_rbio(s));
|
||||||
BIO_set_retry_read(SSL_get_rbio(s));
|
BIO_set_retry_read(SSL_get_rbio(s));
|
||||||
|
@ -1450,16 +1450,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
|
|||||||
* application data at this point (session renegotiation not yet
|
* application data at this point (session renegotiation not yet
|
||||||
* started), we will indulge it.
|
* started), we will indulge it.
|
||||||
*/
|
*/
|
||||||
if (s->s3->in_read_app_data &&
|
if (statem_app_data_allowed(s)) {
|
||||||
(s->s3->total_renegotiations != 0) &&
|
|
||||||
(((s->state & SSL_ST_CONNECT) &&
|
|
||||||
(s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
|
|
||||||
(s->state <= SSL3_ST_CR_SRVR_HELLO_A)
|
|
||||||
) || ((s->state & SSL_ST_ACCEPT) &&
|
|
||||||
(s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
|
|
||||||
(s->state >= SSL3_ST_SR_CLNT_HELLO_A)
|
|
||||||
)
|
|
||||||
)) {
|
|
||||||
s->s3->in_read_app_data = 2;
|
s->s3->in_read_app_data = 2;
|
||||||
return (-1);
|
return (-1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -446,6 +446,70 @@ unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
|
|||||||
return l + SSL_HM_HEADER_LENGTH(s);
|
return l + SSL_HM_HEADER_LENGTH(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum WORK_STATE tls_finish_handshake(SSL *s, enum WORK_STATE wst)
|
||||||
|
{
|
||||||
|
void (*cb) (const SSL *ssl, int type, int val) = NULL;
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_SCTP
|
||||||
|
if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
|
||||||
|
enum WORK_STATE ret;
|
||||||
|
ret = dtls_wait_for_dry(s);
|
||||||
|
if (ret != WORK_FINISHED_CONTINUE)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* clean a few things up */
|
||||||
|
ssl3_cleanup_key_block(s);
|
||||||
|
BUF_MEM_free(s->init_buf);
|
||||||
|
s->init_buf = NULL;
|
||||||
|
|
||||||
|
ssl_free_wbio_buffer(s);
|
||||||
|
|
||||||
|
s->init_num = 0;
|
||||||
|
|
||||||
|
if (!s->server || s->renegotiate == 2) {
|
||||||
|
/* skipped if we just sent a HelloRequest */
|
||||||
|
s->renegotiate = 0;
|
||||||
|
s->new_session = 0;
|
||||||
|
|
||||||
|
if (s->server) {
|
||||||
|
s->renegotiate = 0;
|
||||||
|
s->new_session = 0;
|
||||||
|
|
||||||
|
ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
|
||||||
|
|
||||||
|
s->ctx->stats.sess_accept_good++;
|
||||||
|
s->handshake_func = ssl3_accept;
|
||||||
|
} else {
|
||||||
|
ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
|
||||||
|
if (s->hit)
|
||||||
|
s->ctx->stats.sess_hit++;
|
||||||
|
|
||||||
|
s->handshake_func = ssl3_connect;
|
||||||
|
s->ctx->stats.sess_connect_good++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->info_callback != NULL)
|
||||||
|
cb = s->info_callback;
|
||||||
|
else if (s->ctx->info_callback != NULL)
|
||||||
|
cb = s->ctx->info_callback;
|
||||||
|
|
||||||
|
if (cb != NULL)
|
||||||
|
cb(s, SSL_CB_HANDSHAKE_DONE, 1);
|
||||||
|
|
||||||
|
if (SSL_IS_DTLS(s)) {
|
||||||
|
/* done with handshaking */
|
||||||
|
s->d1->handshake_read_seq = 0;
|
||||||
|
s->d1->handshake_write_seq = 0;
|
||||||
|
s->d1->next_handshake_write_seq = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WORK_FINISHED_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain handshake message of message type 'mt' (any if mt == -1), maximum
|
* Obtain handshake message of message type 'mt' (any if mt == -1), maximum
|
||||||
* acceptable body length 'max'. The first four bytes (msg_type and length)
|
* acceptable body length 'max'. The first four bytes (msg_type and length)
|
||||||
|
@ -165,11 +165,22 @@
|
|||||||
|
|
||||||
static int ssl_set_version(SSL *s);
|
static int ssl_set_version(SSL *s);
|
||||||
static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
|
static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* Temporarily disabled during development of new state machine code.
|
||||||
|
* TODO: Clean me up
|
||||||
|
*/
|
||||||
static int ssl3_check_change(SSL *s);
|
static int ssl3_check_change(SSL *s);
|
||||||
|
#endif
|
||||||
static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
|
static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
|
||||||
unsigned char *p);
|
unsigned char *p);
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* Temporarily disabled during development of new state machine code.
|
||||||
|
* TODO: Clean me up
|
||||||
|
*/
|
||||||
int ssl3_connect(SSL *s)
|
int ssl3_connect(SSL *s)
|
||||||
{
|
{
|
||||||
BUF_MEM *buf = NULL;
|
BUF_MEM *buf = NULL;
|
||||||
@ -631,6 +642,7 @@ int ssl3_connect(SSL *s)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* End temp disabled ssl3_connect */
|
||||||
/*
|
/*
|
||||||
* Work out what version we should be using for the initial ClientHello if
|
* Work out what version we should be using for the initial ClientHello if
|
||||||
* the version is currently set to (D)TLS_ANY_VERSION.
|
* the version is currently set to (D)TLS_ANY_VERSION.
|
||||||
@ -1285,6 +1297,32 @@ enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, unsigned long n)
|
|||||||
goto f_err;
|
goto f_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
BIO_ctrl(SSL_get_wbio(s),
|
||||||
|
BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
|
||||||
|
sizeof(sctpauthkey), sctpauthkey);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return MSG_PROCESS_CONTINUE_READING;
|
return MSG_PROCESS_CONTINUE_READING;
|
||||||
f_err:
|
f_err:
|
||||||
ssl3_send_alert(s, SSL3_AL_FATAL, al);
|
ssl3_send_alert(s, SSL3_AL_FATAL, al);
|
||||||
@ -3489,6 +3527,11 @@ int ssl3_check_cert_and_algorithm(SSL *s)
|
|||||||
* pre-shared secret, we have a "ticket" and the next server message
|
* pre-shared secret, we have a "ticket" and the next server message
|
||||||
* is CCS; and 0 otherwise. It returns -1 upon an error.
|
* is CCS; and 0 otherwise. It returns -1 upon an error.
|
||||||
*/
|
*/
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* TODO: No longer required. Temporarily kept during state machine development
|
||||||
|
* To be deleted by later commits
|
||||||
|
*/
|
||||||
static int ssl3_check_change(SSL *s)
|
static int ssl3_check_change(SSL *s)
|
||||||
{
|
{
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
@ -3518,6 +3561,7 @@ static int ssl3_check_change(SSL *s)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
int ssl3_send_next_proto(SSL *s)
|
int ssl3_send_next_proto(SSL *s)
|
||||||
|
@ -844,6 +844,9 @@ struct statem_st {
|
|||||||
enum HANDSHAKE_STATE hand_state;
|
enum HANDSHAKE_STATE hand_state;
|
||||||
int read_state_first_init;
|
int read_state_first_init;
|
||||||
int use_timer;
|
int use_timer;
|
||||||
|
#ifndef OPENSSL_NO_SCTP
|
||||||
|
int in_sctp_read_sock;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
typedef struct statem_st STATEM;
|
typedef struct statem_st STATEM;
|
||||||
|
|
||||||
@ -2071,6 +2074,7 @@ __owur int tls_get_message_header(SSL *s, int *mt);
|
|||||||
__owur int tls_get_message_body(SSL *s, unsigned long *len);
|
__owur int tls_get_message_body(SSL *s, unsigned long *len);
|
||||||
__owur int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen);
|
__owur int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen);
|
||||||
__owur int tls_construct_finished(SSL *s, const char *sender, int slen);
|
__owur int tls_construct_finished(SSL *s, const char *sender, int slen);
|
||||||
|
__owur enum WORK_STATE tls_finish_handshake(SSL *s, enum WORK_STATE wst);
|
||||||
__owur int ssl3_num_ciphers(void);
|
__owur int ssl3_num_ciphers(void);
|
||||||
__owur const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
|
__owur const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
|
||||||
int ssl3_renegotiate(SSL *ssl);
|
int ssl3_renegotiate(SSL *ssl);
|
||||||
@ -2092,7 +2096,11 @@ __owur int ssl3_connect(SSL *s);
|
|||||||
void statem_clear(SSL *s);
|
void statem_clear(SSL *s);
|
||||||
void statem_set_renegotiate(SSL *s);
|
void statem_set_renegotiate(SSL *s);
|
||||||
void statem_set_error(SSL *s);
|
void statem_set_error(SSL *s);
|
||||||
__owur int statem_client_app_data_allowed(SSL *s);
|
__owur int statem_app_data_allowed(SSL *s);
|
||||||
|
#ifndef OPENSSL_NO_SCTP
|
||||||
|
void statem_set_sctp_read_sock(SSL *s, int read_sock);
|
||||||
|
__owur int statem_in_sctp_read_sock(SSL *s);
|
||||||
|
#endif
|
||||||
__owur int ssl3_read(SSL *s, void *buf, int len);
|
__owur int ssl3_read(SSL *s, void *buf, int len);
|
||||||
__owur int ssl3_peek(SSL *s, void *buf, int len);
|
__owur int ssl3_peek(SSL *s, void *buf, int len);
|
||||||
__owur int ssl3_write(SSL *s, const void *buf, int len);
|
__owur int ssl3_write(SSL *s, const void *buf, int len);
|
||||||
|
682
ssl/statem.c
682
ssl/statem.c
@ -103,11 +103,22 @@ enum SUB_STATE_RETURN {
|
|||||||
SUB_STATE_END_HANDSHAKE
|
SUB_STATE_END_HANDSHAKE
|
||||||
};
|
};
|
||||||
|
|
||||||
int state_machine(SSL *s, int server);
|
static int state_machine(SSL *s, int server);
|
||||||
static void init_read_state_machine(SSL *s);
|
static void init_read_state_machine(SSL *s);
|
||||||
static enum SUB_STATE_RETURN read_state_machine(SSL *s);
|
static enum SUB_STATE_RETURN read_state_machine(SSL *s);
|
||||||
static void init_write_state_machine(SSL *s);
|
static void init_write_state_machine(SSL *s);
|
||||||
static enum SUB_STATE_RETURN write_state_machine(SSL *s);
|
static enum SUB_STATE_RETURN write_state_machine(SSL *s);
|
||||||
|
static inline int cert_req_allowed(SSL *s);
|
||||||
|
static inline int key_exchange_skip_allowed(SSL *s);
|
||||||
|
static int client_read_transition(SSL *s, int mt);
|
||||||
|
static enum WRITE_TRAN client_write_transition(SSL *s);
|
||||||
|
static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst);
|
||||||
|
static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst);
|
||||||
|
static int client_construct_message(SSL *s);
|
||||||
|
static unsigned long client_max_message_size(SSL *s);
|
||||||
|
static enum MSG_PROCESS_RETURN client_process_message(SSL *s,
|
||||||
|
unsigned long len);
|
||||||
|
static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the state machine state and reset back to MSG_FLOW_UNINITED
|
* Clear the state machine state and reset back to MSG_FLOW_UNINITED
|
||||||
@ -136,6 +147,10 @@ void statem_set_error(SSL *s)
|
|||||||
s->state = SSL_ST_ERR;
|
s->state = SSL_ST_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ssl3_connect(SSL *s) {
|
||||||
|
return state_machine(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The main message flow state machine. We start in the MSG_FLOW_UNINITED or
|
* 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
|
* MSG_FLOW_RENEGOTIATE state and finish in MSG_FLOW_FINISHED. Valid states and
|
||||||
@ -164,7 +179,7 @@ void statem_set_error(SSL *s)
|
|||||||
* 1: Success
|
* 1: Success
|
||||||
* <=0: NBIO or error
|
* <=0: NBIO or error
|
||||||
*/
|
*/
|
||||||
int state_machine(SSL *s, int server) {
|
static int state_machine(SSL *s, int server) {
|
||||||
BUF_MEM *buf = NULL;
|
BUF_MEM *buf = NULL;
|
||||||
unsigned long Time = (unsigned long)time(NULL);
|
unsigned long Time = (unsigned long)time(NULL);
|
||||||
void (*cb) (const SSL *ssl, int type, int val) = NULL;
|
void (*cb) (const SSL *ssl, int type, int val) = NULL;
|
||||||
@ -433,11 +448,10 @@ static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
|
|||||||
post_process_message = NULL;
|
post_process_message = NULL;
|
||||||
max_message_size = NULL;
|
max_message_size = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* TODO: Fill these in later when we've implemented them */
|
transition = client_read_transition;
|
||||||
transition = NULL;
|
process_message = client_process_message;
|
||||||
process_message = NULL;
|
max_message_size = client_max_message_size;
|
||||||
post_process_message = NULL;
|
post_process_message = client_post_process_message;
|
||||||
max_message_size = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->read_state_first_init) {
|
if (st->read_state_first_init) {
|
||||||
@ -623,11 +637,10 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
|
|||||||
post_work = NULL;
|
post_work = NULL;
|
||||||
construct_message = NULL;
|
construct_message = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* TODO: Fill these in later when we've implemented them */
|
transition = client_write_transition;
|
||||||
transition = NULL;
|
pre_work = client_pre_work;
|
||||||
pre_work = NULL;
|
post_work = client_post_work;
|
||||||
post_work = NULL;
|
construct_message = client_construct_message;
|
||||||
construct_message = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
@ -704,6 +717,20 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush the write BIO
|
||||||
|
*/
|
||||||
|
static int statem_flush(SSL *s)
|
||||||
|
{
|
||||||
|
s->rwstate = SSL_WRITING;
|
||||||
|
if (BIO_flush(s->wbio) <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s->rwstate = SSL_NOTHING;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called by the record layer to determine whether application data is
|
* Called by the record layer to determine whether application data is
|
||||||
* allowed to be sent in the current handshake state or not.
|
* allowed to be sent in the current handshake state or not.
|
||||||
@ -712,14 +739,637 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
|
|||||||
* 1: Yes (application data allowed)
|
* 1: Yes (application data allowed)
|
||||||
* 0: No (application data not allowed)
|
* 0: No (application data not allowed)
|
||||||
*/
|
*/
|
||||||
int statem_client_app_data_allowed(SSL *s)
|
int statem_app_data_allowed(SSL *s)
|
||||||
{
|
{
|
||||||
STATEM *st = &s->statem;
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
if(st->hand_state != TLS_ST_BEFORE &&
|
if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0))
|
||||||
st->hand_state != TLS_ST_OK &&
|
return 0;
|
||||||
st->hand_state != TLS_ST_CW_CLNT_HELLO)
|
|
||||||
|
if (!s->server) {
|
||||||
|
if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(st->hand_state == TLS_ST_CW_CLNT_HELLO)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the old check for code still using the old state machine. This
|
||||||
|
* will be removed by later commits
|
||||||
|
*/
|
||||||
|
if (((s->state & SSL_ST_CONNECT) && SSL_IS_DTLS(s) &&
|
||||||
|
(s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
|
||||||
|
(s->state <= SSL3_ST_CR_SRVR_HELLO_A)) ||
|
||||||
|
((s->state & SSL_ST_ACCEPT) &&
|
||||||
|
(s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
|
||||||
|
(s->state >= SSL3_ST_SR_CLNT_HELLO_A))
|
||||||
|
)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_SCTP
|
||||||
|
/*
|
||||||
|
* Set flag used by SCTP to determine whether we are in the read sock state
|
||||||
|
*/
|
||||||
|
void statem_set_sctp_read_sock(SSL *s, int read_sock)
|
||||||
|
{
|
||||||
|
s->statem.in_sctp_read_sock = read_sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by the record layer to determine whether we are in the read sock
|
||||||
|
* state or not.
|
||||||
|
*
|
||||||
|
* Return values are:
|
||||||
|
* 1: Yes (we are in the read sock state)
|
||||||
|
* 0: No (we are not in the read sock state)
|
||||||
|
*/
|
||||||
|
int statem_in_sctp_read_sock(SSL *s)
|
||||||
|
{
|
||||||
|
return s->statem.in_sctp_read_sock;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is a CertificateRequest message allowed at the moment or not?
|
||||||
|
*
|
||||||
|
* Return values are:
|
||||||
|
* 1: Yes
|
||||||
|
* 0: No
|
||||||
|
*/
|
||||||
|
static inline int cert_req_allowed(SSL *s)
|
||||||
|
{
|
||||||
|
/* TLS does not like anon-DH with client cert */
|
||||||
|
if (s->version > SSL3_VERSION
|
||||||
|
&& (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Are we allowed to skip the ServerKeyExchange message?
|
||||||
|
*
|
||||||
|
* Return values are:
|
||||||
|
* 1: Yes
|
||||||
|
* 0: No
|
||||||
|
*/
|
||||||
|
static inline int key_exchange_skip_allowed(SSL *s)
|
||||||
|
{
|
||||||
|
long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can't skip server key exchange if this is an ephemeral
|
||||||
|
* ciphersuite.
|
||||||
|
*/
|
||||||
|
if (alg_k & (SSL_kDHE | SSL_kECDHE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* client_read_transition() encapsulates the logic for the allowed handshake
|
||||||
|
* state transitions when the client is reading messages from the server. The
|
||||||
|
* message type that the server has sent is provided in |mt|. The current state
|
||||||
|
* is in |s->statem.hand_state|.
|
||||||
|
*
|
||||||
|
* Return values are:
|
||||||
|
* 1: Success (transition allowed)
|
||||||
|
* 0: Error (transition not allowed)
|
||||||
|
*/
|
||||||
|
static int client_read_transition(SSL *s, int mt)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
case TLS_ST_CW_CLNT_HELLO:
|
||||||
|
if (mt == SSL3_MT_SERVER_HELLO) {
|
||||||
|
st->hand_state = TLS_ST_CR_SRVR_HELLO;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_IS_DTLS(s)) {
|
||||||
|
if (mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
|
||||||
|
st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CR_SRVR_HELLO:
|
||||||
|
if (s->hit) {
|
||||||
|
if (s->tlsext_ticket_expected) {
|
||||||
|
if (mt == SSL3_MT_NEWSESSION_TICKET) {
|
||||||
|
st->hand_state = TLS_ST_CR_SESSION_TICKET;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
|
||||||
|
st->hand_state = TLS_ST_CR_CHANGE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(s->s3->tmp.new_cipher->algorithm_auth
|
||||||
|
& (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
|
||||||
|
if (mt == SSL3_MT_CERTIFICATE) {
|
||||||
|
st->hand_state = TLS_ST_CR_CERT;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
|
||||||
|
st->hand_state = TLS_ST_CR_KEY_EXCH;
|
||||||
|
return 1;
|
||||||
|
} else if (key_exchange_skip_allowed(s)) {
|
||||||
|
if (mt == SSL3_MT_CERTIFICATE_REQUEST
|
||||||
|
&& cert_req_allowed(s)) {
|
||||||
|
st->hand_state = TLS_ST_CR_CERT_REQ;
|
||||||
|
return 1;
|
||||||
|
} else if (mt == SSL3_MT_SERVER_DONE) {
|
||||||
|
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT:
|
||||||
|
if (s->tlsext_status_expected) {
|
||||||
|
if (mt == SSL3_MT_CERTIFICATE_STATUS) {
|
||||||
|
st->hand_state = TLS_ST_CR_CERT_STATUS;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
|
||||||
|
st->hand_state = TLS_ST_CR_KEY_EXCH;
|
||||||
|
return 1;
|
||||||
|
} else if (key_exchange_skip_allowed(s)) {
|
||||||
|
if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
|
||||||
|
st->hand_state = TLS_ST_CR_CERT_REQ;
|
||||||
|
return 1;
|
||||||
|
} else if (mt == SSL3_MT_SERVER_DONE) {
|
||||||
|
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT_STATUS:
|
||||||
|
if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
|
||||||
|
st->hand_state = TLS_ST_CR_KEY_EXCH;
|
||||||
|
return 1;
|
||||||
|
} else if (key_exchange_skip_allowed(s)) {
|
||||||
|
if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
|
||||||
|
st->hand_state = TLS_ST_CR_CERT_REQ;
|
||||||
|
return 1;
|
||||||
|
} else if (mt == SSL3_MT_SERVER_DONE) {
|
||||||
|
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CR_KEY_EXCH:
|
||||||
|
if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
|
||||||
|
st->hand_state = TLS_ST_CR_CERT_REQ;
|
||||||
|
return 1;
|
||||||
|
} else if (mt == SSL3_MT_SERVER_DONE) {
|
||||||
|
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT_REQ:
|
||||||
|
if (mt == SSL3_MT_SERVER_DONE) {
|
||||||
|
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CW_FINISHED:
|
||||||
|
if (mt == SSL3_MT_NEWSESSION_TICKET && s->tlsext_ticket_expected) {
|
||||||
|
st->hand_state = TLS_ST_CR_SESSION_TICKET;
|
||||||
|
return 1;
|
||||||
|
} else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
|
||||||
|
st->hand_state = TLS_ST_CR_CHANGE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CR_SESSION_TICKET:
|
||||||
|
if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
|
||||||
|
st->hand_state = TLS_ST_CR_CHANGE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CHANGE:
|
||||||
|
if (mt == SSL3_MT_FINISHED) {
|
||||||
|
st->hand_state = TLS_ST_CR_FINISHED;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No valid transition found */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* client_write_transition() works out what handshake state to move to next
|
||||||
|
* when the client is writing messages to be sent to the server.
|
||||||
|
*/
|
||||||
|
static enum WRITE_TRAN client_write_transition(SSL *s)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
case TLS_ST_OK:
|
||||||
|
/* Renegotiation - fall through */
|
||||||
|
case TLS_ST_BEFORE:
|
||||||
|
st->hand_state = TLS_ST_CW_CLNT_HELLO;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
|
||||||
|
case TLS_ST_CW_CLNT_HELLO:
|
||||||
|
/*
|
||||||
|
* No transition at the end of writing because we don't know what
|
||||||
|
* we will be sent
|
||||||
|
*/
|
||||||
|
return WRITE_TRAN_FINISHED;
|
||||||
|
|
||||||
|
case TLS_ST_CR_SRVR_DONE:
|
||||||
|
if (s->s3->tmp.cert_req)
|
||||||
|
st->hand_state = TLS_ST_CW_CERT;
|
||||||
|
else
|
||||||
|
st->hand_state = TLS_ST_CW_KEY_EXCH;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
|
||||||
|
case TLS_ST_CW_CERT:
|
||||||
|
st->hand_state = TLS_ST_CW_KEY_EXCH;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
|
||||||
|
case TLS_ST_CW_KEY_EXCH:
|
||||||
|
/*
|
||||||
|
* For TLS, cert_req is set to 2, so a cert chain of nothing is
|
||||||
|
* sent, but no verify packet is sent
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* XXX: For now, we do not support client authentication in ECDH
|
||||||
|
* cipher suites with ECDH (rather than ECDSA) certificates. We
|
||||||
|
* need to skip the certificate verify message when client's
|
||||||
|
* ECDH public key is sent inside the client certificate.
|
||||||
|
*/
|
||||||
|
if (s->s3->tmp.cert_req == 1) {
|
||||||
|
st->hand_state = TLS_ST_CW_CERT_VRFY;
|
||||||
|
} else {
|
||||||
|
st->hand_state = TLS_ST_CW_CHANGE;
|
||||||
|
}
|
||||||
|
if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
|
||||||
|
st->hand_state = TLS_ST_CW_CHANGE;
|
||||||
|
}
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
|
||||||
|
case TLS_ST_CW_CERT_VRFY:
|
||||||
|
st->hand_state = TLS_ST_CW_CHANGE;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
|
||||||
|
case TLS_ST_CW_CHANGE:
|
||||||
|
#if defined(OPENSSL_NO_NEXTPROTONEG)
|
||||||
|
st->hand_state = TLS_ST_CW_FINISHED;
|
||||||
|
#else
|
||||||
|
if (s->s3->next_proto_neg_seen)
|
||||||
|
st->hand_state = TLS_ST_CW_NEXT_PROTO;
|
||||||
|
else
|
||||||
|
st->hand_state = TLS_ST_CW_FINISHED;
|
||||||
|
#endif
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
|
||||||
|
#if !defined(OPENSSL_NO_NEXTPROTONEG)
|
||||||
|
case TLS_ST_CW_NEXT_PROTO:
|
||||||
|
st->hand_state = TLS_ST_CW_FINISHED;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case TLS_ST_CW_FINISHED:
|
||||||
|
if (s->hit) {
|
||||||
|
st->hand_state = TLS_ST_OK;
|
||||||
|
/* TODO: This needs removing */
|
||||||
|
s->state = SSL_ST_OK;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
} else {
|
||||||
|
return WRITE_TRAN_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TLS_ST_CR_FINISHED:
|
||||||
|
if (s->hit) {
|
||||||
|
st->hand_state = TLS_ST_CW_CHANGE;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
} else {
|
||||||
|
st->hand_state = TLS_ST_OK;
|
||||||
|
/* TODO: This needs removing */
|
||||||
|
s->state = SSL_ST_OK;
|
||||||
|
return WRITE_TRAN_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Shouldn't happen */
|
||||||
|
return WRITE_TRAN_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform any pre work that needs to be done prior to sending a message from
|
||||||
|
* the client to the server.
|
||||||
|
*/
|
||||||
|
static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
case TLS_ST_CW_CLNT_HELLO:
|
||||||
|
s->shutdown = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CW_CERT:
|
||||||
|
return tls_prepare_client_certificate(s, wst);
|
||||||
|
|
||||||
|
case TLS_ST_OK:
|
||||||
|
return tls_finish_handshake(s, wst);
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* No pre work to be done */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WORK_FINISHED_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform any work that needs to be done after sending a message from the
|
||||||
|
* client to the server.
|
||||||
|
*/
|
||||||
|
static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
s->init_num = 0;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
case TLS_ST_CW_CLNT_HELLO:
|
||||||
|
/* turn on buffering for the next lot of output */
|
||||||
|
if (s->bbio != s->wbio)
|
||||||
|
s->wbio = BIO_push(s->bbio, s->wbio);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CW_KEY_EXCH:
|
||||||
|
if (tls_client_key_exchange_post_work(s) == 0)
|
||||||
|
return WORK_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CW_CHANGE:
|
||||||
|
s->session->cipher = s->s3->tmp.new_cipher;
|
||||||
|
#ifdef OPENSSL_NO_COMP
|
||||||
|
s->session->compress_meth = 0;
|
||||||
|
#else
|
||||||
|
if (s->s3->tmp.new_compression == NULL)
|
||||||
|
s->session->compress_meth = 0;
|
||||||
|
else
|
||||||
|
s->session->compress_meth = s->s3->tmp.new_compression->id;
|
||||||
|
#endif
|
||||||
|
if (!s->method->ssl3_enc->setup_key_block(s))
|
||||||
|
return WORK_ERROR;
|
||||||
|
|
||||||
|
if (!s->method->ssl3_enc->change_cipher_state(s,
|
||||||
|
SSL3_CHANGE_CIPHER_CLIENT_WRITE))
|
||||||
|
return WORK_ERROR;
|
||||||
|
|
||||||
|
if (SSL_IS_DTLS(s)) {
|
||||||
|
#ifndef OPENSSL_NO_SCTP
|
||||||
|
if (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
|
||||||
|
|
||||||
|
dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_ST_CW_FINISHED:
|
||||||
|
#ifndef OPENSSL_NO_SCTP
|
||||||
|
if (SSL_IS_DTLS(s) && s->hit == 0) {
|
||||||
|
/*
|
||||||
|
* 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 (statem_flush(s) != 1)
|
||||||
|
return WORK_MORE_B;
|
||||||
|
|
||||||
|
if (s->hit && tls_finish_handshake(s, WORK_MORE_A) != 1)
|
||||||
|
return WORK_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* No post work to be done */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WORK_FINISHED_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct a message to be sent from the client to the server.
|
||||||
|
*
|
||||||
|
* Valid return values are:
|
||||||
|
* 1: Success
|
||||||
|
* 0: Error
|
||||||
|
*/
|
||||||
|
static int client_construct_message(SSL *s)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
case TLS_ST_CW_CLNT_HELLO:
|
||||||
|
return tls_construct_client_hello(s);
|
||||||
|
|
||||||
|
case TLS_ST_CW_CERT:
|
||||||
|
return tls_construct_client_certificate(s);
|
||||||
|
|
||||||
|
case TLS_ST_CW_KEY_EXCH:
|
||||||
|
return tls_construct_client_key_exchange(s);
|
||||||
|
|
||||||
|
case TLS_ST_CW_CERT_VRFY:
|
||||||
|
return tls_construct_client_verify(s);
|
||||||
|
|
||||||
|
case TLS_ST_CW_CHANGE:
|
||||||
|
return tls_construct_change_cipher_spec(s);
|
||||||
|
|
||||||
|
#if !defined(OPENSSL_NO_NEXTPROTONEG)
|
||||||
|
case TLS_ST_CW_NEXT_PROTO:
|
||||||
|
return tls_construct_next_proto(s);
|
||||||
|
#endif
|
||||||
|
case TLS_ST_CW_FINISHED:
|
||||||
|
return tls_construct_finished(s,
|
||||||
|
s->method->
|
||||||
|
ssl3_enc->client_finished_label,
|
||||||
|
s->method->
|
||||||
|
ssl3_enc->client_finished_label_len);
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Shouldn't happen */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The spec allows for a longer length than this, but we limit it */
|
||||||
|
#define SERVER_HELLO_MAX_LENGTH 20000
|
||||||
|
#define SERVER_KEY_EXCH_MAX_LENGTH 102400
|
||||||
|
#define SERVER_HELLO_DONE_MAX_LENGTH 0
|
||||||
|
#define CCS_MAX_LENGTH 1
|
||||||
|
/* Max should actually be 36 but we are generous */
|
||||||
|
#define FINISHED_MAX_LENGTH 64
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the maximum allowed length for the current message that we are
|
||||||
|
* reading. Excludes the message header.
|
||||||
|
*/
|
||||||
|
static unsigned long client_max_message_size(SSL *s)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
case TLS_ST_CR_SRVR_HELLO:
|
||||||
|
return SERVER_HELLO_MAX_LENGTH;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT:
|
||||||
|
return s->max_cert_list;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT_STATUS:
|
||||||
|
return SSL3_RT_MAX_PLAIN_LENGTH;
|
||||||
|
|
||||||
|
case TLS_ST_CR_KEY_EXCH:
|
||||||
|
return SERVER_KEY_EXCH_MAX_LENGTH;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT_REQ:
|
||||||
|
return SSL3_RT_MAX_PLAIN_LENGTH;
|
||||||
|
|
||||||
|
case TLS_ST_CR_SRVR_DONE:
|
||||||
|
return SERVER_HELLO_DONE_MAX_LENGTH;
|
||||||
|
|
||||||
|
case TLS_ST_CR_CHANGE:
|
||||||
|
return CCS_MAX_LENGTH;
|
||||||
|
|
||||||
|
case TLS_ST_CR_SESSION_TICKET:
|
||||||
|
return SSL3_RT_MAX_PLAIN_LENGTH;
|
||||||
|
|
||||||
|
case TLS_ST_CR_FINISHED:
|
||||||
|
return FINISHED_MAX_LENGTH;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Shouldn't happen */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a message that the client has been received from the server.
|
||||||
|
*/
|
||||||
|
static enum MSG_PROCESS_RETURN client_process_message(SSL *s, unsigned long len)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
case TLS_ST_CR_SRVR_HELLO:
|
||||||
|
return tls_process_server_hello(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT:
|
||||||
|
return tls_process_server_certificate(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT_STATUS:
|
||||||
|
return tls_process_cert_status(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_KEY_EXCH:
|
||||||
|
return tls_process_key_exchange(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_CERT_REQ:
|
||||||
|
return tls_process_certificate_request(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_SRVR_DONE:
|
||||||
|
return tls_process_server_done(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_CHANGE:
|
||||||
|
return tls_process_change_cipher_spec(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_SESSION_TICKET:
|
||||||
|
return tls_process_new_session_ticket(s, len);
|
||||||
|
|
||||||
|
case TLS_ST_CR_FINISHED:
|
||||||
|
return tls_process_finished(s, len);
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Shouldn't happen */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MSG_PROCESS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform any further processing required following the receipt of a message
|
||||||
|
* from the server
|
||||||
|
*/
|
||||||
|
static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst)
|
||||||
|
{
|
||||||
|
STATEM *st = &s->statem;
|
||||||
|
|
||||||
|
switch(st->hand_state) {
|
||||||
|
#ifndef OPENSSL_NO_SCTP
|
||||||
|
case TLS_ST_CR_SRVR_DONE:
|
||||||
|
/* We only get here if we are using SCTP and we are renegotiating */
|
||||||
|
if (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;
|
||||||
|
}
|
||||||
|
statem_set_sctp_read_sock(s, 0);
|
||||||
|
return WORK_FINISHED_STOP;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case TLS_ST_CR_FINISHED:
|
||||||
|
if (!s->hit)
|
||||||
|
return tls_finish_handshake(s, wst);
|
||||||
|
else
|
||||||
|
return WORK_FINISHED_STOP;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shouldn't happen */
|
||||||
|
return WORK_ERROR;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user