X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Frecord%2Frec_layer_d1.c;h=5e7aa6345afe4512ba94c8969850cc8d7f53c839;hp=eabbddb61d8ec66046b83be046f94e629ff1ae8c;hb=0e97f1e1a7f43be3a5e5c6256fe6bcb90caf9e01;hpb=cf2cede4a75f5e269f791bf1dcc029bba8c1f689 diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c index eabbddb61d..5e7aa6345a 100644 --- a/ssl/record/rec_layer_d1.c +++ b/ssl/record/rec_layer_d1.c @@ -1,135 +1,28 @@ -/* ssl/record/rec_layer_d1.c */ /* - * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. - */ -/* ==================================================================== - * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). + * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved. * - */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ #include #include -#define USE_SOCKETS #include "../ssl_locl.h" #include #include -#include #include "record_locl.h" +#include "../packet_locl.h" +#include "internal/cryptlib.h" int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl) { DTLS_RECORD_LAYER *d; - + if ((d = OPENSSL_malloc(sizeof(*d))) == NULL) return (0); - rl->d = d; d->unprocessed_rcds.q = pqueue_new(); @@ -169,7 +62,7 @@ void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl) pqueue *buffered_app_data; d = rl->d; - + while ((item = pqueue_pop(d->unprocessed_rcds.q)) != NULL) { rdata = (DTLS1_RECORD_DATA *)item->data; OPENSSL_free(rdata->rbuf.buf); @@ -204,36 +97,23 @@ void DTLS_RECORD_LAYER_set_saved_w_epoch(RECORD_LAYER *rl, unsigned short e) { if (e == rl->d->w_epoch - 1) { memcpy(rl->d->curr_write_sequence, - rl->write_sequence, - sizeof(rl->write_sequence)); + rl->write_sequence, sizeof(rl->write_sequence)); memcpy(rl->write_sequence, - rl->d->last_write_sequence, - sizeof(rl->write_sequence)); + rl->d->last_write_sequence, sizeof(rl->write_sequence)); } else if (e == rl->d->w_epoch + 1) { memcpy(rl->d->last_write_sequence, - rl->write_sequence, - sizeof(unsigned char[8])); + rl->write_sequence, sizeof(unsigned char[8])); memcpy(rl->write_sequence, - rl->d->curr_write_sequence, - sizeof(rl->write_sequence)); + rl->d->curr_write_sequence, sizeof(rl->write_sequence)); } rl->d->w_epoch = e; } -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); - /* copy buffered record into SSL structure */ static int dtls1_copy_record(SSL *s, pitem *item) { @@ -339,25 +219,73 @@ int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue) dtls1_retrieve_buffered_record((s), \ &((s)->rlayer.d->unprocessed_rcds)) - int dtls1_process_buffered_records(SSL *s) { pitem *item; + SSL3_BUFFER *rb; + SSL3_RECORD *rr; + DTLS1_BITMAP *bitmap; + unsigned int is_next_epoch; + int replayok = 1; item = pqueue_peek(s->rlayer.d->unprocessed_rcds.q); if (item) { /* Check if epoch is current. */ if (s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch) - return (1); /* Nothing to do. */ + return 1; /* Nothing to do. */ + + rr = RECORD_LAYER_get_rrec(&s->rlayer); + + rb = RECORD_LAYER_get_rbuf(&s->rlayer); + + if (SSL3_BUFFER_get_left(rb) > 0) { + /* + * We've still got data from the current packet to read. There could + * be a record from the new epoch in it - so don't overwrite it + * with the unprocessed records yet (we'll do it when we've + * finished reading the current packet). + */ + return 1; + } /* Process all the records. */ while (pqueue_peek(s->rlayer.d->unprocessed_rcds.q)) { dtls1_get_unprocessed_record(s); - if (!dtls1_process_record(s)) - return (0); + bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); + if (bitmap == NULL) { + /* + * Should not happen. This will only ever be NULL when the + * current record is from a different epoch. But that cannot + * be the case because we already checked the epoch above + */ + SSLerr(SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS, + ERR_R_INTERNAL_ERROR); + return 0; + } +#ifndef OPENSSL_NO_SCTP + /* Only do replay check if no SCTP bio */ + if (!BIO_dgram_is_sctp(SSL_get_rbio(s))) +#endif + { + /* + * Check whether this is a repeat, or aged record. We did this + * check once already when we first received the record - but + * we might have updated the window since then due to + * records we subsequently processed. + */ + replayok = dtls1_record_replay_check(s, bitmap); + } + + if (!replayok || !dtls1_process_record(s, bitmap)) { + /* dump this record */ + rr->length = 0; + RECORD_LAYER_reset_packet_length(&s->rlayer); + continue; + } + if (dtls1_buffer_record(s, &(s->rlayer.d->processed_rcds), - SSL3_RECORD_get_seq_num(&s->rlayer.rrec)) < 0) - return -1; + SSL3_RECORD_get_seq_num(s->rlayer.rrec)) < 0) + return 0; } } @@ -368,10 +296,9 @@ int dtls1_process_buffered_records(SSL *s) s->rlayer.d->processed_rcds.epoch = s->rlayer.d->r_epoch; s->rlayer.d->unprocessed_rcds.epoch = s->rlayer.d->r_epoch + 1; - return (1); + return 1; } - /*- * Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: @@ -402,10 +329,10 @@ int dtls1_process_buffered_records(SSL *s) * none of our business */ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, - int len, int peek) + size_t len, int peek, size_t *readbytes) { - int al, i, j, ret; - unsigned int n; + int al, i, j, iret; + size_t n; SSL3_RECORD *rr; void (*cb) (const SSL *ssl, int type2, int val) = NULL; @@ -422,37 +349,15 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, return -1; } - /* - * check whether there's a handshake message (client hello?) waiting - */ - if ((ret = have_handshake_fragment(s, type, buf, len, peek))) - return ret; - - /* - * Now s->rlayer.d->handshake_fragment_len == 0 if - * type == SSL3_RT_HANDSHAKE. - */ - -#ifndef OPENSSL_NO_SCTP - /* - * Continue handshake if it had to be interrupted to read app data with - * SCTP. - */ - if ((!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) || - (BIO_dgram_is_sctp(SSL_get_rbio(s)) - && ossl_statem_in_sctp_read_sock(s) - && s->s3->in_read_app_data != 2)) -#else if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) -#endif { /* type == SSL3_RT_APPLICATION_DATA */ i = s->handshake_func(s); if (i < 0) - return (i); + return i; if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); - return (-1); + return -1; } } @@ -465,7 +370,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, * s->s3->rrec.off, - offset into 'data' for next read * s->s3->rrec.length, - number of bytes. */ - rr = &s->rlayer.rrec; + rr = s->rlayer.rrec; /* * We are not handshaking and have no data yet, so process data buffered @@ -497,18 +402,26 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, /* get new packet if necessary */ if ((SSL3_RECORD_get_length(rr) == 0) - || (s->rlayer.rstate == SSL_ST_READ_BODY)) { - ret = dtls1_get_record(s); - if (ret <= 0) { - ret = dtls1_read_failed(s, ret); + || (s->rlayer.rstate == SSL_ST_READ_BODY)) { + iret = dtls1_get_record(s); + if (iret <= 0) { + iret = dtls1_read_failed(s, iret); /* anything other than a timeout is an error */ - if (ret <= 0) - return (ret); + if (iret <= 0) + return iret; else goto start; } } + /* + * Reset the count of consecutive warning alerts if we've got a non-empty + * record that isn't an alert. + */ + if (SSL3_RECORD_get_type(rr) != SSL3_RT_ALERT + && SSL3_RECORD_get_length(rr) != 0) + s->rlayer.alert_count = 0; + /* we now have a packet which can be read and processed */ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, @@ -520,7 +433,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, * data for later processing rather than dropping the connection. */ if (dtls1_buffer_record(s, &(s->rlayer.d->buffered_app_data), - SSL3_RECORD_get_seq_num(rr)) < 0) { + SSL3_RECORD_get_seq_num(rr)) < 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } @@ -535,12 +448,12 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { SSL3_RECORD_set_length(rr, 0); s->rwstate = SSL_NOTHING; - return (0); + return 0; } if (type == SSL3_RECORD_get_type(rr) - || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC - && type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) { + || (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC + && type == SSL3_RT_HANDSHAKE && recvd_type != NULL)) { /* * SSL3_RT_APPLICATION_DATA or * SSL3_RT_HANDSHAKE or @@ -560,17 +473,17 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (recvd_type != NULL) *recvd_type = SSL3_RECORD_get_type(rr); - if (len <= 0) - return (len); + if (len == 0) + return 0; - if ((unsigned int)len > SSL3_RECORD_get_length(rr)) + if (len > SSL3_RECORD_get_length(rr)) n = SSL3_RECORD_get_length(rr); else - n = (unsigned int)len; + n = len; memcpy(buf, &(SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]), n); if (!peek) { - SSL3_RECORD_add_length(rr, -n); + SSL3_RECORD_sub_length(rr, n); SSL3_RECORD_add_off(rr, n); if (SSL3_RECORD_get_length(rr) == 0) { s->rlayer.rstate = SSL_ST_READ_HEADER; @@ -578,18 +491,6 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, } } #ifndef OPENSSL_NO_SCTP - /* - * We were about to renegotiate but had to read belated application - * data first, so retry. - */ - if (BIO_dgram_is_sctp(SSL_get_rbio(s)) && - SSL3_RECORD_get_type(rr) == SSL3_RT_APPLICATION_DATA && - ossl_statem_in_sctp_read_sock(s)) { - s->rwstate = SSL_READING; - BIO_clear_retry_flags(SSL_get_rbio(s)); - BIO_set_retry_read(SSL_get_rbio(s)); - } - /* * We might had to delay a close_notify alert because of reordered * app data. If there was an alert and there is no message to read @@ -599,10 +500,11 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, s->d1->shutdown_received && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) { s->shutdown |= SSL_RECEIVED_SHUTDOWN; - return (0); + return 0; } #endif - return (n); + *readbytes = n; + return 1; } /* @@ -610,171 +512,23 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, * 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; - unsigned char *dest = NULL; - unsigned int *dest_len = NULL; - - if (SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) { - dest_maxlen = sizeof s->rlayer.d->handshake_fragment; - dest = s->rlayer.d->handshake_fragment; - dest_len = &s->rlayer.d->handshake_fragment_len; - } else if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) { - dest_maxlen = sizeof(s->rlayer.d->alert_fragment); - dest = s->rlayer.d->alert_fragment; - dest_len = &s->rlayer.d->alert_fragment_len; - } -#ifndef OPENSSL_NO_HEARTBEATS - else if (SSL3_RECORD_get_type(rr) == TLS1_RT_HEARTBEAT) { - /* We allow a 0 return */ - if (dtls1_process_heartbeat(s, SSL3_RECORD_get_data(rr), - SSL3_RECORD_get_length(rr)) < 0) { - return -1; - } - /* Exit and notify application to read again */ - SSL3_RECORD_set_length(rr, 0); - s->rwstate = SSL_READING; - BIO_clear_retry_flags(SSL_get_rbio(s)); - BIO_set_retry_read(SSL_get_rbio(s)); - return (-1); - } -#endif - /* else it's a CCS message, or application data or wrong */ - else if (SSL3_RECORD_get_type(rr) != SSL3_RT_CHANGE_CIPHER_SPEC) { - /* - * Application data while renegotiating is allowed. Try again - * reading. - */ - if (SSL3_RECORD_get_type(rr) == 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); - } + if (SSL3_RECORD_get_type(rr) == SSL3_RT_ALERT) { + unsigned int alert_level, alert_descr; + unsigned char *alert_bytes = SSL3_RECORD_get_data(rr) + + SSL3_RECORD_get_off(rr); + PACKET alert; - /* Not certain if this is the right error handling */ + if (!PACKET_buf_init(&alert, alert_bytes, SSL3_RECORD_get_length(rr)) + || !PACKET_get_1(&alert, &alert_level) + || !PACKET_get_1(&alert, &alert_descr) + || PACKET_remaining(&alert) != 0) { al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_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 (SSL3_RECORD_get_length(rr) < dest_maxlen) { -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE - /* - * for normal alerts rr->length is 2, while - * dest_maxlen is 7 if we were to handle this - * non-existing alert... - */ - FIX ME -#endif - s->rlayer.rstate = SSL_ST_READ_HEADER; - SSL3_RECORD_set_length(rr, 0); - goto start; - } - - /* now move 'n' bytes: */ - for (k = 0; k < dest_maxlen; k++) { - dest[k] = SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]; - SSL3_RECORD_add_off(rr, 1); - SSL3_RECORD_add_length(rr, -1); - } - *dest_len = dest_maxlen; - } - } - - /*- - * s->rlayer.d->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE; - * s->rlayer.d->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->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && - (s->rlayer.d->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && - (s->session != NULL) && (s->session->cipher != NULL)) { - s->rlayer.d->handshake_fragment_len = 0; - - if ((s->rlayer.d->handshake_fragment[1] != 0) || - (s->rlayer.d->handshake_fragment[2] != 0) || - (s->rlayer.d->handshake_fragment[3] != 0)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_HELLO_REQUEST); + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_INVALID_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->rlayer.d->handshake_fragment, 4, s, - s->msg_callback_arg); - - if (SSL_is_init_finished(s) && - !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && - !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) { - SSLerr(SSL_F_DTLS1_READ_BYTES, - SSL_R_SSL_HANDSHAKE_FAILURE); - return (-1); - } - - if (!(s->mode & SSL_MODE_AUTO_RETRY)) { - if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) { - /* no read-ahead left? */ - BIO *bio; - /* - * In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world - */ - s->rwstate = SSL_READING; - bio = SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - 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->rlayer.d->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) { - int alert_level = s->rlayer.d->alert_fragment[0]; - int alert_descr = s->rlayer.d->alert_fragment[1]; - - s->rlayer.d->alert_fragment_len = 0; - if (s->msg_callback) - s->msg_callback(0, s->version, SSL3_RT_ALERT, - s->rlayer.d->alert_fragment, 2, s, + s->msg_callback(0, s->version, SSL3_RT_ALERT, alert_bytes, 2, s, s->msg_callback_arg); if (s->info_callback != NULL) @@ -789,6 +543,14 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, if (alert_level == SSL3_AL_WARNING) { s->s3->warn_alert = alert_descr; + + s->rlayer.alert_count++; + if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS); + goto f_err; + } + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { #ifndef OPENSSL_NO_SCTP /* @@ -806,48 +568,19 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, } #endif s->shutdown |= SSL_RECEIVED_SHUTDOWN; - return (0); - } -#if 0 - /* XXX: this is a possible improvement in the future */ - /* now check if it's a missing record */ - if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) { - unsigned short seq; - unsigned int frag_off; - unsigned char *p = &(s->rlayer.d->alert_fragment[2]); - - n2s(p, seq); - n2l3(p, frag_off); - - dtls1_retransmit_message(s, - dtls1_get_queue_priority - (frag->msg_header.seq, 0), frag_off, - &found); - if (!found && SSL_in_init(s)) { - /* - * fprintf( stderr,"in init = %d\n", SSL_in_init(s)); - */ - /* - * requested a message not yet sent, send an alert - * ourselves - */ - ssl3_send_alert(s, SSL3_AL_WARNING, - DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); - } + return 0; } -#endif } else if (alert_level == SSL3_AL_FATAL) { char tmp[16]; s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; - SSLerr(SSL_F_DTLS1_READ_BYTES, - SSL_AD_REASON_OFFSET + alert_descr); + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; - SSL_CTX_remove_session(s->ctx, s->session); - return (0); + SSL_CTX_remove_session(s->session_ctx, s->session); + return 0; } else { al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); @@ -861,7 +594,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, * shutdown */ s->rwstate = SSL_NOTHING; SSL3_RECORD_set_length(rr, 0); - return (0); + return 0; } if (SSL3_RECORD_get_type(rr) == SSL3_RT_CHANGE_CIPHER_SPEC) { @@ -876,17 +609,22 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, /* * Unexpected handshake message (Client Hello, or protocol violation) */ - if ((s->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && - !ossl_statem_get_in_handshake(s)) { + if ((SSL3_RECORD_get_type(rr) == SSL3_RT_HANDSHAKE) && + !ossl_statem_get_in_handshake(s)) { struct hm_header_st msg_hdr; - /* this may just be a stale retransmit */ - dtls1_get_message_header(rr->data, &msg_hdr); - if (SSL3_RECORD_get_epoch(rr) != s->rlayer.d->r_epoch) { + /* + * This may just be a stale retransmit. Also sanity check that we have + * at least enough record bytes for a message header + */ + if (SSL3_RECORD_get_epoch(rr) != s->rlayer.d->r_epoch + || SSL3_RECORD_get_length(rr) < DTLS1_HM_HEADER_LENGTH) { SSL3_RECORD_set_length(rr, 0); goto start; } + dtls1_get_message_header(rr->data, &msg_hdr); + /* * If we are server, we may have a repeated FINISHED of the client * here, then retransmit our CCS and FINISHED. @@ -900,18 +638,27 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, goto start; } - if (SSL_is_init_finished(s) && - !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { - ossl_statem_set_in_init(s, 1); - s->renegotiate = 1; - s->new_session = 1; + /* + * To get here we must be trying to read app data but found handshake + * data. But if we're trying to read app data, and we're not in init + * (which is tested for at the top of this function) then init must be + * finished + */ + if (!ossl_assert(SSL_is_init_finished(s))) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); + goto f_err; } + + /* We found handshake data, so we're going back into init */ + ossl_statem_set_in_init(s, 1); + i = s->handshake_func(s); if (i < 0) - return (i); + return i; if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); - return (-1); + return -1; } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { @@ -928,7 +675,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); - return (-1); + return -1; } } goto start; @@ -936,11 +683,6 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, switch (SSL3_RECORD_get_type(rr)) { default: - /* TLS just ignores unknown message types */ - if (s->version == TLS1_VERSION) { - SSL3_RECORD_set_length(rr, 0); - goto start; - } al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; @@ -967,7 +709,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, (s->s3->total_renegotiations != 0) && ossl_statem_app_data_allowed(s)) { s->s3->in_read_app_data = 2; - return (-1); + return -1; } else { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); @@ -978,91 +720,65 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); - return (-1); -} - - - /* - * this only happens when a client hello is received and a handshake - * is started. - */ -static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, - int len, int peek) -{ - - if ((type == SSL3_RT_HANDSHAKE) - && (s->rlayer.d->handshake_fragment_len > 0)) - /* (partially) satisfy request from storage */ - { - unsigned char *src = s->rlayer.d->handshake_fragment; - unsigned char *dst = buf; - unsigned int k, n; - - /* peek == 0 */ - n = 0; - while ((len > 0) && (s->rlayer.d->handshake_fragment_len > 0)) { - *dst++ = *src++; - len--; - s->rlayer.d->handshake_fragment_len--; - n++; - } - /* move any remaining fragment bytes: */ - for (k = 0; k < s->rlayer.d->handshake_fragment_len; k++) - s->rlayer.d->handshake_fragment[k] = *src++; - return n; - } - - return 0; + return -1; } /* * 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) +int dtls1_write_bytes(SSL *s, int type, const void *buf, size_t len, + size_t *written) { int i; - OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); + if (!ossl_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH)) { + SSLerr(SSL_F_DTLS1_WRITE_BYTES, ERR_R_INTERNAL_ERROR); + return -1; + } s->rwstate = SSL_NOTHING; - i = do_dtls1_write(s, type, buf, len, 0); + i = do_dtls1_write(s, type, buf, len, 0, written); return i; } int do_dtls1_write(SSL *s, int type, const unsigned char *buf, - unsigned int len, int create_empty_fragment) + size_t len, int create_empty_fragment, size_t *written) { unsigned char *p, *pseq; int i, mac_size, clear = 0; - int prefix_len = 0; + size_t prefix_len = 0; int eivlen; - SSL3_RECORD *wr; + SSL3_RECORD wr; SSL3_BUFFER *wb; SSL_SESSION *sess; - wb = &s->rlayer.wbuf; + wb = &s->rlayer.wbuf[0]; /* * first check if there is a SSL3_BUFFER still being written out. This * will happen with non blocking IO */ - if (SSL3_BUFFER_get_left(wb) != 0) { - OPENSSL_assert(0); /* XDTLS: want to see if we ever get here */ - return (ssl3_write_pending(s, type, buf, len)); + if (!ossl_assert(SSL3_BUFFER_get_left(wb) == 0)) { + SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR); + return 0; } /* If we have an alert to send, lets send it */ if (s->s3->alert_dispatch) { i = s->method->ssl_dispatch_alert(s); if (i <= 0) - return (i); + return i; /* if it went, fall through and send more stuff */ } if (len == 0 && !create_empty_fragment) return 0; - wr = &s->rlayer.wrec; + if (len > s->max_send_fragment) { + SSLerr(SSL_F_DO_DTLS1_WRITE, SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE); + return 0; + } + sess = s->session; if ((sess == NULL) || @@ -1082,13 +798,14 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, /* write the header */ *(p++) = type & 0xff; - SSL3_RECORD_set_type(wr, type); + SSL3_RECORD_set_type(&wr, type); /* * 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) { + if (s->method->version == DTLS_ANY_VERSION && + s->max_proto_version != DTLS1_BAD_VER) { *(p++) = DTLS1_VERSION >> 8; *(p++) = DTLS1_VERSION & 0xff; } else { @@ -1119,78 +836,77 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, eivlen = 0; /* lets setup the record stuff. */ - SSL3_RECORD_set_data(wr, p + eivlen); /* make room for IV in case of CBC */ - SSL3_RECORD_set_length(wr, (int)len); - SSL3_RECORD_set_input(wr, (unsigned char *)buf); + SSL3_RECORD_set_data(&wr, p + eivlen); /* make room for IV in case of CBC */ + SSL3_RECORD_set_length(&wr, len); + SSL3_RECORD_set_input(&wr, (unsigned char *)buf); /* - * we now 'read' from wr->input, wr->length bytes into wr->data + * we now 'read' from wr.input, wr.length bytes into wr.data */ /* first we compress */ if (s->compress != NULL) { - if (!ssl3_do_compress(s)) { + if (!ssl3_do_compress(s, &wr)) { SSLerr(SSL_F_DO_DTLS1_WRITE, SSL_R_COMPRESSION_FAILURE); goto err; } } else { - memcpy(SSL3_RECORD_get_data(wr), SSL3_RECORD_get_input(wr), - SSL3_RECORD_get_length(wr)); - SSL3_RECORD_reset_input(wr); + memcpy(SSL3_RECORD_get_data(&wr), SSL3_RECORD_get_input(&wr), + SSL3_RECORD_get_length(&wr)); + SSL3_RECORD_reset_input(&wr); } /* - * we should still have the output to wr->data and the input from - * wr->input. Length should be wr->length. wr->data still points in the + * we should still have the output to wr.data and the input from + * wr.input. Length should be wr.length. wr.data still points in the * wb->buf */ - if (mac_size != 0) { - if (s->method->ssl3_enc->mac(s, - &(p[SSL3_RECORD_get_length(wr) + eivlen]), 1) < 0) + if (!SSL_WRITE_ETM(s) && mac_size != 0) { + if (!s->method->ssl3_enc->mac(s, &wr, + &(p[SSL3_RECORD_get_length(&wr) + eivlen]), + 1)) goto err; - SSL3_RECORD_add_length(wr, mac_size); + SSL3_RECORD_add_length(&wr, mac_size); } /* this is true regardless of mac size */ - SSL3_RECORD_set_data(wr, p); - SSL3_RECORD_reset_input(wr); + SSL3_RECORD_set_data(&wr, p); + SSL3_RECORD_reset_input(&wr); if (eivlen) - SSL3_RECORD_add_length(wr, eivlen); + SSL3_RECORD_add_length(&wr, eivlen); - if (s->method->ssl3_enc->enc(s, 1) < 1) + if (s->method->ssl3_enc->enc(s, &wr, 1, 1) < 1) goto err; + if (SSL_WRITE_ETM(s) && mac_size != 0) { + if (!s->method->ssl3_enc->mac(s, &wr, + &(p[SSL3_RECORD_get_length(&wr)]), 1)) + goto err; + SSL3_RECORD_add_length(&wr, mac_size); + } + /* record length after mac and block padding */ - /* - * if (type == SSL3_RT_APPLICATION_DATA || (type == SSL3_RT_ALERT && ! - * SSL_in_init(s))) - */ /* there's only one epoch between handshake and app data */ s2n(s->rlayer.d->w_epoch, pseq); - /* XDTLS: ?? */ - /* - * else s2n(s->d1->handshake_epoch, pseq); - */ - memcpy(pseq, &(s->rlayer.write_sequence[2]), 6); pseq += 6; - s2n(SSL3_RECORD_get_length(wr), pseq); + s2n(SSL3_RECORD_get_length(&wr), pseq); if (s->msg_callback) s->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH, DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); /* - * we should now have wr->data pointing to the encrypted data, which is + * we should now have wr.data pointing to the encrypted data, which is * wr->length long */ - SSL3_RECORD_set_type(wr, type); /* not needed but helps for debugging */ - SSL3_RECORD_add_length(wr, DTLS1_RT_HEADER_LENGTH); + SSL3_RECORD_set_type(&wr, type); /* not needed but helps for debugging */ + SSL3_RECORD_add_length(&wr, DTLS1_RT_HEADER_LENGTH); ssl3_record_sequence_update(&(s->rlayer.write_sequence[0])); @@ -1199,11 +915,12 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, * we are in a recursive call; just return the length, don't write * out anything here */ - return wr->length; + *written = wr.length; + return 1; } /* now let's set up wb */ - SSL3_BUFFER_set_left(wb, prefix_len + SSL3_RECORD_get_length(wr)); + SSL3_BUFFER_set_left(wb, prefix_len + SSL3_RECORD_get_length(&wr)); SSL3_BUFFER_set_offset(wb, 0); /* @@ -1216,13 +933,13 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, s->rlayer.wpend_ret = len; /* we now just need to write the buffer */ - return ssl3_write_pending(s, type, buf, len); + return ssl3_write_pending(s, type, buf, len, written); err: return -1; } DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, - unsigned int *is_next_epoch) + unsigned int *is_next_epoch) { *is_next_epoch = 0; @@ -1231,9 +948,14 @@ DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, if (rr->epoch == s->rlayer.d->r_epoch) return &s->rlayer.d->bitmap; - /* Only HM and ALERT messages can be from the next epoch */ + /* + * Only HM and ALERT messages can be from the next epoch and only if we + * have already processed all of the unprocessed records from the last + * epoch + */ else if (rr->epoch == (unsigned long)(s->rlayer.d->r_epoch + 1) && - (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) { + s->rlayer.d->unprocessed_rcds.epoch != s->rlayer.d->r_epoch && + (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) { *is_next_epoch = 1; return &s->rlayer.d->next_bitmap; } @@ -1251,8 +973,13 @@ void dtls1_reset_seq_numbers(SSL *s, int rw) s->rlayer.d->r_epoch++; memcpy(&s->rlayer.d->bitmap, &s->rlayer.d->next_bitmap, sizeof(s->rlayer.d->bitmap)); - memset(&s->rlayer.d->next_bitmap, 0, - sizeof(s->rlayer.d->next_bitmap)); + memset(&s->rlayer.d->next_bitmap, 0, sizeof(s->rlayer.d->next_bitmap)); + + /* + * We must not use any buffered messages received from the previous + * epoch + */ + dtls1_clear_received_buffer(s); } else { seq = s->rlayer.write_sequence; memcpy(s->rlayer.d->last_write_sequence, seq,