#include <errno.h>
#include <stdio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include "bytestring.h"
#include "dtls_locl.h"
#include "ssl_locl.h"
static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
unsigned int len);
static int ssl3_get_record(SSL *s);
void
ssl_force_want_read(SSL *s)
{
BIO *bio;
bio = SSL_get_rbio(s);
BIO_clear_retry_flags(bio);
BIO_set_retry_read(bio);
s->internal->rwstate = SSL_READING;
}
static int
ssl3_read_n(SSL *s, int n, int max, int extend)
{
SSL3_BUFFER_INTERNAL *rb = &(s->s3->rbuf);
int i, len, left;
size_t align;
unsigned char *pkt;
if (n <= 0)
return n;
if (rb->buf == NULL)
if (!ssl3_setup_read_buffer(s))
return -1;
left = rb->left;
align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH;
align = (-align) & (SSL3_ALIGN_PAYLOAD - 1);
if (!extend) {
if (left == 0)
rb->offset = align;
else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH) {
pkt = rb->buf + rb->offset;
if (pkt[0] == SSL3_RT_APPLICATION_DATA &&
(pkt[3]<<8|pkt[4]) >= 128) {
memmove(rb->buf + align, pkt, left);
rb->offset = align;
}
}
s->internal->packet = rb->buf + rb->offset;
s->internal->packet_length = 0;
}
if (SSL_is_dtls(s)) {
if (left > 0 && n > left)
n = left;
}
if (left >= n) {
s->internal->packet_length += n;
rb->left = left - n;
rb->offset += n;
return (n);
}
len = s->internal->packet_length;
pkt = rb->buf + align;
if (s->internal->packet != pkt) {
memmove(pkt, s->internal->packet, len + left);
s->internal->packet = pkt;
rb->offset = len + align;
}
if (n > (int)(rb->len - rb->offset)) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
if (s->internal->read_ahead || SSL_is_dtls(s)) {
if (max < n)
max = n;
if (max > (int)(rb->len - rb->offset))
max = rb->len - rb->offset;
} else {
max = n;
}
while (left < n) {
errno = 0;
if (s->rbio != NULL) {
s->internal->rwstate = SSL_READING;
i = BIO_read(s->rbio, pkt + len + left, max - left);
} else {
SSLerror(s, SSL_R_READ_BIO_NOT_SET);
i = -1;
}
if (i <= 0) {
rb->left = left;
if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS &&
!SSL_is_dtls(s)) {
if (len + left == 0)
ssl3_release_read_buffer(s);
}
return (i);
}
left += i;
if (SSL_is_dtls(s)) {
if (n > left)
n = left;
}
}
rb->offset += n;
rb->left = left - n;
s->internal->packet_length += n;
s->internal->rwstate = SSL_NOTHING;
return (n);
}
int
ssl3_packet_read(SSL *s, int plen)
{
int n;
n = ssl3_read_n(s, plen, s->s3->rbuf.len, 0);
if (n <= 0)
return n;
if (s->internal->packet_length < plen)
return s->internal->packet_length;
return plen;
}
int
ssl3_packet_extend(SSL *s, int plen)
{
int rlen, n;
if (s->internal->packet_length >= plen)
return plen;
rlen = plen - s->internal->packet_length;
n = ssl3_read_n(s, rlen, rlen, 1);
if (n <= 0)
return n;
if (s->internal->packet_length < plen)
return s->internal->packet_length;
return plen;
}
static int
ssl3_get_record(SSL *s)
{
SSL3_BUFFER_INTERNAL *rb = &(s->s3->rbuf);
SSL3_RECORD_INTERNAL *rr = &(s->s3->rrec);
uint8_t alert_desc;
uint8_t *out;
size_t out_len;
int al, n;
int ret = -1;
again:
if ((s->internal->rstate != SSL_ST_READ_BODY) ||
(s->internal->packet_length < SSL3_RT_HEADER_LENGTH)) {
CBS header;
uint16_t len, ssl_version;
uint8_t type;
n = ssl3_packet_read(s, SSL3_RT_HEADER_LENGTH);
if (n <= 0)
return (n);
s->internal->mac_packet = 1;
s->internal->rstate = SSL_ST_READ_BODY;
if (s->server && s->internal->first_packet) {
if ((ret = ssl_server_legacy_first_packet(s)) != 1)
return (ret);
ret = -1;
}
CBS_init(&header, s->internal->packet, SSL3_RT_HEADER_LENGTH);
if (!CBS_get_u8(&header, &type) ||
!CBS_get_u16(&header, &ssl_version) ||
!CBS_get_u16(&header, &len)) {
SSLerror(s, SSL_R_BAD_PACKET_LENGTH);
goto err;
}
rr->type = type;
rr->length = len;
if (!s->internal->first_packet && ssl_version != s->version) {
if ((s->version & 0xFF00) == (ssl_version & 0xFF00) &&
!tls12_record_layer_write_protected(s->internal->rl)) {
s->version = ssl_version;
}
SSLerror(s, SSL_R_WRONG_VERSION_NUMBER);
al = SSL_AD_PROTOCOL_VERSION;
goto fatal_err;
}
if ((ssl_version >> 8) != SSL3_VERSION_MAJOR) {
SSLerror(s, SSL_R_WRONG_VERSION_NUMBER);
goto err;
}
if (rr->length > rb->len - SSL3_RT_HEADER_LENGTH) {
al = SSL_AD_RECORD_OVERFLOW;
SSLerror(s, SSL_R_PACKET_LENGTH_TOO_LONG);
goto fatal_err;
}
}
n = ssl3_packet_extend(s, SSL3_RT_HEADER_LENGTH + rr->length);
if (n <= 0)
return (n);
if (n != SSL3_RT_HEADER_LENGTH + rr->length)
return (n);
s->internal->rstate = SSL_ST_READ_HEADER;
tls12_record_layer_set_version(s->internal->rl, s->version);
if (!tls12_record_layer_open_record(s->internal->rl, s->internal->packet,
s->internal->packet_length, &out, &out_len)) {
tls12_record_layer_alert(s->internal->rl, &alert_desc);
if (alert_desc == 0)
goto err;
if (alert_desc == SSL_AD_RECORD_OVERFLOW)
SSLerror(s, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
else if (alert_desc == SSL_AD_BAD_RECORD_MAC)
SSLerror(s, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
al = alert_desc;
goto fatal_err;
}
rr->data = out;
rr->length = out_len;
rr->off = 0;
s->internal->packet_length = 0;
if (rr->length == 0) {
if (rr->type != SSL3_RT_APPLICATION_DATA) {
SSLerror(s, SSL_R_BAD_LENGTH);
al = SSL_AD_UNEXPECTED_MESSAGE;
goto fatal_err;
}
if (s->internal->empty_record_count++ > SSL_MAX_EMPTY_RECORDS) {
SSLerror(s, SSL_R_PEER_BEHAVING_BADLY);
return -1;
}
if (s->internal->empty_record_count > 1) {
ssl_force_want_read(s);
return -1;
}
goto again;
}
s->internal->empty_record_count = 0;
return (1);
fatal_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
return (ret);
}
int
ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
{
const unsigned char *buf = buf_;
unsigned int tot, n, nw;
int i;
if (len < 0) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
s->internal->rwstate = SSL_NOTHING;
tot = s->s3->wnum;
s->s3->wnum = 0;
if (SSL_in_init(s) && !s->internal->in_handshake) {
i = s->internal->handshake_func(s);
if (i < 0)
return (i);
if (i == 0) {
SSLerror(s, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
}
if (len < tot)
len = tot;
n = (len - tot);
for (;;) {
if (n > s->max_send_fragment)
nw = s->max_send_fragment;
else
nw = n;
i = do_ssl3_write(s, type, &(buf[tot]), nw);
if (i <= 0) {
s->s3->wnum = tot;
return i;
}
if ((i == (int)n) || (type == SSL3_RT_APPLICATION_DATA &&
(s->internal->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) {
s->s3->empty_fragment_done = 0;
return tot + i;
}
n -= i;
tot += i;
}
}
static int
do_ssl3_write(SSL *s, int type, const unsigned char *buf, unsigned int len)
{
SSL3_BUFFER_INTERNAL *wb = &(s->s3->wbuf);
SSL_SESSION *sess = s->session;
int need_empty_fragment = 0;
size_t align, out_len;
uint16_t version;
CBB cbb;
int ret;
memset(&cbb, 0, sizeof(cbb));
if (wb->buf == NULL)
if (!ssl3_setup_write_buffer(s))
return -1;
if (wb->left != 0)
return (ssl3_write_pending(s, type, buf, len));
if (s->s3->alert_dispatch) {
if ((ret = ssl3_dispatch_alert(s)) <= 0)
return (ret);
if (wb->buf == NULL)
if (!ssl3_setup_write_buffer(s))
return -1;
}
if (len == 0)
return 0;
version = s->version;
if (s->s3->hs.state == SSL3_ST_CW_CLNT_HELLO_B &&
!s->internal->renegotiate &&
s->s3->hs.our_max_tls_version > TLS1_VERSION)
version = TLS1_VERSION;
if (sess != NULL && tls12_record_layer_write_protected(s->internal->rl)) {
if (s->s3->need_empty_fragments &&
!s->s3->empty_fragment_done &&
type == SSL3_RT_APPLICATION_DATA)
need_empty_fragment = 1;
}
align = (size_t)wb->buf + SSL3_RT_HEADER_LENGTH;
if (need_empty_fragment)
align += SSL3_RT_HEADER_LENGTH;
align = (-align) & (SSL3_ALIGN_PAYLOAD - 1);
wb->offset = align;
if (!CBB_init_fixed(&cbb, wb->buf + align, wb->len - align))
goto err;
tls12_record_layer_set_version(s->internal->rl, version);
if (need_empty_fragment) {
if (!tls12_record_layer_seal_record(s->internal->rl, type,
buf, 0, &cbb))
goto err;
s->s3->empty_fragment_done = 1;
}
if (!tls12_record_layer_seal_record(s->internal->rl, type, buf, len, &cbb))
goto err;
if (!CBB_finish(&cbb, NULL, &out_len))
goto err;
wb->left = out_len;
s->s3->wpend_tot = len;
s->s3->wpend_buf = buf;
s->s3->wpend_type = type;
s->s3->wpend_ret = len;
return ssl3_write_pending(s, type, buf, len);
err:
CBB_cleanup(&cbb);
return -1;
}
int
ssl3_write_pending(SSL *s, int type, const unsigned char *buf, unsigned int len)
{
int i;
SSL3_BUFFER_INTERNAL *wb = &(s->s3->wbuf);
if ((s->s3->wpend_tot > (int)len) || ((s->s3->wpend_buf != buf) &&
!(s->internal->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) ||
(s->s3->wpend_type != type)) {
SSLerror(s, SSL_R_BAD_WRITE_RETRY);
return (-1);
}
for (;;) {
errno = 0;
if (s->wbio != NULL) {
s->internal->rwstate = SSL_WRITING;
i = BIO_write(s->wbio, (char *)&(wb->buf[wb->offset]),
(unsigned int)wb->left);
} else {
SSLerror(s, SSL_R_BIO_NOT_SET);
i = -1;
}
if (i == wb->left) {
wb->left = 0;
wb->offset += i;
if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS &&
!SSL_is_dtls(s))
ssl3_release_write_buffer(s);
s->internal->rwstate = SSL_NOTHING;
return (s->s3->wpend_ret);
} else if (i <= 0) {
if (SSL_is_dtls(s))
wb->left = 0;
return (i);
}
wb->offset += i;
wb->left -= i;
}
}
int
ssl3_read_alert(SSL *s)
{
SSL3_RECORD_INTERNAL *rr = &s->s3->rrec;
uint8_t alert_level, alert_descr;
CBS cbs;
while (rr->length > 0 &&
s->s3->alert_fragment_len < sizeof(s->s3->alert_fragment)) {
s->s3->alert_fragment[s->s3->alert_fragment_len++] =
rr->data[rr->off++];
rr->length--;
}
if (s->s3->alert_fragment_len < sizeof(s->s3->alert_fragment)) {
if (SSL_is_dtls(s)) {
SSLerror(s, SSL_R_BAD_LENGTH);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
}
return 1;
}
CBS_init(&cbs, s->s3->alert_fragment, sizeof(s->s3->alert_fragment));
ssl_msg_callback_cbs(s, 0, SSL3_RT_ALERT, &cbs);
if (!CBS_get_u8(&cbs, &alert_level))
return -1;
if (!CBS_get_u8(&cbs, &alert_descr))
return -1;
s->s3->alert_fragment_len = 0;
ssl_info_callback(s, SSL_CB_READ_ALERT,
(alert_level << 8) | alert_descr);
if (alert_level == SSL3_AL_WARNING) {
s->s3->warn_alert = alert_descr;
if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
s->internal->shutdown |= SSL_RECEIVED_SHUTDOWN;
return 0;
}
if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
SSLerror(s, SSL_R_NO_RENEGOTIATION);
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_HANDSHAKE_FAILURE);
return -1;
}
} else if (alert_level == SSL3_AL_FATAL) {
s->internal->rwstate = SSL_NOTHING;
s->s3->fatal_alert = alert_descr;
SSLerror(s, SSL_AD_REASON_OFFSET + alert_descr);
ERR_asprintf_error_data("SSL alert number %d", alert_descr);
s->internal->shutdown |= SSL_RECEIVED_SHUTDOWN;
SSL_CTX_remove_session(s->ctx, s->session);
return 0;
} else {
SSLerror(s, SSL_R_UNKNOWN_ALERT_TYPE);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
}
return 1;
}
int
ssl3_read_change_cipher_spec(SSL *s)
{
SSL3_RECORD_INTERNAL *rr = &s->s3->rrec;
const uint8_t ccs[] = { SSL3_MT_CCS };
CBS cbs;
CBS_init(&cbs, rr->data, rr->length);
if (rr->off != 0 || CBS_len(&cbs) != sizeof(ccs)) {
SSLerror(s, SSL_R_BAD_CHANGE_CIPHER_SPEC);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
}
if (!CBS_mem_equal(&cbs, ccs, sizeof(ccs))) {
SSLerror(s, SSL_R_BAD_CHANGE_CIPHER_SPEC);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
}
ssl_msg_callback_cbs(s, 0, SSL3_RT_CHANGE_CIPHER_SPEC, &cbs);
if (s->s3->hs.cipher == NULL) {
SSLerror(s, SSL_R_CCS_RECEIVED_EARLY);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
if (SSL_is_dtls(s)) {
if (!s->d1->change_cipher_spec_ok) {
rr->length = 0;
return 1;
}
s->d1->change_cipher_spec_ok = 0;
} else {
if ((s->s3->flags & SSL3_FLAGS_CCS_OK) == 0) {
SSLerror(s, SSL_R_CCS_RECEIVED_EARLY);
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
}
rr->length = 0;
s->s3->change_cipher_spec = 1;
if (!ssl3_do_change_cipher_spec(s))
return -1;
return 1;
}
static int
ssl3_read_handshake_unexpected(SSL *s)
{
SSL3_RECORD_INTERNAL *rr = &s->s3->rrec;
uint32_t hs_msg_length;
uint8_t hs_msg_type;
CBS cbs;
int ret;
while (rr->length > 0 &&
s->s3->handshake_fragment_len < sizeof(s->s3->handshake_fragment)) {
s->s3->handshake_fragment[s->s3->handshake_fragment_len++] =
rr->data[rr->off++];
rr->length--;
}
if (s->s3->handshake_fragment_len < sizeof(s->s3->handshake_fragment))
return 1;
if (s->internal->in_handshake) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
CBS_init(&cbs, s->s3->handshake_fragment, s->s3->handshake_fragment_len);
if (!CBS_get_u8(&cbs, &hs_msg_type))
return -1;
if (!CBS_get_u24(&cbs, &hs_msg_length))
return -1;
if (hs_msg_type == SSL3_MT_HELLO_REQUEST) {
if (s->server) {
SSLerror(s, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
if (hs_msg_length != 0) {
SSLerror(s, SSL_R_BAD_HELLO_REQUEST);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
}
ssl_msg_callback(s, 0, SSL3_RT_HANDSHAKE,
s->s3->handshake_fragment, s->s3->handshake_fragment_len);
s->s3->handshake_fragment_len = 0;
if (s->session == NULL || s->session->cipher == NULL)
return 1;
if (!SSL_is_init_finished(s) || s->s3->renegotiate ||
(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) != 0)
return 1;
if (!ssl3_renegotiate(s))
return 1;
if (!ssl3_renegotiate_check(s))
return 1;
} else if (hs_msg_type == SSL3_MT_CLIENT_HELLO) {
if (!s->server) {
SSLerror(s, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
if (!SSL_is_init_finished(s)) {
SSLerror(s, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
if ((s->internal->options & SSL_OP_NO_CLIENT_RENEGOTIATION) != 0) {
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_NO_RENEGOTIATION);
return -1;
}
if (s->session == NULL || s->session->cipher == NULL) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
if (!s->s3->send_connection_binding ||
(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) != 0) {
ssl3_send_alert(s, SSL3_AL_WARNING,
SSL_AD_NO_RENEGOTIATION);
return 1;
}
s->s3->hs.state = SSL_ST_ACCEPT;
s->internal->renegotiate = 1;
s->internal->new_session = 1;
} else {
SSLerror(s, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
if ((ret = s->internal->handshake_func(s)) < 0)
return ret;
if (ret == 0) {
SSLerror(s, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
if (!(s->internal->mode & SSL_MODE_AUTO_RETRY)) {
if (s->s3->rbuf.left == 0) {
ssl_force_want_read(s);
return -1;
}
}
return 1;
}
int
ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
{
SSL3_RECORD_INTERNAL *rr;
int rrcount = 0;
unsigned int n;
int ret;
if (s->s3->rbuf.buf == NULL) {
if (!ssl3_setup_read_buffer(s))
return -1;
}
if (len < 0) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
if (type != 0 && type != SSL3_RT_APPLICATION_DATA &&
type != SSL3_RT_HANDSHAKE) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
if (peek && type != SSL3_RT_APPLICATION_DATA) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
if (type == SSL3_RT_HANDSHAKE && s->s3->handshake_fragment_len > 0) {
unsigned char *src = s->s3->handshake_fragment;
unsigned char *dst = buf;
unsigned int k;
n = 0;
while (len > 0 && s->s3->handshake_fragment_len > 0) {
*dst++ = *src++;
len--;
s->s3->handshake_fragment_len--;
n++;
}
for (k = 0; k < s->s3->handshake_fragment_len; k++)
s->s3->handshake_fragment[k] = *src++;
return n;
}
if (SSL_in_init(s) && !s->internal->in_handshake) {
if ((ret = s->internal->handshake_func(s)) < 0)
return ret;
if (ret == 0) {
SSLerror(s, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
}
start:
if (rrcount++ >= 3) {
ssl_force_want_read(s);
return -1;
}
s->internal->rwstate = SSL_NOTHING;
rr = &s->s3->rrec;
if (rr->length == 0 || s->internal->rstate == SSL_ST_READ_BODY) {
if ((ret = ssl3_get_record(s)) <= 0)
return ret;
}
if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE) {
SSLerror(s, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
if (s->internal->shutdown & SSL_RECEIVED_SHUTDOWN) {
s->internal->rwstate = SSL_NOTHING;
rr->length = 0;
return 0;
}
if (type == rr->type) {
if (SSL_in_init(s) && type == SSL3_RT_APPLICATION_DATA &&
!tls12_record_layer_read_protected(s->internal->rl)) {
SSLerror(s, SSL_R_APP_DATA_IN_HANDSHAKE);
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
if (len <= 0)
return len;
if ((unsigned int)len > rr->length)
n = rr->length;
else
n = (unsigned int)len;
memcpy(buf, &rr->data[rr->off], n);
if (!peek) {
memset(&rr->data[rr->off], 0, n);
rr->length -= n;
rr->off += n;
if (rr->length == 0) {
s->internal->rstate = SSL_ST_READ_HEADER;
rr->off = 0;
if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS &&
s->s3->rbuf.left == 0)
ssl3_release_read_buffer(s);
}
}
return n;
}
if (rr->type == SSL3_RT_ALERT) {
if ((ret = ssl3_read_alert(s)) <= 0)
return ret;
goto start;
}
if (s->internal->shutdown & SSL_SENT_SHUTDOWN) {
s->internal->rwstate = SSL_NOTHING;
rr->length = 0;
return 0;
}
if (rr->type == SSL3_RT_APPLICATION_DATA) {
if (s->s3->in_read_app_data != 0 &&
s->s3->total_renegotiations != 0 &&
(((s->s3->hs.state & SSL_ST_CONNECT) &&
(s->s3->hs.state >= SSL3_ST_CW_CLNT_HELLO_A) &&
(s->s3->hs.state <= SSL3_ST_CR_SRVR_HELLO_A)) || (
(s->s3->hs.state & SSL_ST_ACCEPT) &&
(s->s3->hs.state <= SSL3_ST_SW_HELLO_REQ_A) &&
(s->s3->hs.state >= SSL3_ST_SR_CLNT_HELLO_A)))) {
s->s3->in_read_app_data = 2;
return -1;
} else {
SSLerror(s, SSL_R_UNEXPECTED_RECORD);
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
}
if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
if ((ret = ssl3_read_change_cipher_spec(s)) <= 0)
return ret;
goto start;
}
if (rr->type == SSL3_RT_HANDSHAKE) {
if ((ret = ssl3_read_handshake_unexpected(s)) <= 0)
return ret;
goto start;
}
if (ssl_effective_tls_version(s) <= TLS1_1_VERSION) {
rr->length = 0;
goto start;
}
SSLerror(s, SSL_R_UNEXPECTED_RECORD);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
int
ssl3_do_change_cipher_spec(SSL *s)
{
if (s->s3->hs.tls12.key_block == NULL) {
if (s->session == NULL || s->session->master_key_length == 0) {
SSLerror(s, SSL_R_CCS_RECEIVED_EARLY);
return (0);
}
s->session->cipher = s->s3->hs.cipher;
if (!tls1_setup_key_block(s))
return (0);
}
if (!tls1_change_read_cipher_state(s))
return (0);
if (!tls12_derive_peer_finished(s))
return (0);
return (1);
}
static int
ssl3_write_alert(SSL *s)
{
if (SSL_is_dtls(s))
return do_dtls1_write(s, SSL3_RT_ALERT, s->s3->send_alert,
sizeof(s->s3->send_alert));
return do_ssl3_write(s, SSL3_RT_ALERT, s->s3->send_alert,
sizeof(s->s3->send_alert));
}
int
ssl3_send_alert(SSL *s, int level, int desc)
{
if (level == SSL3_AL_FATAL)
SSL_CTX_remove_session(s->ctx, s->session);
s->s3->alert_dispatch = 1;
s->s3->send_alert[0] = level;
s->s3->send_alert[1] = desc;
if (s->s3->wbuf.left != 0)
return -1;
return ssl3_dispatch_alert(s);
}
int
ssl3_dispatch_alert(SSL *s)
{
int ret;
s->s3->alert_dispatch = 0;
if ((ret = ssl3_write_alert(s)) <= 0) {
s->s3->alert_dispatch = 1;
return ret;
}
if (s->s3->send_alert[0] == SSL3_AL_FATAL)
(void)BIO_flush(s->wbio);
ssl_msg_callback(s, 1, SSL3_RT_ALERT, s->s3->send_alert, 2);
ssl_info_callback(s, SSL_CB_WRITE_ALERT,
(s->s3->send_alert[0] << 8) | s->s3->send_alert[1]);
return ret;
}