#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include "bytestring.h"
#include "dtls_local.h"
#include "ssl_local.h"
#include "tls_content.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->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;
}
if (rb->buf == NULL)
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->packet = rb->buf + rb->offset;
s->packet_length = 0;
}
if (SSL_is_dtls(s)) {
if (left > 0 && n > left)
n = left;
}
if (left >= n) {
s->packet_length += n;
rb->left = left - n;
rb->offset += n;
return (n);
}
len = s->packet_length;
pkt = rb->buf + align;
if (s->packet != pkt) {
memmove(pkt, s->packet, len + left);
s->packet = pkt;
rb->offset = len + align;
}
if (n > (int)(rb->len - rb->offset)) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
if (s->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->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->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->packet_length += n;
s->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->packet_length < plen)
return s->packet_length;
return plen;
}
int
ssl3_packet_extend(SSL *s, int plen)
{
int rlen, n;
if (s->packet_length >= plen)
return plen;
rlen = plen - s->packet_length;
n = ssl3_read_n(s, rlen, rlen, 1);
if (n <= 0)
return n;
if (s->packet_length < plen)
return s->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;
int al, n;
int ret = -1;
again:
if ((s->rstate != SSL_ST_READ_BODY) ||
(s->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->rstate = SSL_ST_READ_BODY;
CBS_init(&header, s->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->first_packet && ssl_version != s->version) {
if ((s->version & 0xFF00) == (ssl_version & 0xFF00) &&
!tls12_record_layer_write_protected(s->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->rstate = SSL_ST_READ_HEADER;
tls12_record_layer_set_version(s->rl, s->version);
if (!tls12_record_layer_open_record(s->rl, s->packet, s->packet_length,
s->s3->rcontent)) {
tls12_record_layer_alert(s->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;
}
s->packet_length = 0;
if (tls_content_remaining(s->s3->rcontent) == 0) {
if (rr->type != SSL3_RT_APPLICATION_DATA) {
SSLerror(s, SSL_R_BAD_LENGTH);
al = SSL_AD_UNEXPECTED_MESSAGE;
goto fatal_err;
}
tls_content_clear(s->s3->rcontent);
if (s->empty_record_count++ > SSL_MAX_EMPTY_RECORDS) {
SSLerror(s, SSL_R_PEER_BEHAVING_BADLY);
return -1;
}
if (s->empty_record_count > 1) {
ssl_force_want_read(s);
return -1;
}
goto again;
}
s->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->rwstate = SSL_NOTHING;
tot = s->s3->wnum;
s->s3->wnum = 0;
if (SSL_in_init(s) && !s->in_handshake) {
i = s->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->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
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);
size_t align, out_len;
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;
align = (size_t)wb->buf + 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->rl, s->version);
if (!tls12_record_layer_seal_record(s->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->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->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->mode & SSL_MODE_RELEASE_BUFFERS &&
!SSL_is_dtls(s))
ssl3_release_write_buffer(s);
s->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;
}
}
static ssize_t
ssl3_read_cb(void *buf, size_t n, void *cb_arg)
{
SSL *s = cb_arg;
return tls_content_read(s->s3->rcontent, buf, n);
}
#define SSL3_ALERT_LENGTH 2
int
ssl3_read_alert(SSL *s)
{
uint8_t alert_level, alert_descr;
ssize_t ret;
CBS cbs;
if (s->s3->alert_fragment == NULL) {
if ((s->s3->alert_fragment = tls_buffer_new(0)) == NULL)
return -1;
tls_buffer_set_capacity_limit(s->s3->alert_fragment,
SSL3_ALERT_LENGTH);
}
ret = tls_buffer_extend(s->s3->alert_fragment, SSL3_ALERT_LENGTH,
ssl3_read_cb, s);
if (ret <= 0 && ret != TLS_IO_WANT_POLLIN)
return -1;
if (ret != SSL3_ALERT_LENGTH) {
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;
}
if (!tls_buffer_data(s->s3->alert_fragment, &cbs))
return -1;
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;
tls_buffer_free(s->s3->alert_fragment);
s->s3->alert_fragment = NULL;
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->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->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->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)
{
const uint8_t ccs[1] = { SSL3_MT_CCS };
if (tls_content_remaining(s->s3->rcontent) != sizeof(ccs)) {
SSLerror(s, SSL_R_BAD_CHANGE_CIPHER_SPEC);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
}
if (!tls_content_equal(s->s3->rcontent, 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,
tls_content_cbs(s->s3->rcontent));
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) {
tls_content_clear(s->s3->rcontent);
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;
}
tls_content_clear(s->s3->rcontent);
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)
{
uint32_t hs_msg_length;
uint8_t hs_msg_type;
ssize_t ssret;
CBS cbs;
int ret;
if (s->s3->handshake_fragment == NULL) {
if ((s->s3->handshake_fragment = tls_buffer_new(0)) == NULL)
return -1;
tls_buffer_set_capacity_limit(s->s3->handshake_fragment,
SSL3_HM_HEADER_LENGTH);
}
ssret = tls_buffer_extend(s->s3->handshake_fragment, SSL3_HM_HEADER_LENGTH,
ssl3_read_cb, s);
if (ssret <= 0 && ssret != TLS_IO_WANT_POLLIN)
return -1;
if (ssret != SSL3_HM_HEADER_LENGTH)
return 1;
if (s->in_handshake) {
SSLerror(s, ERR_R_INTERNAL_ERROR);
return -1;
}
if (!tls_buffer_data(s->s3->handshake_fragment, &cbs))
return -1;
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;
}
if (!tls_buffer_data(s->s3->handshake_fragment, &cbs))
return -1;
ssl_msg_callback_cbs(s, 0, SSL3_RT_HANDSHAKE, &cbs);
tls_buffer_free(s->s3->handshake_fragment);
s->s3->handshake_fragment = NULL;
if ((s->options & SSL_OP_NO_RENEGOTIATION) != 0) {
ssl3_send_alert(s, SSL3_AL_WARNING,
SSL_AD_NO_RENEGOTIATION);
return 1;
}
if (s->session == NULL || s->s3->hs.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->options & SSL_OP_NO_CLIENT_RENEGOTIATION) != 0 ||
((s->options & SSL_OP_NO_RENEGOTIATION) != 0 &&
(s->options & SSL_OP_ALLOW_CLIENT_RENEGOTIATION) == 0)) {
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_NO_RENEGOTIATION);
return -1;
}
if (s->session == NULL || s->s3->hs.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->renegotiate = 1;
s->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->handshake_func(s)) < 0)
return ret;
if (ret == 0) {
SSLerror(s, SSL_R_SSL_HANDSHAKE_FAILURE);
return -1;
}
if (!(s->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)
{
int rrcount = 0;
ssize_t ssret;
int ret;
if (s->s3->rbuf.buf == NULL) {
if (!ssl3_setup_read_buffer(s))
return -1;
}
if (s->s3->rcontent == NULL) {
if ((s->s3->rcontent = tls_content_new()) == NULL)
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 != NULL &&
tls_buffer_remaining(s->s3->handshake_fragment) > 0) {
ssize_t ssn;
if ((ssn = tls_buffer_read(s->s3->handshake_fragment, buf,
len)) <= 0)
return -1;
if (tls_buffer_remaining(s->s3->handshake_fragment) == 0) {
tls_buffer_free(s->s3->handshake_fragment);
s->s3->handshake_fragment = NULL;
}
return (int)ssn;
}
if (SSL_in_init(s) && !s->in_handshake) {
if ((ret = s->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->rwstate = SSL_NOTHING;
if (tls_content_remaining(s->s3->rcontent) == 0) {
if ((ret = ssl3_get_record(s)) <= 0)
return ret;
}
if (s->s3->change_cipher_spec &&
tls_content_type(s->s3->rcontent) != 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->shutdown & SSL_RECEIVED_SHUTDOWN) {
s->rwstate = SSL_NOTHING;
tls_content_clear(s->s3->rcontent);
s->s3->rrec.length = 0;
return 0;
}
if (tls_content_type(s->s3->rcontent) == type) {
if (SSL_in_init(s) && type == SSL3_RT_APPLICATION_DATA &&
!tls12_record_layer_read_protected(s->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 (peek) {
ssret = tls_content_peek(s->s3->rcontent, buf, len);
} else {
ssret = tls_content_read(s->s3->rcontent, buf, len);
}
if (ssret < INT_MIN || ssret > INT_MAX)
return -1;
if (ssret < 0)
return (int)ssret;
if (tls_content_remaining(s->s3->rcontent) == 0) {
s->rstate = SSL_ST_READ_HEADER;
if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
s->s3->rbuf.left == 0)
ssl3_release_read_buffer(s);
}
return ssret;
}
if (tls_content_type(s->s3->rcontent) == SSL3_RT_ALERT) {
if ((ret = ssl3_read_alert(s)) <= 0)
return ret;
goto start;
}
if (s->shutdown & SSL_SENT_SHUTDOWN) {
s->rwstate = SSL_NOTHING;
tls_content_clear(s->s3->rcontent);
s->s3->rrec.length = 0;
return 0;
}
if (tls_content_type(s->s3->rcontent) == 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 (tls_content_type(s->s3->rcontent) == SSL3_RT_CHANGE_CIPHER_SPEC) {
if ((ret = ssl3_read_change_cipher_spec(s)) <= 0)
return ret;
goto start;
}
if (tls_content_type(s->s3->rcontent) == SSL3_RT_HANDSHAKE) {
if ((ret = ssl3_read_handshake_unexpected(s)) <= 0)
return ret;
goto start;
}
if (ssl_effective_tls_version(s) <= TLS1_1_VERSION) {
tls_content_clear(s->s3->rcontent);
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_value = s->s3->hs.cipher->value;
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;
}