diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 6b6560dc75..892e129611 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -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 diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 43df925999..ec339de351 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -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 */ diff --git a/ssl/d1_both.c b/ssl/d1_both.c index 155b8bffe0..a1499da3eb 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -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); /* diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c index 52ef8f0834..2c8b94f79b 100644 --- a/ssl/record/rec_layer_d1.c +++ b/ssl/record/rec_layer_d1.c @@ -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; diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index d6e922c652..6feba42518 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -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); } diff --git a/ssl/record/record.h b/ssl/record/record.h index 6931bb4712..5c8fead869 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -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); diff --git a/ssl/s3_both.c b/ssl/s3_both.c index 17a8054868..32193c3460 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -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; diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 080dbf0f18..cd6918aa6b 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -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; } diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 0fc08819ca..d39346af65 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -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; diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index bc7f84f2d1..fd4c87e9e6 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -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; diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 4b4d89ce7a..539146ff08 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -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"}, diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 09975664e9..d13aa05b69 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -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);