Move TLS CCS processing into the state machine

The handling of incoming CCS records is a little strange. Since CCS is not
a handshake message it is handled differently to normal handshake messages.
Unfortunately whilst technically it is not a handhshake message the reality
is that it must be processed in accordance with the state of the handshake.
Currently CCS records are processed entirely within the record layer. In
order to ensure that it is handled in accordance with the handshake state
a flag is used to indicate that it is an acceptable time to receive a CCS.

Previously this flag did not exist (see CVE-2014-0224), but the flag should
only really be considered a workaround for the problem that CCS is not
visible to the state machine.

Outgoing CCS messages are already handled within the state machine.

This patch makes CCS visible to the TLS state machine. A separate commit
will handle DTLS.

Reviewed-by: Tim Hudson <tjh@openssl.org>
This commit is contained in:
Matt Caswell 2015-05-11 09:35:41 +01:00
parent 9ceb2426b0
commit 657da85eea
12 changed files with 177 additions and 145 deletions

View file

@ -1943,6 +1943,7 @@ void ERR_load_SSL_strings(void);
# define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135
# define SSL_F_SSL3_GET_CERT_STATUS 289
# define SSL_F_SSL3_GET_CERT_VERIFY 136
# define SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC 348
# define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137
# define SSL_F_SSL3_GET_CLIENT_HELLO 138
# define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE 139

View file

@ -365,11 +365,6 @@ extern "C" {
# define TLS1_FLAGS_TLS_PADDING_BUG 0x0
# define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010
/*
* Set when the handshake is ready to process peer's ChangeCipherSpec message.
* Cleared after the message has been processed.
*/
# define SSL3_FLAGS_CCS_OK 0x0080
/* Set if we encrypt then mac instead of usual mac then encrypt */
# define TLS1_FLAGS_ENCRYPT_THEN_MAC 0x0100
@ -499,6 +494,9 @@ extern "C" {
# endif
# define DTLS1_MT_HELLO_VERIFY_REQUEST 3
/* Dummy message type for handling CCS like a normal handshake message */
# define SSL3_MT_CHANGE_CIPHER_SPEC 0x0101
# define SSL3_MT_CCS 1
/* These are used when changing over to a new cipher */

View file

@ -679,7 +679,7 @@ dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok)
unsigned char devnull[256];
while (frag_len) {
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
devnull,
frag_len >
sizeof(devnull) ? sizeof(devnull) :
@ -692,7 +692,7 @@ dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok)
}
/* read the body of the fragment (header has already been read */
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
frag->fragment + msg_hdr->frag_off,
frag_len, 0);
if ((unsigned long)i != frag_len)
@ -775,7 +775,7 @@ dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr,
unsigned char devnull[256];
while (frag_len) {
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
devnull,
frag_len >
sizeof(devnull) ? sizeof(devnull) :
@ -801,7 +801,7 @@ dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr,
/*
* read the body of the fragment (header has already been read
*/
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
frag->fragment, frag_len, 0);
if ((unsigned long)i != frag_len)
i = -1;
@ -851,7 +851,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
}
/* read handshake message header */
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, wire,
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL, wire,
DTLS1_HM_HEADER_LENGTH, 0);
if (i <= 0) { /* nbio, or an error */
s->rwstate = SSL_READING;
@ -926,7 +926,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
unsigned char *p =
(unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
&p[frag_off], frag_len, 0);
/*

View file

@ -395,7 +395,8 @@ int dtls1_process_buffered_records(SSL *s)
* Application data protocol
* none of our business
*/
int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
int len, int peek)
{
int al, i, j, ret;
unsigned int n;

View file

@ -955,8 +955,9 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
* (possibly multiple records if we still don't have anything to return).
*
* This function must handle any surprises the peer may have for us, such as
* Alert records (e.g. close_notify), ChangeCipherSpec records (not really
* a surprise, but handled as if it were), or renegotiation requests.
* Alert records (e.g. close_notify) or renegotiation requests. ChangeCipherSpec
* messages are treated as if they were handshake messages *if* the |recd_type|
* argument is non NULL.
* Also if record payloads contain fragments too small to process, we store
* them until there is enough for the respective protocol (the record protocol
* may use arbitrary fragmentation and even interleaving):
@ -971,7 +972,8 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
* Application data protocol
* none of our business
*/
int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
int len, int peek)
{
int al, i, j, ret;
unsigned int n;
@ -1066,9 +1068,14 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
return (0);
}
if (type == SSL3_RECORD_get_type(rr)) {
/* SSL3_RT_APPLICATION_DATA or
* SSL3_RT_HANDSHAKE */
if (type == SSL3_RECORD_get_type(rr)
|| (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
&& type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) {
/*
* SSL3_RT_APPLICATION_DATA or
* SSL3_RT_HANDSHAKE or
* SSL3_RT_CHANGE_CIPHER_SPEC
*/
/*
* make sure that we are not getting application data when we are
* doing a handshake for the first time
@ -1080,6 +1087,17 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
goto f_err;
}
if (type == SSL3_RT_HANDSHAKE
&& SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC
&& s->rlayer.handshake_fragment_len > 0) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
if (recvd_type != NULL)
*recvd_type = SSL3_RECORD_get_type(rr);
if (len <= 0)
return (len);
@ -1105,9 +1123,16 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
/*
* If we get here, then type != rr->type; if we have a handshake message,
* then it was unexpected (Hello Request or Client Hello).
* then it was unexpected (Hello Request or Client Hello) or invalid (we
* were actually expecting a CCS).
*/
if (rr->type == SSL3_RT_HANDSHAKE && type == SSL3_RT_CHANGE_CIPHER_SPEC) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
/*
* Lets just double check that we've not got an SSLv2 record
*/
@ -1344,45 +1369,9 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
}
if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) {
/*
* 'Change Cipher Spec' is just a single byte, so we know exactly
* what the record payload has to look like
*/
if ((SSL3_RECORD_get_length(rr) != 1)
|| (SSL3_RECORD_get_off(rr) != 0)
|| (SSL3_RECORD_get_data(rr)[0] != SSL3_MT_CCS)) {
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_CHANGE_CIPHER_SPEC);
goto f_err;
}
/* Check we have a cipher to change to */
if (s->s3->tmp.new_cipher == NULL) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
if (!(s->s3->flags & SSL3_FLAGS_CCS_OK)) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
SSL3_RECORD_set_length(rr, 0);
if (s->msg_callback)
s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
SSL3_RECORD_get_data(rr), 1, s,
s->msg_callback_arg);
s->s3->change_cipher_spec = 1;
if (!ssl3_do_change_cipher_spec(s))
goto err;
else
goto start;
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
/*
@ -1477,7 +1466,6 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
return (-1);
}

View file

@ -331,7 +331,8 @@ __owur int ssl3_pending(const SSL *s);
__owur int ssl3_write_bytes(SSL *s, int type, const void *buf, int len);
__owur int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
unsigned int len, int create_empty_fragment);
__owur int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
__owur int ssl3_read_bytes(SSL *s, int type, int *recvd_type,
unsigned char *buf, int len, int peek);
__owur int ssl3_setup_buffers(SSL *s);
__owur int ssl3_enc(SSL *s, int send_data);
__owur int n_ssl3_mac(SSL *ssl, unsigned char *md, int send_data);
@ -345,7 +346,8 @@ void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_set_saved_w_epoch(RECORD_LAYER *rl, unsigned short e);
void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_resync_write(RECORD_LAYER *rl);
__owur int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
__owur int dtls1_read_bytes(SSL *s, int type, int *recvd_type,
unsigned char *buf, int len, int peek);
__owur int dtls1_write_bytes(SSL *s, int type, const void *buf, int len);
__owur int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
unsigned int len, int create_empty_fragement);

View file

@ -228,6 +228,47 @@ static void ssl3_take_mac(SSL *s)
}
#endif
int ssl3_get_change_cipher_spec(SSL *s, int a, int b)
{
int ok, al;
long n;
n = s->method->ssl_get_message(s, a, b, SSL3_MT_CHANGE_CIPHER_SPEC, 1, &ok);
if (!ok)
return ((int)n);
/*
* 'Change Cipher Spec' is just a single byte, which should already have
* been consumed by ssl_get_message() so there should be no bytes left
*/
if (n != 0) {
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC, SSL_R_BAD_CHANGE_CIPHER_SPEC);
goto f_err;
}
/* Check we have a cipher to change to */
if (s->s3->tmp.new_cipher == NULL) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
s->s3->change_cipher_spec = 1;
if (!ssl3_do_change_cipher_spec(s)) {
al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
goto f_err;
}
return 1;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 0;
}
int ssl3_get_finished(SSL *s, int a, int b)
{
int al, i, ok;
@ -345,7 +386,7 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
unsigned char *p;
unsigned long l;
long n;
int i, al;
int i, al, recvd_type;
if (s->s3->tmp.reuse_message) {
s->s3->tmp.reuse_message = 0;
@ -369,13 +410,38 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
do {
while (s->init_num < SSL3_HM_HEADER_LENGTH) {
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
&p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, 0);
if (i <= 0) {
s->rwstate = SSL_READING;
*ok = 0;
return i;
}
if (s->init_num == 0
&& recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC
&& (mt < 0 || mt == SSL3_MT_CHANGE_CIPHER_SPEC)) {
if (*p != SSL3_MT_CCS) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_GET_MESSAGE,
SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
s->init_num = i - 1;
s->init_msg = p + 1;
s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
s->s3->tmp.message_size = i - 1;
s->state = stn;
*ok = 1;
if (s->msg_callback)
s->msg_callback(0, s->version,
SSL3_RT_CHANGE_CIPHER_SPEC, p, 1, s,
s->msg_callback_arg);
return i - 1;
} else if (recvd_type != SSL3_RT_HANDSHAKE) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_GET_MESSAGE, SSL_R_CCS_RECEIVED_EARLY);
goto f_err;
}
s->init_num += i;
}
@ -458,8 +524,8 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
p = s->init_msg;
n = s->s3->tmp.message_size - s->init_num;
while (n > 0) {
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &p[s->init_num],
n, 0);
i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
&p[s->init_num], n, 0);
if (i <= 0) {
s->rwstate = SSL_READING;
*ok = 0;

View file

@ -165,7 +165,7 @@
static int ssl_set_version(SSL *s);
static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
static int ssl3_check_finished(SSL *s);
static int ssl3_check_change(SSL *s);
static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
unsigned char *p,
int (*put_cb) (const SSL_CIPHER *,
@ -276,7 +276,6 @@ int ssl3_connect(SSL *s)
s->state = SSL3_ST_CW_CLNT_HELLO_A;
s->ctx->stats.sess_connect++;
s->init_num = 0;
s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
/*
* Should have been reset by ssl3_get_finished, too.
*/
@ -306,7 +305,7 @@ int ssl3_connect(SSL *s)
goto end;
if (s->hit) {
s->state = SSL3_ST_CR_FINISHED_A;
s->state = SSL3_ST_CR_CHANGE_A;
if (s->tlsext_ticket_expected) {
/* receive renewed session ticket */
s->state = SSL3_ST_CR_SESSION_TICKET_A;
@ -319,12 +318,12 @@ int ssl3_connect(SSL *s)
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
/* Noop (ret = 0) for everything but EAP-FAST. */
ret = ssl3_check_finished(s);
ret = ssl3_check_change(s);
if (ret < 0)
goto end;
if (ret == 1) {
s->hit = 1;
s->state = SSL3_ST_CR_FINISHED_A;
s->state = SSL3_ST_CR_CHANGE_A;
s->init_num = 0;
break;
}
@ -525,7 +524,7 @@ int ssl3_connect(SSL *s)
if (s->tlsext_ticket_expected)
s->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A;
else
s->s3->tmp.next_state = SSL3_ST_CR_FINISHED_A;
s->s3->tmp.next_state = SSL3_ST_CR_CHANGE_A;
}
s->init_num = 0;
break;
@ -535,7 +534,7 @@ int ssl3_connect(SSL *s)
ret = ssl3_get_new_session_ticket(s);
if (ret <= 0)
goto end;
s->state = SSL3_ST_CR_FINISHED_A;
s->state = SSL3_ST_CR_CHANGE_A;
s->init_num = 0;
break;
@ -548,10 +547,19 @@ int ssl3_connect(SSL *s)
s->init_num = 0;
break;
case SSL3_ST_CR_CHANGE_A:
case SSL3_ST_CR_CHANGE_B:
ret = ssl3_get_change_cipher_spec(s, SSL3_ST_CR_CHANGE_A,
SSL3_ST_CR_CHANGE_B);
if (ret <= 0)
goto end;
s->state = SSL3_ST_CR_FINISHED_A;
s->init_num = 0;
break;
case SSL3_ST_CR_FINISHED_A:
case SSL3_ST_CR_FINISHED_B:
if (!s->s3->change_cipher_spec)
s->s3->flags |= SSL3_FLAGS_CCS_OK;
ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A,
SSL3_ST_CR_FINISHED_B);
if (ret <= 0)
@ -3368,11 +3376,11 @@ int ssl3_check_cert_and_algorithm(SSL *s)
* the session ID. EAP-FAST (RFC 4851), however, relies on the next server
* message after the ServerHello to determine if the server is resuming.
* Therefore, we allow EAP-FAST to peek ahead.
* ssl3_check_finished returns 1 if we are resuming from an external
* pre-shared secret, we have a "ticket" and the next server handshake message
* is Finished; and 0 otherwise. It returns -1 upon an error.
* ssl3_check_change returns 1 if we are resuming from an external
* pre-shared secret, we have a "ticket" and the next server message
* is CCS; and 0 otherwise. It returns -1 upon an error.
*/
static int ssl3_check_finished(SSL *s)
static int ssl3_check_change(SSL *s)
{
int ok = 0;
@ -3380,8 +3388,6 @@ static int ssl3_check_finished(SSL *s)
!s->session->tlsext_tick)
return 0;
/* Need to permit this temporarily, in case the next message is Finished. */
s->s3->flags |= SSL3_FLAGS_CCS_OK;
/*
* This function is called when we might get a Certificate message instead,
* so permit appropriate message length.
@ -3392,23 +3398,15 @@ static int ssl3_check_finished(SSL *s)
SSL3_ST_CR_CERT_A,
SSL3_ST_CR_CERT_B,
-1, s->max_cert_list, &ok);
s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
if (!ok)
return -1;
s->s3->tmp.reuse_message = 1;
if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
if (s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC)
return 1;
/* If we're not done, then the CCS arrived early and we should bail. */
if (s->s3->change_cipher_spec) {
SSLerr(SSL_F_SSL3_CHECK_FINISHED, SSL_R_CCS_RECEIVED_EARLY);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
return 0;
}

View file

@ -4808,7 +4808,7 @@ int ssl3_shutdown(SSL *s)
/*
* If we are waiting for a close from our peer, we are closed
*/
s->method->ssl_read_bytes(s, 0, NULL, 0, 0);
s->method->ssl_read_bytes(s, 0, NULL, NULL, 0, 0);
if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) {
return (-1); /* return WANT_READ */
}
@ -4840,7 +4840,7 @@ static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)
ssl3_renegotiate_check(s);
s->s3->in_read_app_data = 1;
ret =
s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len,
s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf, len,
peek);
if ((ret == -1) && (s->s3->in_read_app_data == 2)) {
/*
@ -4852,8 +4852,8 @@ static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)
*/
s->in_handshake++;
ret =
s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len,
peek);
s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf,
len, peek);
s->in_handshake--;
} else
s->s3->in_read_app_data = 0;

View file

@ -281,7 +281,6 @@ int ssl3_accept(SSL *s)
s->init_num = 0;
s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
/*
* Should have been reset by ssl3_get_finished, too.
*/
@ -576,14 +575,7 @@ int ssl3_accept(SSL *s)
* not sent. Also for GOST ciphersuites when the client uses
* its key from the certificate for key exchange.
*/
#if defined(OPENSSL_NO_NEXTPROTONEG)
s->state = SSL3_ST_SR_FINISHED_A;
#else
if (s->s3->next_proto_neg_seen)
s->state = SSL3_ST_SR_NEXT_PROTO_A;
else
s->state = SSL3_ST_SR_FINISHED_A;
#endif
s->state = SSL3_ST_SR_CHANGE_A;
s->init_num = 0;
} else if (SSL_USE_SIGALGS(s)) {
s->state = SSL3_ST_SR_CERT_VRFY_A;
@ -650,6 +642,29 @@ int ssl3_accept(SSL *s)
if (ret <= 0)
goto end;
s->state = SSL3_ST_SR_CHANGE_A;
s->init_num = 0;
break;
#if !defined(OPENSSL_NO_NEXTPROTONEG)
case SSL3_ST_SR_NEXT_PROTO_A:
case SSL3_ST_SR_NEXT_PROTO_B:
ret = ssl3_get_next_proto(s);
if (ret <= 0)
goto end;
s->init_num = 0;
s->state = SSL3_ST_SR_FINISHED_A;
break;
#endif
case SSL3_ST_SR_CHANGE_A:
case SSL3_ST_SR_CHANGE_B:
ret = ssl3_get_change_cipher_spec(s, SSL3_ST_SR_CHANGE_A,
SSL3_ST_SR_CHANGE_B);
if (ret <= 0)
goto end;
#if defined(OPENSSL_NO_NEXTPROTONEG)
s->state = SSL3_ST_SR_FINISHED_A;
#else
@ -661,41 +676,8 @@ int ssl3_accept(SSL *s)
s->init_num = 0;
break;
#if !defined(OPENSSL_NO_NEXTPROTONEG)
case SSL3_ST_SR_NEXT_PROTO_A:
case SSL3_ST_SR_NEXT_PROTO_B:
/*
* Enable CCS for NPN. Receiving a CCS clears the flag, so make
* sure not to re-enable it to ban duplicates. This *should* be the
* first time we have received one - but we check anyway to be
* cautious.
* s->s3->change_cipher_spec is set when a CCS is
* processed in s3_pkt.c, and remains set until
* the client's Finished message is read.
*/
if (!s->s3->change_cipher_spec)
s->s3->flags |= SSL3_FLAGS_CCS_OK;
ret = ssl3_get_next_proto(s);
if (ret <= 0)
goto end;
s->init_num = 0;
s->state = SSL3_ST_SR_FINISHED_A;
break;
#endif
case SSL3_ST_SR_FINISHED_A:
case SSL3_ST_SR_FINISHED_B:
/*
* Enable CCS for handshakes without NPN. In NPN the CCS flag has
* already been set. Receiving a CCS clears the flag, so make
* sure not to re-enable it to ban duplicates.
* s->s3->change_cipher_spec is set when a CCS is
* processed in s3_pkt.c, and remains set until
* the client's Finished message is read.
*/
if (!s->s3->change_cipher_spec)
s->s3->flags |= SSL3_FLAGS_CCS_OK;
ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A,
SSL3_ST_SR_FINISHED_B);
if (ret <= 0)
@ -769,14 +751,7 @@ int ssl3_accept(SSL *s)
goto end;
s->state = SSL3_ST_SW_FLUSH;
if (s->hit) {
#if defined(OPENSSL_NO_NEXTPROTONEG)
s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A;
#else
if (s->s3->next_proto_neg_seen) {
s->s3->tmp.next_state = SSL3_ST_SR_NEXT_PROTO_A;
} else
s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A;
#endif
s->s3->tmp.next_state = SSL3_ST_SR_CHANGE_A;
} else
s->s3->tmp.next_state = SSL_ST_OK;
s->init_num = 0;

View file

@ -131,6 +131,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
"ssl3_get_certificate_request"},
{ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "ssl3_get_cert_status"},
{ERR_FUNC(SSL_F_SSL3_GET_CERT_VERIFY), "ssl3_get_cert_verify"},
{ERR_FUNC(SSL_F_SSL3_GET_CHANGE_CIPHER_SPEC),
"ssl3_get_change_cipher_spec"},
{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_CERTIFICATE),
"ssl3_get_client_certificate"},
{ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO), "ssl3_get_client_hello"},

View file

@ -563,8 +563,8 @@ struct ssl_method_st {
int (*ssl_renegotiate_check) (SSL *s);
long (*ssl_get_message) (SSL *s, int st1, int stn, int mt, long
max, int *ok);
int (*ssl_read_bytes) (SSL *s, int type, unsigned char *buf, int len,
int peek);
int (*ssl_read_bytes) (SSL *s, int type, int *recvd_type,
unsigned char *buf, int len, int peek);
int (*ssl_write_bytes) (SSL *s, int type, const void *buf_, int len);
int (*ssl_dispatch_alert) (SSL *s);
long (*ssl_ctrl) (SSL *s, int cmd, long larg, void *parg);
@ -1912,6 +1912,7 @@ void ssl3_init_finished_mac(SSL *s);
__owur int ssl3_send_server_certificate(SSL *s);
__owur int ssl3_send_newsession_ticket(SSL *s);
__owur int ssl3_send_cert_status(SSL *s);
__owur int ssl3_get_change_cipher_spec(SSL *s, int a, int b);
__owur int ssl3_get_finished(SSL *s, int state_a, int state_b);
__owur int ssl3_setup_key_block(SSL *s);
__owur int ssl3_send_change_cipher_spec(SSL *s, int state_a, int state_b);