[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Mon Dec 5 17:08:40 UTC 2016


The branch master has been updated
       via  44e58f3b7be54b0a29aad6ca26bd2ae60759d9a3 (commit)
       via  829754a62245df76584078011f045185218c60c4 (commit)
       via  88858868ab7b55d17c259f7f2d631d1d984c6139 (commit)
       via  e8eb224b8cd2b6dc29843eab01227eab00fcf774 (commit)
       via  f31d5e10058115679ba553d53bc0ee9bd17ea646 (commit)
       via  b4c6e37e7428eec3d46b6737b60df8e423d0a8df (commit)
       via  e60ce9c4513c432705c84b0efebf1421ee769eee (commit)
       via  6a149cee78dd65dea7c8b3a36cb479f79ec2b3a3 (commit)
       via  c7c42022b9283d073d355b427ebb578f4ff15eb1 (commit)
       via  3171bad66e461052e584e1628693db67b990e94e (commit)
      from  c53f7355b93885d1f12237f94b363ad747f03dad (commit)


- Log -----------------------------------------------------------------
commit 44e58f3b7be54b0a29aad6ca26bd2ae60759d9a3
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Dec 5 10:27:04 2016 +0000

    Change various repeated wr[someindex]/pkt[someindex] references to a pointer
    
    Improves the readability of the code, and reduces the liklihood of errors.
    Also made a few minor style changes.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 829754a62245df76584078011f045185218c60c4
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Dec 2 11:10:16 2016 +0000

    Various style fixes from the TLSv1.3 record changes review
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 88858868ab7b55d17c259f7f2d631d1d984c6139
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Dec 2 11:09:16 2016 +0000

    Change various repeated rr[someindex] references to a pointer
    
    Improves the readability of the code, and reduces the liklihood of errors.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit e8eb224b8cd2b6dc29843eab01227eab00fcf774
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Dec 1 10:20:59 2016 +0000

    Ensure compressdata is always initialised
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit f31d5e10058115679ba553d53bc0ee9bd17ea646
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 21 17:11:51 2016 +0000

    Add a TLS1.3 TODO for the msg callback
    
    At the moment the msg callback only received the record header with the
    outer record type in it. We never pass the inner record type - we probably
    need to at some point.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit b4c6e37e7428eec3d46b6737b60df8e423d0a8df
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 21 16:22:00 2016 +0000

    Add more TLS1.3 record tests
    
    Add some tests for the new record construction
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit e60ce9c4513c432705c84b0efebf1421ee769eee
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 18 23:44:09 2016 +0000

    Update the record layer to use TLSv1.3 style record construction
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 6a149cee78dd65dea7c8b3a36cb479f79ec2b3a3
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 18 17:06:14 2016 +0000

    Convert TLS Record receipt to use PACKET
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit c7c42022b9283d073d355b427ebb578f4ff15eb1
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 18 16:35:46 2016 +0000

    Convert TLS record construction to use WPACKET
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 3171bad66e461052e584e1628693db67b990e94e
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 18 16:34:01 2016 +0000

    Add an ability to find out the current write location from a WPACKET
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 include/openssl/ssl.h             |   1 +
 ssl/packet.c                      |   8 +-
 ssl/packet_locl.h                 |   8 +-
 ssl/record/rec_layer_s3.c         | 232 ++++++++++++++++++++++++++++----------
 ssl/record/ssl3_record.c          | 198 +++++++++++++++++++++-----------
 ssl/ssl_err.c                     |   1 +
 test/recipes/70-test_sslrecords.t |  52 ++++++++-
 test/sslcorrupttest.c             |   8 +-
 util/TLSProxy/Proxy.pm            |   2 +-
 util/TLSProxy/Record.pm           |  62 ++++++++--
 10 files changed, 429 insertions(+), 143 deletions(-)

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 8769f46..840eb6e 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2326,6 +2326,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_BAD_LENGTH                                 271
 # define SSL_R_BAD_PACKET_LENGTH                          115
 # define SSL_R_BAD_PROTOCOL_VERSION_NUMBER                116
+# define SSL_R_BAD_RECORD_TYPE                            443
 # define SSL_R_BAD_RSA_ENCRYPT                            119
 # define SSL_R_BAD_SIGNATURE                              123
 # define SSL_R_BAD_SRP_A_LENGTH                           347
diff --git a/ssl/packet.c b/ssl/packet.c
index 5c55133..12321e7 100644
--- a/ssl/packet.c
+++ b/ssl/packet.c
@@ -62,7 +62,8 @@ int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
         if (BUF_MEM_grow(pkt->buf, newlen) == 0)
             return 0;
     }
-    *allocbytes = GETBUF(pkt) + pkt->curr;
+    if (allocbytes != NULL)
+        *allocbytes = WPACKET_get_curr(pkt);
 
     return 1;
 }
@@ -376,6 +377,11 @@ int WPACKET_get_length(WPACKET *pkt, size_t *len)
     return 1;
 }
 
+unsigned char *WPACKET_get_curr(WPACKET *pkt)
+{
+    return GETBUF(pkt) + pkt->curr;
+}
+
 void WPACKET_cleanup(WPACKET *pkt)
 {
     WPACKET_SUB *sub, *parent;
diff --git a/ssl/packet_locl.h b/ssl/packet_locl.h
index 4658734..61233d9 100644
--- a/ssl/packet_locl.h
+++ b/ssl/packet_locl.h
@@ -728,7 +728,7 @@ int WPACKET_start_sub_packet(WPACKET *pkt);
 /*
  * Allocate bytes in the WPACKET for the output. This reserves the bytes
  * and counts them as "written", but doesn't actually do the writing. A pointer
- * to the allocated bytes is stored in |*allocbytes|.
+ * to the allocated bytes is stored in |*allocbytes|. |allocbytes| may be NULL.
  * WARNING: the allocated bytes must be filled in immediately, without further
  * WPACKET_* calls. If not then the underlying buffer may be realloc'd and
  * change its location.
@@ -854,6 +854,12 @@ int WPACKET_get_total_written(WPACKET *pkt, size_t *written);
  */
 int WPACKET_get_length(WPACKET *pkt, size_t *len);
 
+/*
+ * Returns a pointer to the current write location, but does not allocate any
+ * bytes.
+ */
+unsigned char *WPACKET_get_curr(WPACKET *pkt);
+
 /* Release resources in a WPACKET if a failure has occurred. */
 void WPACKET_cleanup(WPACKET *pkt);
 
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 317ee30..62bc3b0 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -633,15 +633,18 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                   size_t *pipelens, size_t numpipes,
                   int create_empty_fragment, size_t *written)
 {
-    unsigned char *outbuf[SSL_MAX_PIPELINES], *plen[SSL_MAX_PIPELINES];
+    WPACKET pkt[SSL_MAX_PIPELINES];
     SSL3_RECORD wr[SSL_MAX_PIPELINES];
+    WPACKET *thispkt;
+    SSL3_RECORD *thiswr;
+    unsigned char *recordstart;
     int i, mac_size, clear = 0;
     size_t prefix_len = 0;
-    int eivlen;
+    int eivlen = 0;
     size_t align = 0;
     SSL3_BUFFER *wb;
     SSL_SESSION *sess;
-    size_t totlen = 0;
+    size_t totlen = 0, len, wpinited = 0;
     size_t j;
 
     for (j = 0; j < numpipes; j++)
@@ -726,21 +729,42 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
         align = (size_t)SSL3_BUFFER_get_buf(wb) + 2 * SSL3_RT_HEADER_LENGTH;
         align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
 #endif
-        outbuf[0] = SSL3_BUFFER_get_buf(wb) + align;
         SSL3_BUFFER_set_offset(wb, align);
+        if (!WPACKET_init_static_len(&pkt[0], SSL3_BUFFER_get_buf(wb),
+                                     SSL3_BUFFER_get_len(wb), 0)
+                || !WPACKET_allocate_bytes(&pkt[0], align, NULL)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        wpinited = 1;
     } else if (prefix_len) {
         wb = &s->rlayer.wbuf[0];
-        outbuf[0] = SSL3_BUFFER_get_buf(wb) + SSL3_BUFFER_get_offset(wb)
-            + prefix_len;
+        if (!WPACKET_init_static_len(&pkt[0],
+                                     SSL3_BUFFER_get_buf(wb),
+                                     SSL3_BUFFER_get_len(wb), 0)
+                || !WPACKET_allocate_bytes(&pkt[0], SSL3_BUFFER_get_offset(wb)
+                                                    + prefix_len, NULL)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        wpinited = 1;
     } else {
         for (j = 0; j < numpipes; j++) {
+            thispkt = &pkt[j];
+
             wb = &s->rlayer.wbuf[j];
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
             align = (size_t)SSL3_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
             align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
 #endif
-            outbuf[j] = SSL3_BUFFER_get_buf(wb) + align;
             SSL3_BUFFER_set_offset(wb, align);
+            if (!WPACKET_init_static_len(thispkt, SSL3_BUFFER_get_buf(wb),
+                                         SSL3_BUFFER_get_len(wb), 0)
+                    || !WPACKET_allocate_bytes(thispkt, align, NULL)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            wpinited++;
         }
     }
 
@@ -752,111 +776,197 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
             eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
             if (eivlen <= 1)
                 eivlen = 0;
-        }
-        /* Need explicit part of IV for GCM mode */
-        else if (mode == EVP_CIPH_GCM_MODE)
+        } else if (mode == EVP_CIPH_GCM_MODE) {
+            /* Need explicit part of IV for GCM mode */
             eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
-        else if (mode == EVP_CIPH_CCM_MODE)
+        } else if (mode == EVP_CIPH_CCM_MODE) {
             eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
-        else
-            eivlen = 0;
-    } else
-        eivlen = 0;
+        }
+    }
 
     totlen = 0;
     /* Clear our SSL3_RECORD structures */
     memset(wr, 0, sizeof wr);
     for (j = 0; j < numpipes; j++) {
-        /* write the header */
-        *(outbuf[j]++) = type & 0xff;
-        SSL3_RECORD_set_type(&wr[j], type);
+        unsigned int version = s->version;
+        unsigned char *compressdata = NULL;
+        size_t maxcomplen;
+        unsigned int rectype;
 
-        *(outbuf[j]++) = (s->version >> 8);
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
+
+        SSL3_RECORD_set_type(thiswr, type);
+        /*
+         * In TLSv1.3, once encrypting, we always use application data for the
+         * record type
+         */
+        if (SSL_IS_TLS13(s) && s->enc_write_ctx != NULL)
+            rectype = SSL3_RT_APPLICATION_DATA;
+        else
+            rectype = type;
         /*
          * Some servers hang if initial client hello is larger than 256 bytes
          * and record version number > TLS 1.0
          */
         if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
             && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION)
-            *(outbuf[j]++) = 0x1;
-        else
-            *(outbuf[j]++) = s->version & 0xff;
+            version = TLS1_VERSION;
 
-        /* field where we are to write out packet length */
-        plen[j] = outbuf[j];
-        outbuf[j] += 2;
+        maxcomplen = pipelens[j];
+        if (s->compress != NULL)
+            pipelens[j] += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+
+        /* write the header */
+        if (!WPACKET_put_bytes_u8(thispkt, rectype)
+                || !WPACKET_put_bytes_u16(thispkt, version)
+                || !WPACKET_start_sub_packet_u16(thispkt)
+                || (eivlen > 0
+                    && !WPACKET_allocate_bytes(thispkt, eivlen, NULL))
+                || (maxcomplen > 0
+                    && !WPACKET_reserve_bytes(thispkt, maxcomplen,
+                                              &compressdata))) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
 
         /* lets setup the record stuff. */
-        SSL3_RECORD_set_data(&wr[j], outbuf[j] + eivlen);
-        SSL3_RECORD_set_length(&wr[j], pipelens[j]);
-        SSL3_RECORD_set_input(&wr[j], (unsigned char *)&buf[totlen]);
+        SSL3_RECORD_set_data(thiswr, compressdata);
+        SSL3_RECORD_set_length(thiswr, pipelens[j]);
+        SSL3_RECORD_set_input(thiswr, (unsigned char *)&buf[totlen]);
         totlen += pipelens[j];
 
         /*
-         * we now 'read' from wr->input, wr->length bytes into wr->data
+         * we now 'read' from thiswr->input, thiswr->length bytes into
+         * thiswr->data
          */
 
         /* first we compress */
         if (s->compress != NULL) {
-            if (!ssl3_do_compress(s, &wr[j])) {
+            /*
+             * TODO(TLS1.3): Make sure we prevent compression!!!
+             */
+            if (!ssl3_do_compress(s, thiswr)
+                    || !WPACKET_allocate_bytes(thispkt, thiswr->length, NULL)) {
                 SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_COMPRESSION_FAILURE);
                 goto err;
             }
         } else {
-            memcpy(wr[j].data, wr[j].input, wr[j].length);
+            if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
             SSL3_RECORD_reset_input(&wr[j]);
         }
 
+        if (SSL_IS_TLS13(s) && s->enc_write_ctx != NULL) {
+            if (!WPACKET_put_bytes_u8(thispkt, type)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL3_RECORD_add_length(thiswr, 1);
+            /*
+             * TODO(TLS1.3): Padding goes here. Do we need an API to add this?
+             * For now, use no padding
+             */
+        }
+
         /*
-         * 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
+         * we should still have the output to thiswr->data and the input from
+         * wr->input. Length should be thiswr->length. thiswr->data still points
+         * in the wb->buf
          */
 
         if (!SSL_USE_ETM(s) && mac_size != 0) {
-            if (!s->method->ssl3_enc->mac(s, &wr[j],
-                                          &(outbuf[j][wr[j].length + eivlen]),
-                                          1))
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
                 goto err;
-            SSL3_RECORD_add_length(&wr[j], mac_size);
+            }
         }
 
-        SSL3_RECORD_set_data(&wr[j], outbuf[j]);
-        SSL3_RECORD_reset_input(&wr[j]);
-
-        if (eivlen) {
-            /*
-             * if (RAND_pseudo_bytes(p, eivlen) <= 0) goto err;
-             */
-            SSL3_RECORD_add_length(&wr[j], eivlen);
+        /*
+         * Reserve some bytes for any growth that may occur during encryption.
+         * This will be at most one cipher block or the tag length if using
+         * AEAD. SSL_RT_MAX_CIPHER_BLOCK_SIZE covers either case.
+         */
+        if(!WPACKET_reserve_bytes(thispkt, SSL_RT_MAX_CIPHER_BLOCK_SIZE,
+                                  NULL)
+                   /*
+                    * We also need next the amount of bytes written to this
+                    * sub-packet
+                    */
+                || !WPACKET_get_length(thispkt, &len)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
         }
+
+        /* Get a pointer to the start of this record excluding header */
+        recordstart = WPACKET_get_curr(thispkt) - len;
+
+        SSL3_RECORD_set_data(thiswr, recordstart);
+        SSL3_RECORD_reset_input(thiswr);
+        SSL3_RECORD_set_length(thiswr, len);
     }
 
     if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1)
         goto err;
 
     for (j = 0; j < numpipes; j++) {
+        size_t origlen;
+
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
+
+        /* Allocate bytes for the encryption overhead */
+        if (!WPACKET_get_length(thispkt, &origlen)
+                   /* Encryption should never shrink the data! */
+                || origlen > thiswr->length
+                || (thiswr->length > origlen
+                    && !WPACKET_allocate_bytes(thispkt,
+                                               thiswr->length - origlen, NULL))) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
         if (SSL_USE_ETM(s) && mac_size != 0) {
-            if (!s->method->ssl3_enc->mac(s, &wr[j],
-                                          outbuf[j] + wr[j].length, 1))
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
                 goto err;
-            SSL3_RECORD_add_length(&wr[j], mac_size);
+            }
+            SSL3_RECORD_add_length(thiswr, mac_size);
         }
 
-        /* record length after mac and block padding */
-        s2n(SSL3_RECORD_get_length(&wr[j]), plen[j]);
+        if (!WPACKET_get_length(thispkt, &len)
+                || !WPACKET_close(thispkt)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
 
-        if (s->msg_callback)
-            s->msg_callback(1, 0, SSL3_RT_HEADER, plen[j] - 5, 5, s,
+        if (s->msg_callback) {
+            recordstart = WPACKET_get_curr(thispkt) - len
+                          - SSL3_RT_HEADER_LENGTH;
+            s->msg_callback(1, 0, SSL3_RT_HEADER, recordstart,
+                            SSL3_RT_HEADER_LENGTH, s,
                             s->msg_callback_arg);
+        }
+
+        if (!WPACKET_finish(thispkt)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
 
         /*
-         * we should now have wr->data pointing to the encrypted data, which is
-         * wr->length long
+         * we should now have thiswr->data pointing to the encrypted data, which
+         * is thiswr->length long
          */
-        SSL3_RECORD_set_type(&wr[j], type); /* not needed but helps for
+        SSL3_RECORD_set_type(thiswr, type); /* not needed but helps for
                                              * debugging */
-        SSL3_RECORD_add_length(&wr[j], SSL3_RT_HEADER_LENGTH);
+        SSL3_RECORD_add_length(thiswr, SSL3_RT_HEADER_LENGTH);
 
         if (create_empty_fragment) {
             /*
@@ -868,13 +978,13 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                 SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
                 goto err;
             }
-            *written = SSL3_RECORD_get_length(wr);
+            *written = SSL3_RECORD_get_length(thiswr);
             return 1;
         }
 
         /* now let's set up wb */
         SSL3_BUFFER_set_left(&s->rlayer.wbuf[j],
-                             prefix_len + SSL3_RECORD_get_length(&wr[j]));
+                             prefix_len + SSL3_RECORD_get_length(thiswr));
     }
 
     /*
@@ -889,6 +999,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
     /* we now just need to write the buffer */
     return ssl3_write_pending(s, type, buf, totlen, written);
  err:
+    for (j = 0; j < wpinited; j++)
+        WPACKET_cleanup(&pkt[j]);
     return -1;
 }
 
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index d106e38..0190ecf 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -124,19 +124,20 @@ static int ssl3_record_app_data_waiting(SSL *s)
 /* used only by ssl3_read_bytes */
 int ssl3_get_record(SSL *s)
 {
-    int ssl_major, ssl_minor, al;
+    int al;
     int enc_err, rret, ret = -1;
     int i;
     size_t more, n;
-    SSL3_RECORD *rr;
+    SSL3_RECORD *rr, *thisrr;
     SSL3_BUFFER *rbuf;
     SSL_SESSION *sess;
     unsigned char *p;
     unsigned char md[EVP_MAX_MD_SIZE];
-    short version;
+    unsigned int version;
     size_t mac_size;
     int imac_size;
     size_t num_recs = 0, max_recs, j;
+    PACKET pkt, sslv2pkt;
 
     rr = RECORD_LAYER_get_rrec(&s->rlayer);
     rbuf = RECORD_LAYER_get_rbuf(&s->rlayer);
@@ -146,10 +147,15 @@ int ssl3_get_record(SSL *s)
     sess = s->session;
 
     do {
+        thisrr = &rr[num_recs];
+
         /* check if we have the header */
         if ((RECORD_LAYER_get_rstate(&s->rlayer) != SSL_ST_READ_BODY) ||
             (RECORD_LAYER_get_packet_length(&s->rlayer)
              < SSL3_RT_HEADER_LENGTH)) {
+            size_t sslv2len;
+            unsigned int type;
+
             rret = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH,
                                SSL3_BUFFER_get_len(rbuf), 0,
                                num_recs == 0 ? 1 : 0, &n);
@@ -158,12 +164,25 @@ int ssl3_get_record(SSL *s)
             RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_BODY);
 
             p = RECORD_LAYER_get_packet(&s->rlayer);
-
+            if (!PACKET_buf_init(&pkt, RECORD_LAYER_get_packet(&s->rlayer),
+                                 RECORD_LAYER_get_packet_length(&s->rlayer))) {
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
+                goto f_err;
+            }
+            sslv2pkt = pkt;
+            if (!PACKET_get_net_2_len(&sslv2pkt, &sslv2len)
+                    || !PACKET_get_1(&sslv2pkt, &type)) {
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
+                goto f_err;
+            }
             /*
              * The first record received by the server may be a V2ClientHello.
              */
             if (s->server && RECORD_LAYER_is_first_record(&s->rlayer)
-                && (p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO)) {
+                    && (sslv2len & 0x8000) != 0
+                    && (type == SSL2_MT_CLIENT_HELLO)) {
                 /*
                  *  SSLv2 style record
                  *
@@ -173,44 +192,52 @@ int ssl3_get_record(SSL *s)
                  * because it is an SSLv2ClientHello. We keep it using
                  * |num_recs| for the sake of consistency
                  */
-                rr[num_recs].type = SSL3_RT_HANDSHAKE;
-                rr[num_recs].rec_version = SSL2_VERSION;
+                thisrr->type = SSL3_RT_HANDSHAKE;
+                thisrr->rec_version = SSL2_VERSION;
 
-                rr[num_recs].length = ((p[0] & 0x7f) << 8) | p[1];
+                thisrr->length = sslv2len & 0x7fff;
 
-                if (rr[num_recs].length > SSL3_BUFFER_get_len(rbuf)
+                if (thisrr->length > SSL3_BUFFER_get_len(rbuf)
                     - SSL2_RT_HEADER_LENGTH) {
                     al = SSL_AD_RECORD_OVERFLOW;
                     SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
                     goto f_err;
                 }
 
-                if (rr[num_recs].length < MIN_SSL2_RECORD_LEN) {
+                if (thisrr->length < MIN_SSL2_RECORD_LEN) {
                     al = SSL_AD_HANDSHAKE_FAILURE;
                     SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
                     goto f_err;
                 }
             } else {
                 /* SSLv3+ style record */
+                /*
+                 * TODO(TLS1.3): This callback only provides the "outer" record
+                 * type to the callback. Somehow we need to pass the "inner"
+                 * record type
+                 */
                 if (s->msg_callback)
                     s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s,
                                     s->msg_callback_arg);
 
                 /* Pull apart the header into the SSL3_RECORD */
-                rr[num_recs].type = *(p++);
-                ssl_major = *(p++);
-                ssl_minor = *(p++);
-                version = (ssl_major << 8) | ssl_minor;
-                rr[num_recs].rec_version = version;
-                n2s(p, rr[num_recs].length);
+                if (!PACKET_get_1(&pkt, &type)
+                        || !PACKET_get_net_2(&pkt, &version)
+                        || !PACKET_get_net_2_len(&pkt, &thisrr->length)) {
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
+                    goto f_err;
+                }
+                thisrr->type = type;
+                thisrr->rec_version = version;
 
                 /* Lets check version. In TLSv1.3 we ignore this field */
                 if (!s->first_packet && !SSL_IS_TLS13(s)
-                        && version != s->version) {
+                        && version != (unsigned int)s->version) {
                     SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
                     if ((s->version & 0xFF00) == (version & 0xFF00)
                         && !s->enc_write_ctx && !s->write_hash) {
-                        if (rr->type == SSL3_RT_ALERT) {
+                        if (thisrr->type == SSL3_RT_ALERT) {
                             /*
                              * The record is using an incorrect version number,
                              * but what we've got appears to be an alert. We
@@ -259,7 +286,14 @@ int ssl3_get_record(SSL *s)
                     }
                 }
 
-                if (rr[num_recs].length >
+                if (SSL_IS_TLS13(s) && s->enc_read_ctx != NULL
+                        && thisrr->type != SSL3_RT_APPLICATION_DATA) {
+                    SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_RECORD_TYPE);
+                    al = SSL_AD_UNEXPECTED_MESSAGE;
+                    goto f_err;
+                }
+
+                if (thisrr->length >
                     SSL3_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) {
                     al = SSL_AD_RECORD_OVERFLOW;
                     SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG);
@@ -275,11 +309,11 @@ int ssl3_get_record(SSL *s)
          * Calculate how much more data we need to read for the rest of the
          * record
          */
-        if (rr[num_recs].rec_version == SSL2_VERSION) {
-            more = rr[num_recs].length + SSL2_RT_HEADER_LENGTH
+        if (thisrr->rec_version == SSL2_VERSION) {
+            more = thisrr->length + SSL2_RT_HEADER_LENGTH
                 - SSL3_RT_HEADER_LENGTH;
         } else {
-            more = rr[num_recs].length;
+            more = thisrr->length;
         }
         if (more > 0) {
             /* now s->packet_length == SSL3_RT_HEADER_LENGTH */
@@ -293,43 +327,44 @@ int ssl3_get_record(SSL *s)
         RECORD_LAYER_set_rstate(&s->rlayer, SSL_ST_READ_HEADER);
 
         /*
-         * At this point, s->packet_length == SSL3_RT_HEADER_LENGTH + rr->length,
-         * or s->packet_length == SSL2_RT_HEADER_LENGTH + rr->length
-         * and we have that many bytes in s->packet
+         * At this point, s->packet_length == SSL3_RT_HEADER_LENGTH
+         * + thisrr->length, or s->packet_length == SSL2_RT_HEADER_LENGTH
+         * + thisrr->length and we have that many bytes in s->packet
          */
-        if (rr[num_recs].rec_version == SSL2_VERSION) {
-            rr[num_recs].input =
+        if (thisrr->rec_version == SSL2_VERSION) {
+            thisrr->input =
                 &(RECORD_LAYER_get_packet(&s->rlayer)[SSL2_RT_HEADER_LENGTH]);
         } else {
-            rr[num_recs].input =
+            thisrr->input =
                 &(RECORD_LAYER_get_packet(&s->rlayer)[SSL3_RT_HEADER_LENGTH]);
         }
 
         /*
-         * ok, we can now read from 's->packet' data into 'rr' rr->input points
-         * at rr->length bytes, which need to be copied into rr->data by either
-         * the decryption or by the decompression When the data is 'copied' into
-         * the rr->data buffer, rr->input will be pointed at the new buffer
+         * ok, we can now read from 's->packet' data into 'thisrr' thisrr->input
+         * points at thisrr->length bytes, which need to be copied into
+         * thisrr->data by either the decryption or by the decompression When
+         * the data is 'copied' into the thisrr->data buffer, thisrr->input will
+         * be pointed at the new buffer
          */
 
         /*
-         * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length
-         * bytes of encrypted compressed stuff.
+         * We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+         * thisrr->length bytes of encrypted compressed stuff.
          */
 
         /* check is not needed I believe */
-        if (rr[num_recs].length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
+        if (thisrr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
             al = SSL_AD_RECORD_OVERFLOW;
             SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
             goto f_err;
         }
 
-        /* decrypt in place in 'rr->input' */
-        rr[num_recs].data = rr[num_recs].input;
-        rr[num_recs].orig_len = rr[num_recs].length;
+        /* decrypt in place in 'thisrr->input' */
+        thisrr->data = thisrr->input;
+        thisrr->orig_len = thisrr->length;
 
         /* Mark this record as not read by upper layers yet */
-        rr[num_recs].read = 0;
+        thisrr->read = 0;
 
         num_recs++;
 
@@ -337,7 +372,7 @@ int ssl3_get_record(SSL *s)
         RECORD_LAYER_reset_packet_length(&s->rlayer);
         RECORD_LAYER_clear_first_record(&s->rlayer);
     } while (num_recs < max_recs
-             && rr[num_recs - 1].type == SSL3_RT_APPLICATION_DATA
+             && thisrr->type == SSL3_RT_APPLICATION_DATA
              && SSL_USE_EXPLICIT_IV(s)
              && s->enc_read_ctx != NULL
              && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx))
@@ -360,14 +395,16 @@ int ssl3_get_record(SSL *s)
         mac_size = (size_t)imac_size;
         OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
         for (j = 0; j < num_recs; j++) {
-            if (rr[j].length < mac_size) {
+            thisrr = &rr[j];
+
+            if (thisrr->length < mac_size) {
                 al = SSL_AD_DECODE_ERROR;
                 SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
                 goto f_err;
             }
-            rr[j].length -= mac_size;
-            mac = rr[j].data + rr[j].length;
-            i = s->method->ssl3_enc->mac(s, &rr[j], md, 0 /* not send */ );
+            thisrr->length -= mac_size;
+            mac = thisrr->data + thisrr->length;
+            i = s->method->ssl3_enc->mac(s, thisrr, md, 0 /* not send */ );
             if (i == 0 || CRYPTO_memcmp(md, mac, mac_size) != 0) {
                 al = SSL_AD_BAD_RECORD_MAC;
                 SSLerr(SSL_F_SSL3_GET_RECORD,
@@ -378,6 +415,7 @@ int ssl3_get_record(SSL *s)
     }
 
     enc_err = s->method->ssl3_enc->enc(s, rr, num_recs, 0);
+
     /*-
      * enc_err is:
      *    0: (in non-constant time) if the record is publically invalid.
@@ -390,11 +428,11 @@ int ssl3_get_record(SSL *s)
         goto f_err;
     }
 #ifdef SSL_DEBUG
-    printf("dec %"OSSLzu"\n", rr->length);
+    printf("dec %"OSSLzu"\n", rr[0].length);
     {
         size_t z;
-        for (z = 0; z < rr->length; z++)
-            printf("%02X%c", rr->data[z], ((z + 1) % 16) ? ' ' : '\n');
+        for (z = 0; z < rr[0].length; z++)
+            printf("%02X%c", rr[0].data[z], ((z + 1) % 16) ? ' ' : '\n');
     }
     printf("\n");
 #endif
@@ -411,16 +449,17 @@ int ssl3_get_record(SSL *s)
         OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
 
         for (j = 0; j < num_recs; j++) {
+            thisrr = &rr[j];
             /*
              * orig_len is the length of the record before any padding was
              * removed. This is public information, as is the MAC in use,
              * therefore we can safely process the record in a different amount
              * of time if it's too short to possibly contain a MAC.
              */
-            if (rr[j].orig_len < mac_size ||
+            if (thisrr->orig_len < mac_size ||
                 /* CBC records must have a padding length byte too. */
                 (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
-                 rr[j].orig_len < mac_size + 1)) {
+                 thisrr->orig_len < mac_size + 1)) {
                 al = SSL_AD_DECODE_ERROR;
                 SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT);
                 goto f_err;
@@ -434,23 +473,23 @@ int ssl3_get_record(SSL *s)
                  * contents of the padding bytes.
                  */
                 mac = mac_tmp;
-                ssl3_cbc_copy_mac(mac_tmp, &rr[j], mac_size);
-                rr[j].length -= mac_size;
+                ssl3_cbc_copy_mac(mac_tmp, thisrr, mac_size);
+                thisrr->length -= mac_size;
             } else {
                 /*
                  * In this case there's no padding, so |rec->orig_len| equals
                  * |rec->length| and we checked that there's enough bytes for
                  * |mac_size| above.
                  */
-                rr[j].length -= mac_size;
-                mac = &rr[j].data[rr[j].length];
+                thisrr->length -= mac_size;
+                mac = &thisrr->data[thisrr->length];
             }
 
-            i = s->method->ssl3_enc->mac(s, &rr[j], md, 0 /* not send */ );
+            i = s->method->ssl3_enc->mac(s, thisrr, md, 0 /* not send */ );
             if (i == 0 || mac == NULL
                 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
                 enc_err = -1;
-            if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
+            if (thisrr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
                 enc_err = -1;
         }
     }
@@ -470,37 +509,64 @@ int ssl3_get_record(SSL *s)
     }
 
     for (j = 0; j < num_recs; j++) {
-        /* rr[j].length is now just compressed */
+        thisrr = &rr[j];
+
+        /* thisrr->length is now just compressed */
         if (s->expand != NULL) {
-            if (rr[j].length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
+            if (thisrr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
                 al = SSL_AD_RECORD_OVERFLOW;
                 SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_COMPRESSED_LENGTH_TOO_LONG);
                 goto f_err;
             }
-            if (!ssl3_do_uncompress(s, &rr[j])) {
+            if (!ssl3_do_uncompress(s, thisrr)) {
                 al = SSL_AD_DECOMPRESSION_FAILURE;
                 SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_DECOMPRESSION);
                 goto f_err;
             }
         }
 
-        if (rr[j].length > SSL3_RT_MAX_PLAIN_LENGTH) {
+        if (SSL_IS_TLS13(s) && s->enc_read_ctx != NULL) {
+            size_t end;
+
+            if (thisrr->length == 0) {
+                al = SSL_AD_UNEXPECTED_MESSAGE;
+                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_RECORD_TYPE);
+                goto f_err;
+            }
+
+            /* Strip trailing padding */
+            for (end = thisrr->length - 1; end > 0 && thisrr->data[end] == 0;
+                 end--)
+                continue;
+
+            thisrr->length = end;
+            thisrr->type = thisrr->data[end];
+            if (thisrr->type != SSL3_RT_APPLICATION_DATA
+                    && thisrr->type != SSL3_RT_ALERT
+                    && thisrr->type != SSL3_RT_HANDSHAKE) {
+                al = SSL_AD_UNEXPECTED_MESSAGE;
+                SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_RECORD_TYPE);
+                goto f_err;
+            }
+        }
+
+        if (thisrr->length > SSL3_RT_MAX_PLAIN_LENGTH) {
             al = SSL_AD_RECORD_OVERFLOW;
             SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_DATA_LENGTH_TOO_LONG);
             goto f_err;
         }
 
-        rr[j].off = 0;
+        thisrr->off = 0;
         /*-
          * So at this point the following is true
-         * rr[j].type   is the type of record
-         * rr[j].length == number of bytes in record
-         * rr[j].off    == offset to first valid byte
-         * rr[j].data   == where to take bytes from, increment after use :-).
+         * thisrr->type   is the type of record
+         * thisrr->length == number of bytes in record
+         * thisrr->off    == offset to first valid byte
+         * thisrr->data   == where to take bytes from, increment after use :-).
          */
 
         /* just read a 0 length packet */
-        if (rr[j].length == 0) {
+        if (thisrr->length == 0) {
             RECORD_LAYER_inc_empty_record_count(&s->rlayer);
             if (RECORD_LAYER_get_empty_record_count(&s->rlayer)
                 > MAX_EMPTY_RECORDS) {
@@ -553,7 +619,7 @@ int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr)
 
     /* TODO(size_t): Convert this call */
     i = COMP_compress_block(ssl->compress, wr->data,
-                            SSL3_RT_MAX_COMPRESSED_LENGTH,
+                            (int)(wr->length + SSL3_RT_MAX_COMPRESSED_OVERHEAD),
                             wr->input, (int)wr->length);
     if (i < 0)
         return (0);
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 49a9d44..5c8e9d4 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -357,6 +357,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_BAD_PACKET_LENGTH), "bad packet length"},
     {ERR_REASON(SSL_R_BAD_PROTOCOL_VERSION_NUMBER),
      "bad protocol version number"},
+    {ERR_REASON(SSL_R_BAD_RECORD_TYPE), "bad record type"},
     {ERR_REASON(SSL_R_BAD_RSA_ENCRYPT), "bad rsa encrypt"},
     {ERR_REASON(SSL_R_BAD_SIGNATURE), "bad signature"},
     {ERR_REASON(SSL_R_BAD_SRP_A_LENGTH), "bad srp a length"},
diff --git a/test/recipes/70-test_sslrecords.t b/test/recipes/70-test_sslrecords.t
index e6f7a36..f699058 100644
--- a/test/recipes/70-test_sslrecords.t
+++ b/test/recipes/70-test_sslrecords.t
@@ -44,7 +44,7 @@ if (!disabled("tls1_1")) {
     $num_tests++;
 }
 if (!disabled("tls1_3")) {
-    $num_tests++;
+    $num_tests += 3;
 }
 plan tests => $num_tests;
 ok(TLSProxy::Message->fail(), "Out of context empty records test");
@@ -148,13 +148,28 @@ $proxy->filter(\&change_version);
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Changed record version in TLS1.2");
 
-#Test 13: Sending a different record version in TLS1.3 should succeed
+#TLS1.3 specific tests
 if (!disabled("tls1_3")) {
+    #Test 13: Sending a different record version in TLS1.3 should succeed
     $proxy->clear();
     $proxy->filter(\&change_version);
     $proxy->start();
     ok(TLSProxy::Message->success(), "Changed record version in TLS1.3");
-}
+
+    #Test 14: Sending an unrecognised record type in TLS1.3 should fail
+    $proxy->clear();
+    $proxy->filter(\&add_unknown_record_type);
+    $proxy->start();
+    ok(TLSProxy::Message->fail(), "Unrecognised record type in TLS1.3");
+
+    #Test 15: Sending an outer record type other than app data once encrypted
+    #should fail
+    $proxy->clear();
+    $proxy->filter(\&change_outer_record_type);
+    $proxy->start();
+    ok(TLSProxy::Message->fail(), "Wrong outer record type in TLS1.3");
+ }
+
 
 sub add_empty_recs_filter
 {
@@ -388,13 +403,13 @@ sub add_unknown_record_type
     my $proxy = shift;
 
     # We'll change a record after the initial version neg has taken place
-    if ($proxy->flight != 2) {
+    if ($proxy->flight != 1) {
         return;
     }
 
     my $lastrec = ${$proxy->record_list}[-1];
     my $record = TLSProxy::Record->new(
-        2,
+        1,
         TLSProxy::Record::RT_UNKNOWN,
         $lastrec->version(),
         1,
@@ -405,7 +420,14 @@ sub add_unknown_record_type
         "X"
     );
 
-    unshift @{$proxy->record_list}, $record;
+    #Find ServerHello record and insert after that
+    my $i;
+    for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
+        next;
+    }
+    $i++;
+
+    splice @{$proxy->record_list}, $i, 0, $record;
 }
 
 sub change_version
@@ -419,3 +441,21 @@ sub change_version
 
     (${$proxy->record_list}[-1])->version(TLSProxy::Record::VERS_TLS_1_1);
 }
+
+sub change_outer_record_type
+{
+    my $proxy = shift;
+
+    # We'll change a record after the initial version neg has taken place
+    if ($proxy->flight != 1) {
+        return;
+    }
+
+    #Find ServerHello record and change record after that
+    my $i;
+    for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
+        next;
+    }
+    $i++;
+    ${$proxy->record_list}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE);
+}
diff --git a/test/sslcorrupttest.c b/test/sslcorrupttest.c
index f07cfce..c1f074b 100644
--- a/test/sslcorrupttest.c
+++ b/test/sslcorrupttest.c
@@ -11,6 +11,8 @@
 #include "ssltestlib.h"
 #include "testutil.h"
 
+static int docorrupt = 0;
+
 static void copy_flags(BIO *bio)
 {
     int flags;
@@ -38,7 +40,7 @@ static int tls_corrupt_write(BIO *bio, const char *in, int inl)
     BIO *next = BIO_next(bio);
     char *copy;
 
-    if (in[0] == SSL3_RT_APPLICATION_DATA) {
+    if (docorrupt) {
         copy = BUF_memdup(in, inl);
         TEST_check(copy != NULL);
         /* corrupt last bit of application data */
@@ -186,6 +188,8 @@ static int test_ssl_corrupt(int testidx)
     STACK_OF(SSL_CIPHER) *ciphers;
     const SSL_CIPHER *currcipher;
 
+    docorrupt = 0;
+
     printf("Starting Test %d, %s\n", testidx, cipher_list[testidx]);
 
     if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
@@ -242,6 +246,8 @@ static int test_ssl_corrupt(int testidx)
         goto end;
     }
 
+    docorrupt = 1;
+
     if (SSL_write(client, junk, sizeof(junk)) < 0) {
         printf("Unable to SSL_write\n");
         ERR_print_errors_fp(stdout);
diff --git a/util/TLSProxy/Proxy.pm b/util/TLSProxy/Proxy.pm
index be9f8f8..ccfc5c9 100644
--- a/util/TLSProxy/Proxy.pm
+++ b/util/TLSProxy/Proxy.pm
@@ -343,7 +343,7 @@ sub process_packet
         if ($record->flight != $self->flight) {
             next;
         }
-        $packet .= $record->reconstruct_record();
+        $packet .= $record->reconstruct_record($server);
     }
 
     $self->{flight} = $self->{flight} + 1;
diff --git a/util/TLSProxy/Record.pm b/util/TLSProxy/Record.pm
index 5a35925..202c1ec 100644
--- a/util/TLSProxy/Record.pm
+++ b/util/TLSProxy/Record.pm
@@ -116,6 +116,12 @@ sub get_records
                 } else {
                     $record->decrypt();
                 }
+                $record->encrypted(1);
+            }
+
+            if (TLSProxy::Proxy->is_tls13()) {
+                print "  Inner content type: "
+                      .$record_type{$record->content_type()}."\n";
             }
 
             push @record_list, $record;
@@ -188,7 +194,9 @@ sub new
         decrypt_len => $decrypt_len,
         data => $data,
         decrypt_data => $decrypt_data,
-        orig_decrypt_data => $decrypt_data
+        orig_decrypt_data => $decrypt_data,
+        encrypted => 0,
+        outer_content_type => RT_APPLICATION_DATA
     };
 
     return bless $self, $class;
@@ -257,6 +265,13 @@ sub decrypt()
     #Throw away the MAC or TAG
     $data = substr($data, 0, length($data) - $mactaglen);
 
+    if (TLSProxy::Proxy->is_tls13()) {
+        #Get the content type
+        my $content_type = unpack("C", substr($data, length($data) - 1));
+        $self->content_type($content_type);
+        $data = substr($data, 0, length($data) - 1);
+    }
+
     $self->decrypt_data($data);
     $self->decrypt_len(length($data));
 
@@ -267,15 +282,29 @@ sub decrypt()
 sub reconstruct_record
 {
     my $self = shift;
+    my $server = shift;
     my $data;
+    my $tls13_enc = 0;
 
     if ($self->sslv2) {
         $data = pack('n', $self->len | 0x8000);
     } else {
-        $data = pack('Cnn', $self->content_type, $self->version, $self->len);
+        if (TLSProxy::Proxy->is_tls13() && $self->encrypted) {
+            $data = pack('Cnn', $self->outer_content_type, $self->version,
+                         $self->len + 1);
+            $tls13_enc = 1;
+        } else {
+            $data = pack('Cnn', $self->content_type, $self->version,
+                         $self->len);
+        }
+
     }
     $data .= $self->data;
 
+    if ($tls13_enc) {
+        $data .= pack('C', $self->content_type);
+    }
+
     return $data;
 }
 
@@ -285,11 +314,6 @@ sub flight
     my $self = shift;
     return $self->{flight};
 }
-sub content_type
-{
-    my $self = shift;
-    return $self->{content_type};
-}
 sub sslv2
 {
     my $self = shift;
@@ -347,4 +371,28 @@ sub version
     }
     return $self->{version};
 }
+sub content_type
+{
+    my $self = shift;
+    if (@_) {
+      $self->{content_type} = shift;
+    }
+    return $self->{content_type};
+}
+sub encrypted
+{
+    my $self = shift;
+    if (@_) {
+      $self->{encrypted} = shift;
+    }
+    return $self->{encrypted};
+}
+sub outer_content_type
+{
+    my $self = shift;
+    if (@_) {
+      $self->{outer_content_type} = shift;
+    }
+    return $self->{outer_content_type};
+}
 1;


More information about the openssl-commits mailing list