aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/openssl/ssl.h5
-rw-r--r--ssl/d1_both.c15
-rw-r--r--ssl/d1_lib.c385
-rw-r--r--ssl/d1_srvr.c44
-rw-r--r--ssl/record/rec_layer_d1.c6
-rw-r--r--ssl/record/record.h5
-rw-r--r--ssl/ssl_err.c6
-rw-r--r--ssl/ssl_locl.h9
8 files changed, 449 insertions, 26 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 1334eb6161..192640e1db 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1913,6 +1913,7 @@ void ERR_load_SSL_strings(void);
# define SSL_F_DTLS1_GET_RECORD 254
# define SSL_F_DTLS1_HANDLE_TIMEOUT 297
# define SSL_F_DTLS1_HEARTBEAT 305
+# define SSL_F_DTLS1_LISTEN 350
# define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255
# define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288
# define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256
@@ -2166,6 +2167,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307
# define SSL_R_COMPRESSION_LIBRARY_ERROR 142
# define SSL_R_CONNECTION_TYPE_NOT_SET 144
+# define SSL_R_COOKIE_GEN_CALLBACK_FAILURE 400
# define SSL_R_COOKIE_MISMATCH 308
# define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145
# define SSL_R_DATA_LENGTH_TOO_LONG 146
@@ -2189,6 +2191,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151
# define SSL_R_EXCESSIVE_MESSAGE_SIZE 152
# define SSL_R_EXTRA_DATA_IN_MESSAGE 153
+# define SSL_R_FRAGMENTED_CLIENT_HELLO 401
# define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154
# define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 355
# define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 356
@@ -2201,6 +2204,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_INVALID_COMPRESSION_ALGORITHM 341
# define SSL_R_INVALID_NULL_CMD_NAME 385
# define SSL_R_INVALID_PURPOSE 278
+# define SSL_R_INVALID_SEQUENCE_NUMBER 402
# define SSL_R_INVALID_SERVERINFO_DATA 388
# define SSL_R_INVALID_SRP_USERNAME 357
# define SSL_R_INVALID_STATUS_RESPONSE 328
@@ -2250,6 +2254,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_NO_SHARED_SIGATURE_ALGORITHMS 376
# define SSL_R_NO_SRTP_PROFILES 359
# define SSL_R_NO_VERIFY_CALLBACK 194
+# define SSL_R_NO_VERIFY_COOKIE_CALLBACK 403
# define SSL_R_NULL_SSL_CTX 195
# define SSL_R_NULL_SSL_METHOD_PASSED 196
# define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 52b7304af2..a69622aea5 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -454,15 +454,26 @@ long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
* 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;
}
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index d3b582a98c..8a8ced8abb 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -499,23 +499,394 @@ static void get_current_time(struct timeval *t)
#endif
}
+
+#define LISTEN_SUCCESS 2
+#define LISTEN_SEND_VERIFY_REQUEST 1
+
+
int dtls1_listen(SSL *s, struct sockaddr *client)
{
- int ret;
+ int next, n, ret = 0, clearpkt = 0;
+ unsigned char cookie[DTLS1_COOKIE_LENGTH];
+ unsigned char seq[SEQ_NUM_SIZE];
+ unsigned char *data, *p, *buf;
+ unsigned long reclen, fragoff, fraglen, msglen;
+ unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
+ BIO *rbio, *wbio;
+ BUF_MEM *bufm;
+ struct sockaddr_storage tmpclient;
+ PACKET pkt, msgpkt, msgpayload, session, cookiepkt;
/* Ensure there is no state left over from a previous invocation */
if (!SSL_clear(s))
return -1;
+ ERR_clear_error();
+
+ rbio = SSL_get_rbio(s);
+ wbio = SSL_get_wbio(s);
+
+ if(!rbio || !wbio) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+
+ /*
+ * We only peek at incoming ClientHello's until we're sure we are going to
+ * to respond with a HelloVerifyRequest. If its a ClientHello with a valid
+ * cookie then we leave it in the BIO for dtls1_accept to handle.
+ */
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);
+
+ /*
+ * Note: This check deliberately excludes DTLS1_BAD_VER because that version
+ * requires the MAC to be calculated *including* the first ClientHello
+ * (without the cookie). Since DTLSv1_listen is stateless that cannot be
+ * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via
+ * SSL_accept)
+ */
+ if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNSUPPORTED_SSL_VERSION);
+ return -1;
+ }
+
+ if (s->init_buf == NULL) {
+ if ((bufm = BUF_MEM_new()) == NULL) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+
+ if (!BUF_MEM_grow(bufm, SSL3_RT_MAX_PLAIN_LENGTH)) {
+ BUF_MEM_free(bufm);
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->init_buf = bufm;
+ }
+ buf = (unsigned char *)s->init_buf->data;
+
+ do {
+ /* Get a packet */
+
+ clear_sys_error();
+ /*
+ * Technically a ClientHello could be SSL3_RT_MAX_PLAIN_LENGTH
+ * + DTLS1_RT_HEADER_LENGTH bytes long. Normally init_buf does not store
+ * the record header as well, but we do here. We've set up init_buf to
+ * be the standard size for simplicity. In practice we shouldn't ever
+ * receive a ClientHello as long as this. If we do it will get dropped
+ * in the record length check below.
+ */
+ n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
+
+ if (n <= 0) {
+ if(BIO_should_retry(rbio)) {
+ /* Non-blocking IO */
+ goto end;
+ }
+ return -1;
+ }
+
+ /* If we hit any problems we need to clear this packet from the BIO */
+ clearpkt = 1;
+
+ if (!PACKET_buf_init(&pkt, buf, n)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /*
+ * Parse the received record. If there are any problems with it we just
+ * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is
+ * resilient in the face of invalid records (e.g., invalid formatting,
+ * length, MAC, etc.). In general, invalid records SHOULD be silently
+ * discarded, thus preserving the association; however, an error MAY be
+ * logged for diagnostic purposes."
+ */
+
+ /* this packet contained a partial record, dump it */
+ if (n < DTLS1_RT_HEADER_LENGTH) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_RECORD_TOO_SMALL);
+ goto end;
+ }
+
+ if (s->msg_callback)
+ s->msg_callback(0, 0, SSL3_RT_HEADER, buf,
+ DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+ /* Get the record header */
+ if (!PACKET_get_1(&pkt, &rectype)
+ || !PACKET_get_1(&pkt, &versmajor)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ if (rectype != SSL3_RT_HANDSHAKE) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+ goto end;
+ }
+
+ /*
+ * Check record version number. We only check that the major version is
+ * the same.
+ */
+ if (versmajor != DTLS1_VERSION_MAJOR) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
+ goto end;
+ }
+
+ if (!PACKET_forward(&pkt, 1)
+ /* Save the sequence number: 64 bits, with top 2 bytes = epoch */
+ || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE)
+ || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)
+ || PACKET_remaining(&pkt) != 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ /* This is an initial ClientHello so the epoch has to be 0 */
+ if (seq[0] != 0 || seq[1] != 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+ goto end;
+ }
+
+ /* Get a pointer to the raw message for the later callback */
+ data = PACKET_data(&msgpkt);
+
+ /* Finished processing the record header, now process the message */
+ if (!PACKET_get_1(&msgpkt, &msgtype)
+ || !PACKET_get_net_3(&msgpkt, &msglen)
+ || !PACKET_get_net_2(&msgpkt, &msgseq)
+ || !PACKET_get_net_3(&msgpkt, &fragoff)
+ || !PACKET_get_net_3(&msgpkt, &fraglen)
+ || !PACKET_get_sub_packet(&msgpkt, &msgpayload, msglen)
+ || PACKET_remaining(&msgpkt) != 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ if (msgtype != SSL3_MT_CLIENT_HELLO) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+ goto end;
+ }
+
+ /* Message sequence number can only be 0 or 1 */
+ if(msgseq > 2) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER);
+ goto end;
+ }
+
+ /* We don't support a fragmented ClientHello whilst listening */
+ if (fragoff != 0 || fraglen != msglen) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO);
+ goto end;
+ }
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data,
+ msglen + DTLS1_HM_HEADER_LENGTH, s,
+ s->msg_callback_arg);
+
+ if (!PACKET_get_net_2(&msgpayload, &clientvers)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ /*
+ * Verify client version is supported
+ */
+ if ((clientvers > (unsigned int)s->method->version &&
+ s->method->version != DTLS_ANY_VERSION)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_WRONG_VERSION_NUMBER);
+ goto end;
+ }
+
+ if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE)
+ || !PACKET_get_length_prefixed_1(&msgpayload, &session)
+ || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ /*
+ * Check if we have a cookie or not. If not we need to send a
+ * HelloVerifyRequest.
+ */
+ if (PACKET_remaining(&cookiepkt) == 0) {
+ next = LISTEN_SEND_VERIFY_REQUEST;
+ } else {
+ /*
+ * We have a cookie, so lets check it.
+ */
+ if (s->ctx->app_verify_cookie_cb == NULL) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_NO_VERIFY_COOKIE_CALLBACK);
+ /* This is fatal */
+ return -1;
+ }
+ if (PACKET_remaining(&cookiepkt) > sizeof(s->d1->rcvd_cookie)
+ || s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt),
+ PACKET_remaining(&cookiepkt)) == 0) {
+ /*
+ * We treat invalid cookies in the same was as no cookie as
+ * per RFC6347
+ */
+ next = LISTEN_SEND_VERIFY_REQUEST;
+ } else {
+ /* Cookie verification succeeded */
+ next = LISTEN_SUCCESS;
+ }
+ }
+
+ if (next == LISTEN_SEND_VERIFY_REQUEST) {
+ /*
+ * There was no cookie in the ClientHello so we need to send a
+ * HelloVerifyRequest. If this fails we do not worry about trying
+ * to resend, we just drop it.
+ */
+
+ /*
+ * Dump the read packet, we don't need it any more. Ignore return
+ * value
+ */
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
+ BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);
+
+ /* Generate the cookie */
+ if (s->ctx->app_gen_cookie_cb == NULL ||
+ s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+ /* This is fatal */
+ return -1;
+ }
+
+ p = &buf[DTLS1_RT_HEADER_LENGTH];
+ msglen = dtls1_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
+ cookie, cookielen);
+
+ *p++ = DTLS1_MT_HELLO_VERIFY_REQUEST;
+
+ /* Message length */
+ l2n3(msglen, p);
+
+ /* Message sequence number is always 0 for a HelloVerifyRequest */
+ s2n(0, p);
+
+ /*
+ * We never fragment a HelloVerifyRequest, so fragment offset is 0
+ * and fragment length is message length
+ */
+ l2n3(0, p);
+ l2n3(msglen, p);
+
+ /* Set reclen equal to length of whole handshake message */
+ reclen = msglen + DTLS1_HM_HEADER_LENGTH;
+
+ /* Add the record header */
+ p = buf;
+
+ *(p++) = SSL3_RT_HANDSHAKE;
+ /*
+ * Special case: for hello verify request, client version 1.0 and we
+ * haven't decided which version to use yet send back using version
+ * 1.0 header: otherwise some clients will ignore it.
+ */
+ if (s->method->version == DTLS_ANY_VERSION) {
+ *(p++) = DTLS1_VERSION >> 8;
+ *(p++) = DTLS1_VERSION & 0xff;
+ } else {
+ *(p++) = s->version >> 8;
+ *(p++) = s->version & 0xff;
+ }
+
+ /*
+ * Record sequence number is always the same as in the received
+ * ClientHello
+ */
+ memcpy(p, seq, SEQ_NUM_SIZE);
+ p += SEQ_NUM_SIZE;
+
+ /* Length */
+ s2n(reclen, p);
+
+ /*
+ * Set reclen equal to length of whole record including record
+ * header
+ */
+ reclen += DTLS1_RT_HEADER_LENGTH;
+
+ if (s->msg_callback)
+ s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
+ DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+ /*
+ * This is unneccessary if rbio and wbio are one and the same - but
+ * maybe they're not.
+ */
+ if(BIO_dgram_get_peer(rbio, &tmpclient) <= 0
+ || BIO_dgram_set_peer(wbio, &tmpclient) <= 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
+ goto end;
+ }
+
+ if (BIO_write(wbio, buf, reclen) < (int)reclen) {
+ if(BIO_should_retry(wbio)) {
+ /*
+ * Non-blocking IO...but we're stateless, so we're just
+ * going to drop this packet.
+ */
+ goto end;
+ }
+ return -1;
+ }
+
+ if (BIO_flush(wbio) <= 0) {
+ if(BIO_should_retry(wbio)) {
+ /*
+ * Non-blocking IO...but we're stateless, so we're just
+ * going to drop this packet.
+ */
+ goto end;
+ }
+ return -1;
+ }
+ }
+ } while (next != LISTEN_SUCCESS);
+
+ /*
+ * Set expected sequence numbers to continue the handshake.
+ */
+ s->d1->handshake_read_seq = 1;
+ s->d1->handshake_write_seq = 1;
+ s->d1->next_handshake_write_seq = 1;
+ DTLS_RECORD_LAYER_set_write_sequence(&s->rlayer, seq);
+
+ /*
+ * We are doing cookie exchange, so make sure we set that option in the
+ * SSL object
+ */
SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
- s->d1->listen = 1;
- ret = SSL_accept(s);
- if (ret <= 0)
- return ret;
+ /*
+ * Put us into the "init" state so that dtls1_accept doesn't clear our
+ * state
+ */
+ s->state = SSL_ST_ACCEPT;
+
+ if(BIO_dgram_get_peer(rbio, client) <= 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
- (void)BIO_dgram_get_peer(SSL_get_rbio(s), client);
- return 1;
+ ret = 1;
+ clearpkt = 0;
+end:
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
+ if (clearpkt) {
+ /* Dump this packet. Ignore return value */
+ BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
+ }
+ return ret;
}
static int dtls1_set_handshake_header(SSL *s, int htype, unsigned long len)
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index f56bf5adef..3d3d3f751f 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -883,19 +883,35 @@ int dtls1_accept(SSL *s)
return (ret);
}
-int dtls1_send_hello_verify_request(SSL *s)
+unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
+ unsigned char *cookie,
+ unsigned char cookie_len)
{
unsigned int msg_len;
- unsigned char *msg, *buf, *p;
+ unsigned char *p;
+
+ p = buf;
+ /* Always use DTLS 1.0 version: see RFC 6347 */
+ *(p++) = DTLS1_VERSION >> 8;
+ *(p++) = DTLS1_VERSION & 0xFF;
+
+ *(p++) = (unsigned char)cookie_len;
+ memcpy(p, cookie, cookie_len);
+ p += cookie_len;
+ msg_len = p - buf;
+
+ return msg_len;
+}
+
+
+int dtls1_send_hello_verify_request(SSL *s)
+{
+ unsigned int len;
+ unsigned char *buf;
if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A) {
buf = (unsigned char *)s->init_buf->data;
- msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
- /* Always use DTLS 1.0 version: see RFC 6347 */
- *(p++) = DTLS1_VERSION >> 8;
- *(p++) = DTLS1_VERSION & 0xFF;
-
if (s->ctx->app_gen_cookie_cb == NULL ||
s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
&(s->d1->cookie_len)) == 0) {
@@ -905,18 +921,16 @@ int dtls1_send_hello_verify_request(SSL *s)
return 0;
}
- *(p++) = (unsigned char)s->d1->cookie_len;
- memcpy(p, s->d1->cookie, s->d1->cookie_len);
- p += s->d1->cookie_len;
- msg_len = p - msg;
+ len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
+ s->d1->cookie, s->d1->cookie_len);
- dtls1_set_message_header(s, buf,
- DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0,
- msg_len);
+ dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
+ len);
+ len += DTLS1_HM_HEADER_LENGTH;
s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
/* number of bytes to write */
- s->init_num = p - buf;
+ s->init_num = len;
s->init_off = 0;
}
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index 74796bed6f..b5548e626a 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -226,6 +226,12 @@ void DTLS_RECORD_LAYER_resync_write(RECORD_LAYER *rl)
memcpy(rl->write_sequence, rl->read_sequence, sizeof(rl->write_sequence));
}
+
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq)
+{
+ memcpy(rl->write_sequence, seq, SEQ_NUM_SIZE);
+}
+
static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
int len, int peek);
diff --git a/ssl/record/record.h b/ssl/record/record.h
index 5c8fead869..96370710c4 100644
--- a/ssl/record/record.h
+++ b/ssl/record/record.h
@@ -288,8 +288,8 @@ typedef struct record_layer_st {
int wpend_ret;
const unsigned char *wpend_buf;
- unsigned char read_sequence[8];
- unsigned char write_sequence[8];
+ unsigned char read_sequence[SEQ_NUM_SIZE];
+ unsigned char write_sequence[SEQ_NUM_SIZE];
DTLS_RECORD_LAYER *d;
} RECORD_LAYER;
@@ -346,6 +346,7 @@ void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_set_saved_w_epoch(RECORD_LAYER *rl, unsigned short e);
void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_resync_write(RECORD_LAYER *rl);
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq);
__owur int dtls1_read_bytes(SSL *s, int type, int *recvd_type,
unsigned char *buf, int len, int peek);
__owur int dtls1_write_bytes(SSL *s, int type, const void *buf, int len);
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 21836d831d..447bac6937 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -87,6 +87,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_DTLS1_GET_RECORD), "dtls1_get_record"},
{ERR_FUNC(SSL_F_DTLS1_HANDLE_TIMEOUT), "dtls1_handle_timeout"},
{ERR_FUNC(SSL_F_DTLS1_HEARTBEAT), "dtls1_heartbeat"},
+ {ERR_FUNC(SSL_F_DTLS1_LISTEN), "DTLS1_LISTEN"},
{ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN), "dtls1_output_cert_chain"},
{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "DTLS1_PREPROCESS_FRAGMENT"},
{ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE),
@@ -406,6 +407,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"compression id not within private range"},
{ERR_REASON(SSL_R_COMPRESSION_LIBRARY_ERROR), "compression library error"},
{ERR_REASON(SSL_R_CONNECTION_TYPE_NOT_SET), "connection type not set"},
+ {ERR_REASON(SSL_R_COOKIE_GEN_CALLBACK_FAILURE),
+ "cookie gen callback failure"},
{ERR_REASON(SSL_R_COOKIE_MISMATCH), "cookie mismatch"},
{ERR_REASON(SSL_R_DATA_BETWEEN_CCS_AND_FINISHED),
"data between ccs and finished"},
@@ -440,6 +443,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"error in received cipher list"},
{ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE), "excessive message size"},
{ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE), "extra data in message"},
+ {ERR_REASON(SSL_R_FRAGMENTED_CLIENT_HELLO), "fragmented client hello"},
{ERR_REASON(SSL_R_GOT_A_FIN_BEFORE_A_CCS), "got a fin before a ccs"},
{ERR_REASON(SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS),
"got next proto before a ccs"},
@@ -455,6 +459,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"invalid compression algorithm"},
{ERR_REASON(SSL_R_INVALID_NULL_CMD_NAME), "invalid null cmd name"},
{ERR_REASON(SSL_R_INVALID_PURPOSE), "invalid purpose"},
+ {ERR_REASON(SSL_R_INVALID_SEQUENCE_NUMBER), "invalid sequence number"},
{ERR_REASON(SSL_R_INVALID_SERVERINFO_DATA), "invalid serverinfo data"},
{ERR_REASON(SSL_R_INVALID_SRP_USERNAME), "invalid srp username"},
{ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE), "invalid status response"},
@@ -510,6 +515,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"no shared sigature algorithms"},
{ERR_REASON(SSL_R_NO_SRTP_PROFILES), "no srtp profiles"},
{ERR_REASON(SSL_R_NO_VERIFY_CALLBACK), "no verify callback"},
+ {ERR_REASON(SSL_R_NO_VERIFY_COOKIE_CALLBACK), "no verify cookie callback"},
{ERR_REASON(SSL_R_NULL_SSL_CTX), "null ssl ctx"},
{ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED), "null ssl method passed"},
{ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 32e6338adc..84b7458a56 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1376,6 +1376,12 @@ typedef struct ssl3_state_st {
/* Max MTU overhead we know about so far is 40 for IPv6 + 8 for UDP */
# define DTLS1_MAX_MTU_OVERHEAD 48
+/*
+ * Flag used in message reuse to indicate the buffer contains the record
+ * header as well as the the handshake message header.
+ */
+# define DTLS1_SKIP_RECORD_HEADER 2
+
struct dtls1_retransmit_state {
EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
EVP_MD_CTX *write_hash; /* used for mac generation */
@@ -1990,6 +1996,9 @@ void dtls1_start_timer(SSL *s);
void dtls1_stop_timer(SSL *s);
__owur int dtls1_is_timer_expired(SSL *s);
void dtls1_double_timeout(SSL *s);
+__owur unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
+ unsigned char *cookie,
+ unsigned char cookie_len);
__owur int dtls1_send_newsession_ticket(SSL *s);
__owur unsigned int dtls1_min_mtu(SSL *s);
__owur unsigned int dtls1_link_min_mtu(void);