Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de>, Michael Tuexen <tuexen...
[openssl.git] / ssl / d1_pkt.c
index 355d5ed9cdcbeedc59bbe83855cb02a77cbccecf..fdeaac88049134a5f274ee5f31f365606383f844 100644 (file)
@@ -196,6 +196,9 @@ dtls1_copy_record(SSL *s, pitem *item)
     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);
     }
@@ -229,6 +232,14 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
 
        item->data = rdata;
 
+#ifndef OPENSSL_NO_SCTP
+       /* Store bio_dgram_sctp_rcvinfo struct */
+       if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+           (s->state == SSL3_ST_SR_FINISHED_A || s->state == SSL3_ST_CR_FINISHED_A)) {
+               BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
+       }
+#endif
+
        /* insert should not fail, since duplicates are dropped */
        if (pqueue_insert(queue->q, item) == NULL)
                {
@@ -293,9 +304,6 @@ dtls1_process_buffered_records(SSL *s)
     item = pqueue_peek(s->d1->unprocessed_rcds.q);
     if (item)
         {
-        DTLS1_RECORD_DATA *rdata;
-        rdata = (DTLS1_RECORD_DATA *)item->data;
-        
         /* Check if epoch is current. */
         if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
             return(1);  /* Nothing to do. */
@@ -375,6 +383,7 @@ dtls1_process_record(SSL *s)
        SSL3_RECORD *rr;
        unsigned int mac_size;
        unsigned char md[EVP_MAX_MD_SIZE];
+       int decryption_failed_or_bad_record_mac = 0;
 
 
        rr= &(s->s3->rrec);
@@ -409,12 +418,10 @@ dtls1_process_record(SSL *s)
        enc_err = s->method->ssl3_enc->enc(s,0);
        if (enc_err <= 0)
                {
-               if (enc_err == 0)
-                       /* SSLerr() and ssl3_send_alert() have been called */
-                       goto err;
-
-               /* otherwise enc_err == -1 */
-               goto decryption_failed_or_bad_record_mac;
+               /* To minimize information leaked via timing, we will always
+                * perform all computations before discarding the message.
+                */
+               decryption_failed_or_bad_record_mac = 1;
                }
 
 #ifdef TLS_DEBUG
@@ -444,7 +451,7 @@ printf("\n");
                        SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
                        goto f_err;
 #else
-                       goto decryption_failed_or_bad_record_mac;
+                       decryption_failed_or_bad_record_mac = 1;
 #endif                 
                        }
                /* check the MAC for rr->input (it's in mac_size bytes at the tail) */
@@ -455,17 +462,25 @@ printf("\n");
                        SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT);
                        goto f_err;
 #else
-                       goto decryption_failed_or_bad_record_mac;
+                       decryption_failed_or_bad_record_mac = 1;
 #endif
                        }
                rr->length-=mac_size;
                i=s->method->ssl3_enc->mac(s,md,0);
                if (i < 0 || memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
                        {
-                       goto decryption_failed_or_bad_record_mac;
+                       decryption_failed_or_bad_record_mac = 1;
                        }
                }
 
+       if (decryption_failed_or_bad_record_mac)
+               {
+               /* decryption failed, silently discard message */
+               rr->length = 0;
+               s->packet_length = 0;
+               goto err;
+               }
+
        /* r->length is now just compressed */
        if (s->expand != NULL)
                {
@@ -504,14 +519,6 @@ printf("\n");
        dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
        return(1);
 
-decryption_failed_or_bad_record_mac:
-       /* Separate 'decryption_failed' alert was introduced with TLS 1.0,
-        * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
-        * failure is directly visible from the ciphertext anyway,
-        * we should not reveal which kind of error occured -- this
-        * might become visible to an attacker (e.g. via logfile) */
-       al=SSL_AD_BAD_RECORD_MAC;
-       SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
@@ -533,19 +540,16 @@ int dtls1_get_record(SSL *s)
        int ssl_major,ssl_minor;
        int i,n;
        SSL3_RECORD *rr;
-       SSL_SESSION *sess;
-       unsigned char *p;
+       unsigned char *p = NULL;
        unsigned short version;
        DTLS1_BITMAP *bitmap;
        unsigned int is_next_epoch;
 
        rr= &(s->s3->rrec);
-       sess=s->session;
 
        /* The epoch may have changed.  If so, process all the
         * pending records.  This is a non-blocking operation. */
-       if ( ! dtls1_process_buffered_records(s))
-            return 0;
+       dtls1_process_buffered_records(s);
 
        /* if we're renegotiating, then there may be buffered records */
        if (dtls1_get_processed_record(s))
@@ -648,33 +652,54 @@ again:
                goto again;   /* get another record */
                }
 
-       /* check whether this is a repeat, or aged record */
-       if ( ! dtls1_record_replay_check(s, bitmap))
-               {
-               rr->length = 0;
-               s->packet_length=0; /* dump this record */
-               goto again;     /* get another record */
-               }
+#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.
+                * Don't check if we're listening and this message is
+                * a ClientHello. They can look as if they're replayed,
+                * since they arrive from different connections and
+                * would be dropped unnecessarily.
+                */
+               if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
+                   *p == SSL3_MT_CLIENT_HELLO) &&
+                   !dtls1_record_replay_check(s, bitmap))
+                       {
+                       rr->length = 0;
+                       s->packet_length=0; /* dump this record */
+                       goto again;     /* get another record */
+                       }
+#ifndef OPENSSL_NO_SCTP
+               }
+#endif
 
        /* just read a 0 length packet */
        if (rr->length == 0) goto again;
 
        /* If this record is from the next epoch (either HM or ALERT),
-        * buffer it since it cannot be processed at this time. Records
-        * from the next epoch are marked as received even though they
-        * are not processed, so as to prevent any potential resource
-        * DoS attack */
+        * and a handshake is currently in progress, buffer it since it
+        * cannot be processed at this time. However, do not buffer
+        * anything while listening.
+        */
        if (is_next_epoch)
                {
-               dtls1_record_bitmap_update(s, bitmap);
-               dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+               if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen)
+                       {
+                       dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+                       }
                rr->length = 0;
                s->packet_length = 0;
                goto again;
                }
 
-       if ( ! dtls1_process_record(s))
-               return(0);
+       if (!dtls1_process_record(s))
+               {
+               rr->length = 0;
+               s->packet_length = 0;  /* dump this record */
+               goto again;   /* get another record */
+               }
 
        dtls1_clear_timeouts(s);  /* done waiting */
        return(1);
@@ -734,7 +759,17 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
        /* Now s->d1->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 ((!s->in_handshake && SSL_in_init(s)) ||
+           (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+            (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK) &&
+            s->s3->in_read_app_data != 2))
+#else
        if (!s->in_handshake && SSL_in_init(s))
+#endif
                {
                /* type == SSL3_RT_APPLICATION_DATA */
                i=s->handshake_func(s);
@@ -765,6 +800,15 @@ start:
                item = pqueue_pop(s->d1->buffered_app_data.q);
                if (item)
                        {
+#ifndef OPENSSL_NO_SCTP
+                       /* Restore bio_dgram_sctp_rcvinfo struct */
+                       if (BIO_dgram_is_sctp(SSL_get_rbio(s)))
+                               {
+                               DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *) item->data;
+                               BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, sizeof(rdata->recordinfo), &rdata->recordinfo);
+                               }
+#endif
+
                        dtls1_copy_record(s, item);
 
                        OPENSSL_free(item->data);
@@ -802,7 +846,7 @@ start:
                 * buffer the application data for later processing rather
                 * than dropping the connection.
                 */
-               dtls1_buffer_record(s, &(s->d1->buffered_app_data), 0);
+               dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num);
                rr->length = 0;
                goto start;
                }
@@ -847,6 +891,31 @@ start:
                                rr->off=0;
                                }
                        }
+
+#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)) &&
+                           rr->type == SSL3_RT_APPLICATION_DATA &&
+                           (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK))
+                               {
+                               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 anymore, finally set shutdown.
+                        */
+                       if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+                           s->d1->shutdown_received && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
+                               {
+                               s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+                               return(0);
+                               }
+#endif                 
                return(n);
                }
 
@@ -874,6 +943,19 @@ start:
                        dest = s->d1->alert_fragment;
                        dest_len = &s->d1->alert_fragment_len;
                        }
+#ifndef OPENSSL_NO_HEARTBEATS
+               else if (rr->type == TLS1_RT_HEARTBEAT)
+                       {
+                       dtls1_process_heartbeat(s);
+
+                       /* Exit and notify application to read again */
+                       rr->length = 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 (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
                        {
@@ -957,6 +1039,7 @@ start:
                        !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
                        !s->s3->renegotiate)
                        {
+                       s->new_session = 1;
                        ssl3_renegotiate(s);
                        if (ssl3_renegotiate_check(s))
                                {
@@ -1018,6 +1101,21 @@ start:
                        s->s3->warn_alert = alert_descr;
                        if (alert_descr == SSL_AD_CLOSE_NOTIFY)
                                {
+#ifndef OPENSSL_NO_SCTP
+                               /* With SCTP and streams the socket may deliver app data
+                                * after a close_notify alert. We have to check this
+                                * first so that nothing gets discarded.
+                                */
+                               if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
+                                       BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s)))
+                                       {
+                                       s->d1->shutdown_received = 1;
+                                       s->rwstate=SSL_READING;
+                                       BIO_clear_retry_flags(SSL_get_rbio(s));
+                                       BIO_set_retry_read(SSL_get_rbio(s));
+                                       return -1;
+                                       }
+#endif
                                s->shutdown |= SSL_RECEIVED_SHUTDOWN;
                                return(0);
                                }
@@ -1124,6 +1222,15 @@ start:
                if (s->version == DTLS1_BAD_VER)
                        s->d1->handshake_read_seq++;
 
+#ifndef OPENSSL_NO_SCTP
+               /* Remember that a CCS has been received,
+                * so that an old key of SCTP-Auth can be
+                * deleted when a CCS is sent. Will be ignored
+                * if no SCTP is used
+                */
+               BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
+#endif
+
                goto start;
                }
 
@@ -1163,6 +1270,7 @@ start:
 #else
                        s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
 #endif
+                       s->renegotiate=1;
                        s->new_session=1;
                        }
                i=s->handshake_func(s);
@@ -1259,7 +1367,16 @@ dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
        {
        int i;
 
-       if (SSL_in_init(s) && !s->in_handshake)
+#ifndef OPENSSL_NO_SCTP
+               /* Check if we have to continue an interrupted handshake
+                * for reading belated app data with SCTP.
+                */
+               if ((SSL_in_init(s) && !s->in_handshake) ||
+                   (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
+                    (s->state == DTLS1_SCTP_ST_SR_READ_SOCK || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)))
+#else
+               if (SSL_in_init(s) && !s->in_handshake)
+#endif
                {
                i=s->handshake_func(s);
                if (i < 0) return(i);