Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/d1_both.c')
-rw-r--r--ssl/d1_both.c308
1 files changed, 139 insertions, 169 deletions
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index ee4cbc9e..78f566e5 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -115,14 +115,12 @@
#include <assert.h>
#include <limits.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
@@ -251,12 +249,12 @@ static void dtls1_update_mtu(SSL *ssl) {
/* TODO(davidben): What is this code doing and do we need it? */
if (ssl->d1->mtu < dtls1_min_mtu() &&
!(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
- long mtu = BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+ long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
ssl->d1->mtu = (unsigned)mtu;
} else {
ssl->d1->mtu = kDefaultMTU;
- BIO_ctrl(SSL_get_wbio(ssl), BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL);
+ BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_SET_MTU, ssl->d1->mtu, NULL);
}
}
@@ -276,7 +274,7 @@ static size_t dtls1_max_record_size(SSL *ssl) {
}
ret -= overhead;
- size_t pending = BIO_wpending(SSL_get_wbio(ssl));
+ size_t pending = BIO_wpending(ssl->wbio);
if (ret <= pending) {
return 0;
}
@@ -292,28 +290,24 @@ static int dtls1_write_change_cipher_spec(SSL *ssl,
/* During the handshake, wbio is buffered to pack messages together. Flush the
* buffer if the ChangeCipherSpec would not fit in a packet. */
if (dtls1_max_record_size(ssl) == 0) {
- ssl->rwstate = SSL_WRITING;
- int ret = BIO_flush(SSL_get_wbio(ssl));
+ int ret = BIO_flush(ssl->wbio);
if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
return ret;
}
- ssl->rwstate = SSL_NOTHING;
}
static const uint8_t kChangeCipherSpec[1] = {SSL3_MT_CCS};
int ret =
- dtls1_write_bytes(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
- sizeof(kChangeCipherSpec), use_epoch);
+ dtls1_write_record(ssl, SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
+ sizeof(kChangeCipherSpec), use_epoch);
if (ret <= 0) {
return ret;
}
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(1 /* write */, ssl->version, SSL3_RT_CHANGE_CIPHER_SPEC,
- kChangeCipherSpec, sizeof(kChangeCipherSpec), ssl,
- ssl->msg_callback_arg);
- }
-
+ ssl_do_msg_callback(ssl, 1 /* write */, ssl->version,
+ SSL3_RT_CHANGE_CIPHER_SPEC, kChangeCipherSpec,
+ sizeof(kChangeCipherSpec));
return 1;
}
@@ -342,14 +336,13 @@ int dtls1_do_handshake_write(SSL *ssl, enum dtls1_use_epoch_t use_epoch) {
/* During the handshake, wbio is buffered to pack messages together. Flush
* the buffer if there isn't enough room to make progress. */
if (dtls1_max_record_size(ssl) < DTLS1_HM_HEADER_LENGTH + 1) {
- ssl->rwstate = SSL_WRITING;
- int flush_ret = BIO_flush(SSL_get_wbio(ssl));
+ int flush_ret = BIO_flush(ssl->wbio);
if (flush_ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
ret = flush_ret;
goto err;
}
- ssl->rwstate = SSL_NOTHING;
- assert(BIO_wpending(SSL_get_wbio(ssl)) == 0);
+ assert(BIO_wpending(ssl->wbio) == 0);
}
size_t todo = dtls1_max_record_size(ssl);
@@ -382,8 +375,8 @@ int dtls1_do_handshake_write(SSL *ssl, enum dtls1_use_epoch_t use_epoch) {
goto err;
}
- int write_ret = dtls1_write_bytes(ssl, SSL3_RT_HANDSHAKE, buf, len,
- use_epoch);
+ int write_ret =
+ dtls1_write_record(ssl, SSL3_RT_HANDSHAKE, buf, len, use_epoch);
if (write_ret <= 0) {
ret = write_ret;
goto err;
@@ -392,11 +385,9 @@ int dtls1_do_handshake_write(SSL *ssl, enum dtls1_use_epoch_t use_epoch) {
ssl->init_num -= todo;
} while (ssl->init_num > 0);
- if (ssl->msg_callback != NULL) {
- ssl->msg_callback(
- 1 /* write */, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
- (size_t)(ssl->init_off + ssl->init_num), ssl, ssl->msg_callback_arg);
- }
+ ssl_do_msg_callback(ssl, 1 /* write */, ssl->version, SSL3_RT_HANDSHAKE,
+ ssl->init_buf->data,
+ (size_t)(ssl->init_off + ssl->init_num));
ssl->init_off = 0;
ssl->init_num = 0;
@@ -424,24 +415,6 @@ static int dtls1_is_next_message_complete(SSL *ssl) {
frag->reassembly == NULL;
}
-/* dtls1_discard_fragment_body discards a handshake fragment body of length
- * |frag_len|. It returns one on success and zero on error.
- *
- * TODO(davidben): This function will go away when ssl_read_bytes is gone from
- * the DTLS side. */
-static int dtls1_discard_fragment_body(SSL *ssl, size_t frag_len) {
- uint8_t discard[256];
- while (frag_len > 0) {
- size_t chunk = frag_len < sizeof(discard) ? frag_len : sizeof(discard);
- int ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, discard, chunk, 0);
- if (ret != (int) chunk) {
- return 0;
- }
- frag_len -= chunk;
- }
- return 1;
-}
-
/* dtls1_get_buffered_message returns the buffered message corresponding to
* |msg_hdr|. If none exists, it creates a new one and inserts it in the
* queue. Otherwise, it checks |msg_hdr| is consistent with the existing one. It
@@ -487,93 +460,99 @@ static hm_fragment *dtls1_get_buffered_message(
return frag;
}
-/* dtls1_max_handshake_message_len returns the maximum number of bytes
- * permitted in a DTLS handshake message for |ssl|. The minimum is 16KB, but may
- * be greater if the maximum certificate list size requires it. */
-static size_t dtls1_max_handshake_message_len(const SSL *ssl) {
- size_t max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
- if (max_len < ssl->max_cert_list) {
- return ssl->max_cert_list;
- }
- return max_len;
-}
+/* dtls1_process_handshake_record reads a handshake record and processes it. It
+ * returns one if the record was successfully processed and 0 or -1 on error. */
+static int dtls1_process_handshake_record(SSL *ssl) {
+ SSL3_RECORD *rr = &ssl->s3->rrec;
-/* dtls1_process_fragment reads a handshake fragment and processes it. It
- * returns one if a fragment was successfully processed and 0 or -1 on error. */
-static int dtls1_process_fragment(SSL *ssl) {
- /* Read handshake message header. */
- uint8_t header[DTLS1_HM_HEADER_LENGTH];
- int ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, header,
- DTLS1_HM_HEADER_LENGTH, 0);
- if (ret <= 0) {
- return ret;
+start:
+ if (rr->length == 0) {
+ int ret = dtls1_get_record(ssl);
+ if (ret <= 0) {
+ return ret;
+ }
}
- if (ret != DTLS1_HM_HEADER_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
+
+ /* Cross-epoch records are discarded, but we may receive out-of-order
+ * application data between ChangeCipherSpec and Finished or a ChangeCipherSpec
+ * before the appropriate point in the handshake. Those must be silently
+ * discarded.
+ *
+ * However, only allow the out-of-order records in the correct epoch.
+ * Application data must come in the encrypted epoch, and ChangeCipherSpec in
+ * the unencrypted epoch (we never renegotiate). Other cases fall through and
+ * fail with a fatal error. */
+ if ((rr->type == SSL3_RT_APPLICATION_DATA &&
+ ssl->s3->aead_read_ctx != NULL) ||
+ (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC &&
+ ssl->s3->aead_read_ctx == NULL)) {
+ rr->length = 0;
+ goto start;
+ }
+
+ if (rr->type != SSL3_RT_HANDSHAKE) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
return -1;
}
- /* Parse the message fragment header. */
- struct hm_header_st msg_hdr;
- dtls1_get_message_header(header, &msg_hdr);
-
- /* TODO(davidben): dtls1_read_bytes is the wrong abstraction for DTLS. There
- * should be no need to reach into |ssl->s3->rrec.length|. */
- const size_t frag_off = msg_hdr.frag_off;
- const size_t frag_len = msg_hdr.frag_len;
- const size_t msg_len = msg_hdr.msg_len;
- if (frag_off > msg_len || frag_off + frag_len < frag_off ||
- frag_off + frag_len > msg_len ||
- msg_len > dtls1_max_handshake_message_len(ssl) ||
- frag_len > ssl->s3->rrec.length) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return -1;
- }
+ CBS cbs;
+ CBS_init(&cbs, rr->data, rr->length);
- if (msg_hdr.seq < ssl->d1->handshake_read_seq ||
- msg_hdr.seq > (unsigned)ssl->d1->handshake_read_seq +
- kHandshakeBufferSize) {
- /* Ignore fragments from the past, or ones too far in the future. */
- if (!dtls1_discard_fragment_body(ssl, frag_len)) {
+ 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);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
}
- return 1;
- }
- hm_fragment *frag = dtls1_get_buffered_message(ssl, &msg_hdr);
- if (frag == NULL) {
- return -1;
- }
- assert(frag->msg_header.msg_len == msg_len);
+ const size_t frag_off = msg_hdr.frag_off;
+ const size_t frag_len = msg_hdr.frag_len;
+ const size_t msg_len = msg_hdr.msg_len;
+ if (frag_off > msg_len || frag_off + frag_len < frag_off ||
+ frag_off + frag_len > msg_len ||
+ msg_len > ssl_max_handshake_message_len(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return -1;
+ }
- if (frag->reassembly == NULL) {
- /* The message is already assembled. */
- if (!dtls1_discard_fragment_body(ssl, frag_len)) {
+ if (msg_hdr.seq < ssl->d1->handshake_read_seq ||
+ msg_hdr.seq >
+ (unsigned)ssl->d1->handshake_read_seq + kHandshakeBufferSize) {
+ /* Ignore fragments from the past, or ones too far in the future. */
+ continue;
+ }
+
+ hm_fragment *frag = dtls1_get_buffered_message(ssl, &msg_hdr);
+ if (frag == NULL) {
return -1;
}
- return 1;
- }
- assert(msg_len > 0);
+ assert(frag->msg_header.msg_len == msg_len);
- /* Read the body of the fragment. */
- ret = dtls1_read_bytes(ssl, SSL3_RT_HANDSHAKE, frag->fragment + frag_off,
- frag_len, 0);
- if (ret != (int) frag_len) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return -1;
+ if (frag->reassembly == NULL) {
+ /* The message is already assembled. */
+ continue;
+ }
+ assert(msg_len > 0);
+
+ /* Copy the body into the fragment. */
+ memcpy(frag->fragment + frag_off, CBS_data(&body), CBS_len(&body));
+ dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
}
- dtls1_hm_fragment_mark(frag, frag_off, frag_off + frag_len);
+ rr->length = 0;
+ ssl_read_buffer_discard(ssl);
return 1;
}
/* dtls1_get_message reads a handshake message of message type |msg_type| (any
- * if |msg_type| == -1), maximum acceptable body length |max|. Read an entire
- * handshake message. Handshake messages arrive in fragments. */
-long dtls1_get_message(SSL *ssl, int st1, int stn, int msg_type, long max,
+ * if |msg_type| == -1). Read an entire handshake message. Handshake messages
+ * arrive in fragments. */
+long dtls1_get_message(SSL *ssl, int msg_type,
enum ssl_hash_message_t hash_message, int *ok) {
pitem *item = NULL;
hm_fragment *frag = NULL;
@@ -593,14 +572,15 @@ long dtls1_get_message(SSL *ssl, int st1, int stn, int msg_type, long max,
goto f_err;
}
*ok = 1;
+ assert(ssl->init_buf->length >= DTLS1_HM_HEADER_LENGTH);
ssl->init_msg = (uint8_t *)ssl->init_buf->data + DTLS1_HM_HEADER_LENGTH;
- ssl->init_num = (int)ssl->s3->tmp.message_size;
+ ssl->init_num = (int)ssl->init_buf->length - DTLS1_HM_HEADER_LENGTH;
return ssl->init_num;
}
- /* Process fragments until one is found. */
+ /* Process handshake records until the next message is ready. */
while (!dtls1_is_next_message_complete(ssl)) {
- int ret = dtls1_process_fragment(ssl);
+ int ret = dtls1_process_handshake_record(ssl);
if (ret <= 0) {
*ok = 0;
return ret;
@@ -614,17 +594,11 @@ long dtls1_get_message(SSL *ssl, int st1, int stn, int msg_type, long max,
assert(ssl->d1->handshake_read_seq == frag->msg_header.seq);
assert(frag->reassembly == NULL);
- if (frag->msg_header.msg_len > (size_t)max) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- goto err;
- }
-
/* Reconstruct the assembled message. */
- size_t len;
CBB cbb;
CBB_zero(&cbb);
- if (!BUF_MEM_grow(ssl->init_buf, (size_t)frag->msg_header.msg_len +
- DTLS1_HM_HEADER_LENGTH) ||
+ if (!BUF_MEM_reserve(ssl->init_buf, (size_t)frag->msg_header.msg_len +
+ DTLS1_HM_HEADER_LENGTH) ||
!CBB_init_fixed(&cbb, (uint8_t *)ssl->init_buf->data,
ssl->init_buf->max) ||
!CBB_add_u8(&cbb, frag->msg_header.type) ||
@@ -633,19 +607,19 @@ long dtls1_get_message(SSL *ssl, int st1, int stn, int msg_type, long max,
!CBB_add_u24(&cbb, 0 /* frag_off */) ||
!CBB_add_u24(&cbb, frag->msg_header.msg_len) ||
!CBB_add_bytes(&cbb, frag->fragment, frag->msg_header.msg_len) ||
- !CBB_finish(&cbb, NULL, &len)) {
+ !CBB_finish(&cbb, NULL, &ssl->init_buf->length)) {
CBB_cleanup(&cbb);
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- assert(len == (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH);
+ assert(ssl->init_buf->length ==
+ (size_t)frag->msg_header.msg_len + DTLS1_HM_HEADER_LENGTH);
ssl->d1->handshake_read_seq++;
/* TODO(davidben): This function has a lot of implicit outputs. Simplify the
* |ssl_get_message| API. */
ssl->s3->tmp.message_type = frag->msg_header.type;
- ssl->s3->tmp.message_size = frag->msg_header.msg_len;
ssl->init_msg = (uint8_t *)ssl->init_buf->data + DTLS1_HM_HEADER_LENGTH;
ssl->init_num = frag->msg_header.msg_len;
@@ -657,16 +631,14 @@ long dtls1_get_message(SSL *ssl, int st1, int stn, int msg_type, long max,
if (hash_message == ssl_hash_message && !ssl3_hash_current_message(ssl)) {
goto err;
}
- if (ssl->msg_callback) {
- ssl->msg_callback(0, ssl->version, SSL3_RT_HANDSHAKE, ssl->init_buf->data,
- ssl->init_num + DTLS1_HM_HEADER_LENGTH, ssl,
- ssl->msg_callback_arg);
- }
+
+ ssl_do_msg_callback(ssl, 0 /* read */, ssl->version, SSL3_RT_HANDSHAKE,
+ ssl->init_buf->data,
+ ssl->init_num + DTLS1_HM_HEADER_LENGTH);
pitem_free(item);
dtls1_hm_fragment_free(frag);
- ssl->state = stn;
*ok = 1;
return ssl->init_num;
@@ -679,27 +651,6 @@ err:
return -1;
}
-int dtls1_read_failed(SSL *ssl, int code) {
- if (code > 0) {
- assert(0);
- return 1;
- }
-
- if (!dtls1_is_timer_expired(ssl)) {
- /* not a timeout, none of our business, let higher layers handle this. In
- * fact, it's probably an error */
- return code;
- }
-
- if (!SSL_in_init(ssl)) {
- /* done, no need to send a retransmit */
- BIO_set_flags(SSL_get_rbio(ssl), BIO_FLAGS_READ);
- return code;
- }
-
- return DTLSv1_handle_timeout(ssl);
-}
-
static uint16_t dtls1_get_queue_priority(uint16_t seq, int is_ccs) {
assert(seq * 2 >= seq);
@@ -741,25 +692,39 @@ static int dtls1_retransmit_message(SSL *ssl, hm_fragment *frag) {
ret = dtls1_do_handshake_write(ssl, use_epoch);
}
- /* TODO(davidben): Check return value? */
- (void)BIO_flush(SSL_get_wbio(ssl));
return ret;
}
-
int dtls1_retransmit_buffered_messages(SSL *ssl) {
- pqueue sent = ssl->d1->sent_messages;
- piterator iter = pqueue_iterator(sent);
- pitem *item;
+ /* Ensure we are packing handshake messages. */
+ const int was_buffered = ssl_is_wbio_buffered(ssl);
+ assert(was_buffered == SSL_in_init(ssl));
+ if (!was_buffered && !ssl_init_wbio_buffer(ssl)) {
+ return -1;
+ }
+ assert(ssl_is_wbio_buffered(ssl));
+ int ret = -1;
+ piterator iter = pqueue_iterator(ssl->d1->sent_messages);
+ pitem *item;
for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) {
hm_fragment *frag = (hm_fragment *)item->data;
if (dtls1_retransmit_message(ssl, frag) <= 0) {
- return -1;
+ goto err;
}
}
- return 1;
+ ret = BIO_flush(ssl->wbio);
+ if (ret <= 0) {
+ ssl->rwstate = SSL_WRITING;
+ goto err;
+ }
+
+err:
+ if (!was_buffered) {
+ ssl_free_wbio_buffer(ssl);
+ }
+ return ret;
}
/* dtls1_buffer_change_cipher_spec adds a ChangeCipherSpec to the current
@@ -869,13 +834,18 @@ unsigned int dtls1_min_mtu(void) {
return kMinMTU;
}
-void dtls1_get_message_header(uint8_t *data,
- struct hm_header_st *msg_hdr) {
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
- msg_hdr->type = *(data++);
- n2l3(data, msg_hdr->msg_len);
+int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
+ CBS *out_body) {
+ memset(out_hdr, 0x00, sizeof(struct hm_header_st));
- n2s(data, msg_hdr->seq);
- n2l3(data, msg_hdr->frag_off);
- n2l3(data, msg_hdr->frag_len);
+ if (!CBS_get_u8(cbs, &out_hdr->type) ||
+ !CBS_get_u24(cbs, &out_hdr->msg_len) ||
+ !CBS_get_u16(cbs, &out_hdr->seq) ||
+ !CBS_get_u24(cbs, &out_hdr->frag_off) ||
+ !CBS_get_u24(cbs, &out_hdr->frag_len) ||
+ !CBS_get_bytes(cbs, out_body, out_hdr->frag_len)) {
+ return 0;
+ }
+
+ return 1;
}