More state machine reorg
Move some function definitions around within the state machine to make sure they are in the correct files. Also create a statem_locl.h header for stuff entirely local to the state machine code and move various definitions into it. Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Richard Levitte <levitte@openssl.org>
This commit is contained in:
parent
8ba708e516
commit
61ae935a98
@ -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
|
||||
|
@ -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);
|
||||
|
1376
ssl/statem/statem.c
1376
ssl/statem/statem.c
File diff suppressed because it is too large
Load Diff
@ -86,14 +86,6 @@ enum WRITE_TRAN {
|
||||
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 */
|
||||
|
@ -150,6 +150,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../ssl_locl.h"
|
||||
#include "statem_locl.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/objects.h>
|
||||
@ -163,11 +164,633 @@
|
||||
# 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.
|
||||
|
@ -117,6 +117,7 @@
|
||||
#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>
|
||||
|
@ -118,6 +118,7 @@
|
||||
#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>
|
||||
|
181
ssl/statem/statem_locl.h
Normal file
181
ssl/statem/statem_locl.h
Normal file
@ -0,0 +1,181 @@
|
||||
/* 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);
|
@ -151,6 +151,7 @@
|
||||
|
||||
#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>
|
||||
@ -169,6 +170,726 @@ static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
|
||||
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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user