unsigned short seq_num,
unsigned long frag_off,
unsigned long frag_len);
-static long dtls1_get_message_fragment(SSL *s, int st1, int stn, long max,
+static long dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt,
int *ok);
+static int dtls_get_reassembled_message(SSL *s, long *len);
static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len,
int reassembly)
unsigned char *buf = NULL;
unsigned char *bitmask = NULL;
- frag = OPENSSL_malloc(sizeof(hm_fragment));
+ frag = OPENSSL_malloc(sizeof(*frag));
if (frag == NULL)
return NULL;
/* Initialize reassembly bitmask if necessary */
if (reassembly) {
- bitmask = OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len));
+ bitmask = OPENSSL_zalloc(RSMBLY_BITMASK_SIZE(frag_len));
if (bitmask == NULL) {
OPENSSL_free(buf);
OPENSSL_free(frag);
return NULL;
}
- memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len));
}
frag->reassembly = bitmask;
if (s->write_hash) {
if (s->enc_write_ctx
- && EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE)
+ && ((EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE) ||
+ (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CCM_MODE)))
mac_size = 0;
else
mac_size = EVP_MD_CTX_size(s->write_hash);
* absence of an optional handshake message
*/
if (s->s3->tmp.reuse_message) {
- s->s3->tmp.reuse_message = 0;
if ((mt >= 0) && (s->s3->tmp.message_type != mt)) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
*ok = 1;
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+
+
+ /*
+ * Messages reused from dtls1_listen also have the record header in
+ * the buffer which we need to skip over.
+ */
+ if (s->s3->tmp.reuse_message == DTLS1_SKIP_RECORD_HEADER) {
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH
+ + DTLS1_RT_HEADER_LENGTH;
+ } else {
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+ }
s->init_num = (int)s->s3->tmp.message_size;
+ s->s3->tmp.reuse_message = 0;
return s->init_num;
}
msg_hdr = &s->d1->r_msg_hdr;
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+ memset(msg_hdr, 0, sizeof(*msg_hdr));
again:
- i = dtls1_get_message_fragment(s, st1, stn, max, ok);
+ i = dtls1_get_message_fragment(s, st1, stn, mt, ok);
if (i == DTLS1_HM_BAD_FRAGMENT || i == DTLS1_HM_FRAGMENT_RETRY) {
/* bad fragment received */
goto again;
return i;
}
+ if (mt >= 0 && s->s3->tmp.message_type != mt) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+
p = (unsigned char *)s->init_buf->data;
+
+ if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ if (s->msg_callback) {
+ s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
+ p, 1, s, s->msg_callback_arg);
+ }
+ /*
+ * This isn't a real handshake message so skip the processing below.
+ * dtls1_get_message_fragment() will never return a CCS if mt == -1,
+ * so we are ok to continue in that case.
+ */
+ return i;
+ }
+
msg_len = msg_hdr->msg_len;
/* reconstruct message header */
msg_len += DTLS1_HM_HEADER_LENGTH;
}
+ if (msg_len > (unsigned long)max) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ goto f_err;
+ }
+
ssl3_finish_mac(s, p, msg_len);
if (s->msg_callback)
s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
p, msg_len, s, s->msg_callback_arg);
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+ memset(msg_hdr, 0, sizeof(*msg_hdr));
+
+ s->d1->handshake_read_seq++;
- /* Don't change sequence numbers while listening */
- if (!s->d1->listen)
- s->d1->handshake_read_seq++;
s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
return s->init_num;
return -1;
}
-static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr,
- int max)
+int dtls_get_message(SSL *s, int *mt, unsigned long *len)
+{
+ struct hm_header_st *msg_hdr;
+ unsigned char *p;
+ unsigned long msg_len;
+ int ok;
+ long tmplen;
+
+ msg_hdr = &s->d1->r_msg_hdr;
+ memset(msg_hdr, 0, sizeof(*msg_hdr));
+
+ again:
+ ok = dtls_get_reassembled_message(s, &tmplen);
+ if (tmplen == DTLS1_HM_BAD_FRAGMENT
+ || tmplen == DTLS1_HM_FRAGMENT_RETRY) {
+ /* bad fragment received */
+ goto again;
+ } else if (tmplen <= 0 && !ok) {
+ return 0;
+ }
+
+ *mt = s->s3->tmp.message_type;
+
+ p = (unsigned char *)s->init_buf->data;
+
+ if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ if (s->msg_callback) {
+ s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
+ p, 1, s, s->msg_callback_arg);
+ }
+ /*
+ * This isn't a real handshake message so skip the processing below.
+ */
+ return 1;
+ }
+
+ msg_len = msg_hdr->msg_len;
+
+ /* reconstruct message header */
+ *(p++) = msg_hdr->type;
+ l2n3(msg_len, p);
+ s2n(msg_hdr->seq, p);
+ l2n3(0, p);
+ l2n3(msg_len, p);
+ if (s->version != DTLS1_BAD_VER) {
+ p -= DTLS1_HM_HEADER_LENGTH;
+ msg_len += DTLS1_HM_HEADER_LENGTH;
+ }
+
+ ssl3_finish_mac(s, p, msg_len);
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+ p, msg_len, s, s->msg_callback_arg);
+
+ memset(msg_hdr, 0, sizeof(*msg_hdr));
+
+ s->d1->handshake_read_seq++;
+
+
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+ *len = s->init_num;
+
+ return 1;
+}
+
+static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr)
{
size_t frag_off, frag_len, msg_len;
return SSL_AD_ILLEGAL_PARAMETER;
}
- if ((frag_off + frag_len) > (unsigned long)max) {
- SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- return SSL_AD_ILLEGAL_PARAMETER;
- }
-
if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */
/*
* msg_len is limited to 2^24, but is effectively checked against max
return 0; /* no error */
}
-static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
+static int dtls1_retrieve_buffered_fragment(SSL *s, int *ok)
{
/*-
* (0) check whether the desired fragment is available
unsigned long frag_len = frag->msg_header.frag_len;
pqueue_pop(s->d1->buffered_messages);
- al = dtls1_preprocess_fragment(s, &frag->msg_header, max);
+ al = dtls1_preprocess_fragment(s, &frag->msg_header);
if (al == 0) { /* no alert */
unsigned char *p =
unsigned char devnull[256];
while (frag_len) {
- i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
+ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
devnull,
frag_len >
sizeof(devnull) ? sizeof(devnull) :
}
/* read the body of the fragment (header has already been read */
- i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
+ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
frag->fragment + msg_hdr->frag_off,
frag_len, 0);
if ((unsigned long)i != frag_len)
unsigned char devnull[256];
while (frag_len) {
- i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
+ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
devnull,
frag_len >
sizeof(devnull) ? sizeof(devnull) :
/*
* read the body of the fragment (header has already been read
*/
- i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
+ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
frag->fragment, frag_len, 0);
if ((unsigned long)i != frag_len)
i = -1;
}
static long
-dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
+dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, int *ok)
+{
+ long len;
+
+ do {
+ *ok = dtls_get_reassembled_message(s, &len);
+ /* A CCS isn't a real handshake message, so if we get one there is no
+ * message sequence number to give us confidence that this was really
+ * intended to be at this point in the handshake sequence. Therefore we
+ * only allow this if we were explicitly looking for it (i.e. if |mt|
+ * is -1 we still don't allow it). If we get one when we're not
+ * expecting it then probably something got re-ordered or this is a
+ * retransmit. We should drop this and try again.
+ */
+ } while (*ok && mt != SSL3_MT_CHANGE_CIPHER_SPEC
+ && s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC);
+
+ if (*ok)
+ s->state = stn;
+
+ return len;
+}
+
+static int dtls_get_reassembled_message(SSL *s, long *len)
{
unsigned char wire[DTLS1_HM_HEADER_LENGTH];
- unsigned long len, frag_off, frag_len;
- int i, al;
+ unsigned long mlen, frag_off, frag_len;
+ int i, al, recvd_type;
struct hm_header_st msg_hdr;
+ int ok;
redo:
/* see if we have the required fragment already */
- if ((frag_len = dtls1_retrieve_buffered_fragment(s, max, ok)) || *ok) {
- if (*ok)
+ if ((frag_len = dtls1_retrieve_buffered_fragment(s, &ok)) || ok) {
+ if (ok)
s->init_num = frag_len;
- return frag_len;
+ *len = frag_len;
+ return ok;
}
/* read handshake message header */
- i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, wire,
+ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, wire,
DTLS1_HM_HEADER_LENGTH, 0);
if (i <= 0) { /* nbio, or an error */
s->rwstate = SSL_READING;
- *ok = 0;
- return i;
+ *len = i;
+ return 0;
}
+ if(recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+ if (wire[0] != SSL3_MT_CCS) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
+ SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ goto f_err;
+ }
+
+ memcpy(s->init_buf->data, wire, i);
+ s->init_num = i - 1;
+ s->init_msg = s->init_buf->data + 1;
+ s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
+ s->s3->tmp.message_size = i - 1;
+ *len = i - 1;
+ return 1;
+ }
+
/* Handshake fails if message header is incomplete */
if (i != DTLS1_HM_HEADER_LENGTH) {
al = SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL_R_UNEXPECTED_MESSAGE);
+ SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
/* parse the message fragment header */
dtls1_get_message_header(wire, &msg_hdr);
+ mlen = msg_hdr.msg_len;
+ frag_off = msg_hdr.frag_off;
+ frag_len = msg_hdr.frag_len;
+
+ /*
+ * We must have at least frag_len bytes left in the record to be read.
+ * Fragments must not span records.
+ */
+ if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) {
+ al = SSL3_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH);
+ goto f_err;
+ }
+
/*
* if this is a future (or stale) message it gets buffered
* (or dropped)--no further processing at this time
* While listening, we accept seq 1 (ClientHello with cookie)
* although we're still expecting seq 0 (ClientHello)
*/
- if (msg_hdr.seq != s->d1->handshake_read_seq
- && !(s->d1->listen && msg_hdr.seq == 1))
- return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
-
- len = msg_hdr.msg_len;
- frag_off = msg_hdr.frag_off;
- frag_len = msg_hdr.frag_len;
+ if (msg_hdr.seq != s->d1->handshake_read_seq) {
+ *len = dtls1_process_out_of_seq_message(s, &msg_hdr, &ok);
+ return ok;
+ }
- if (frag_len && frag_len < len)
- return dtls1_reassemble_fragment(s, &msg_hdr, ok);
+ if (frag_len && frag_len < mlen) {
+ *len = dtls1_reassemble_fragment(s, &msg_hdr, &ok);
+ return ok;
+ }
if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
wire[0] == SSL3_MT_HELLO_REQUEST) {
} else { /* Incorrectly formated Hello request */
al = SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,
+ SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
}
- if ((al = dtls1_preprocess_fragment(s, &msg_hdr, max)))
+ if ((al = dtls1_preprocess_fragment(s, &msg_hdr)))
goto f_err;
- /* XDTLS: ressurect this when restart is in place */
- s->state = stn;
-
if (frag_len > 0) {
unsigned char *p =
(unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
- i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE,
+ i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
&p[frag_off], frag_len, 0);
+
/*
- * XDTLS: fix this--message fragments cannot span multiple packets
+ * This shouldn't ever fail due to NBIO because we already checked
+ * that we have enough data in the record
*/
if (i <= 0) {
s->rwstate = SSL_READING;
- *ok = 0;
- return i;
+ *len = i;
+ return 0;
}
} else
i = 0;
*/
if (i != (int)frag_len) {
al = SSL3_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL3_AD_ILLEGAL_PARAMETER);
+ SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL3_AD_ILLEGAL_PARAMETER);
goto f_err;
}
- *ok = 1;
-
/*
* Note that s->init_num is *not* used as current offset in
* s->init_buf->data, but as a counter summing up fragments' lengths: as
* soon as they sum up to handshake packet length, we assume we have got
* all the fragments.
*/
- s->init_num = frag_len;
- return frag_len;
+ *len = s->init_num = frag_len;
+ return 1;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
s->init_num = 0;
-
- *ok = 0;
- return (-1);
+ *len = -1;
+ return 0;
}
/*-
unsigned long frag_off,
unsigned long frag_len)
{
- /* Don't change sequence numbers while listening */
- if (frag_off == 0 && !s->d1->listen) {
+ if (frag_off == 0) {
s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
s->d1->next_handshake_write_seq++;
}
void
dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
{
- memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+ memset(msg_hdr, 0, sizeof(*msg_hdr));
msg_hdr->type = *(data++);
n2l3(data, msg_hdr->msg_len);
n2l3(data, msg_hdr->frag_len);
}
-void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr)
-{
- memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
-
- ccs_hdr->type = *(data++);
-}
-
int dtls1_shutdown(SSL *s)
{
int ret;
#ifndef OPENSSL_NO_SCTP
- if (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
+ BIO *wbio;
+
+ wbio = SSL_get_wbio(s);
+ if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
!(s->shutdown & SSL_SENT_SHUTDOWN)) {
- ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
+ ret = BIO_dgram_sctp_wait_for_dry(wbio);
if (ret < 0)
return -1;