Ver a proveniência

Lift BIO above SSL_PROTOCOL_METHOD.

This gets us closer to exposing BIO-free APIs. The next step is probably
to make the experimental bssl::OpenRecord function call a split out core
of ssl_read_impl.

Change-Id: I4acebb43f708df8c52eb4e328da8ae3551362fb9
Reviewed-on: https://boringssl-review.googlesource.com/21865
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
kris/onging/CECPQ3_patch15
David Benjamin há 7 anos
committed by CQ bot account: commit-bot@chromium.org
ascendente
cometimento
d9229f9802
10 ficheiros alterados com 418 adições e 475 eliminações
  1. +46
    -48
      ssl/d1_both.cc
  2. +40
    -105
      ssl/d1_pkt.cc
  3. +4
    -4
      ssl/dtls_method.cc
  4. +23
    -13
      ssl/handshake.cc
  5. +52
    -41
      ssl/internal.h
  6. +76
    -72
      ssl/s3_both.cc
  7. +84
    -167
      ssl/s3_pkt.cc
  8. +40
    -0
      ssl/ssl_buffer.cc
  9. +48
    -17
      ssl/ssl_lib.cc
  10. +5
    -8
      ssl/tls_method.cc

+ 46
- 48
ssl/d1_both.cc Ver ficheiro

@@ -272,9 +272,10 @@ static bool dtls1_is_current_message_complete(const SSL *ssl) {
// queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It
// returns NULL on failure. The caller does not take ownership of the result.
static hm_fragment *dtls1_get_incoming_message(
SSL *ssl, const struct hm_header_st *msg_hdr) {
SSL *ssl, uint8_t *out_alert, const struct hm_header_st *msg_hdr) {
if (msg_hdr->seq < ssl->d1->handshake_read_seq ||
msg_hdr->seq - ssl->d1->handshake_read_seq >= SSL_MAX_HANDSHAKE_FLIGHT) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return NULL;
}

@@ -287,7 +288,7 @@ static hm_fragment *dtls1_get_incoming_message(
if (frag->type != msg_hdr->type ||
frag->msg_len != msg_hdr->msg_len) {
OPENSSL_PUT_ERROR(SSL, SSL_R_FRAGMENT_MISMATCH);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return NULL;
}
return frag;
@@ -296,81 +297,76 @@ static hm_fragment *dtls1_get_incoming_message(
// This is the first fragment from this message.
frag = dtls1_hm_fragment_new(msg_hdr);
if (frag == NULL) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return NULL;
}
ssl->d1->incoming_messages[idx] = frag;
return frag;
}

int dtls1_read_message(SSL *ssl) {
SSL3_RECORD *rr = &ssl->s3->rrec;
if (rr->length == 0) {
int ret = dtls1_get_record(ssl);
if (ret <= 0) {
return ret;
}
ssl_open_record_t dtls1_open_handshake(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in) {
uint8_t type;
Span<uint8_t> record;
auto ret = dtls_open_record(ssl, &type, &record, out_consumed, out_alert, in);
if (ret != ssl_open_record_success) {
return ret;
}

switch (rr->type) {
switch (type) {
case SSL3_RT_APPLICATION_DATA:
// Unencrypted application data records are always illegal.
if (ssl->s3->aead_read_ctx->is_null_cipher()) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

// Out-of-order application data may be received between ChangeCipherSpec
// and finished. Discard it.
rr->length = 0;
ssl_read_buffer_discard(ssl);
return 1;
return ssl_open_record_discard;

case SSL3_RT_CHANGE_CIPHER_SPEC:
// We do not support renegotiation, so encrypted ChangeCipherSpec records
// are illegal.
if (!ssl->s3->aead_read_ctx->is_null_cipher()) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) {
if (record.size() != 1u || record[0] != SSL3_MT_CCS) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return ssl_open_record_error;
}

// Flag the ChangeCipherSpec for later.
ssl->d1->has_change_cipher_spec = true;
ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC,
MakeSpan(rr->data, rr->length));

rr->length = 0;
ssl_read_buffer_discard(ssl);
return 1;
record);
return ssl_open_record_success;

case SSL3_RT_HANDSHAKE:
// Break out to main processing.
break;

default:
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

CBS cbs;
CBS_init(&cbs, rr->data, rr->length);

CBS_init(&cbs, record.data(), record.size());
while (CBS_len(&cbs) > 0) {
// Read a handshake fragment.
struct hm_header_st msg_hdr;
CBS body;
if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
*out_alert = SSL_AD_DECODE_ERROR;
return ssl_open_record_error;
}

const size_t frag_off = msg_hdr.frag_off;
@@ -380,15 +376,15 @@ int dtls1_read_message(SSL *ssl) {
frag_off + frag_len > msg_len ||
msg_len > ssl_max_handshake_message_len(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return ssl_open_record_error;
}

// The encrypted epoch in DTLS has only one handshake message.
if (ssl->d1->r_epoch == 1 && msg_hdr.seq != ssl->d1->handshake_read_seq) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

if (msg_hdr.seq < ssl->d1->handshake_read_seq ||
@@ -398,9 +394,9 @@ int dtls1_read_message(SSL *ssl) {
continue;
}

hm_fragment *frag = dtls1_get_incoming_message(ssl, &msg_hdr);
hm_fragment *frag = dtls1_get_incoming_message(ssl, out_alert, &msg_hdr);
if (frag == NULL) {
return -1;
return ssl_open_record_error;
}
assert(frag->msg_len == msg_len);

@@ -416,9 +412,7 @@ int dtls1_read_message(SSL *ssl) {
dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
}

rr->length = 0;
ssl_read_buffer_discard(ssl);
return 1;
return ssl_open_record_success;
}

bool dtls1_get_message(SSL *ssl, SSLMessage *out) {
@@ -496,17 +490,21 @@ bool dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
return true;
}

int dtls1_read_change_cipher_spec(SSL *ssl) {
// Process handshake records until there is a ChangeCipherSpec.
while (!ssl->d1->has_change_cipher_spec) {
int ret = dtls1_read_message(ssl);
if (ret <= 0) {
ssl_open_record_t dtls1_open_change_cipher_spec(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert,
Span<uint8_t> in) {
if (!ssl->d1->has_change_cipher_spec) {
// dtls1_open_handshake processes both handshake and ChangeCipherSpec.
auto ret = dtls1_open_handshake(ssl, out_consumed, out_alert, in);
if (ret != ssl_open_record_success) {
return ret;
}
}

ssl->d1->has_change_cipher_spec = false;
return 1;
if (ssl->d1->has_change_cipher_spec) {
ssl->d1->has_change_cipher_spec = false;
return ssl_open_record_success;
}
return ssl_open_record_discard;
}




+ 40
- 105
ssl/d1_pkt.cc Ver ficheiro

@@ -128,84 +128,29 @@

namespace bssl {

int dtls1_get_record(SSL *ssl) {
for (;;) {
Span<uint8_t> body;
uint8_t type, alert;
size_t consumed;
enum ssl_open_record_t open_ret = dtls_open_record(
ssl, &type, &body, &consumed, &alert, ssl_read_buffer(ssl));
if (open_ret != ssl_open_record_partial) {
ssl_read_buffer_consume(ssl, consumed);
}
switch (open_ret) {
case ssl_open_record_partial: {
assert(ssl_read_buffer(ssl).empty());
int read_ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */);
if (read_ret <= 0) {
return read_ret;
}
continue;
}

case ssl_open_record_success: {
if (body.size() > 0xffff) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return -1;
}

SSL3_RECORD *rr = &ssl->s3->rrec;
rr->type = type;
rr->length = static_cast<uint16_t>(body.size());
rr->data = body.data();
return 1;
}

case ssl_open_record_discard:
continue;

case ssl_open_record_close_notify:
return 0;

case ssl_open_record_error:
if (alert != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
}
return -1;
}

assert(0);
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
}

int dtls1_read_app_data(SSL *ssl, bool *out_got_handshake, uint8_t *buf,
int len, int peek) {
ssl_open_record_t dtls1_open_app_data(SSL *ssl, Span<uint8_t> *out,
size_t *out_consumed, uint8_t *out_alert,
Span<uint8_t> in) {
assert(!SSL_in_init(ssl));

*out_got_handshake = false;
SSL3_RECORD *rr = &ssl->s3->rrec;

again:
if (rr->length == 0) {
int ret = dtls1_get_record(ssl);
if (ret <= 0) {
return ret;
}
uint8_t type;
Span<uint8_t> record;
auto ret = dtls_open_record(ssl, &type, &record, out_consumed, out_alert, in);
if (ret != ssl_open_record_success) {
return ret;
}

if (rr->type == SSL3_RT_HANDSHAKE) {
if (type == SSL3_RT_HANDSHAKE) {
// Parse the first fragment header to determine if this is a pre-CCS or
// post-CCS handshake record. DTLS resets handshake message numbers on each
// handshake, so renegotiations and retransmissions are ambiguous.
CBS cbs, body;
struct hm_header_st msg_hdr;
CBS_init(&cbs, rr->data, rr->length);
CBS_init(&cbs, record.data(), record.size());
if (!dtls1_parse_fragment(&cbs, &msg_hdr, &body)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
return -1;
*out_alert = SSL_AD_DECODE_ERROR;
return ssl_open_record_error;
}

if (msg_hdr.type == SSL3_MT_FINISHED &&
@@ -215,62 +160,52 @@ again:
// Finished, they may not have received ours. Only do this for the
// first fragment, in case the Finished was fragmented.
if (!dtls1_check_timeout_num(ssl)) {
return -1;
*out_alert = 0; // TODO(davidben): Send an alert?
return ssl_open_record_error;
}

dtls1_retransmit_outgoing_messages(ssl);
}

rr->length = 0;
goto again;
return ssl_open_record_discard;
}

// Otherwise, this is a pre-CCS handshake message from an unsupported
// renegotiation attempt. Fall through to the error path.
}

if (rr->type != SSL3_RT_APPLICATION_DATA) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
if (type != SSL3_RT_APPLICATION_DATA) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

// Discard empty records.
if (rr->length == 0) {
goto again;
if (record.empty()) {
return ssl_open_record_discard;
}

if (len <= 0) {
return len;
}

if ((unsigned)len > rr->length) {
len = rr->length;
}

OPENSSL_memcpy(buf, rr->data, len);
if (!peek) {
// TODO(davidben): Should the record be truncated instead? This is a
// datagram transport. See https://crbug.com/boringssl/65.
rr->length -= len;
rr->data += len;
if (rr->length == 0) {
// The record has been consumed, so we may now clear the buffer.
ssl_read_buffer_discard(ssl);
}
}

return len;
*out = record;
return ssl_open_record_success;
}

void dtls1_read_close_notify(SSL *ssl) {
// Bidirectional shutdown doesn't make sense for an unordered transport. DTLS
// alerts also aren't delivered reliably, so we may even time out because the
// peer never received our close_notify. Report to the caller that the channel
// has fully shut down.
if (ssl->s3->read_shutdown == ssl_shutdown_none) {
ssl->s3->read_shutdown = ssl_shutdown_close_notify;
ssl_open_record_t dtls1_open_close_notify(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert,
bssl::Span<uint8_t> in) {
switch (ssl->s3->read_shutdown) {
// Bidirectional shutdown doesn't make sense for an unordered transport.
// DTLS alerts also aren't delivered reliably, so we may even time out
// because the peer never received our close_notify. Report to the caller
// that the channel has fully shut down.
case ssl_shutdown_none:
case ssl_shutdown_close_notify:
ssl->s3->read_shutdown = ssl_shutdown_close_notify;
return ssl_open_record_close_notify;
case ssl_shutdown_error:
ERR_restore_state(ssl->s3->read_error);
*out_alert = 0;
return ssl_open_record_error;
}
assert(0);
return ssl_open_record_error;
}

int dtls1_write_app_data(SSL *ssl, bool *out_needs_handshake,


+ 4
- 4
ssl/dtls_method.cc Ver ficheiro

@@ -117,11 +117,11 @@ static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
dtls1_new,
dtls1_free,
dtls1_get_message,
dtls1_read_message,
dtls1_next_message,
dtls1_read_app_data,
dtls1_read_change_cipher_spec,
dtls1_read_close_notify,
dtls1_open_handshake,
dtls1_open_change_cipher_spec,
dtls1_open_app_data,
dtls1_open_close_notify,
dtls1_write_app_data,
dtls1_dispatch_alert,
dtls1_supports_cipher,


+ 23
- 13
ssl/handshake.cc Ver ficheiro

@@ -498,12 +498,22 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
}

case ssl_hs_read_server_hello:
case ssl_hs_read_message: {
int ret = ssl->method->read_message(ssl);
if (ret <= 0) {
case ssl_hs_read_message:
case ssl_hs_read_change_cipher_spec: {
uint8_t alert = SSL_AD_DECODE_ERROR;
size_t consumed = 0;
ssl_open_record_t ret;
if (hs->wait == ssl_hs_read_change_cipher_spec) {
ret = ssl->method->open_change_cipher_spec(ssl, &consumed, &alert,
ssl_read_buffer(ssl));
} else {
ret = ssl->method->open_handshake(ssl, &consumed, &alert,
ssl_read_buffer(ssl));
}
if (ret == ssl_open_record_error &&
hs->wait == ssl_hs_read_server_hello) {
uint32_t err = ERR_peek_error();
if (hs->wait == ssl_hs_read_server_hello &&
ERR_GET_LIB(err) == ERR_LIB_SSL &&
if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) {
// Add a dedicated error code to the queue for a handshake_failure
// alert in response to ClientHello. This matches NSS's client
@@ -514,16 +524,16 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
// See https://crbug.com/446505.
OPENSSL_PUT_ERROR(SSL, SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO);
}
return ret;
}
break;
}
case ssl_hs_read_change_cipher_spec: {
int ret = ssl->method->read_change_cipher_spec(ssl);
if (ret <= 0) {
return ret;
bool retry;
int bio_ret = ssl_handle_open_record(ssl, &retry, ret, consumed, alert);
if (bio_ret <= 0) {
return bio_ret;
}
if (retry) {
continue;
}
ssl_read_buffer_discard(ssl);
break;
}



+ 52
- 41
ssl/internal.h Ver ficheiro

@@ -1062,6 +1062,12 @@ void ssl_read_buffer_discard(SSL *ssl);
// zero-initializes it.
void ssl_read_buffer_clear(SSL *ssl);

// ssl_handle_open_record handles the result of passing |ssl_read_buffer| to a
// record-processing function. If |ret| is a success or if the caller should
// retry, it returns one and sets |*out_retry|. Otherwise, it returns <= 0.
int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret,
size_t consumed, uint8_t alert);

// ssl_write_buffer_is_pending returns one if the write buffer has pending data
// and zero if is empty.
int ssl_write_buffer_is_pending(const SSL *ssl);
@@ -1728,20 +1734,31 @@ struct SSL_PROTOCOL_METHOD {
// get_message sets |*out| to the current handshake message and returns true
// if one has been received. It returns false if more input is needed.
bool (*get_message)(SSL *ssl, SSLMessage *out);
// read_message reads additional handshake data for |get_message|. On success,
// it returns one. Otherwise, it returns <= 0.
int (*read_message)(SSL *ssl);
// next_message is called to release the current handshake message.
void (*next_message)(SSL *ssl);
// read_app_data reads up to |len| bytes of application data into |buf|. On
// success, it returns the number of bytes read. Otherwise, it returns <= 0
// and sets |*out_got_handshake| to whether the failure was due to a
// post-handshake handshake message. If so, any handshake messages consumed
// may be read with |get_message|.
int (*read_app_data)(SSL *ssl, bool *out_got_handshake, uint8_t *buf, int len,
int peek);
int (*read_change_cipher_spec)(SSL *ssl);
void (*read_close_notify)(SSL *ssl);
// open_handshake processes a record from |in| for reading a handshake
// message.
ssl_open_record_t (*open_handshake)(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);
// open_change_cipher_spec processes a record from |in| for reading a
// ChangeCipherSpec. If an out-of-order record was received in DTLS, it
// succeeds without consuming input.
ssl_open_record_t (*open_change_cipher_spec)(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert,
Span<uint8_t> in);
// open_app_data processes a record from |in| for reading application data.
// On success, it returns |ssl_open_record_success| and sets |*out| to the
// input. If it encounters a post-handshake message, it returns
// |ssl_open_record_discard|. The caller should then retry, after processing
// any messages received with |get_message|.
ssl_open_record_t (*open_app_data)(SSL *ssl, Span<uint8_t> *out,
size_t *out_consumed, uint8_t *out_alert,
Span<uint8_t> in);
// open_close_notify processes a record from |in| for reading close_notify.
// It discards all records and returns |ssl_open_record_close_notify| when it
// receives one.
ssl_open_record_t (*open_close_notify)(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);
int (*write_app_data)(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf,
int len);
int (*dispatch_alert)(SSL *ssl);
@@ -2107,15 +2124,6 @@ struct SSLContext {
bool ed25519_enabled:1;
};

struct SSL3_RECORD {
// type is the record type.
uint8_t type;
// length is the number of unconsumed bytes in the record.
uint16_t length;
// data is a non-owning pointer to the first unconsumed byte of the record.
uint8_t *data;
};

struct SSL3_BUFFER {
// buf is the memory allocated for this buffer.
uint8_t *buf;
@@ -2147,7 +2155,9 @@ struct SSL3_STATE {
// write_buffer holds data to be written to the transport.
SSL3_BUFFER write_buffer;

SSL3_RECORD rrec; // each decoded record goes in here
// pending_app_data is the unconsumed application data. It points into
// |read_buffer|.
Span<uint8_t> pending_app_data;

// partial write - check the numbers match
unsigned int wnum; // number of bytes sent so far
@@ -2690,18 +2700,19 @@ void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);

int ssl_send_alert(SSL *ssl, int level, int desc);
bool ssl3_get_message(SSL *ssl, SSLMessage *out);
int ssl3_read_message(SSL *ssl);
ssl_open_record_t ssl3_open_handshake(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);
void ssl3_next_message(SSL *ssl);

int ssl3_dispatch_alert(SSL *ssl);
int ssl3_read_app_data(SSL *ssl, bool *out_got_handshake, uint8_t *buf, int len,
int peek);
int ssl3_read_change_cipher_spec(SSL *ssl);
void ssl3_read_close_notify(SSL *ssl);
// ssl3_get_record reads a new input record. On success, it places it in
// |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
// more data is needed.
int ssl3_get_record(SSL *ssl);
ssl_open_record_t ssl3_open_app_data(SSL *ssl, Span<uint8_t> *out,
size_t *out_consumed, uint8_t *out_alert,
Span<uint8_t> in);
ssl_open_record_t ssl3_open_change_cipher_spec(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert,
Span<uint8_t> in);
ssl_open_record_t ssl3_open_close_notify(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);
int ssl3_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf,
int len);

@@ -2730,15 +2741,14 @@ bool ssl_add_message_cbb(SSL *ssl, CBB *cbb);
// on success and false on allocation failure.
bool ssl_hash_message(SSL_HANDSHAKE *hs, const SSLMessage &msg);

// dtls1_get_record reads a new input record. On success, it places it in
// |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
// more data is needed.
int dtls1_get_record(SSL *ssl);

int dtls1_read_app_data(SSL *ssl, bool *out_got_handshake, uint8_t *buf,
int len, int peek);
int dtls1_read_change_cipher_spec(SSL *ssl);
void dtls1_read_close_notify(SSL *ssl);
ssl_open_record_t dtls1_open_app_data(SSL *ssl, Span<uint8_t> *out,
size_t *out_consumed, uint8_t *out_alert,
Span<uint8_t> in);
ssl_open_record_t dtls1_open_change_cipher_spec(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert,
Span<uint8_t> in);
ssl_open_record_t dtls1_open_close_notify(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);

int dtls1_write_app_data(SSL *ssl, bool *out_needs_handshake,
const uint8_t *buf, int len);
@@ -2762,7 +2772,8 @@ bool dtls1_new(SSL *ssl);
void dtls1_free(SSL *ssl);

bool dtls1_get_message(SSL *ssl, SSLMessage *out);
int dtls1_read_message(SSL *ssl);
ssl_open_record_t dtls1_open_handshake(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in);
void dtls1_next_message(SSL *ssl);
int dtls1_dispatch_alert(SSL *ssl);



+ 76
- 72
ssl/s3_both.cc Ver ficheiro

@@ -274,55 +274,28 @@ int ssl3_flush_flight(SSL *ssl) {
return 1;
}

static int read_v2_client_hello(SSL *ssl) {
// Read the first 5 bytes, the size of the TLS record header. This is
// sufficient to detect a V2ClientHello and ensures that we never read beyond
// the first record.
int ret = ssl_read_buffer_extend_to(ssl, SSL3_RT_HEADER_LENGTH);
if (ret <= 0) {
return ret;
}
const uint8_t *p = ssl_read_buffer(ssl).data();

// Some dedicated error codes for protocol mixups should the application wish
// to interpret them differently. (These do not overlap with ClientHello or
// V2ClientHello.)
if (strncmp("GET ", (const char *)p, 4) == 0 ||
strncmp("POST ", (const char *)p, 5) == 0 ||
strncmp("HEAD ", (const char *)p, 5) == 0 ||
strncmp("PUT ", (const char *)p, 4) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_HTTP_REQUEST);
return -1;
}
if (strncmp("CONNE", (const char *)p, 5) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_HTTPS_PROXY_REQUEST);
return -1;
}

if ((p[0] & 0x80) == 0 || p[2] != SSL2_MT_CLIENT_HELLO ||
p[3] != SSL3_VERSION_MAJOR) {
// Not a V2ClientHello.
return 1;
}

static ssl_open_record_t read_v2_client_hello(SSL *ssl, size_t *out_consumed,
Span<const uint8_t> in) {
*out_consumed = 0;
assert(in.size() >= SSL3_RT_HEADER_LENGTH);
// Determine the length of the V2ClientHello.
size_t msg_length = ((p[0] & 0x7f) << 8) | p[1];
size_t msg_length = ((in[0] & 0x7f) << 8) | in[1];
if (msg_length > (1024 * 4)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_TOO_LARGE);
return -1;
return ssl_open_record_error;
}
if (msg_length < SSL3_RT_HEADER_LENGTH - 2) {
// Reject lengths that are too short early. We have already read
// |SSL3_RT_HEADER_LENGTH| bytes, so we should not attempt to process an
// (invalid) V2ClientHello which would be shorter than that.
OPENSSL_PUT_ERROR(SSL, SSL_R_RECORD_LENGTH_MISMATCH);
return -1;
return ssl_open_record_error;
}

// Read the remainder of the V2ClientHello.
ret = ssl_read_buffer_extend_to(ssl, 2 + msg_length);
if (ret <= 0) {
return ret;
// Ask for the remainder of the V2ClientHello.
if (in.size() < 2 + msg_length) {
*out_consumed = 2 + msg_length;
return ssl_open_record_partial;
}

CBS v2_client_hello = CBS(ssl_read_buffer(ssl).subspan(2, msg_length));
@@ -330,7 +303,7 @@ static int read_v2_client_hello(SSL *ssl) {
// hash. This is only ever called at the start of the handshake, so hs is
// guaranteed to be non-NULL.
if (!ssl->s3->hs->transcript.Update(v2_client_hello)) {
return -1;
return ssl_open_record_error;
}

ssl_do_msg_callback(ssl, 0 /* read */, 0 /* V2ClientHello */,
@@ -349,7 +322,7 @@ static int read_v2_client_hello(SSL *ssl) {
!CBS_get_bytes(&v2_client_hello, &challenge, challenge_length) ||
CBS_len(&v2_client_hello) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return -1;
return ssl_open_record_error;
}

// msg_type has already been checked.
@@ -385,7 +358,7 @@ static int read_v2_client_hello(SSL *ssl) {
!CBB_add_u8(&hello_body, 0) ||
!CBB_add_u16_length_prefixed(&hello_body, &cipher_suites)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return -1;
return ssl_open_record_error;
}

// Copy the cipher suites.
@@ -393,7 +366,7 @@ static int read_v2_client_hello(SSL *ssl) {
uint32_t cipher_spec;
if (!CBS_get_u24(&cipher_specs, &cipher_spec)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return -1;
return ssl_open_record_error;
}

// Skip SSLv2 ciphers.
@@ -402,7 +375,7 @@ static int read_v2_client_hello(SSL *ssl) {
}
if (!CBB_add_u16(&cipher_suites, cipher_spec)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
return ssl_open_record_error;
}
}

@@ -411,15 +384,12 @@ static int read_v2_client_hello(SSL *ssl) {
!CBB_add_u8(&hello_body, 0) ||
!CBB_finish(client_hello.get(), NULL, &ssl->init_buf->length)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
return ssl_open_record_error;
}

// Consume and discard the V2ClientHello.
ssl_read_buffer_consume(ssl, 2 + msg_length);
ssl_read_buffer_discard(ssl);

*out_consumed = 2 + msg_length;
ssl->s3->is_v2_hello = true;
return 1;
return ssl_open_record_success;
}

static bool parse_message(const SSL *ssl, SSLMessage *out,
@@ -497,58 +467,92 @@ bool tls_has_unprocessed_handshake_data(const SSL *ssl) {
return ssl->init_buf != NULL && ssl->init_buf->length > msg_len;
}

int ssl3_read_message(SSL *ssl) {
ssl_open_record_t ssl3_open_handshake(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in) {
*out_consumed = 0;
// Re-create the handshake buffer if needed.
if (ssl->init_buf == NULL) {
ssl->init_buf = BUF_MEM_new();
if (ssl->init_buf == NULL) {
return -1;
*out_alert = SSL_AD_INTERNAL_ERROR;
return ssl_open_record_error;
}
}

// Bypass the record layer for the first message to handle V2ClientHello.
if (ssl->server && !ssl->s3->v2_hello_done) {
int ret = read_v2_client_hello(ssl);
if (ret > 0) {
ssl->s3->v2_hello_done = true;
// Ask for the first 5 bytes, the size of the TLS record header. This is
// sufficient to detect a V2ClientHello and ensures that we never read
// beyond the first record.
if (in.size() < SSL3_RT_HEADER_LENGTH) {
*out_consumed = SSL3_RT_HEADER_LENGTH;
return ssl_open_record_partial;
}
return ret;
}

SSL3_RECORD *rr = &ssl->s3->rrec;
// Get new packet if necessary.
if (rr->length == 0) {
int ret = ssl3_get_record(ssl);
if (ret <= 0) {
// Some dedicated error codes for protocol mixups should the application
// wish to interpret them differently. (These do not overlap with
// ClientHello or V2ClientHello.)
const char *str = reinterpret_cast<const char*>(in.data());
if (strncmp("GET ", str, 4) == 0 ||
strncmp("POST ", str, 5) == 0 ||
strncmp("HEAD ", str, 5) == 0 ||
strncmp("PUT ", str, 4) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_HTTP_REQUEST);
*out_alert = 0;
return ssl_open_record_error;
}
if (strncmp("CONNE", str, 5) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_HTTPS_PROXY_REQUEST);
*out_alert = 0;
return ssl_open_record_error;
}

// Check for a V2ClientHello.
if ((in[0] & 0x80) != 0 && in[2] == SSL2_MT_CLIENT_HELLO &&
in[3] == SSL3_VERSION_MAJOR) {
auto ret = read_v2_client_hello(ssl, out_consumed, in);
if (ret == ssl_open_record_error) {
*out_alert = 0;
} else if (ret == ssl_open_record_success) {
ssl->s3->v2_hello_done = true;
}
return ret;
}

ssl->s3->v2_hello_done = true;
}

uint8_t type;
Span<uint8_t> body;
auto ret = tls_open_record(ssl, &type, &body, out_consumed, out_alert, in);
if (ret != ssl_open_record_success) {
return ret;
}

// WatchGuard's TLS 1.3 interference bug is very distinctive: they drop the
// ServerHello and send the remaining encrypted application data records
// as-is. This manifests as an application data record when we expect
// handshake. Report a dedicated error code for this case.
if (!ssl->server && rr->type == SSL3_RT_APPLICATION_DATA &&
if (!ssl->server && type == SSL3_RT_APPLICATION_DATA &&
ssl->s3->aead_read_ctx->is_null_cipher()) {
OPENSSL_PUT_ERROR(SSL, SSL_R_APPLICATION_DATA_INSTEAD_OF_HANDSHAKE);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

if (rr->type != SSL3_RT_HANDSHAKE) {
if (type != SSL3_RT_HANDSHAKE) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

// Append the entire handshake record to the buffer.
if (!BUF_MEM_append(ssl->init_buf, rr->data, rr->length)) {
return -1;
if (!BUF_MEM_append(ssl->init_buf, body.data(), body.size())) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return ssl_open_record_error;
}

rr->length = 0;
ssl_read_buffer_discard(ssl);
return 1;
return ssl_open_record_success;
}

void ssl3_next_message(SSL *ssl) {


+ 84
- 167
ssl/s3_pkt.cc Ver ficheiro

@@ -126,57 +126,6 @@ namespace bssl {

static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len);

int ssl3_get_record(SSL *ssl) {
for (;;) {
Span<uint8_t> body;
uint8_t type, alert = SSL_AD_DECODE_ERROR;
size_t consumed;
enum ssl_open_record_t open_ret = tls_open_record(
ssl, &type, &body, &consumed, &alert, ssl_read_buffer(ssl));
if (open_ret != ssl_open_record_partial) {
ssl_read_buffer_consume(ssl, consumed);
}
switch (open_ret) {
case ssl_open_record_partial: {
int read_ret = ssl_read_buffer_extend_to(ssl, consumed);
if (read_ret <= 0) {
return read_ret;
}
continue;
}

case ssl_open_record_success: {
if (body.size() > 0xffff) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return -1;
}

SSL3_RECORD *rr = &ssl->s3->rrec;
rr->type = type;
rr->length = static_cast<uint16_t>(body.size());
rr->data = body.data();
return 1;
}

case ssl_open_record_discard:
continue;

case ssl_open_record_close_notify:
return 0;

case ssl_open_record_error:
if (alert != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
}
return -1;
}

assert(0);
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
}

int ssl3_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf,
int len) {
assert(ssl_can_write(ssl));
@@ -333,152 +282,120 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) {
return ssl3_write_pending(ssl, type, buf, len);
}

static int consume_record(SSL *ssl, uint8_t *out, int len, int peek) {
SSL3_RECORD *rr = &ssl->s3->rrec;
ssl_open_record_t ssl3_open_app_data(SSL *ssl, Span<uint8_t> *out,
size_t *out_consumed, uint8_t *out_alert,
Span<uint8_t> in) {
assert(ssl_can_read(ssl));
assert(!ssl->s3->aead_read_ctx->is_null_cipher());

if (len <= 0) {
return len;
uint8_t type;
Span<uint8_t> body;
auto ret = tls_open_record(ssl, &type, &body, out_consumed, out_alert, in);
if (ret != ssl_open_record_success) {
return ret;
}

if (len > (int)rr->length) {
len = (int)rr->length;
}
const bool is_early_data_read = ssl->server && SSL_in_early_data(ssl);

OPENSSL_memcpy(out, rr->data, len);
if (!peek) {
rr->length -= len;
rr->data += len;
if (rr->length == 0) {
// The record has been consumed, so we may now clear the buffer.
ssl_read_buffer_discard(ssl);
if (type == SSL3_RT_HANDSHAKE) {
// If reading 0-RTT data, reject handshake data. 0-RTT data is terminated
// by an alert.
if (is_early_data_read) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}
}
return len;
}

int ssl3_read_app_data(SSL *ssl, bool *out_got_handshake, uint8_t *buf, int len,
int peek) {
assert(ssl_can_read(ssl));
assert(!ssl->s3->aead_read_ctx->is_null_cipher());
*out_got_handshake = false;

SSL3_RECORD *rr = &ssl->s3->rrec;

for (;;) {
// Get new packet if necessary.
if (rr->length == 0) {
int ret = ssl3_get_record(ssl);
if (ret <= 0) {
return ret;
}
// Post-handshake data prior to TLS 1.3 is always renegotiation, which we
// never accept as a server. Otherwise |ssl3_get_message| will send
// |SSL_R_EXCESSIVE_MESSAGE_SIZE|.
if (ssl->server && ssl_protocol_version(ssl) < TLS1_3_VERSION) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
*out_alert = SSL_AD_NO_RENEGOTIATION;
return ssl_open_record_error;
}

const bool is_early_data_read = ssl->server && SSL_in_early_data(ssl);

if (rr->type == SSL3_RT_HANDSHAKE) {
// If reading 0-RTT data, reject handshake data. 0-RTT data is terminated
// by an alert.
if (is_early_data_read) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}

// Post-handshake data prior to TLS 1.3 is always renegotiation, which we
// never accept as a server. Otherwise |ssl3_get_message| will send
// |SSL_R_EXCESSIVE_MESSAGE_SIZE|.
if (ssl->server && ssl_protocol_version(ssl) < TLS1_3_VERSION) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_NO_RENEGOTIATION);
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION);
return -1;
}

if (ssl->init_buf == NULL) {
ssl->init_buf = BUF_MEM_new();
}
if (ssl->init_buf == NULL ||
!BUF_MEM_append(ssl->init_buf, rr->data, rr->length)) {
return -1;
}
*out_got_handshake = true;
rr->length = 0;
ssl_read_buffer_discard(ssl);
return -1;
if (ssl->init_buf == NULL) {
ssl->init_buf = BUF_MEM_new();
}

// Handle the end_of_early_data alert.
if (rr->type == SSL3_RT_ALERT &&
rr->length == 2 &&
rr->data[0] == SSL3_AL_WARNING &&
rr->data[1] == TLS1_AD_END_OF_EARLY_DATA &&
is_early_data_read) {
// Consume the record.
rr->length = 0;
ssl_read_buffer_discard(ssl);
// Stop accepting early data.
ssl->s3->hs->can_early_read = false;
*out_got_handshake = true;
return -1;
if (ssl->init_buf == NULL ||
!BUF_MEM_append(ssl->init_buf, body.data(), body.size())) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return ssl_open_record_error;
}
return ssl_open_record_discard;
}

if (rr->type != SSL3_RT_APPLICATION_DATA) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
}
// Handle the end_of_early_data alert.
static const uint8_t kEndOfEarlyData[2] = {SSL3_AL_WARNING,
TLS1_AD_END_OF_EARLY_DATA};
if (is_early_data_read && type == SSL3_RT_ALERT && body == kEndOfEarlyData) {
// Stop accepting early data.
ssl->s3->hs->can_early_read = false;
return ssl_open_record_discard;
}

if (is_early_data_read) {
if (rr->length > kMaxEarlyDataAccepted - ssl->s3->hs->early_data_read) {
OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MUCH_READ_EARLY_DATA);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
return -1;
}
if (type != SSL3_RT_APPLICATION_DATA) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

ssl->s3->hs->early_data_read += rr->length;
if (is_early_data_read) {
if (body.size() > kMaxEarlyDataAccepted - ssl->s3->hs->early_data_read) {
OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MUCH_READ_EARLY_DATA);
*out_alert = SSL3_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

if (rr->length != 0) {
return consume_record(ssl, buf, len, peek);
}
ssl->s3->hs->early_data_read += body.size();
}

// Discard empty records and loop again.
if (body.empty()) {
return ssl_open_record_discard;
}

*out = body;
return ssl_open_record_success;
}

int ssl3_read_change_cipher_spec(SSL *ssl) {
SSL3_RECORD *rr = &ssl->s3->rrec;
if (rr->length == 0) {
int ret = ssl3_get_record(ssl);
if (ret <= 0) {
return ret;
}
ssl_open_record_t ssl3_open_change_cipher_spec(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert,
Span<uint8_t> in) {
uint8_t type;
Span<uint8_t> body;
auto ret = tls_open_record(ssl, &type, &body, out_consumed, out_alert, in);
if (ret != ssl_open_record_success) {
return ret;
}

if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
if (type != SSL3_RT_CHANGE_CIPHER_SPEC) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
return -1;
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}

if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) {
if (body.size() != 1 || body[0] != SSL3_MT_CCS) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return ssl_open_record_error;
}

ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC,
MakeSpan(rr->data, rr->length));

rr->length = 0;
ssl_read_buffer_discard(ssl);
return 1;
ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC, body);
return ssl_open_record_success;
}

void ssl3_read_close_notify(SSL *ssl) {
// Read records until an error or close_notify.
while (ssl3_get_record(ssl) > 0) {
;
ssl_open_record_t ssl3_open_close_notify(SSL *ssl, size_t *out_consumed,
uint8_t *out_alert, Span<uint8_t> in) {
// TODO(davidben): Replace this with open_app_data so we actually process
// various bad behaviors.
uint8_t type;
Span<uint8_t> body;
auto ret = tls_open_record(ssl, &type, &body, out_consumed, out_alert, in);
if (ret == ssl_open_record_success) {
return ssl_open_record_discard;
}
return ret;
}

int ssl_send_alert(SSL *ssl, int level, int desc) {


+ 40
- 0
ssl/ssl_buffer.cc Ver ficheiro

@@ -202,6 +202,46 @@ void ssl_read_buffer_clear(SSL *ssl) {
clear_buffer(&ssl->s3->read_buffer);
}

int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret,
size_t consumed, uint8_t alert) {
*out_retry = false;
if (ret != ssl_open_record_partial) {
ssl_read_buffer_consume(ssl, consumed);
}
if (ret != ssl_open_record_success) {
// Nothing was returned to the caller, so discard anything marked consumed.
ssl_read_buffer_discard(ssl);
}
switch (ret) {
case ssl_open_record_success:
return 1;

case ssl_open_record_partial: {
int read_ret = ssl_read_buffer_extend_to(ssl, consumed);
if (read_ret <= 0) {
return read_ret;
}
*out_retry = true;
return 1;
}

case ssl_open_record_discard:
*out_retry = true;
return 1;

case ssl_open_record_close_notify:
return 0;

case ssl_open_record_error:
if (alert != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
}
return -1;
}
assert(0);
return -1;
}


int ssl_write_buffer_is_pending(const SSL *ssl) {
return ssl->s3->write_buffer.len > 0;


+ 48
- 17
ssl/ssl_lib.cc Ver ficheiro

@@ -907,7 +907,7 @@ no_renegotiation:
return 0;
}

static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
static int ssl_read_impl(SSL *ssl, void *buf, int num, bool peek) {
ssl_reset_error_state(ssl);

if (ssl->do_handshake == NULL) {
@@ -941,25 +941,48 @@ static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) {
continue; // Loop again. We may have begun a new handshake.
}

bool got_handshake = false;
int ret = ssl->method->read_app_data(ssl, &got_handshake, (uint8_t *)buf,
num, peek);
if (got_handshake) {
continue; // Loop again to process the handshake data.
}
if (ret > 0) {
if (ssl->s3->pending_app_data.empty()) {
uint8_t alert = SSL_AD_DECODE_ERROR;
size_t consumed = 0;
auto ret =
ssl->method->open_app_data(ssl, &ssl->s3->pending_app_data, &consumed,
&alert, ssl_read_buffer(ssl));
bool retry;
int bio_ret = ssl_handle_open_record(ssl, &retry, ret, consumed, alert);
if (bio_ret <= 0) {
return bio_ret;
}
if (retry) {
continue;
}
ssl->s3->key_update_count = 0;
}
return ret;

if (num <= 0) {
return num;
}

size_t todo =
std::min(ssl->s3->pending_app_data.size(), static_cast<size_t>(num));
OPENSSL_memcpy(buf, ssl->s3->pending_app_data.data(), todo);
if (!peek) {
// TODO(davidben): In DTLS, should the rest of the record be discarded?
// DTLS is not a stream. See https://crbug.com/boringssl/65.
ssl->s3->pending_app_data = ssl->s3->pending_app_data.subspan(todo);
if (ssl->s3->pending_app_data.empty()) {
ssl_read_buffer_discard(ssl);
}
}
return static_cast<int>(todo);
}
}

int SSL_read(SSL *ssl, void *buf, int num) {
return ssl_read_impl(ssl, buf, num, 0 /* consume bytes */);
return ssl_read_impl(ssl, buf, num, false /* consume bytes */);
}

int SSL_peek(SSL *ssl, void *buf, int num) {
return ssl_read_impl(ssl, buf, num, 1 /* peek */);
return ssl_read_impl(ssl, buf, num, true /* peek */);
}

int SSL_write(SSL *ssl, const void *buf, int num) {
@@ -1033,8 +1056,19 @@ int SSL_shutdown(SSL *ssl) {
return -1;
}
} else if (ssl->s3->read_shutdown != ssl_shutdown_close_notify) {
// Wait for the peer's close_notify.
ssl->method->read_close_notify(ssl);
ssl->s3->pending_app_data = Span<uint8_t>();
for (;;) {
uint8_t alert = SSL_AD_DECODE_ERROR;
size_t consumed = 0;
auto ret = ssl->method->open_close_notify(ssl, &consumed, &alert,
ssl_read_buffer(ssl));
bool retry;
int bio_ret = ssl_handle_open_record(ssl, &retry, ret, consumed, alert);
if (bio_ret <= 0) {
break;
}
assert(retry); // open_close_notify never reports success.
}
if (ssl->s3->read_shutdown != ssl_shutdown_close_notify) {
return -1;
}
@@ -1467,10 +1501,7 @@ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { }
void SSL_set_read_ahead(SSL *ssl, int yes) { }

int SSL_pending(const SSL *ssl) {
if (ssl->s3->rrec.type != SSL3_RT_APPLICATION_DATA) {
return 0;
}
return ssl->s3->rrec.length;
return static_cast<int>(ssl->s3->pending_app_data.size());
}

// Fix this so it checks all the valid key/cert options


+ 5
- 8
ssl/tls_method.cc Ver ficheiro

@@ -86,10 +86,7 @@ static void ssl3_on_handshake_complete(SSL *ssl) {

static bool ssl3_set_read_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) {
// Cipher changes are forbidden if the current epoch has leftover data.
//
// TODO(davidben): ssl->s3->rrec.length should be impossible now. Remove it
// once it is only used for application data.
if (ssl->s3->rrec.length != 0 || tls_has_unprocessed_handshake_data(ssl)) {
if (tls_has_unprocessed_handshake_data(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return false;
@@ -115,11 +112,11 @@ static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
ssl3_new,
ssl3_free,
ssl3_get_message,
ssl3_read_message,
ssl3_next_message,
ssl3_read_app_data,
ssl3_read_change_cipher_spec,
ssl3_read_close_notify,
ssl3_open_handshake,
ssl3_open_change_cipher_spec,
ssl3_open_app_data,
ssl3_open_close_notify,
ssl3_write_app_data,
ssl3_dispatch_alert,
ssl3_supports_cipher,


Carregando…
Cancelar
Guardar