diff options
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/Makefile | 9 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 63 | ||||
-rw-r--r-- | ssl/statem/statem.c | 1376 | ||||
-rw-r--r-- | ssl/statem/statem.h | 8 | ||||
-rw-r--r-- | ssl/statem/statem_clnt.c | 623 | ||||
-rw-r--r-- | ssl/statem/statem_dtls.c | 1 | ||||
-rw-r--r-- | ssl/statem/statem_lib.c | 1 | ||||
-rw-r--r-- | ssl/statem/statem_locl.h | 181 | ||||
-rw-r--r-- | ssl/statem/statem_srvr.c | 721 |
9 files changed, 1535 insertions, 1448 deletions
diff --git a/ssl/Makefile b/ssl/Makefile index 9f1fe8d8c2..0865631d69 100644 --- a/ssl/Makefile +++ b/ssl/Makefile @@ -682,6 +682,7 @@ statem/statem.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h statem/statem.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h statem/statem.o: statem/../packet_locl.h statem/../record/record.h statem/statem.o: statem/../ssl_locl.h statem/../statem/statem.h statem/statem.c +statem/statem.o: statem/statem_locl.h statem/statem_clnt.o: ../e_os.h ../include/openssl/asn1.h statem/statem_clnt.o: ../include/openssl/bio.h ../include/openssl/bn.h statem/statem_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h @@ -706,7 +707,7 @@ statem/statem_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h statem/statem_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h statem/statem_clnt.o: statem/../packet_locl.h statem/../record/record.h statem/statem_clnt.o: statem/../ssl_locl.h statem/../statem/statem.h -statem/statem_clnt.o: statem/statem_clnt.c +statem/statem_clnt.o: statem/statem_clnt.c statem/statem_locl.h statem/statem_dtls.o: ../e_os.h ../include/openssl/asn1.h statem/statem_dtls.o: ../include/openssl/bio.h ../include/openssl/bn.h statem/statem_dtls.o: ../include/openssl/buffer.h ../include/openssl/comp.h @@ -730,7 +731,7 @@ statem/statem_dtls.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h statem/statem_dtls.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h statem/statem_dtls.o: statem/../packet_locl.h statem/../record/record.h statem/statem_dtls.o: statem/../ssl_locl.h statem/../statem/statem.h -statem/statem_dtls.o: statem/statem_dtls.c +statem/statem_dtls.o: statem/statem_dtls.c statem/statem_locl.h statem/statem_lib.o: ../e_os.h ../include/openssl/asn1.h statem/statem_lib.o: ../include/openssl/bio.h ../include/openssl/bn.h statem/statem_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h @@ -754,7 +755,7 @@ statem/statem_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h statem/statem_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h statem/statem_lib.o: statem/../packet_locl.h statem/../record/record.h statem/statem_lib.o: statem/../ssl_locl.h statem/../statem/statem.h -statem/statem_lib.o: statem/statem_lib.c +statem/statem_lib.o: statem/statem_lib.c statem/statem_locl.h statem/statem_srvr.o: ../e_os.h ../include/internal/constant_time_locl.h statem/statem_srvr.o: ../include/openssl/asn1.h ../include/openssl/bio.h statem/statem_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h @@ -779,7 +780,7 @@ statem/statem_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h statem/statem_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h statem/statem_srvr.o: statem/../packet_locl.h statem/../record/record.h statem/statem_srvr.o: statem/../ssl_locl.h statem/../statem/statem.h -statem/statem_srvr.o: statem/statem_srvr.c +statem/statem_srvr.o: statem/statem_locl.h statem/statem_srvr.c t1_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h t1_enc.o: ../include/openssl/bn.h ../include/openssl/buffer.h t1_enc.o: ../include/openssl/comp.h ../include/openssl/crypto.h diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 25afff8c9b..d30663f43b 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1914,15 +1914,7 @@ __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen, __owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p); __owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); void ssl3_init_finished_mac(SSL *s); -__owur int tls_construct_server_certificate(SSL *s); -__owur int tls_construct_new_session_ticket(SSL *s); -__owur int tls_construct_cert_status(SSL *s); -__owur enum MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, - PACKET *pkt); -__owur enum MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt); __owur int ssl3_setup_key_block(SSL *s); -__owur int tls_construct_change_cipher_spec(SSL *s); -__owur int dtls_construct_change_cipher_spec(SSL *s); __owur int ssl3_change_cipher_state(SSL *s, int which); void ssl3_cleanup_key_block(SSL *s); __owur int ssl3_do_write(SSL *s, int type); @@ -1930,12 +1922,6 @@ int ssl3_send_alert(SSL *s, int level, int desc); __owur int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, int len); __owur int ssl3_get_req_cert_type(SSL *s, unsigned char *p); -__owur long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok); -__owur int tls_get_message_header(SSL *s, int *mt); -__owur int tls_get_message_body(SSL *s, unsigned long *len); -__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 enum WORK_STATE dtls_wait_for_dry(SSL *s); __owur int ssl3_num_ciphers(void); __owur const SSL_CIPHER *ssl3_get_cipher(unsigned int u); int ssl3_renegotiate(SSL *ssl); @@ -2007,54 +1993,6 @@ __owur unsigned int dtls1_link_min_mtu(void); void dtls1_hm_fragment_free(hm_fragment *frag); __owur int dtls1_query_mtu(SSL *s); -/* some client-only functions */ -__owur int tls_construct_client_hello(SSL *s); -__owur enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, - PACKET *pkt); -__owur enum MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, - PACKET *pkt); -__owur enum MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, - PACKET *pkt); -__owur enum MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt); -__owur enum MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt); -__owur int tls_construct_client_verify(SSL *s); -__owur enum WORK_STATE tls_prepare_client_certificate(SSL *s, - enum WORK_STATE wst); -__owur int tls_construct_client_certificate(SSL *s); -__owur int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey); -__owur int tls_construct_client_key_exchange(SSL *s); -__owur int tls_client_key_exchange_post_work(SSL *s); -__owur enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, - PACKET *pkt); -__owur enum MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, - PACKET *pkt); -__owur int ssl3_check_cert_and_algorithm(SSL *s); -# ifndef OPENSSL_NO_NEXTPROTONEG -__owur int tls_construct_next_proto(SSL *s); -# endif -__owur enum MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt); - -/* some server-only functions */ -__owur enum MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt); -__owur enum WORK_STATE tls_post_process_client_hello(SSL *s, - enum WORK_STATE wst); -__owur int tls_construct_server_hello(SSL *s); -__owur int tls_construct_hello_request(SSL *s); -__owur int dtls_construct_hello_verify_request(SSL *s); -__owur int tls_construct_server_key_exchange(SSL *s); -__owur int tls_construct_certificate_request(SSL *s); -__owur int tls_construct_server_done(SSL *s); -__owur enum MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, - PACKET *pkt); -__owur enum MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, - PACKET *pkt); -__owur enum WORK_STATE tls_post_process_client_key_exchange(SSL *s, - enum WORK_STATE wst); -__owur enum MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt); -# ifndef OPENSSL_NO_NEXTPROTONEG -__owur enum MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt); -# endif - __owur int tls1_new(SSL *s); void tls1_free(SSL *s); void tls1_clear(SSL *s); @@ -2067,7 +2005,6 @@ void dtls1_clear(SSL *s); long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg); __owur int dtls1_shutdown(SSL *s); -__owur int dtls_get_message(SSL *s, int *mt, unsigned long *len); __owur int dtls1_dispatch_alert(SSL *s); __owur int ssl_init_wbio_buffer(SSL *s, int push); diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 7e4f524ddc..f0b3260829 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -58,6 +58,7 @@ #include <openssl/rand.h> #include "../ssl_locl.h" +#include "statem_locl.h" /* * This file implements the SSL/TLS/DTLS state machines. @@ -83,7 +84,7 @@ * | Message flow state machine | | | * | | | | * | -------------------- -------------------- | Transition | Handshake state | - * | | MSG_FLOW_READING | | MSG_FLOW_WRITING | | Event | machine | + * | | MSG_FLOW_READING | | MSG_FLOW_WRITING | | Event | machine | * | | sub-state | | sub-state | |----------->| | * | | machine for | | machine for | | | | * | | reading messages | | writing messages | | | | @@ -108,27 +109,6 @@ static void init_read_state_machine(SSL *s); static enum SUB_STATE_RETURN read_state_machine(SSL *s); static void init_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, PACKET *pkt); -static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst); -static int server_read_transition(SSL *s, int mt); -static inline int send_server_key_exchange(SSL *s); -static inline int send_certificate_request(SSL *s); -static enum WRITE_TRAN server_write_transition(SSL *s); -static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst); -static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst); -static int server_construct_message(SSL *s); -static unsigned long server_max_message_size(SSL *s); -static enum MSG_PROCESS_RETURN server_process_message(SSL *s, PACKET *pkt); -static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst); - enum HANDSHAKE_STATE SSL_state(const SSL *ssl) { @@ -818,7 +798,7 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s) /* * Flush the write BIO */ -static int statem_flush(SSL *s) +int statem_flush(SSL *s) { s->rwstate = SSL_WRITING; if (BIO_flush(s->wbio) <= 0) { @@ -867,7 +847,6 @@ int statem_app_data_allowed(SSL *s) return 0; } - #ifndef OPENSSL_NO_SCTP /* * Set flag used by SCTP to determine whether we are in the read sock state @@ -890,1352 +869,3 @@ 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 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 (SSL_IS_DTLS(s) && mt == DTLS1_MT_HELLO_VERIFY_REQUEST) { - st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST; - 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 DTLS_ST_CR_HELLO_VERIFY_REQUEST: - st->hand_state = TLS_ST_CW_CLNT_HELLO; - return WRITE_TRAN_CONTINUE; - - 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 (!SSL_IS_DTLS(s) && 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; - statem_set_in_init(s, 0); - 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; - statem_set_in_init(s, 0); - 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; - if (SSL_IS_DTLS(s)) { - /* every DTLS ClientHello resets Finished MAC */ - ssl3_init_finished_mac(s); - } - break; - - case TLS_ST_CW_CERT: - return tls_prepare_client_certificate(s, wst); - - case TLS_ST_CW_CHANGE: - if (SSL_IS_DTLS(s)) { - if (s->hit) { - /* - * We're into the last flight so we don't retransmit these - * messages unless we need to. - */ - st->use_timer = 0; - } -#ifndef OPENSSL_NO_SCTP - if (BIO_dgram_is_sctp(SSL_get_wbio(s))) - return dtls_wait_for_dry(s); -#endif - } - return WORK_FINISHED_CONTINUE; - - 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: - if (SSL_IS_DTLS(s) && s->d1->cookie_len > 0 && statem_flush(s) != 1) - return WORK_MORE_A; -#ifndef OPENSSL_NO_SCTP - /* Disable buffering for SCTP */ - if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s))) { -#endif - /* - * turn on buffering for the next lot of output - */ - if (s->bbio != s->wbio) - s->wbio = BIO_push(s->bbio, s->wbio); -#ifndef OPENSSL_NO_SCTP - } -#endif - if (SSL_IS_DTLS(s)) { - /* Treat the next message as the first packet */ - s->first_packet = 1; - } - 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 (wst == WORK_MORE_A && 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: - if (SSL_IS_DTLS(s)) - return dtls_construct_change_cipher_spec(s); - else - 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 HELLO_VERIFY_REQUEST_MAX_LENGTH 258 -#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 DTLS_ST_CR_HELLO_VERIFY_REQUEST: - return HELLO_VERIFY_REQUEST_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, PACKET *pkt) -{ - STATEM *st = &s->statem; - - switch(st->hand_state) { - case TLS_ST_CR_SRVR_HELLO: - return tls_process_server_hello(s, pkt); - - case DTLS_ST_CR_HELLO_VERIFY_REQUEST: - return dtls_process_hello_verify(s, pkt); - - case TLS_ST_CR_CERT: - return tls_process_server_certificate(s, pkt); - - case TLS_ST_CR_CERT_STATUS: - return tls_process_cert_status(s, pkt); - - case TLS_ST_CR_KEY_EXCH: - return tls_process_key_exchange(s, pkt); - - case TLS_ST_CR_CERT_REQ: - return tls_process_certificate_request(s, pkt); - - case TLS_ST_CR_SRVR_DONE: - return tls_process_server_done(s, pkt); - - case TLS_ST_CR_CHANGE: - return tls_process_change_cipher_spec(s, pkt); - - case TLS_ST_CR_SESSION_TICKET: - return tls_process_new_session_ticket(s, pkt); - - case TLS_ST_CR_FINISHED: - return tls_process_finished(s, pkt); - - 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; -} - - -/* - * server_read_transition() encapsulates the logic for the allowed handshake - * state transitions when the server is reading messages from the client. The - * message type that the client has sent is provided in |mt|. The current state - * is in |s->statem.hand_state|. - * - * Valid return values are: - * 1: Success (transition allowed) - * 0: Error (transition not allowed) - */ -static int server_read_transition(SSL *s, int mt) -{ - STATEM *st = &s->statem; - - 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; - } - break; - - case TLS_ST_SW_SRVR_DONE: - /* - * If we get a CKE message after a ServerDone then either - * 1) We didn't request a Certificate - * OR - * 2) If we did request one then - * a) We allow no Certificate to be returned - * AND - * b) We are running SSL3 (in TLS1.0+ the client must return a 0 - * list if we requested a certificate) - */ - if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE - && (!s->s3->tmp.cert_request - || (!((s->verify_mode & SSL_VERIFY_PEER) && - (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) - && (s->version == SSL3_VERSION)))) { - st->hand_state = TLS_ST_SR_KEY_EXCH; - return 1; - } else if (s->s3->tmp.cert_request) { - if (mt == SSL3_MT_CERTIFICATE) { - st->hand_state = TLS_ST_SR_CERT; - return 1; - } - } - break; - - case TLS_ST_SR_CERT: - if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) { - st->hand_state = TLS_ST_SR_KEY_EXCH; - return 1; - } - break; - - case TLS_ST_SR_KEY_EXCH: - /* - * We should only process a CertificateVerify message if we have - * received a Certificate from the client. If so then |s->session->peer| - * will be non NULL. In some instances a CertificateVerify message is - * not required even if the peer has sent a Certificate (e.g. such as in - * the case of static DH). In that case |s->no_cert_verify| should be - * set. - */ - if (s->session->peer == NULL || s->no_cert_verify) { - if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { - /* - * For the ECDH ciphersuites when the client sends its ECDH - * pub key in a certificate, the CertificateVerify message is - * not sent. Also for GOST ciphersuites when the client uses - * its key from the certificate for key exchange. - */ - st->hand_state = TLS_ST_SR_CHANGE; - return 1; - } - } else { - if (mt == SSL3_MT_CERTIFICATE_VERIFY) { - st->hand_state = TLS_ST_SR_CERT_VRFY; - return 1; - } - } - break; - - case TLS_ST_SR_CERT_VRFY: - if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { - st->hand_state = TLS_ST_SR_CHANGE; - return 1; - } - break; - - case TLS_ST_SR_CHANGE: -#ifndef OPENSSL_NO_NEXTPROTONEG - if (s->s3->next_proto_neg_seen) { - if (mt == SSL3_MT_NEXT_PROTO) { - st->hand_state = TLS_ST_SR_NEXT_PROTO; - return 1; - } - } else { -#endif - if (mt == SSL3_MT_FINISHED) { - st->hand_state = TLS_ST_SR_FINISHED; - return 1; - } -#ifndef |