svn commit: r306229 - in stable/9/crypto/openssl: crypto/bn crypto/dsa crypto/mdc2 ssl

Xin LI delphij at FreeBSD.org
Fri Sep 23 07:44:13 UTC 2016


Author: delphij
Date: Fri Sep 23 07:44:10 2016
New Revision: 306229
URL: https://svnweb.freebsd.org/changeset/base/306229

Log:
  Fix multiple OpenSSL vulnerabilities.
  
  Security:	FreeBSD-SA-16:26.openssl

Modified:
  stable/9/crypto/openssl/crypto/bn/bn_print.c
  stable/9/crypto/openssl/crypto/dsa/dsa_ossl.c
  stable/9/crypto/openssl/crypto/mdc2/mdc2dgst.c
  stable/9/crypto/openssl/ssl/d1_both.c
  stable/9/crypto/openssl/ssl/d1_clnt.c
  stable/9/crypto/openssl/ssl/d1_lib.c
  stable/9/crypto/openssl/ssl/d1_pkt.c
  stable/9/crypto/openssl/ssl/d1_srvr.c
  stable/9/crypto/openssl/ssl/s3_clnt.c
  stable/9/crypto/openssl/ssl/s3_srvr.c
  stable/9/crypto/openssl/ssl/ssl.h
  stable/9/crypto/openssl/ssl/ssl_err.c
  stable/9/crypto/openssl/ssl/ssl_locl.h
  stable/9/crypto/openssl/ssl/ssl_sess.c
  stable/9/crypto/openssl/ssl/t1_lib.c

Modified: stable/9/crypto/openssl/crypto/bn/bn_print.c
==============================================================================
--- stable/9/crypto/openssl/crypto/bn/bn_print.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/crypto/bn/bn_print.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -111,6 +111,7 @@ char *BN_bn2dec(const BIGNUM *a)
     char *p;
     BIGNUM *t = NULL;
     BN_ULONG *bn_data = NULL, *lp;
+    int bn_data_num;
 
     /*-
      * get an upper bound for the length of the decimal integer
@@ -120,8 +121,8 @@ char *BN_bn2dec(const BIGNUM *a)
      */
     i = BN_num_bits(a) * 3;
     num = (i / 10 + i / 1000 + 1) + 1;
-    bn_data =
-        (BN_ULONG *)OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG));
+    bn_data_num = num / BN_DEC_NUM + 1;
+    bn_data = OPENSSL_malloc(bn_data_num * sizeof(BN_ULONG));
     buf = (char *)OPENSSL_malloc(num + 3);
     if ((buf == NULL) || (bn_data == NULL)) {
         BNerr(BN_F_BN_BN2DEC, ERR_R_MALLOC_FAILURE);
@@ -143,7 +144,11 @@ char *BN_bn2dec(const BIGNUM *a)
         i = 0;
         while (!BN_is_zero(t)) {
             *lp = BN_div_word(t, BN_DEC_CONV);
+            if (*lp == (BN_ULONG)-1)
+                goto err;
             lp++;
+            if (lp - bn_data >= bn_data_num)
+                goto err;
         }
         lp--;
         /*

Modified: stable/9/crypto/openssl/crypto/dsa/dsa_ossl.c
==============================================================================
--- stable/9/crypto/openssl/crypto/dsa/dsa_ossl.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/crypto/dsa/dsa_ossl.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -235,11 +235,13 @@ static int dsa_sign_setup(DSA *dsa, BN_C
     do
         if (!BN_rand_range(&k, dsa->q))
             goto err;
-    while (BN_is_zero(&k)) ;
+    while (BN_is_zero(&k));
+
     if ((dsa->flags & DSA_FLAG_NO_EXP_CONSTTIME) == 0) {
         BN_set_flags(&k, BN_FLG_CONSTTIME);
     }
 
+
     if (dsa->flags & DSA_FLAG_CACHE_MONT_P) {
         if (!BN_MONT_CTX_set_locked(&dsa->method_mont_p,
                                     CRYPTO_LOCK_DSA, dsa->p, ctx))
@@ -252,6 +254,8 @@ static int dsa_sign_setup(DSA *dsa, BN_C
         if (!BN_copy(&kq, &k))
             goto err;
 
+        BN_set_flags(&kq, BN_FLG_CONSTTIME);
+
         /*
          * We do not want timing information to leak the length of k, so we
          * compute g^k using an equivalent exponent of fixed length. (This
@@ -270,6 +274,7 @@ static int dsa_sign_setup(DSA *dsa, BN_C
     } else {
         K = &k;
     }
+
     DSA_BN_MOD_EXP(goto err, dsa, r, dsa->g, K, dsa->p, ctx,
                    dsa->method_mont_p);
     if (!BN_mod(r, r, dsa->q, ctx))

Modified: stable/9/crypto/openssl/crypto/mdc2/mdc2dgst.c
==============================================================================
--- stable/9/crypto/openssl/crypto/mdc2/mdc2dgst.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/crypto/mdc2/mdc2dgst.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -94,7 +94,7 @@ int MDC2_Update(MDC2_CTX *c, const unsig
 
     i = c->num;
     if (i != 0) {
-        if (i + len < MDC2_BLOCK) {
+        if (len < MDC2_BLOCK - i) {
             /* partial block */
             memcpy(&(c->data[i]), in, len);
             c->num += (int)len;

Modified: stable/9/crypto/openssl/ssl/d1_both.c
==============================================================================
--- stable/9/crypto/openssl/ssl/d1_both.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/d1_both.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -543,11 +543,23 @@ static int dtls1_retrieve_buffered_fragm
     int al;
 
     *ok = 0;
-    item = pqueue_peek(s->d1->buffered_messages);
-    if (item == NULL)
-        return 0;
+    do {
+        item = pqueue_peek(s->d1->buffered_messages);
+        if (item == NULL)
+            return 0;
+
+        frag = (hm_fragment *)item->data;
+
+        if (frag->msg_header.seq < s->d1->handshake_read_seq) {
+            /* This is a stale message that has been buffered so clear it */
+            pqueue_pop(s->d1->buffered_messages);
+            dtls1_hm_fragment_free(frag);
+            pitem_free(item);
+            item = NULL;
+            frag = NULL;
+        }
+    } while (item == NULL);
 
-    frag = (hm_fragment *)item->data;
 
     /* Don't return if reassembly still in progress */
     if (frag->reassembly != NULL)
@@ -1335,18 +1347,6 @@ dtls1_retransmit_message(SSL *s, unsigne
     return ret;
 }
 
-/* call this function when the buffered messages are no longer needed */
-void dtls1_clear_record_buffer(SSL *s)
-{
-    pitem *item;
-
-    for (item = pqueue_pop(s->d1->sent_messages);
-         item != NULL; item = pqueue_pop(s->d1->sent_messages)) {
-        dtls1_hm_fragment_free((hm_fragment *)item->data);
-        pitem_free(item);
-    }
-}
-
 unsigned char *dtls1_set_message_header(SSL *s, unsigned char *p,
                                         unsigned char mt, unsigned long len,
                                         unsigned long frag_off,

Modified: stable/9/crypto/openssl/ssl/d1_clnt.c
==============================================================================
--- stable/9/crypto/openssl/ssl/d1_clnt.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/d1_clnt.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -564,6 +564,7 @@ int dtls1_connect(SSL *s)
             /* done with handshaking */
             s->d1->handshake_read_seq = 0;
             s->d1->next_handshake_write_seq = 0;
+            dtls1_clear_received_buffer(s);
             goto end;
             /* break; */
 

Modified: stable/9/crypto/openssl/ssl/d1_lib.c
==============================================================================
--- stable/9/crypto/openssl/ssl/d1_lib.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/d1_lib.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -155,7 +155,6 @@ int dtls1_new(SSL *s)
 static void dtls1_clear_queues(SSL *s)
 {
     pitem *item = NULL;
-    hm_fragment *frag = NULL;
     DTLS1_RECORD_DATA *rdata;
 
     while ((item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL) {
@@ -176,12 +175,36 @@ static void dtls1_clear_queues(SSL *s)
         pitem_free(item);
     }
 
+    while ((item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) {
+        rdata = (DTLS1_RECORD_DATA *)item->data;
+        if (rdata->rbuf.buf) {
+            OPENSSL_free(rdata->rbuf.buf);
+        }
+        OPENSSL_free(item->data);
+        pitem_free(item);
+    }
+
+    dtls1_clear_received_buffer(s);
+    dtls1_clear_sent_buffer(s);
+}
+
+void dtls1_clear_received_buffer(SSL *s)
+{
+    pitem *item = NULL;
+    hm_fragment *frag = NULL;
+
     while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) {
         frag = (hm_fragment *)item->data;
         OPENSSL_free(frag->fragment);
         OPENSSL_free(frag);
         pitem_free(item);
     }
+}
+
+void dtls1_clear_sent_buffer(SSL *s)
+{
+    pitem *item = NULL;
+    hm_fragment *frag = NULL;
 
     while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) {
         frag = (hm_fragment *)item->data;
@@ -189,17 +212,9 @@ static void dtls1_clear_queues(SSL *s)
         OPENSSL_free(frag);
         pitem_free(item);
     }
-
-    while ((item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) {
-        rdata = (DTLS1_RECORD_DATA *)item->data;
-        if (rdata->rbuf.buf) {
-            OPENSSL_free(rdata->rbuf.buf);
-        }
-        OPENSSL_free(item->data);
-        pitem_free(item);
-    }
 }
 
+
 void dtls1_free(SSL *s)
 {
     ssl3_free(s);
@@ -431,7 +446,7 @@ void dtls1_stop_timer(SSL *s)
     BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
              &(s->d1->next_timeout));
     /* Clear retransmission buffer */
-    dtls1_clear_record_buffer(s);
+    dtls1_clear_sent_buffer(s);
 }
 
 int dtls1_check_timeout_num(SSL *s)

Modified: stable/9/crypto/openssl/ssl/d1_pkt.c
==============================================================================
--- stable/9/crypto/openssl/ssl/d1_pkt.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/d1_pkt.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -124,8 +124,7 @@
 
 static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
                                    int len, int peek);
-static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap,
-                                     PQ_64BIT * seq_num);
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap);
 static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
 static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
                                       unsigned int *is_next_epoch);
@@ -135,7 +134,7 @@ static int dtls1_record_needs_buffering(
                                         unsigned long *offset);
 #endif
 static int dtls1_buffer_record(SSL *s, record_pqueue *q, PQ_64BIT * priority);
-static int dtls1_process_record(SSL *s);
+static int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
 #if PQ_64BIT_IS_INTEGER
 static PQ_64BIT bytes_to_long_long(unsigned char *bytes, PQ_64BIT * num);
 #endif
@@ -248,20 +247,66 @@ static int dtls1_retrieve_buffered_recor
 static 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->d1->unprocessed_rcds.q);
     if (item) {
         /* Check if epoch is current. */
         if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
-            return (1);         /* Nothing to do. */
+            return 1;         /* Nothing to do. */
+
+        rr = &s->s3->rrec;
+        rb = &s->s3->rbuf;
+
+        if (rb->left > 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->d1->unprocessed_rcds.q)) {
             dtls1_get_unprocessed_record(s);
-            if (!dtls1_process_record(s))
-                return (0);
-            dtls1_buffer_record(s, &(s->d1->processed_rcds),
-                                &s->s3->rrec.seq_num);
+            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;
+            }
+            {
+                /*
+                 * 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;
+                s->packet_length = 0;
+                continue;
+            }
+
+            if (dtls1_buffer_record(s, &(s->d1->processed_rcds),
+                                    &s->s3->rrec.seq_num) < 0)
+                return 0;
         }
     }
 
@@ -272,7 +317,7 @@ static int dtls1_process_buffered_record
     s->d1->processed_rcds.epoch = s->d1->r_epoch;
     s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
 
-    return (1);
+    return 1;
 }
 
 #if 0
@@ -319,7 +364,7 @@ static int dtls1_get_buffered_record(SSL
 
 #endif
 
-static int dtls1_process_record(SSL *s)
+static int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap)
 {
     int i, al;
     int enc_err;
@@ -478,8 +523,10 @@ static int dtls1_process_record(SSL *s)
 
     /* we have pulled in a full packet so zero things */
     s->packet_length = 0;
-    dtls1_record_bitmap_update(s, &(s->d1->bitmap)); /* Mark receipt of
-                                                      * record. */
+
+    /* Mark receipt of record. */
+    dtls1_record_bitmap_update(s, bitmap);
+
     return (1);
 
  f_err:
@@ -510,6 +557,7 @@ int dtls1_get_record(SSL *s)
 
     rr = &(s->s3->rrec);
 
+ again:
     /*
      * The epoch may have changed.  If so, process all the pending records.
      * This is a non-blocking operation.
@@ -521,7 +569,6 @@ int dtls1_get_record(SSL *s)
         return 1;
 
     /* get something from the wire */
- again:
     /* check if we have the header */
     if ((s->rstate != SSL_ST_READ_BODY) ||
         (s->packet_length < DTLS1_RT_HEADER_LENGTH)) {
@@ -620,7 +667,7 @@ int dtls1_get_record(SSL *s)
     if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
           s->packet_length > DTLS1_RT_HEADER_LENGTH &&
           s->packet[DTLS1_RT_HEADER_LENGTH] == SSL3_MT_CLIENT_HELLO) &&
-        !dtls1_record_replay_check(s, bitmap, &(rr->seq_num))) {
+        !dtls1_record_replay_check(s, bitmap)) {
         rr->length = 0;
         s->packet_length = 0;   /* dump this record */
         goto again;             /* get another record */
@@ -638,14 +685,16 @@ int dtls1_get_record(SSL *s)
      */
     if (is_next_epoch) {
         if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) {
-            dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), &rr->seq_num);
+            if (dtls1_buffer_record
+                (s, &(s->d1->unprocessed_rcds), &rr->seq_num) < 0)
+                return -1;
         }
         rr->length = 0;
         s->packet_length = 0;
         goto again;
     }
 
-    if (!dtls1_process_record(s)) {
+    if (!dtls1_process_record(s, bitmap)) {
         rr->length = 0;
         s->packet_length = 0;   /* dump this record */
         goto again;             /* get another record */
@@ -1514,8 +1563,7 @@ int do_dtls1_write(SSL *s, int type, con
     return -1;
 }
 
-static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap,
-                                     PQ_64BIT * seq_num)
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap)
 {
 #if PQ_64BIT_IS_INTEGER
     PQ_64BIT mask = 0x0000000000000001L;
@@ -1530,7 +1578,7 @@ static int dtls1_record_replay_check(SSL
 
     if (pq_64bit_gt(&rcd_num, &(bitmap->max_seq_num)) ||
         pq_64bit_eq(&rcd_num, &(bitmap->max_seq_num))) {
-        pq_64bit_assign(seq_num, &rcd_num);
+        pq_64bit_assign(&s->s3->rrec.seq_num, &rcd_num);
         pq_64bit_free(&rcd_num);
         pq_64bit_free(&tmp);
         return 1;               /* this record is new */
@@ -1561,7 +1609,7 @@ static int dtls1_record_replay_check(SSL
         return 0;               /* record previously received */
 #endif
 
-    pq_64bit_assign(seq_num, &rcd_num);
+    pq_64bit_assign(&s->s3->rrec.seq_num, &rcd_num);
     pq_64bit_free(&rcd_num);
     pq_64bit_free(&tmp);
     return 1;
@@ -1687,8 +1735,13 @@ static DTLS1_BITMAP *dtls1_get_bitmap(SS
     if (rr->epoch == s->d1->r_epoch)
         return &s->d1->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->d1->r_epoch + 1) &&
+             s->d1->unprocessed_rcds.epoch != s->d1->r_epoch &&
              (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
         *is_next_epoch = 1;
         return &s->d1->next_bitmap;
@@ -1776,6 +1829,12 @@ void dtls1_reset_seq_numbers(SSL *s, int
         memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP));
         pq_64bit_init(&(s->d1->next_bitmap.map));
         pq_64bit_init(&(s->d1->next_bitmap.max_seq_num));
+
+        /*
+         * We must not use any buffered messages received from the previous
+         * epoch
+         */
+        dtls1_clear_received_buffer(s);
     } else {
         seq = s->s3->write_sequence;
         memcpy(s->d1->last_write_sequence, seq,

Modified: stable/9/crypto/openssl/ssl/d1_srvr.c
==============================================================================
--- stable/9/crypto/openssl/ssl/d1_srvr.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/d1_srvr.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -242,7 +242,7 @@ int dtls1_accept(SSL *s)
         case SSL3_ST_SW_HELLO_REQ_B:
 
             s->shutdown = 0;
-            dtls1_clear_record_buffer(s);
+            dtls1_clear_sent_buffer(s);
             dtls1_start_timer(s);
             ret = dtls1_send_hello_request(s);
             if (ret <= 0)
@@ -648,6 +648,7 @@ int dtls1_accept(SSL *s)
             /* next message is server hello */
             s->d1->handshake_write_seq = 0;
             s->d1->next_handshake_write_seq = 0;
+            dtls1_clear_received_buffer(s);
             goto end;
             /* break; */
 

Modified: stable/9/crypto/openssl/ssl/s3_clnt.c
==============================================================================
--- stable/9/crypto/openssl/ssl/s3_clnt.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/s3_clnt.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -931,6 +931,12 @@ int ssl3_get_server_certificate(SSL *s)
         goto f_err;
     }
     for (nc = 0; nc < llen;) {
+        if (nc + 3 > llen) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
         n2l3(p, l);
         if ((l + nc + 3) > llen) {
             al = SSL_AD_DECODE_ERROR;
@@ -1627,6 +1633,11 @@ int ssl3_get_certificate_request(SSL *s)
     }
 
     for (nc = 0; nc < llen;) {
+        if (nc + 2 > llen) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+            SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_CA_DN_TOO_LONG);
+            goto err;
+        }
         n2s(p, l);
         if ((l + nc + 2) > llen) {
             if ((s->options & SSL_OP_NETSCAPE_CA_DN_BUG))

Modified: stable/9/crypto/openssl/ssl/s3_srvr.c
==============================================================================
--- stable/9/crypto/openssl/ssl/s3_srvr.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/s3_srvr.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -819,7 +819,7 @@ int ssl3_get_client_hello(SSL *s)
 
         session_length = *(p + SSL3_RANDOM_SIZE);
 
-        if (p + SSL3_RANDOM_SIZE + session_length + 1 >= d + n) {
+        if (SSL3_RANDOM_SIZE + session_length + 1 >= (d + n) - p) {
             al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
@@ -837,7 +837,7 @@ int ssl3_get_client_hello(SSL *s)
     /* get the session-id */
     j = *(p++);
 
-    if (p + j > d + n) {
+    if ((d + n) - p < j) {
         al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
         goto f_err;
@@ -874,14 +874,14 @@ int ssl3_get_client_hello(SSL *s)
 
     if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) {
         /* cookie stuff */
-        if (p + 1 > d + n) {
+        if ((d + n) - p < 1) {
             al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
         }
         cookie_len = *(p++);
 
-        if (p + cookie_len > d + n) {
+        if ((d + n ) - p < cookie_len) {
             al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
@@ -927,7 +927,7 @@ int ssl3_get_client_hello(SSL *s)
         p += cookie_len;
     }
 
-    if (p + 2 > d + n) {
+    if ((d + n ) - p < 2) {
         al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
         goto f_err;
@@ -941,7 +941,7 @@ int ssl3_get_client_hello(SSL *s)
     }
 
     /* i bytes of cipher data + 1 byte for compression length later */
-    if ((p + i + 1) > (d + n)) {
+    if ((d + n) - p < i + 1) {
         /* not enough data */
         al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
@@ -1007,7 +1007,7 @@ int ssl3_get_client_hello(SSL *s)
 
     /* compression */
     i = *(p++);
-    if ((p + i) > (d + n)) {
+    if ((d + n) - p < i) {
         /* not enough data */
         al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
@@ -1029,7 +1029,7 @@ int ssl3_get_client_hello(SSL *s)
 #ifndef OPENSSL_NO_TLSEXT
     /* TLS extensions */
     if (s->version >= SSL3_VERSION) {
-        if (!ssl_parse_clienthello_tlsext(s, &p, d, n, &al)) {
+        if (!ssl_parse_clienthello_tlsext(s, &p, d + n, &al)) {
             /* 'al' set by ssl_parse_clienthello_tlsext */
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
             goto f_err;
@@ -2526,6 +2526,12 @@ int ssl3_get_client_certificate(SSL *s)
         goto f_err;
     }
     for (nc = 0; nc < llen;) {
+        if (nc + 3 > llen) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
         n2l3(p, l);
         if ((l + nc + 3) > llen) {
             al = SSL_AD_DECODE_ERROR;

Modified: stable/9/crypto/openssl/ssl/ssl.h
==============================================================================
--- stable/9/crypto/openssl/ssl/ssl.h	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/ssl.h	Fri Sep 23 07:44:10 2016	(r306229)
@@ -1803,6 +1803,7 @@ void ERR_load_SSL_strings(void);
 # define SSL_F_DTLS1_HANDLE_TIMEOUT                       282
 # define SSL_F_DTLS1_OUTPUT_CERT_CHAIN                    255
 # define SSL_F_DTLS1_PREPROCESS_FRAGMENT                  277
+# define SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS             424
 # define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE           256
 # define SSL_F_DTLS1_PROCESS_RECORD                       257
 # define SSL_F_DTLS1_READ_BYTES                           258

Modified: stable/9/crypto/openssl/ssl/ssl_err.c
==============================================================================
--- stable/9/crypto/openssl/ssl/ssl_err.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/ssl_err.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -1,6 +1,6 @@
 /* ssl/ssl_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2011 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2016 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
@@ -92,6 +92,8 @@ static ERR_STRING_DATA SSL_str_functs[] 
     {ERR_FUNC(SSL_F_DTLS1_HANDLE_TIMEOUT), "DTLS1_HANDLE_TIMEOUT"},
     {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_BUFFERED_RECORDS),
+     "DTLS1_PROCESS_BUFFERED_RECORDS"},
     {ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE),
      "DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
     {ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD), "DTLS1_PROCESS_RECORD"},

Modified: stable/9/crypto/openssl/ssl/ssl_locl.h
==============================================================================
--- stable/9/crypto/openssl/ssl/ssl_locl.h	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/ssl_locl.h	Fri Sep 23 07:44:10 2016	(r306229)
@@ -910,7 +910,8 @@ int dtls1_retransmit_message(SSL *s, uns
                              unsigned long frag_off, int *found);
 int dtls1_get_queue_priority(unsigned short seq, int is_ccs);
 int dtls1_retransmit_buffered_messages(SSL *s);
-void dtls1_clear_record_buffer(SSL *s);
+void dtls1_clear_received_buffer(SSL *s);
+void dtls1_clear_sent_buffer(SSL *s);
 void dtls1_get_message_header(unsigned char *data,
                               struct hm_header_st *msg_hdr);
 void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
@@ -1022,7 +1023,7 @@ unsigned char *ssl_add_clienthello_tlsex
 unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p,
                                           unsigned char *limit);
 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data,
-                                 unsigned char *d, int n, int *al);
+                                 unsigned char *limit, int *al);
 int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data,
                                  unsigned char *d, int n, int *al);
 int ssl_prepare_clienthello_tlsext(SSL *s);

Modified: stable/9/crypto/openssl/ssl/ssl_sess.c
==============================================================================
--- stable/9/crypto/openssl/ssl/ssl_sess.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/ssl_sess.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -384,7 +384,7 @@ int ssl_get_prev_session(SSL *s, unsigne
     if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
         goto err;
 
-    if (session_id + len > limit) {
+    if (limit - session_id < len) {
         fatal = 1;
         goto err;
     }

Modified: stable/9/crypto/openssl/ssl/t1_lib.c
==============================================================================
--- stable/9/crypto/openssl/ssl/t1_lib.c	Fri Sep 23 07:41:23 2016	(r306228)
+++ stable/9/crypto/openssl/ssl/t1_lib.c	Fri Sep 23 07:44:10 2016	(r306229)
@@ -357,7 +357,7 @@ unsigned char *ssl_add_serverhello_tlsex
  * 10.8..10.8.3 (which don't work).
  */
 static void ssl_check_for_safari(SSL *s, const unsigned char *data,
-                                 const unsigned char *d, int n)
+                                 const unsigned char *limit)
 {
     unsigned short type, size;
     static const unsigned char kSafariExtensionsBlock[] = {
@@ -386,11 +386,11 @@ static void ssl_check_for_safari(SSL *s,
         0x02, 0x03,             /* SHA-1/ECDSA */
     };
 
-    if (data >= (d + n - 2))
+    if (limit - data <= 2)
         return;
     data += 2;
 
-    if (data > (d + n - 4))
+    if (limit - data < 4)
         return;
     n2s(data, type);
     n2s(data, size);
@@ -398,7 +398,7 @@ static void ssl_check_for_safari(SSL *s,
     if (type != TLSEXT_TYPE_server_name)
         return;
 
-    if (data + size > d + n)
+    if (limit - data < size)
         return;
     data += size;
 
@@ -406,7 +406,7 @@ static void ssl_check_for_safari(SSL *s,
         const size_t len1 = sizeof(kSafariExtensionsBlock);
         const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
 
-        if (data + len1 + len2 != d + n)
+        if (limit - data != (int)(len1 + len2))
             return;
         if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
             return;
@@ -415,7 +415,7 @@ static void ssl_check_for_safari(SSL *s,
     } else {
         const size_t len = sizeof(kSafariExtensionsBlock);
 
-        if (data + len != d + n)
+        if (limit - data != (int)(len))
             return;
         if (memcmp(data, kSafariExtensionsBlock, len) != 0)
             return;
@@ -425,8 +425,8 @@ static void ssl_check_for_safari(SSL *s,
 }
 # endif                         /* !OPENSSL_NO_EC */
 
-int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
-                                 int n, int *al)
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
+                                 unsigned char *limit, int *al)
 {
     unsigned short type;
     unsigned short size;
@@ -439,24 +439,26 @@ int ssl_parse_clienthello_tlsext(SSL *s,
 
 # ifndef OPENSSL_NO_EC
     if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
-        ssl_check_for_safari(s, data, d, n);
+        ssl_check_for_safari(s, data, limit);
 # endif                         /* !OPENSSL_NO_EC */
 
-    if (data >= (d + n - 2))
+    if (data == limit)
         goto ri_check;
 
+    if (limit - data < 2)
+        goto err;
+
     n2s(data, len);
 
-    if (data > (d + n - len))
-        goto ri_check;
+    if (limit - data != len)
+        goto err;
 
-    while (data <= (d + n - 4)) {
+    while (limit - data >= 4) {
         n2s(data, type);
         n2s(data, size);
 
-        if (data + size > (d + n))
-            goto ri_check;
-
+        if (limit - data < size)
+            goto err;
         if (s->tlsext_debug_cb)
             s->tlsext_debug_cb(s, 0, type, data, size, s->tlsext_debug_arg);
 /*-
@@ -580,6 +582,23 @@ int ssl_parse_clienthello_tlsext(SSL *s,
                     *al = SSL_AD_DECODE_ERROR;
                     return 0;
                 }
+
+                /*
+                 * We remove any OCSP_RESPIDs from a previous handshake
+                 * to prevent unbounded memory growth - CVE-2016-6304
+                 */
+                sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids,
+                                        OCSP_RESPID_free);
+                if (dsize > 0) {
+                    s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null();
+                    if (s->tlsext_ocsp_ids == NULL) {
+                        *al = SSL_AD_INTERNAL_ERROR;
+                        return 0;
+                    }
+                } else {
+                    s->tlsext_ocsp_ids = NULL;
+                }
+
                 while (dsize > 0) {
                     OCSP_RESPID *id;
                     int idsize;
@@ -606,13 +625,6 @@ int ssl_parse_clienthello_tlsext(SSL *s,
                         *al = SSL_AD_DECODE_ERROR;
                         return 0;
                     }
-                    if (!s->tlsext_ocsp_ids
-                        && !(s->tlsext_ocsp_ids =
-                             sk_OCSP_RESPID_new_null())) {
-                        OCSP_RESPID_free(id);
-                        *al = SSL_AD_INTERNAL_ERROR;
-                        return 0;
-                    }
                     if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) {
                         OCSP_RESPID_free(id);
                         *al = SSL_AD_INTERNAL_ERROR;
@@ -672,6 +684,10 @@ int ssl_parse_clienthello_tlsext(SSL *s,
     }
 
     return 1;
+
+err:
+    *al = SSL_AD_DECODE_ERROR;
+    return 0;
 }
 
 int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
@@ -684,20 +700,20 @@ int ssl_parse_serverhello_tlsext(SSL *s,
     int tlsext_servername = 0;
     int renegotiate_seen = 0;
 
-    if (data >= (d + n - 2))
+    if ((d + n) - data <= 2)
         goto ri_check;
 
     n2s(data, length);
-    if (data + length != d + n) {
+    if ((d + n) - data != length) {
         *al = SSL_AD_DECODE_ERROR;
         return 0;
     }
 
-    while (data <= (d + n - 4)) {
+    while ((d + n) - data >= 4) {
         n2s(data, type);
         n2s(data, size);
 
-        if (data + size > (d + n))
+        if ((d + n) - data < size)
             goto ri_check;
 
         if (s->tlsext_debug_cb)
@@ -960,29 +976,33 @@ int tls1_process_ticket(SSL *s, unsigned
     /* Skip past DTLS cookie */
     if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) {
         i = *(p++);
-        p += i;
-        if (p >= limit)
+
+        if (limit - p <= i)
             return -1;
+
+        p += i;
     }
     /* Skip past cipher list */
     n2s(p, i);
-    p += i;
-    if (p >= limit)
+    if (limit - p <= i)
         return -1;
+    p += i;
+
     /* Skip past compression algorithm list */
     i = *(p++);
-    p += i;
-    if (p > limit)
+    if (limit - p < i)
         return -1;
+    p += i;
+
     /* Now at start of extensions */
-    if ((p + 2) >= limit)
+    if (limit - p <= 2)
         return 1;
     n2s(p, i);
-    while ((p + 4) <= limit) {
+    while (limit - p >= 4) {
         unsigned short type, size;
         n2s(p, type);
         n2s(p, size);
-        if (p + size > limit)
+        if (limit - p < size)
             return 1;
         if (type == TLSEXT_TYPE_session_ticket) {
             /*
@@ -1012,9 +1032,7 @@ static int tls_decrypt_ticket(SSL *s, co
     HMAC_CTX hctx;
     EVP_CIPHER_CTX ctx;
     SSL_CTX *tctx = s->initial_ctx;
-    /* Need at least keyname + iv + some encrypted data */
-    if (eticklen < 48)
-        goto tickerr;
+
     /* Initialize session ticket encryption and HMAC contexts */
     HMAC_CTX_init(&hctx);
     EVP_CIPHER_CTX_init(&ctx);
@@ -1042,6 +1060,13 @@ static int tls_decrypt_ticket(SSL *s, co
      * checks on ticket.
      */
     mlen = HMAC_size(&hctx);
+    /* Sanity check ticket length: must exceed keyname + IV + HMAC */
+    if (eticklen <= 16 + EVP_CIPHER_CTX_iv_length(&ctx) + mlen) {
+        HMAC_CTX_cleanup(&hctx);
+        EVP_CIPHER_CTX_cleanup(&ctx);
+        return 2;
+    }
+
     eticklen -= mlen;
     /* Check HMAC of encrypted ticket */
     HMAC_Update(&hctx, etick, eticklen);


More information about the svn-src-stable-9 mailing list