PR: 2756
[openssl.git] / ssl / d1_pkt.c
index 1fd58bf598a706411559bf1ce8695ba76cbbf68c..987af608358d914a72fa8a4620d7faf8188d22f0 100644 (file)
@@ -179,7 +179,6 @@ static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
 static int dtls1_buffer_record(SSL *s, record_pqueue *q,
        unsigned char *priority);
 static int dtls1_process_record(SSL *s);
-static void dtls1_clear_timeouts(SSL *s);
 
 /* copy buffered record into SSL structure */
 static int
@@ -232,6 +231,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)
                {
@@ -375,6 +382,8 @@ 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;
+       unsigned char *mac = NULL;
 
 
        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 err;
+               /* 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,28 +451,32 @@ printf("\n");
                        SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
                        goto f_err;
 #else
-                       goto err;
+                       decryption_failed_or_bad_record_mac = 1;
 #endif                 
                        }
                /* check the MAC for rr->input (it's in mac_size bytes at the tail) */
-               if (rr->length < mac_size)
+               if (rr->length >= mac_size)
                        {
-#if 0 /* OK only for stream ciphers */
-                       al=SSL_AD_DECODE_ERROR;
-                       SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT);
-                       goto f_err;
-#else
-                       goto err;
-#endif
+                       rr->length -= mac_size;
+                       mac = &rr->data[rr->length];
                        }
-               rr->length-=mac_size;
+               else
+                       rr->length = 0;
                i=s->method->ssl3_enc->mac(s,md,0);
-               if (i < 0 || memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
+               if (i < 0 || mac == NULL || memcmp(md, mac, mac_size) != 0)
                        {
-                       goto err;
+                       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)
                {
@@ -637,30 +648,40 @@ again:
                goto again;   /* get another record */
                }
 
-       /* 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
+       /* 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),
         * and a handshake is currently in progress, buffer it since it
-        * cannot be processed at this time. */
+        * cannot be processed at this time. However, do not buffer
+        * anything while listening.
+        */
        if (is_next_epoch)
                {
-               if (SSL_in_init(s) || s->in_handshake)
+               if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen)
                        {
                        dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
                        }
@@ -676,7 +697,6 @@ again:
                goto again;   /* get another record */
                }
 
-       dtls1_clear_timeouts(s);  /* done waiting */
        return(1);
 
        }
@@ -734,7 +754,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 +795,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);
@@ -847,6 +886,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 +938,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 +1034,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 +1096,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 +1217,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;
                }
 
@@ -1146,6 +1248,9 @@ start:
                 */
                if (msg_hdr.type == SSL3_MT_FINISHED)
                        {
+                       if (dtls1_check_timeout_num(s) < 0)
+                               return -1;
+
                        dtls1_retransmit_buffered_messages(s);
                        rr->length = 0;
                        goto start;
@@ -1163,6 +1268,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 +1365,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);
@@ -1759,10 +1874,3 @@ dtls1_reset_seq_numbers(SSL *s, int rw)
 
        memset(seq, 0x00, seq_bytes);
        }
-
-
-static void
-dtls1_clear_timeouts(SSL *s)
-       {
-       memset(&(s->d1->timeout), 0x00, sizeof(struct dtls1_timeout_st));
-       }