summaryrefslogtreecommitdiffstats
path: root/src/ssl/d1_pkt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl/d1_pkt.c')
-rw-r--r--src/ssl/d1_pkt.c554
1 files changed, 78 insertions, 476 deletions
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index a77ad4e..9e056ac 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -109,9 +109,9 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
-#include <stdio.h>
-#include <errno.h>
#include <assert.h>
+#include <stdio.h>
+#include <string.h>
#include <openssl/buf.h>
#include <openssl/mem.h>
@@ -119,7 +119,7 @@
#include <openssl/err.h>
#include <openssl/rand.h>
-#include "ssl_locl.h"
+#include "internal.h"
/* mod 128 saturating subtract of two 64-bit values in big-endian order */
@@ -181,152 +181,12 @@ static int satsub64be(const uint8_t *v1, const uint8_t *v2) {
}
}
-static int have_handshake_fragment(SSL *s, int type, uint8_t *buf, int len,
- int peek);
static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
-static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
- unsigned int *is_next_epoch);
-static int dtls1_buffer_record(SSL *s, record_pqueue *q,
- uint8_t *priority);
static int dtls1_process_record(SSL *s);
static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
unsigned int len);
-/* copy buffered record into SSL structure */
-static int dtls1_copy_record(SSL *s, pitem *item) {
- DTLS1_RECORD_DATA *rdata;
-
- rdata = (DTLS1_RECORD_DATA *)item->data;
-
- if (s->s3->rbuf.buf != NULL) {
- OPENSSL_free(s->s3->rbuf.buf);
- }
-
- s->packet = rdata->packet;
- s->packet_length = rdata->packet_length;
- memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
- memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
-
- /* Set proper sequence number for mac calculation */
- memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6);
-
- return 1;
-}
-
-static int dtls1_buffer_record(SSL *s, record_pqueue *queue,
- uint8_t *priority) {
- DTLS1_RECORD_DATA *rdata;
- pitem *item;
-
- /* Limit the size of the queue to prevent DOS attacks */
- if (pqueue_size(queue->q) >= 100) {
- return 0;
- }
-
- rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
- item = pitem_new(priority, rdata);
- if (rdata == NULL || item == NULL) {
- if (rdata != NULL) {
- OPENSSL_free(rdata);
- }
- if (item != NULL) {
- pitem_free(item);
- }
-
- OPENSSL_PUT_ERROR(SSL, dtls1_buffer_record, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- rdata->packet = s->packet;
- rdata->packet_length = s->packet_length;
- memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER));
- memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD));
-
- item->data = rdata;
-
- s->packet = NULL;
- s->packet_length = 0;
- memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER));
- memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD));
-
- if (!ssl3_setup_buffers(s)) {
- goto internal_error;
- }
-
- /* insert should not fail, since duplicates are dropped */
- if (pqueue_insert(queue->q, item) == NULL) {
- goto internal_error;
- }
-
- return 1;
-
-internal_error:
- OPENSSL_PUT_ERROR(SSL, dtls1_buffer_record, ERR_R_INTERNAL_ERROR);
- if (rdata->rbuf.buf != NULL) {
- OPENSSL_free(rdata->rbuf.buf);
- }
- OPENSSL_free(rdata);
- pitem_free(item);
- return -1;
-}
-
-static int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue) {
- pitem *item;
-
- item = pqueue_pop(queue->q);
- if (item) {
- dtls1_copy_record(s, item);
-
- OPENSSL_free(item->data);
- pitem_free(item);
-
- return 1;
- }
-
- return 0;
-}
-
-/* retrieve a buffered record that belongs to the new epoch, i.e., not
- * processed yet */
-#define dtls1_get_unprocessed_record(s) \
- dtls1_retrieve_buffered_record((s), &((s)->d1->unprocessed_rcds))
-
-/* retrieve a buffered record that belongs to the current epoch, i.e.,
- * processed */
-#define dtls1_get_processed_record(s) \
- dtls1_retrieve_buffered_record((s), &((s)->d1->processed_rcds))
-
-static int dtls1_process_buffered_records(SSL *s) {
- pitem *item;
-
- item = pqueue_peek(s->d1->unprocessed_rcds.q);
- if (item) {
- /* Check if epoch is current. */
- if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch) {
- return 1; /* Nothing to do. */
- }
-
- /* Process all the records. */
- while (pqueue_peek(s->d1->unprocessed_rcds.q)) {
- dtls1_get_unprocessed_record(s);
- if (!dtls1_process_record(s)) {
- return 0;
- }
- if (dtls1_buffer_record(s, &(s->d1->processed_rcds),
- s->s3->rrec.seq_num) < 0) {
- return -1;
- }
- }
- }
-
- /* sync epoch numbers once all the unprocessed records have been processed */
- s->d1->processed_rcds.epoch = s->d1->r_epoch;
- s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
-
- return 1;
-}
-
static int dtls1_process_record(SSL *s) {
int al;
SSL3_RECORD *rr;
@@ -405,28 +265,15 @@ int dtls1_get_record(SSL *s) {
SSL3_RECORD *rr;
unsigned char *p = NULL;
unsigned short version;
- DTLS1_BITMAP *bitmap;
- unsigned int is_next_epoch;
rr = &(s->s3->rrec);
- /* The epoch may have changed. If so, process all the pending records. This
- * is a non-blocking operation. */
- if (dtls1_process_buffered_records(s) < 0) {
- return -1;
- }
-
- /* If we're renegotiating, then there may be buffered records. */
- if (dtls1_get_processed_record(s)) {
- return 1;
- }
-
/* get something from the wire */
again:
/* check if we have the header */
if ((s->rstate != SSL_ST_READ_BODY) ||
(s->packet_length < DTLS1_RT_HEADER_LENGTH)) {
- n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+ n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, 0);
/* read timeout is handled by dtls1_read_bytes */
if (n <= 0) {
return n; /* error or non-blocking */
@@ -498,7 +345,7 @@ again:
if (rr->length > s->packet_length - DTLS1_RT_HEADER_LENGTH) {
/* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
i = rr->length;
- n = ssl3_read_n(s, i, i, 1);
+ n = ssl3_read_n(s, i, 1);
if (n <= 0) {
return n; /* error or non-blocking io */
}
@@ -515,16 +362,17 @@ again:
}
s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */
- /* match epochs. NULL means the packet is dropped on the floor */
- bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
- if (bitmap == NULL) {
+ if (rr->epoch != s->d1->r_epoch) {
+ /* This record is from the wrong epoch. If it is the next epoch, it could be
+ * buffered. For simplicity, drop it and expect retransmit to handle it
+ * later; DTLS is supposed to handle packet loss. */
rr->length = 0;
- s->packet_length = 0; /* dump this record */
- goto again; /* get another record */
+ s->packet_length = 0;
+ goto again;
}
/* Check whether this is a repeat, or aged record. */
- if (!dtls1_record_replay_check(s, bitmap)) {
+ if (!dtls1_record_replay_check(s, &s->d1->bitmap)) {
rr->length = 0;
s->packet_length = 0; /* dump this record */
goto again; /* get another record */
@@ -535,28 +383,12 @@ again:
goto again;
}
- /* If this record is from the next epoch (either HM or ALERT),
- * and a handshake is currently in progress, buffer it since it
- * cannot be processed at this time.
- */
- if (is_next_epoch) {
- if (SSL_in_init(s) || s->in_handshake) {
- if (dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num) < 0) {
- return -1;
- }
- dtls1_record_bitmap_update(s, bitmap); /* Mark receipt of record. */
- }
- rr->length = 0;
- s->packet_length = 0;
- goto again;
- }
-
if (!dtls1_process_record(s)) {
rr->length = 0;
s->packet_length = 0; /* dump this record */
goto again; /* get another record */
}
- dtls1_record_bitmap_update(s, bitmap); /* Mark receipt of record. */
+ dtls1_record_bitmap_update(s, &s->d1->bitmap); /* Mark receipt of record. */
return 1;
}
@@ -589,15 +421,11 @@ again:
* none of our business
*/
int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) {
- int al, i, j, ret;
+ int al, i, ret;
unsigned int n;
SSL3_RECORD *rr;
void (*cb)(const SSL *ssl, int type2, int val) = NULL;
- if (s->s3->rbuf.buf == NULL && !ssl3_setup_buffers(s)) {
- return -1;
- }
-
/* XXX: check what the second '&& type' is about */
if ((type && (type != SSL3_RT_APPLICATION_DATA) &&
(type != SSL3_RT_HANDSHAKE) && type) ||
@@ -606,14 +434,6 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) {
return -1;
}
- /* check whether there's a handshake message (client hello?) waiting */
- ret = have_handshake_fragment(s, type, buf, len, peek);
- if (ret) {
- return ret;
- }
-
- /* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
-
if (!s->in_handshake && SSL_in_init(s)) {
/* type == SSL3_RT_APPLICATION_DATA */
i = s->handshake_func(s);
@@ -635,23 +455,8 @@ start:
* s->s3->rrec.length - number of bytes. */
rr = &s->s3->rrec;
- /* We are not handshaking and have no data yet,
- * so process data buffered during the last handshake
- * in advance, if any.
- */
- if (s->state == SSL_ST_OK && rr->length == 0) {
- pitem *item;
- item = pqueue_pop(s->d1->buffered_app_data.q);
- if (item) {
- dtls1_copy_record(s, item);
-
- OPENSSL_free(item->data);
- pitem_free(item);
- }
- }
-
/* Check for timeout */
- if (dtls1_handle_timeout(s) > 0) {
+ if (DTLSv1_handle_timeout(s) > 0) {
goto start;
}
@@ -673,14 +478,11 @@ start:
/* |change_cipher_spec is set when we receive a ChangeCipherSpec and reset by
* ssl3_get_finished. */
- if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE) {
- /* We now have application data between CCS and Finished. Most likely the
- * packets were reordered on their way, so buffer the application data for
- * later processing rather than dropping the connection. */
- if (dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num) < 0) {
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR);
- return -1;
- }
+ if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE &&
+ rr->type != SSL3_RT_ALERT) {
+ /* We now have an unexpected record between CCS and Finished. Most likely
+ * the packets were reordered on their way. DTLS is unreliable, so drop the
+ * packet and expect the peer to retransmit. */
rr->length = 0;
goto start;
}
@@ -729,118 +531,25 @@ start:
return n;
}
- /* If we get here, then type != rr->type; if we have a handshake message,
- * then it was unexpected (Hello Request or Client Hello). */
-
- /* In case of record types for which we have 'fragment' storage, fill that so
- * that we can process the data at a fixed place. */
- {
- unsigned int k, dest_maxlen = 0;
- uint8_t *dest = NULL;
- unsigned int *dest_len = NULL;
-
- if (rr->type == SSL3_RT_HANDSHAKE) {
- dest_maxlen = sizeof s->d1->handshake_fragment;
- dest = s->d1->handshake_fragment;
- dest_len = &s->d1->handshake_fragment_len;
- } else if (rr->type == SSL3_RT_ALERT) {
- dest_maxlen = sizeof(s->d1->alert_fragment);
- dest = s->d1->alert_fragment;
- dest_len = &s->d1->alert_fragment_len;
- }
- /* else it's a CCS message, or application data or wrong */
- else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) {
- /* Application data while renegotiating is allowed. Try again reading. */
- if (rr->type == SSL3_RT_APPLICATION_DATA) {
- BIO *bio;
- s->s3->in_read_app_data = 2;
- bio = SSL_get_rbio(s);
- s->rwstate = SSL_READING;
- BIO_clear_retry_flags(bio);
- BIO_set_retry_read(bio);
- return -1;
- }
-
- /* Not certain if this is the right error handling */
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- }
-
- if (dest_maxlen > 0) {
- /* XDTLS: In a pathalogical case, the Client Hello
- * may be fragmented--don't always expect dest_maxlen bytes */
- if (rr->length < dest_maxlen) {
- s->rstate = SSL_ST_READ_HEADER;
- rr->length = 0;
- goto start;
- }
-
- /* now move 'n' bytes: */
- for (k = 0; k < dest_maxlen; k++) {
- dest[k] = rr->data[rr->off++];
- rr->length--;
- }
- *dest_len = dest_maxlen;
- }
- }
-
- /* s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE;
- * s->d1->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT.
- * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
-
- /* If we are a client, check for an incoming 'Hello Request': */
- if (!s->server && s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH &&
- s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST &&
- s->session != NULL && s->session->cipher != NULL) {
- s->d1->handshake_fragment_len = 0;
+ /* If we get here, then type != rr->type. */
- if ((s->d1->handshake_fragment[1] != 0) ||
- (s->d1->handshake_fragment[2] != 0) ||
- (s->d1->handshake_fragment[3] != 0)) {
+ /* If an alert record, process one alert out of the record. Note that we allow
+ * a single record to contain multiple alerts. */
+ if (rr->type == SSL3_RT_ALERT) {
+ /* Alerts may not be fragmented. */
+ if (rr->length < 2) {
al = SSL_AD_DECODE_ERROR;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_HELLO_REQUEST);
+ OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_ALERT);
goto f_err;
}
- /* no need to check sequence number on HELLO REQUEST messages */
-
- if (s->msg_callback) {
- s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
- s->d1->handshake_fragment, 4, s, s->msg_callback_arg);
- }
-
- if (SSL_is_init_finished(s) && !s->s3->renegotiate) {
- s->d1->handshake_read_seq++;
- s->new_session = 1;
- ssl3_renegotiate(s);
- if (ssl3_renegotiate_check(s)) {
- i = s->handshake_func(s);
- if (i < 0) {
- return i;
- }
- if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
- }
-
- /* we either finished a handshake or ignored the request, now try again to
- * obtain the (application) data we were asked for */
- goto start;
- }
-
- if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) {
- int alert_level = s->d1->alert_fragment[0];
- int alert_descr = s->d1->alert_fragment[1];
-
- s->d1->alert_fragment_len = 0;
-
if (s->msg_callback) {
- s->msg_callback(0, s->version, SSL3_RT_ALERT, s->d1->alert_fragment, 2, s,
+ s->msg_callback(0, s->version, SSL3_RT_ALERT, &rr->data[rr->off], 2, s,
s->msg_callback_arg);
}
+ const uint8_t alert_level = rr->data[rr->off++];
+ const uint8_t alert_descr = rr->data[rr->off++];
+ rr->length -= 2;
if (s->info_callback != NULL) {
cb = s->info_callback;
@@ -849,17 +558,17 @@ start:
}
if (cb != NULL) {
- j = (alert_level << 8) | alert_descr;
- cb(s, SSL_CB_READ_ALERT, j);
+ uint16_t alert = (alert_level << 8) | alert_descr;
+ cb(s, SSL_CB_READ_ALERT, alert);
}
- if (alert_level == 1) { /* warning */
+ 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;
}
- } else if (alert_level == 2) { /* fatal */
+ } else if (alert_level == SSL3_AL_FATAL) {
char tmp[16];
s->rwstate = SSL_NOTHING;
@@ -888,16 +597,9 @@ start:
}
if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
- struct ccs_header_st ccs_hdr;
- unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH;
-
- dtls1_get_ccs_header(rr->data, &ccs_hdr);
-
- /* 'Change Cipher Spec' is just a single byte, so we know
- * exactly what the record payload has to look like */
- /* XDTLS: check that epoch is consistent */
- if ((rr->length != ccs_hdr_len) || (rr->off != 0) ||
- (rr->data[0] != SSL3_MT_CCS)) {
+ /* 'Change Cipher Spec' is just a single byte, so we know exactly what the
+ * record payload has to look like */
+ if (rr->length != 1 || rr->off != 0 || rr->data[0] != SSL3_MT_CCS) {
al = SSL_AD_ILLEGAL_PARAMETER;
OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_CHANGE_CIPHER_SPEC);
goto f_err;
@@ -930,91 +632,41 @@ start:
goto start;
}
- /* Unexpected handshake message (Client Hello, or protocol violation) */
- if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
- !s->in_handshake) {
- struct hm_header_st msg_hdr;
-
- /* this may just be a stale retransmit */
- dtls1_get_message_header(rr->data, &msg_hdr);
- if (rr->epoch != s->d1->r_epoch) {
- rr->length = 0;
- goto start;
+ /* Unexpected handshake message. It may be a retransmitted Finished (the only
+ * post-CCS message). Otherwise, it's a pre-CCS handshake message from an
+ * unsupported renegotiation attempt. */
+ if (rr->type == SSL3_RT_HANDSHAKE && !s->in_handshake) {
+ if (rr->length < DTLS1_HM_HEADER_LENGTH) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_BAD_HANDSHAKE_RECORD);
+ goto f_err;
}
+ struct hm_header_st msg_hdr;
+ dtls1_get_message_header(&rr->data[rr->off], &msg_hdr);
- /* If we are server, we may have a repeated FINISHED of the client here,
- * then retransmit our CCS and FINISHED. */
+ /* Ignore a stray Finished from the previous handshake. */
if (msg_hdr.type == SSL3_MT_FINISHED) {
- if (dtls1_check_timeout_num(s) < 0) {
- return -1;
+ if (msg_hdr.frag_off == 0) {
+ /* Retransmit our last flight of messages. If the peer sends the second
+ * 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(s) < 0) {
+ return -1;
+ }
+
+ dtls1_retransmit_buffered_messages(s);
}
- dtls1_retransmit_buffered_messages(s);
rr->length = 0;
goto start;
}
-
- if ((s->state & SSL_ST_MASK) == SSL_ST_OK) {
- s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
- s->renegotiate = 1;
- s->new_session = 1;
- }
- i = s->handshake_func(s);
- if (i < 0) {
- return i;
- }
- if (i == 0) {
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
-
- goto start;
}
- switch (rr->type) {
- default:
- /* TLS just ignores unknown message types */
- if (s->version == TLS1_VERSION) {
- rr->length = 0;
- goto start;
- }
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
- goto f_err;
-
- case SSL3_RT_CHANGE_CIPHER_SPEC:
- case SSL3_RT_ALERT:
- case SSL3_RT_HANDSHAKE:
- /* we already handled all of these, with the possible exception of
- * SSL3_RT_HANDSHAKE when s->in_handshake is set, but that should not
- * happen when type != rr->type */
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR);
- goto f_err;
-
- case SSL3_RT_APPLICATION_DATA:
- /* At this point, we were expecting handshake data, but have application
- * data. If the library was running inside ssl3_read() (i.e.
- * in_read_app_data is set) and it makes sense to read application data
- * at this point (session renegotiation not yet started), we will indulge
- * it. */
- if (s->s3->in_read_app_data && (s->s3->total_renegotiations != 0) &&
- (((s->state & SSL_ST_CONNECT) &&
- (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
- (s->state <= SSL3_ST_CR_SRVR_HELLO_A)) ||
- ((s->state & SSL_ST_ACCEPT) &&
- (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
- (s->state >= SSL3_ST_SR_CLNT_HELLO_A)))) {
- s->s3->in_read_app_data = 2;
- return -1;
- } else {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
- goto f_err;
- }
- }
+ /* We already handled these. */
+ assert(rr->type != SSL3_RT_CHANGE_CIPHER_SPEC && rr->type != SSL3_RT_ALERT);
- /* not reached */
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_UNEXPECTED_RECORD);
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -1047,35 +699,6 @@ int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) {
return i;
}
-
-/* this only happens when a client hello is received and a handshake is
- * started. */
-static int have_handshake_fragment(SSL *s, int type, uint8_t *buf,
- int len, int peek) {
- if (type == SSL3_RT_HANDSHAKE && s->d1->handshake_fragment_len > 0) {
- /* (partially) satisfy request from storage */
- uint8_t *src = s->d1->handshake_fragment;
- uint8_t *dst = buf;
- unsigned int k, n;
-
- /* peek == 0 */
- n = 0;
- while (len > 0 && s->d1->handshake_fragment_len > 0) {
- *dst++ = *src++;
- len--;
- s->d1->handshake_fragment_len--;
- n++;
- }
- /* move any remaining fragment bytes: */
- for (k = 0; k < s->d1->handshake_fragment_len; k++) {
- s->d1->handshake_fragment[k] = *src++;
- }
- return n;
- }
-
- return 0;
-}
-
/* Call this to write data in records of type 'type' It will return <= 0 if not
* all data has been sent or non-blocking IO. */
int dtls1_write_bytes(SSL *s, int type, const void *buf, int len) {
@@ -1096,12 +719,9 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
SSL3_RECORD *wr;
SSL3_BUFFER *wb;
- /* first check if there is a SSL3_BUFFER still being written
- * out. This will happen with non blocking IO */
- if (s->s3->wbuf.left != 0) {
- assert(0); /* XDTLS: want to see if we ever get here */
- return ssl3_write_pending(s, type, buf, len);
- }
+ /* ssl3_write_pending drops the write if |BIO_write| fails in DTLS, so there
+ * is never pending data. */
+ assert(s->s3->wbuf.left == 0);
/* If we have an alert to send, lets send it */
if (s->s3->alert_dispatch) {
@@ -1119,6 +739,9 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
wr = &(s->s3->wrec);
wb = &(s->s3->wbuf);
+ if (wb->buf == NULL && !ssl3_setup_write_buffer(s)) {
+ return -1;
+ }
p = wb->buf + prefix_len;
/* write the header */
@@ -1147,19 +770,14 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
eivlen = s->aead_write_ctx->variable_nonce_len;
}
- /* lets setup the record stuff. */
- wr->data = p + eivlen; /* make room for IV in case of CBC */
- wr->length = (int)len;
- wr->input = (unsigned char *)buf;
-
- /* we now 'read' from wr->input, wr->length bytes into wr->data */
- memcpy(wr->data, wr->input, wr->length);
- wr->input = wr->data;
-
- /* this is true regardless of mac size */
+ /* Assemble the input for |s->enc_method->enc|. The input is the plaintext
+ * with |eivlen| bytes of space prepended for the explicit nonce. */
wr->input = p;
+ wr->length = eivlen + len;
+ memcpy(p + eivlen, buf, len);
+
+ /* Encrypt in-place, so the output also goes into |p|. */
wr->data = p;
- wr->length += eivlen;
if (!s->enc_method->enc(s, 1)) {
goto err;
@@ -1182,7 +800,9 @@ static int do_dtls1_write(SSL *s, int type, const uint8_t *buf,
wr->type = type; /* not needed but helps for debugging */
wr->length += DTLS1_RT_HEADER_LENGTH;
- ssl3_record_sequence_update(&(s->s3->write_sequence[0]));
+ if (!ssl3_record_sequence_update(&s->s3->write_sequence[2], 6)) {
+ goto err;
+ }
/* now let's set up wb */
wb->left = prefix_len + wr->length;
@@ -1285,23 +905,6 @@ int dtls1_dispatch_alert(SSL *s) {
return i;
}
-static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
- unsigned int *is_next_epoch) {
- *is_next_epoch = 0;
-
- /* In current epoch, accept HM, CCS, DATA, & ALERT */
- if (rr->epoch == s->d1->r_epoch) {
- return &s->d1->bitmap;
- } else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) &&
- (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
- /* Only HM and ALERT messages can be from the next epoch */
- *is_next_epoch = 1;
- return &s->d1->next_bitmap;
- }
-
- return NULL;
-}
-
void dtls1_reset_seq_numbers(SSL *s, int rw) {
uint8_t *seq;
unsigned int seq_bytes = sizeof(s->s3->read_sequence);
@@ -1309,8 +912,7 @@ void dtls1_reset_seq_numbers(SSL *s, int rw) {
if (rw & SSL3_CC_READ) {
seq = s->s3->read_sequence;
s->d1->r_epoch++;
- memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP));
- memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP));
+ memset(&s->d1->bitmap, 0, sizeof(DTLS1_BITMAP));
} else {
seq = s->s3->write_sequence;
memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence));