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
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
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
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
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
__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);
__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);
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);
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);
#include <openssl/rand.h>
#include "../ssl_locl.h"
+#include "statem_locl.h"
/*
* This file implements the SSL/TLS/DTLS state machines.
* | 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 | | | |
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)
{
/*
* 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) {
return 0;
}
-
#ifndef OPENSSL_NO_SCTP
/*
* Set flag used by SCTP to determine whether we are in the read sock state
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 OPENSSL_NO_NEXTPROTONEG
- }
-#endif
- break;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- case TLS_ST_SR_NEXT_PROTO:
- if (mt == SSL3_MT_FINISHED) {
- st->hand_state = TLS_ST_SR_FINISHED;
- return 1;
- }
- break;
-#endif
-
- case TLS_ST_SW_FINISHED:
- if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
- st->hand_state = TLS_ST_SR_CHANGE;
- return 1;
- }
- break;
-
- default:
- break;
- }
-
- /* No valid transition found */
- return 0;
-}
-
-/*
- * Should we send a ServerKeyExchange message?
- *
- * Valid return values are:
- * 1: Yes
- * 0: No
- */
-static inline int send_server_key_exchange(SSL *s)
-{
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
- /*
- * only send a ServerKeyExchange if DH, fortezza or RSA but we have a
- * sign only certificate PSK: may send PSK identity hints For
- * ECC ciphersuites, we send a serverKeyExchange message only if
- * the cipher suite is either ECDH-anon or ECDHE. In other cases,
- * the server certificate contains the server's public key for
- * key exchange.
- */
- if ( (alg_k & SSL_kDHE)
- || (alg_k & SSL_kECDHE)
- || ((alg_k & SSL_kRSA)
- && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
- || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
- && EVP_PKEY_size(s->cert->pkeys
- [SSL_PKEY_RSA_ENC].privatekey) *
- 8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
- )
- )
- )
- /*
- * PSK: send ServerKeyExchange if PSK identity hint if
- * provided
- */
-#ifndef OPENSSL_NO_PSK
- /* Only send SKE if we have identity hint for plain PSK */
- || ((alg_k & (SSL_kPSK | SSL_kRSAPSK))
- && s->cert->psk_identity_hint)
- /* For other PSK always send SKE */
- || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
-#endif
-#ifndef OPENSSL_NO_SRP
- /* SRP: send ServerKeyExchange */
- || (alg_k & SSL_kSRP)
-#endif
- ) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Should we send a CertificateRequest message?
- *
- * Valid return values are:
- * 1: Yes
- * 0: No
- */
-static inline int send_certificate_request(SSL *s)
-{
- if (
- /* don't request cert unless asked for it: */
- s->verify_mode & SSL_VERIFY_PEER
- /*
- * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
- * during re-negotiation:
- */
- && ((s->session->peer == NULL) ||
- !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
- /*
- * never request cert in anonymous ciphersuites (see
- * section "Certificate request" in SSL 3 drafts and in
- * RFC 2246):
- */
- && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
- /*
- * ... except when the application insists on
- * verification (against the specs, but s3_clnt.c accepts
- * this for SSL 3)
- */
- || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
- /* don't request certificate for SRP auth */
- && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
- /*
- * With normal PSK Certificates and Certificate Requests
- * are omitted
- */
- && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- * server_write_transition() works out what handshake state to move to next
- * when the server is writing messages to be sent to the client.
- */
-static enum WRITE_TRAN server_write_transition(SSL *s)
-{
- STATEM *st = &s->statem;
-
- switch(st->hand_state) {
- case TLS_ST_BEFORE:
- /* Just go straight to trying to read from the client */;
- return WRITE_TRAN_FINISHED;
-
- case TLS_ST_OK:
- /* We must be trying to renegotiate */
- st->hand_state = TLS_ST_SW_HELLO_REQ;
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SW_HELLO_REQ:
- st->hand_state = TLS_ST_OK;
- statem_set_in_init(s, 0);
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SR_CLNT_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)
- st->hand_state = TLS_ST_SW_SESSION_TICKET;
- else
- st->hand_state = TLS_ST_SW_CHANGE;
- } else {
- /* Check if it is anon DH or anon ECDH, */
- /* normal PSK or SRP */
- if (!(s->s3->tmp.new_cipher->algorithm_auth &
- (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
- st->hand_state = TLS_ST_SW_CERT;
- } else if (send_server_key_exchange(s)) {
- st->hand_state = TLS_ST_SW_KEY_EXCH;
- } else if (send_certificate_request(s)) {
- st->hand_state = TLS_ST_SW_CERT_REQ;
- } else {
- st->hand_state = TLS_ST_SW_SRVR_DONE;
- }
- }
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SW_CERT:
- if (s->tlsext_status_expected) {
- st->hand_state = TLS_ST_SW_CERT_STATUS;
- return WRITE_TRAN_CONTINUE;
- }
- /* Fall through */
-
- case TLS_ST_SW_CERT_STATUS:
- if (send_server_key_exchange(s)) {
- st->hand_state = TLS_ST_SW_KEY_EXCH;
- return WRITE_TRAN_CONTINUE;
- }
- /* Fall through */
-
- case TLS_ST_SW_KEY_EXCH:
- if (send_certificate_request(s)) {
- st->hand_state = TLS_ST_SW_CERT_REQ;
- return WRITE_TRAN_CONTINUE;
- }
- /* Fall through */
-
- case TLS_ST_SW_CERT_REQ:
- st->hand_state = TLS_ST_SW_SRVR_DONE;
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SW_SRVR_DONE:
- return WRITE_TRAN_FINISHED;
-
- case TLS_ST_SR_FINISHED:
- if (s->hit) {
- st->hand_state = TLS_ST_OK;
- statem_set_in_init(s, 0);
- return WRITE_TRAN_CONTINUE;
- } else if (s->tlsext_ticket_expected) {
- st->hand_state = TLS_ST_SW_SESSION_TICKET;
- } else {
- st->hand_state = TLS_ST_SW_CHANGE;
- }
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SW_SESSION_TICKET:
- st->hand_state = TLS_ST_SW_CHANGE;
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SW_CHANGE:
- st->hand_state = TLS_ST_SW_FINISHED;
- return WRITE_TRAN_CONTINUE;
-
- case TLS_ST_SW_FINISHED:
- if (s->hit) {
- return WRITE_TRAN_FINISHED;
- }
- 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 server to the client.
- */
-static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst)
-{
- STATEM *st = &s->statem;
-
- 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:
- s->session->cipher = s->s3->tmp.new_cipher;
- if (!s->method->ssl3_enc->setup_key_block(s)) {
- 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:
- 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
- * server to the client.
- */
-static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst)
-{
- STATEM *st = &s->statem;
-
- s->init_num = 0;
-
- switch(st->hand_state) {
- case TLS_ST_SW_HELLO_REQ:
- if (statem_flush(s) != 1)
- return WORK_MORE_A;
- 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:
- if (statem_flush(s) != 1)
- return WORK_MORE_A;
- break;
-
- 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:
- /* No post work to be done */
- break;
- }
-
- return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Construct a message to be sent from the server to the client.
- *
- * Valid return values are:
- * 1: Success
- * 0: Error
- */
-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);
-
- case TLS_ST_SW_SRVR_HELLO:
- return tls_construct_server_hello(s);
-
- case TLS_ST_SW_CERT:
- return tls_construct_server_certificate(s);
-
- case TLS_ST_SW_KEY_EXCH:
- return tls_construct_server_key_exchange(s);
-
- case TLS_ST_SW_CERT_REQ:
- return tls_construct_certificate_request(s);
-
- case TLS_ST_SW_SRVR_DONE:
- return tls_construct_server_done(s);
-
- case TLS_ST_SW_SESSION_TICKET:
- return tls_construct_new_session_ticket(s);
-
- case TLS_ST_SW_CERT_STATUS:
- return tls_construct_cert_status(s);
-
- case TLS_ST_SW_CHANGE:
- if (SSL_IS_DTLS(s))
- return dtls_construct_change_cipher_spec(s);
- else
- return tls_construct_change_cipher_spec(s);
-
- case TLS_ST_SW_FINISHED:
- return tls_construct_finished(s,
- s->method->
- ssl3_enc->server_finished_label,
- s->method->
- ssl3_enc->server_finished_label_len);
-
- default:
- /* Shouldn't happen */
- break;
- }
-
- return 0;
-}
-
-#define CLIENT_KEY_EXCH_MAX_LENGTH 2048
-#define NEXT_PROTO_MAX_LENGTH 514
-
-/*
- * Returns the maximum allowed length for the current message that we are
- * reading. Excludes the message header.
- */
-static unsigned long server_max_message_size(SSL *s)
-{
- STATEM *st = &s->statem;
-
- switch(st->hand_state) {
- case TLS_ST_SR_CLNT_HELLO:
- return SSL3_RT_MAX_PLAIN_LENGTH;
-
- case TLS_ST_SR_CERT:
- return s->max_cert_list;
-
- case TLS_ST_SR_KEY_EXCH:
- return CLIENT_KEY_EXCH_MAX_LENGTH;
-
- case TLS_ST_SR_CERT_VRFY:
- return SSL3_RT_MAX_PLAIN_LENGTH;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- case TLS_ST_SR_NEXT_PROTO:
- return NEXT_PROTO_MAX_LENGTH;
-#endif
-
- case TLS_ST_SR_CHANGE:
- return CCS_MAX_LENGTH;
-
- case TLS_ST_SR_FINISHED:
- return FINISHED_MAX_LENGTH;
-
- default:
- /* Shouldn't happen */
- break;
- }
-
- return 0;
-}
-
-/*
- * Process a message that the server has received from the client.
- */
-static enum MSG_PROCESS_RETURN server_process_message(SSL *s, PACKET *pkt)
-{
- STATEM *st = &s->statem;
-
- switch(st->hand_state) {
- case TLS_ST_SR_CLNT_HELLO:
- return tls_process_client_hello(s, pkt);
-
- case TLS_ST_SR_CERT:
- return tls_process_client_certificate(s, pkt);
-
- case TLS_ST_SR_KEY_EXCH:
- return tls_process_client_key_exchange(s, pkt);
-
- case TLS_ST_SR_CERT_VRFY:
- return tls_process_cert_verify(s, pkt);
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- case TLS_ST_SR_NEXT_PROTO:
- return tls_process_next_proto(s, pkt);
-#endif
-
- case TLS_ST_SR_CHANGE:
- return tls_process_change_cipher_spec(s, pkt);
-
- case TLS_ST_SR_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 client
- */
-static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst)
-{
- STATEM *st = &s->statem;
-
- switch(st->hand_state) {
- case TLS_ST_SR_CLNT_HELLO:
- return tls_post_process_client_hello(s, 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);
- else
- return WORK_FINISHED_STOP;
- default:
- break;
- }
-
- /* Shouldn't happen */
- return WORK_ERROR;
-}
WRITE_TRAN_FINISHED
};
-/* Message processing return codes */
-enum MSG_PROCESS_RETURN {
- MSG_PROCESS_ERROR,
- MSG_PROCESS_FINISHED_READING,
- MSG_PROCESS_CONTINUE_PROCESSING,
- MSG_PROCESS_CONTINUE_READING
-};
-
/* Message flow states */
enum MSG_FLOW_STATE {
/* No handshake in progress */
#include <stdio.h>
#include "../ssl_locl.h"
+#include "statem_locl.h"
#include <openssl/buffer.h>
#include <openssl/rand.h>
#include <openssl/objects.h>
# include <openssl/engine.h>
#endif
+static inline int cert_req_allowed(SSL *s);
+static inline int key_exchange_skip_allowed(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 ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
unsigned char *p);
+
+/*
+ * 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)
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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
+ */
+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;
+}
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+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.
+ */
+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
+ */
+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;
+}
+
/*
* Work out what version we should be using for the initial ClientHello if
* the version is currently set to (D)TLS_ANY_VERSION.
#include <string.h>
#include <stdio.h>
#include "../ssl_locl.h"
+#include "statem_locl.h"
#include <openssl/buffer.h>
#include <openssl/rand.h>
#include <openssl/objects.h>
#include <string.h>
#include <stdio.h>
#include "../ssl_locl.h"
+#include "statem_locl.h"
#include <openssl/buffer.h>
#include <openssl/rand.h>
#include <openssl/objects.h>
--- /dev/null
+/* ssl/statem/statem_locl.h */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*****************************************************************************
+ * *
+ * The following definitions are PRIVATE to the state machine. They should *
+ * NOT be used outside of the state machine. *
+ * *
+ *****************************************************************************/
+
+/* Max message length definitions */
+
+/* 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
+
+/* Message processing return codes */
+enum MSG_PROCESS_RETURN {
+ /* Something bad happened */
+ MSG_PROCESS_ERROR,
+ /* We've finished reading - swap to writing */
+ MSG_PROCESS_FINISHED_READING,
+ /*
+ * We've completed the main processing of this message but there is some
+ * post processing to be done.
+ */
+ MSG_PROCESS_CONTINUE_PROCESSING,
+ /* We've finished this message - read the next message */
+ MSG_PROCESS_CONTINUE_READING
+};
+
+/* Flush the write BIO */
+int statem_flush(SSL *s);
+
+/*
+ * TLS/DTLS client state machine functions
+ */
+int client_read_transition(SSL *s, int mt);
+enum WRITE_TRAN client_write_transition(SSL *s);
+enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst);
+enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst);
+int client_construct_message(SSL *s);
+unsigned long client_max_message_size(SSL *s);
+enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt);
+enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst);
+
+/*
+ * TLS/DTLS server state machine functions
+ */
+int server_read_transition(SSL *s, int mt);
+enum WRITE_TRAN server_write_transition(SSL *s);
+enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst);
+enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst);
+int server_construct_message(SSL *s);
+unsigned long server_max_message_size(SSL *s);
+enum MSG_PROCESS_RETURN server_process_message(SSL *s, PACKET *pkt);
+enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst);
+
+/* Functions for getting new message data */
+__owur int tls_get_message_header(SSL *s, int *mt);
+__owur int tls_get_message_body(SSL *s, unsigned long *len);
+__owur int dtls_get_message(SSL *s, int *mt, unsigned long *len);
+
+/* Message construction and processing functions */
+__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 tls_construct_change_cipher_spec(SSL *s);
+__owur int dtls_construct_change_cipher_spec(SSL *s);
+
+__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);
+
+/* 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 int tls_construct_cert_status(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_certificate(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 tls_construct_new_session_ticket(SSL *s);
#include <stdio.h>
#include "../ssl_locl.h"
+#include "statem_locl.h"
#include "internal/constant_time_locl.h"
#include <openssl/buffer.h>
#include <openssl/rand.h>
STACK_OF(SSL_CIPHER) **skp,
int sslv2format, int *al);
+/*
+ * 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)
+ */
+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 OPENSSL_NO_NEXTPROTONEG
+ }
+#endif
+ break;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ case TLS_ST_SR_NEXT_PROTO:
+ if (mt == SSL3_MT_FINISHED) {
+ st->hand_state = TLS_ST_SR_FINISHED;
+ return 1;
+ }
+ break;
+#endif
+
+ case TLS_ST_SW_FINISHED:
+ if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_SR_CHANGE;
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* No valid transition found */
+ return 0;
+}
+
+/*
+ * Should we send a ServerKeyExchange message?
+ *
+ * Valid return values are:
+ * 1: Yes
+ * 0: No
+ */
+static inline int send_server_key_exchange(SSL *s)
+{
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+ /*
+ * only send a ServerKeyExchange if DH, fortezza or RSA but we have a
+ * sign only certificate PSK: may send PSK identity hints For
+ * ECC ciphersuites, we send a serverKeyExchange message only if
+ * the cipher suite is either ECDH-anon or ECDHE. In other cases,
+ * the server certificate contains the server's public key for
+ * key exchange.
+ */
+ if ( (alg_k & SSL_kDHE)
+ || (alg_k & SSL_kECDHE)
+ || ((alg_k & SSL_kRSA)
+ && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+ || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+ && EVP_PKEY_size(s->cert->pkeys
+ [SSL_PKEY_RSA_ENC].privatekey) *
+ 8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+ )
+ )
+ )
+ /*
+ * PSK: send ServerKeyExchange if PSK identity hint if
+ * provided
+ */
+#ifndef OPENSSL_NO_PSK
+ /* Only send SKE if we have identity hint for plain PSK */
+ || ((alg_k & (SSL_kPSK | SSL_kRSAPSK))
+ && s->cert->psk_identity_hint)
+ /* For other PSK always send SKE */
+ || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
+#endif
+#ifndef OPENSSL_NO_SRP
+ /* SRP: send ServerKeyExchange */
+ || (alg_k & SSL_kSRP)
+#endif
+ ) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Should we send a CertificateRequest message?
+ *
+ * Valid return values are:
+ * 1: Yes
+ * 0: No
+ */
+static inline int send_certificate_request(SSL *s)
+{
+ if (
+ /* don't request cert unless asked for it: */
+ s->verify_mode & SSL_VERIFY_PEER
+ /*
+ * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
+ * during re-negotiation:
+ */
+ && ((s->session->peer == NULL) ||
+ !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
+ /*
+ * never request cert in anonymous ciphersuites (see
+ * section "Certificate request" in SSL 3 drafts and in
+ * RFC 2246):
+ */
+ && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+ /*
+ * ... except when the application insists on
+ * verification (against the specs, but s3_clnt.c accepts
+ * this for SSL 3)
+ */
+ || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+ /* don't request certificate for SRP auth */
+ && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
+ /*
+ * With normal PSK Certificates and Certificate Requests
+ * are omitted
+ */
+ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * server_write_transition() works out what handshake state to move to next
+ * when the server is writing messages to be sent to the client.
+ */
+enum WRITE_TRAN server_write_transition(SSL *s)
+{
+ STATEM *st = &s->statem;
+
+ switch(st->hand_state) {
+ case TLS_ST_BEFORE:
+ /* Just go straight to trying to read from the client */;
+ return WRITE_TRAN_FINISHED;
+
+ case TLS_ST_OK:
+ /* We must be trying to renegotiate */
+ st->hand_state = TLS_ST_SW_HELLO_REQ;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_HELLO_REQ:
+ st->hand_state = TLS_ST_OK;
+ statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SR_CLNT_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)
+ st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ else
+ st->hand_state = TLS_ST_SW_CHANGE;
+ } else {
+ /* Check if it is anon DH or anon ECDH, */
+ /* normal PSK or SRP */
+ if (!(s->s3->tmp.new_cipher->algorithm_auth &
+ (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
+ st->hand_state = TLS_ST_SW_CERT;
+ } else if (send_server_key_exchange(s)) {
+ st->hand_state = TLS_ST_SW_KEY_EXCH;
+ } else if (send_certificate_request(s)) {
+ st->hand_state = TLS_ST_SW_CERT_REQ;
+ } else {
+ st->hand_state = TLS_ST_SW_SRVR_DONE;
+ }
+ }
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_CERT:
+ if (s->tlsext_status_expected) {
+ st->hand_state = TLS_ST_SW_CERT_STATUS;
+ return WRITE_TRAN_CONTINUE;
+ }
+ /* Fall through */
+
+ case TLS_ST_SW_CERT_STATUS:
+ if (send_server_key_exchange(s)) {
+ st->hand_state = TLS_ST_SW_KEY_EXCH;
+ return WRITE_TRAN_CONTINUE;
+ }
+ /* Fall through */
+
+ case TLS_ST_SW_KEY_EXCH:
+ if (send_certificate_request(s)) {
+ st->hand_state = TLS_ST_SW_CERT_REQ;
+ return WRITE_TRAN_CONTINUE;
+ }
+ /* Fall through */
+
+ case TLS_ST_SW_CERT_REQ:
+ st->hand_state = TLS_ST_SW_SRVR_DONE;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_SRVR_DONE:
+ return WRITE_TRAN_FINISHED;
+
+ case TLS_ST_SR_FINISHED:
+ if (s->hit) {
+ st->hand_state = TLS_ST_OK;
+ statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
+ } else if (s->tlsext_ticket_expected) {
+ st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ } else {
+ st->hand_state = TLS_ST_SW_CHANGE;
+ }
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_SESSION_TICKET:
+ st->hand_state = TLS_ST_SW_CHANGE;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_CHANGE:
+ st->hand_state = TLS_ST_SW_FINISHED;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_FINISHED:
+ if (s->hit) {
+ return WRITE_TRAN_FINISHED;
+ }
+ 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 server to the client.
+ */
+enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst)
+{
+ STATEM *st = &s->statem;
+
+ 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:
+ s->session->cipher = s->s3->tmp.new_cipher;
+ if (!s->method->ssl3_enc->setup_key_block(s)) {
+ 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:
+ 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
+ * server to the client.
+ */
+enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst)
+{
+ STATEM *st = &s->statem;
+
+ s->init_num = 0;
+
+ switch(st->hand_state) {
+ case TLS_ST_SW_HELLO_REQ:
+ if (statem_flush(s) != 1)
+ return WORK_MORE_A;
+ 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:
+ if (statem_flush(s) != 1)
+ return WORK_MORE_A;
+ break;
+
+ 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:
+ /* No post work to be done */
+ break;
+ }
+
+ return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Construct a message to be sent from the server to the client.
+ *
+ * Valid return values are:
+ * 1: Success
+ * 0: Error
+ */
+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);
+
+ case TLS_ST_SW_SRVR_HELLO:
+ return tls_construct_server_hello(s);
+
+ case TLS_ST_SW_CERT:
+ return tls_construct_server_certificate(s);
+
+ case TLS_ST_SW_KEY_EXCH:
+ return tls_construct_server_key_exchange(s);
+
+ case TLS_ST_SW_CERT_REQ:
+ return tls_construct_certificate_request(s);
+
+ case TLS_ST_SW_SRVR_DONE:
+ return tls_construct_server_done(s);
+
+ case TLS_ST_SW_SESSION_TICKET:
+ return tls_construct_new_session_ticket(s);
+
+ case TLS_ST_SW_CERT_STATUS:
+ return tls_construct_cert_status(s);
+
+ case TLS_ST_SW_CHANGE:
+ if (SSL_IS_DTLS(s))
+ return dtls_construct_change_cipher_spec(s);
+ else
+ return tls_construct_change_cipher_spec(s);
+
+ case TLS_ST_SW_FINISHED:
+ return tls_construct_finished(s,
+ s->method->
+ ssl3_enc->server_finished_label,
+ s->method->
+ ssl3_enc->server_finished_label_len);
+
+ default:
+ /* Shouldn't happen */
+ break;
+ }
+
+ return 0;
+}
+
+#define CLIENT_KEY_EXCH_MAX_LENGTH 2048
+#define NEXT_PROTO_MAX_LENGTH 514
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+unsigned long server_max_message_size(SSL *s)
+{
+ STATEM *st = &s->statem;
+
+ switch(st->hand_state) {
+ case TLS_ST_SR_CLNT_HELLO:
+ return SSL3_RT_MAX_PLAIN_LENGTH;
+
+ case TLS_ST_SR_CERT:
+ return s->max_cert_list;
+
+ case TLS_ST_SR_KEY_EXCH:
+ return CLIENT_KEY_EXCH_MAX_LENGTH;
+
+ case TLS_ST_SR_CERT_VRFY:
+ return SSL3_RT_MAX_PLAIN_LENGTH;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ case TLS_ST_SR_NEXT_PROTO:
+ return NEXT_PROTO_MAX_LENGTH;
+#endif
+
+ case TLS_ST_SR_CHANGE:
+ return CCS_MAX_LENGTH;
+
+ case TLS_ST_SR_FINISHED:
+ return FINISHED_MAX_LENGTH;
+
+ default:
+ /* Shouldn't happen */
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Process a message that the server has received from the client.
+ */
+enum MSG_PROCESS_RETURN server_process_message(SSL *s, PACKET *pkt)
+{
+ STATEM *st = &s->statem;
+
+ switch(st->hand_state) {
+ case TLS_ST_SR_CLNT_HELLO:
+ return tls_process_client_hello(s, pkt);
+
+ case TLS_ST_SR_CERT:
+ return tls_process_client_certificate(s, pkt);
+
+ case TLS_ST_SR_KEY_EXCH:
+ return tls_process_client_key_exchange(s, pkt);
+
+ case TLS_ST_SR_CERT_VRFY:
+ return tls_process_cert_verify(s, pkt);
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ case TLS_ST_SR_NEXT_PROTO:
+ return tls_process_next_proto(s, pkt);
+#endif
+
+ case TLS_ST_SR_CHANGE:
+ return tls_process_change_cipher_spec(s, pkt);
+
+ case TLS_ST_SR_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 client
+ */
+enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst)
+{
+ STATEM *st = &s->statem;
+
+ switch(st->hand_state) {
+ case TLS_ST_SR_CLNT_HELLO:
+ return tls_post_process_client_hello(s, 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);
+ else
+ return WORK_FINISHED_STOP;
+ default:
+ break;
+ }
+
+ /* Shouldn't happen */
+ return WORK_ERROR;
+}
+
#ifndef OPENSSL_NO_SRP
static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
{