Convert the legacy TLS stack to tls_content.
authorjsing <jsing@openbsd.org>
Fri, 11 Nov 2022 17:15:26 +0000 (17:15 +0000)
committerjsing <jsing@openbsd.org>
Fri, 11 Nov 2022 17:15:26 +0000 (17:15 +0000)
This converts the legacy TLS stack to tls_content - records are now
opened into a tls_content structure, rather than being written back into
the same buffer that the sealed record was read into.

This will allow for further clean up of the legacy record layer.

ok tb@

lib/libssl/d1_lib.c
lib/libssl/d1_pkt.c
lib/libssl/dtls_locl.h
lib/libssl/s3_lib.c
lib/libssl/ssl_locl.h
lib/libssl/ssl_pkt.c
lib/libssl/tls12_record_layer.c
lib/libssl/tls13_record_layer.c
lib/libssl/tls_content.c
lib/libssl/tls_content.h

index cf4c510..fe51769 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: d1_lib.c,v 1.62 2022/10/02 16:36:41 jsing Exp $ */
+/* $OpenBSD: d1_lib.c,v 1.63 2022/11/11 17:15:26 jsing Exp $ */
 /*
  * DTLS implementation written by Nagendra Modadugu
  * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
@@ -104,6 +104,23 @@ dtls1_new(SSL *s)
        return (0);
 }
 
+static void
+dtls1_drain_rcontents(pqueue queue)
+{
+       DTLS1_RCONTENT_DATA_INTERNAL *rdata;
+       pitem *item;
+
+       if (queue == NULL)
+               return;
+
+       while ((item = pqueue_pop(queue)) != NULL) {
+               rdata = (DTLS1_RCONTENT_DATA_INTERNAL *)item->data;
+               tls_content_free(rdata->rcontent);
+               free(item->data);
+               pitem_free(item);
+       }
+}
+
 static void
 dtls1_drain_records(pqueue queue)
 {
@@ -141,7 +158,7 @@ dtls1_clear_queues(SSL *s)
        dtls1_drain_records(s->d1->unprocessed_rcds.q);
        dtls1_drain_fragments(s->d1->buffered_messages);
        dtls1_drain_fragments(s->d1->sent_messages);
-       dtls1_drain_records(s->d1->buffered_app_data.q);
+       dtls1_drain_rcontents(s->d1->buffered_app_data.q);
 }
 
 void
index 1431434..35d5d8e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: d1_pkt.c,v 1.124 2022/10/02 16:36:41 jsing Exp $ */
+/* $OpenBSD: d1_pkt.c,v 1.125 2022/11/11 17:15:26 jsing Exp $ */
 /*
  * DTLS implementation written by Nagendra Modadugu
  * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
 
 #include <endian.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 
 #include <openssl/buffer.h>
 #include "dtls_locl.h"
 #include "pqueue.h"
 #include "ssl_locl.h"
+#include "tls_content.h"
 
 /* mod 128 saturating subtract of two 64-bit values in big-endian order */
 static int
@@ -247,6 +249,44 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority)
        return (-1);
 }
 
+static int
+dtls1_buffer_rcontent(SSL *s, rcontent_pqueue *queue, unsigned char *priority)
+{
+       DTLS1_RCONTENT_DATA_INTERNAL *rdata;
+       pitem *item;
+
+       /* Limit the size of the queue to prevent DOS attacks */
+       if (pqueue_size(queue->q) >= 100)
+               return 0;
+
+       rdata = malloc(sizeof(DTLS1_RCONTENT_DATA_INTERNAL));
+       item = pitem_new(priority, rdata);
+       if (rdata == NULL || item == NULL)
+               goto init_err;
+
+       rdata->rcontent = s->s3->rcontent;
+       s->s3->rcontent = NULL;
+
+       item->data = rdata;
+
+       /* insert should not fail, since duplicates are dropped */
+       if (pqueue_insert(queue->q, item) == NULL)
+               goto err;
+
+       if ((s->s3->rcontent = tls_content_new()) == NULL)
+               goto err;
+
+       return (1);
+
+ err:
+       tls_content_free(rdata->rcontent);
+
+ init_err:
+       SSLerror(s, ERR_R_INTERNAL_ERROR);
+       free(rdata);
+       pitem_free(item);
+       return (-1);
+}
 
 static int
 dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
@@ -266,6 +306,29 @@ dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
        return (0);
 }
 
+static int
+dtls1_retrieve_buffered_rcontent(SSL *s, rcontent_pqueue *queue)
+{
+       DTLS1_RCONTENT_DATA_INTERNAL *rdata;
+       pitem *item;
+
+       item = pqueue_pop(queue->q);
+       if (item) {
+               rdata = item->data;
+
+               tls_content_free(s->s3->rcontent);
+               s->s3->rcontent = rdata->rcontent;
+               s->s3->rrec.epoch = tls_content_epoch(s->s3->rcontent);
+
+               free(item->data);
+               pitem_free(item);
+
+               return (1);
+       }
+
+       return (0);
+}
+
 static int
 dtls1_process_buffered_record(SSL *s)
 {
@@ -295,13 +358,11 @@ dtls1_process_record(SSL *s)
 {
        SSL3_RECORD_INTERNAL *rr = &(s->s3->rrec);
        uint8_t alert_desc;
-       uint8_t *out;
-       size_t out_len;
 
        tls12_record_layer_set_version(s->rl, s->version);
 
-       if (!tls12_record_layer_open_record(s->rl, s->packet,
-           s->packet_length, &out, &out_len)) {
+       if (!tls12_record_layer_open_record(s->rl, s->packet, s->packet_length,
+           s->s3->rcontent)) {
                tls12_record_layer_alert(s->rl, &alert_desc);
 
                if (alert_desc == 0)
@@ -311,10 +372,8 @@ dtls1_process_record(SSL *s)
                 * DTLS should silently discard invalid records, including those
                 * with a bad MAC, as per RFC 6347 section 4.1.2.1.
                 */
-               if (alert_desc == SSL_AD_BAD_RECORD_MAC) {
-                       out_len = 0;
+               if (alert_desc == SSL_AD_BAD_RECORD_MAC)
                        goto done;
-               }
 
                if (alert_desc == SSL_AD_RECORD_OVERFLOW)
                        SSLerror(s, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
@@ -322,11 +381,10 @@ dtls1_process_record(SSL *s)
                goto fatal_err;
        }
 
- done:
-       rr->data = out;
-       rr->length = out_len;
-       rr->off = 0;
+       /* XXX move to record layer. */
+       tls_content_set_epoch(s->s3->rcontent, rr->epoch);
 
+ done:
        s->packet_length = 0;
 
        return (1);
@@ -485,7 +543,6 @@ dtls1_get_record(SSL *s)
 static int
 dtls1_read_handshake_unexpected(SSL *s)
 {
-       SSL3_RECORD_INTERNAL *rr = &s->s3->rrec;
        struct hm_header_st hs_msg_hdr;
        CBS cbs;
        int ret;
@@ -495,19 +552,16 @@ dtls1_read_handshake_unexpected(SSL *s)
                return -1;
        }
 
-       if (rr->off != 0) {
-               SSLerror(s, ERR_R_INTERNAL_ERROR);
-               return -1;
-       }
-
        /* Parse handshake message header. */
-       CBS_init(&cbs, rr->data, rr->length);
+       CBS_dup(&cbs, tls_content_cbs(s->s3->rcontent));
        if (!dtls1_get_message_header(&cbs, &hs_msg_hdr))
                return -1; /* XXX - probably should drop/continue. */
 
        /* This may just be a stale retransmit. */
-       if (rr->epoch != tls12_record_layer_read_epoch(s->rl)) {
-               rr->length = 0;
+       if (tls_content_epoch(s->s3->rcontent) !=
+           tls12_record_layer_read_epoch(s->rl)) {
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
                return 1;
        }
 
@@ -532,10 +586,11 @@ dtls1_read_handshake_unexpected(SSL *s)
                        return -1;
                }
 
-               ssl_msg_callback(s, 0, SSL3_RT_HANDSHAKE, rr->data,
-                   DTLS1_HM_HEADER_LENGTH);
+               ssl_msg_callback_cbs(s, 0, SSL3_RT_HANDSHAKE,
+                   tls_content_cbs(s->s3->rcontent));
 
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
 
                /*
                 * It should be impossible to hit this, but keep the safety
@@ -624,7 +679,8 @@ dtls1_read_handshake_unexpected(SSL *s)
 
                dtls1_retransmit_buffered_messages(s);
 
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
 
                return 1;
 
@@ -685,9 +741,8 @@ dtls1_read_handshake_unexpected(SSL *s)
 int
 dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 {
-       SSL3_RECORD_INTERNAL *rr;
        int rrcount = 0;
-       unsigned int n;
+       ssize_t ssret;
        int ret;
 
        if (s->s3->rbuf.buf == NULL) {
@@ -695,6 +750,11 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
                        return -1;
        }
 
+       if (s->s3->rcontent == NULL) {
+               if ((s->s3->rcontent = tls_content_new()) == NULL)
+                       return -1;
+       }
+
        if (len < 0) {
                SSLerror(s, ERR_R_INTERNAL_ERROR);
                return -1;
@@ -735,19 +795,18 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
        s->rwstate = SSL_NOTHING;
 
-       rr = &s->s3->rrec;
-
        /*
         * We are not handshaking and have no data yet, so process data buffered
         * during the last handshake in advance, if any.
         */
-       if (s->s3->hs.state == SSL_ST_OK && rr->length == 0)
-               dtls1_retrieve_buffered_record(s, &s->d1->buffered_app_data);
+       if (s->s3->hs.state == SSL_ST_OK &&
+           tls_content_remaining(s->s3->rcontent) == 0)
+               dtls1_retrieve_buffered_rcontent(s, &s->d1->buffered_app_data);
 
        if (dtls1_handle_timeout(s) > 0)
                goto start;
 
-       if (rr->length == 0 || s->rstate == SSL_ST_READ_BODY) {
+       if (tls_content_remaining(s->s3->rcontent) == 0) {
                if ((ret = dtls1_get_record(s)) <= 0) {
                        /* Anything other than a timeout is an error. */
                        if ((ret = dtls1_read_failed(s, ret)) <= 0)
@@ -756,26 +815,30 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
                }
        }
 
-       if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE) {
-               rr->length = 0;
+       if (s->d1->listen &&
+           tls_content_type(s->s3->rcontent) != SSL3_RT_HANDSHAKE) {
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
                goto start;
        }
 
        /* We now have a packet which can be read and processed. */
 
-       if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE) {
+       if (s->s3->change_cipher_spec &&
+           tls_content_type(s->s3->rcontent) != SSL3_RT_HANDSHAKE) {
                /*
                 * We now have application data between CCS and Finished.
                 * Most likely the packets were reordered on their way, so
                 * buffer the application data for later processing rather
                 * than dropping the connection.
                 */
-               if (dtls1_buffer_record(s, &s->d1->buffered_app_data,
-                   rr->seq_num) < 0) {
+               if (dtls1_buffer_rcontent(s, &s->d1->buffered_app_data,
+                   s->s3->rrec.seq_num) < 0) {
                        SSLerror(s, ERR_R_INTERNAL_ERROR);
                        return (-1);
                }
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
                goto start;
        }
 
@@ -785,12 +848,13 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
         */
        if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
                s->rwstate = SSL_NOTHING;
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
                return 0;
        }
 
        /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
-       if (type == rr->type) {
+       if (tls_content_type(s->s3->rcontent) == type) {
                /*
                 * Make sure that we are not getting application data when we
                 * are doing a handshake for the first time.
@@ -806,31 +870,23 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
                if (len <= 0)
                        return len;
 
-               if ((unsigned int)len > rr->length)
-                       n = rr->length;
-               else
-                       n = (unsigned int)len;
-
-               memcpy(buf, &rr->data[rr->off], n);
-               if (!peek) {
-                       memset(&rr->data[rr->off], 0, n);
-                       rr->length -= n;
-                       rr->off += n;
-                       if (rr->length == 0) {
-                               s->rstate = SSL_ST_READ_HEADER;
-                               rr->off = 0;
-                       }
+               if (peek) {
+                       ssret = tls_content_peek(s->s3->rcontent, buf, len);
+               } else {
+                       ssret = tls_content_read(s->s3->rcontent, buf, len);
                }
+               if (ssret < INT_MIN || ssret > INT_MAX)
+                       return -1;
+               if (ssret < 0)
+                       return (int)ssret;
 
-               return n;
-       }
+               if (tls_content_remaining(s->s3->rcontent) == 0)
+                       s->rstate = SSL_ST_READ_HEADER;
 
-       /*
-        * If we get here, then type != rr->type; if we have a handshake
-        * message, then it was unexpected (Hello Request or Client Hello).
-        */
+               return (int)ssret;
+       }
 
-       if (rr->type == SSL3_RT_ALERT) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_ALERT) {
                if ((ret = ssl3_read_alert(s)) <= 0)
                        return ret;
                goto start;
@@ -838,11 +894,12 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
        if (s->shutdown & SSL_SENT_SHUTDOWN) {
                s->rwstate = SSL_NOTHING;
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
                return (0);
        }
 
-       if (rr->type == SSL3_RT_APPLICATION_DATA) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_APPLICATION_DATA) {
                /*
                 * At this point, we were expecting handshake data, but have
                 * application data. If the library was running inside
@@ -868,13 +925,13 @@ dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
                }
        }
 
-       if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_CHANGE_CIPHER_SPEC) {
                if ((ret = ssl3_read_change_cipher_spec(s)) <= 0)
                        return ret;
                goto start;
        }
 
-       if (rr->type == SSL3_RT_HANDSHAKE) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_HANDSHAKE) {
                if ((ret = dtls1_read_handshake_unexpected(s)) <= 0)
                        return ret;
                goto start;
@@ -891,8 +948,7 @@ dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
 {
        int i;
 
-       if (SSL_in_init(s) && !s->in_handshake)
-       {
+       if (SSL_in_init(s) && !s->in_handshake) {
                i = s->handshake_func(s);
                if (i < 0)
                        return (i);
index da5c259..784d397 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: dtls_locl.h,v 1.10 2021/10/23 13:45:44 jsing Exp $ */
+/* $OpenBSD: dtls_locl.h,v 1.11 2022/11/11 17:15:26 jsing Exp $ */
 /*
  * DTLS implementation written by Nagendra Modadugu
  * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
@@ -65,6 +65,7 @@
 #include <openssl/dtls1.h>
 
 #include "ssl_locl.h"
+#include "tls_content.h"
 
 __BEGIN_HIDDEN_DECLS
 
@@ -109,6 +110,11 @@ typedef struct record_pqueue_st {
        struct _pqueue *q;
 } record_pqueue;
 
+typedef struct rcontent_pqueue_st {
+       unsigned short epoch;
+       struct _pqueue *q;
+} rcontent_pqueue;
+
 typedef struct hm_fragment_st {
        struct hm_header_st msg_header;
        unsigned char *fragment;
@@ -122,6 +128,10 @@ typedef struct dtls1_record_data_internal_st {
        SSL3_RECORD_INTERNAL rrec;
 } DTLS1_RECORD_DATA_INTERNAL;
 
+typedef struct dtls1_rcontent_data_internal_st {
+       struct tls_content *rcontent;
+} DTLS1_RCONTENT_DATA_INTERNAL;
+
 struct dtls1_state_st {
        /* Buffered (sent) handshake records */
        struct _pqueue *sent_messages;
@@ -160,7 +170,7 @@ struct dtls1_state_st {
         * to prevent either protocol violation or
         * unnecessary message loss.
         */
-       record_pqueue buffered_app_data;
+       rcontent_pqueue buffered_app_data;
 
        /* Is set when listening for new connections with dtls1_listen() */
        unsigned int listen;
index 68c6fc6..8709206 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: s3_lib.c,v 1.240 2022/11/10 18:06:37 jsing Exp $ */
+/* $OpenBSD: s3_lib.c,v 1.241 2022/11/11 17:15:26 jsing Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
 #include "ssl_locl.h"
 #include "ssl_sigalgs.h"
 #include "ssl_tlsext.h"
+#include "tls_content.h"
 
 #define SSL3_NUM_CIPHERS       (sizeof(ssl3_ciphers) / sizeof(SSL_CIPHER))
 
@@ -1441,11 +1442,12 @@ ssl3_cipher_get_value(const SSL_CIPHER *c)
 int
 ssl3_pending(const SSL *s)
 {
-       if (s->rstate == SSL_ST_READ_BODY)
+       if (s->s3->rcontent == NULL)
+               return 0;
+       if (tls_content_type(s->s3->rcontent) != SSL3_RT_APPLICATION_DATA)
                return 0;
 
-       return (s->s3->rrec.type == SSL3_RT_APPLICATION_DATA) ?
-           s->s3->rrec.length : 0;
+       return tls_content_remaining(s->s3->rcontent);
 }
 
 int
@@ -1560,6 +1562,8 @@ ssl3_free(SSL *s)
        ssl3_release_read_buffer(s);
        ssl3_release_write_buffer(s);
 
+       tls_content_free(s->s3->rcontent);
+
        tls_buffer_free(s->s3->alert_fragment);
        tls_buffer_free(s->s3->handshake_fragment);
 
@@ -1637,6 +1641,9 @@ ssl3_clear(SSL *s)
        rlen = s->s3->rbuf.len;
        wlen = s->s3->wbuf.len;
 
+       tls_content_free(s->s3->rcontent);
+       s->s3->rcontent = NULL;
+
        tls1_transcript_free(s);
        tls1_transcript_hash_free(s);
 
index 69546c0..8387513 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_locl.h,v 1.431 2022/11/10 18:06:37 jsing Exp $ */
+/* $OpenBSD: ssl_locl.h,v 1.432 2022/11/11 17:15:26 jsing Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
 #include <openssl/stack.h>
 
 #include "bytestring.h"
+#include "tls_content.h"
 #include "tls13_internal.h"
 
 __BEGIN_HIDDEN_DECLS
@@ -706,7 +707,7 @@ int tls12_record_layer_change_read_cipher_state(struct tls12_record_layer *rl,
 int tls12_record_layer_change_write_cipher_state(struct tls12_record_layer *rl,
     CBS *mac_key, CBS *key, CBS *iv);
 int tls12_record_layer_open_record(struct tls12_record_layer *rl,
-    uint8_t *buf, size_t buf_len, uint8_t **out, size_t *out_len);
+    uint8_t *buf, size_t buf_len, struct tls_content *out);
 int tls12_record_layer_seal_record(struct tls12_record_layer *rl,
     uint8_t content_type, const uint8_t *content, size_t content_len,
     CBB *out);
@@ -1157,6 +1158,10 @@ typedef struct ssl3_state_st {
        SSL3_BUFFER_INTERNAL rbuf;      /* read IO goes into here */
        SSL3_BUFFER_INTERNAL wbuf;      /* write IO goes into here */
 
+       SSL3_RECORD_INTERNAL rrec;      /* each decoded record goes in here */
+
+       struct tls_content *rcontent;   /* Content from opened TLS records. */
+
        /* we allow one fatal and one warning alert to be outstanding,
         * send close alert via the warning alert */
        int alert_dispatch;
@@ -1166,8 +1171,6 @@ typedef struct ssl3_state_st {
        int need_empty_fragments;
        int empty_fragment_done;
 
-       SSL3_RECORD_INTERNAL rrec;      /* each decoded record goes in here */
-
        /* Unprocessed Alert/Handshake protocol data. */
        struct tls_buffer *alert_fragment;
        struct tls_buffer *handshake_fragment;
index 58d3ee1..4d79981 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_pkt.c,v 1.63 2022/11/10 18:06:37 jsing Exp $ */
+/* $OpenBSD: ssl_pkt.c,v 1.64 2022/11/11 17:15:26 jsing Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
  */
 
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 
 #include <openssl/buffer.h>
 #include "bytestring.h"
 #include "dtls_locl.h"
 #include "ssl_locl.h"
+#include "tls_content.h"
 
 static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
     unsigned int len);
@@ -333,8 +335,6 @@ ssl3_get_record(SSL *s)
        SSL3_BUFFER_INTERNAL *rb = &(s->s3->rbuf);
        SSL3_RECORD_INTERNAL *rr = &(s->s3->rrec);
        uint8_t alert_desc;
-       uint8_t *out;
-       size_t out_len;
        int al, n;
        int ret = -1;
 
@@ -410,8 +410,8 @@ ssl3_get_record(SSL *s)
         */
        tls12_record_layer_set_version(s->rl, s->version);
 
-       if (!tls12_record_layer_open_record(s->rl, s->packet,
-           s->packet_length, &out, &out_len)) {
+       if (!tls12_record_layer_open_record(s->rl, s->packet, s->packet_length,
+           s->s3->rcontent)) {
                tls12_record_layer_alert(s->rl, &alert_desc);
 
                if (alert_desc == 0)
@@ -426,14 +426,10 @@ ssl3_get_record(SSL *s)
                goto fatal_err;
        }
 
-       rr->data = out;
-       rr->length = out_len;
-       rr->off = 0;
-
        /* we have pulled in a full packet so zero things */
        s->packet_length = 0;
 
-       if (rr->length == 0) {
+       if (tls_content_remaining(s->s3->rcontent) == 0) {
                /*
                 * Zero-length fragments are only permitted for application
                 * data, as per RFC 5246 section 6.2.1.
@@ -444,6 +440,8 @@ ssl3_get_record(SSL *s)
                        goto fatal_err;
                }
 
+               tls_content_clear(s->s3->rcontent);
+
                /*
                 * CBC countermeasures for known IV weaknesses can legitimately
                 * insert a single empty record, so we allow ourselves to read
@@ -691,20 +689,9 @@ ssl3_write_pending(SSL *s, int type, const unsigned char *buf, unsigned int len)
 static ssize_t
 ssl3_read_cb(void *buf, size_t n, void *cb_arg)
 {
-       SSL3_RECORD_INTERNAL *rr;
        SSL *s = cb_arg;
 
-       rr = &s->s3->rrec;
-
-       if (n > rr->length)
-               n = rr->length;
-
-       memcpy(buf, &rr->data[rr->off], n);
-
-       rr->off += n;
-       rr->length -= n;
-
-       return n;
+       return tls_content_read(s->s3->rcontent, buf, n);
 }
 
 #define SSL3_ALERT_LENGTH      2
@@ -791,21 +778,18 @@ ssl3_read_alert(SSL *s)
 int
 ssl3_read_change_cipher_spec(SSL *s)
 {
-       SSL3_RECORD_INTERNAL *rr = &s->s3->rrec;
-       const uint8_t ccs[] = { SSL3_MT_CCS };
-       CBS cbs;
+       const uint8_t ccs[1] = { SSL3_MT_CCS };
 
        /*
         * 'Change Cipher Spec' is just a single byte, so we know exactly what
         * the record payload has to look like.
         */
-       CBS_init(&cbs, rr->data, rr->length);
-       if (rr->off != 0 || CBS_len(&cbs) != sizeof(ccs)) {
+       if (tls_content_remaining(s->s3->rcontent) != sizeof(ccs)) {
                SSLerror(s, SSL_R_BAD_CHANGE_CIPHER_SPEC);
                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
                return -1;
        }
-       if (!CBS_mem_equal(&cbs, ccs, sizeof(ccs))) {
+       if (!tls_content_equal(s->s3->rcontent, ccs, sizeof(ccs))) {
                SSLerror(s, SSL_R_BAD_CHANGE_CIPHER_SPEC);
                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
                return -1;
@@ -813,7 +797,8 @@ ssl3_read_change_cipher_spec(SSL *s)
 
        /* XDTLS: check that epoch is consistent */
 
-       ssl_msg_callback_cbs(s, 0, SSL3_RT_CHANGE_CIPHER_SPEC, &cbs);
+       ssl_msg_callback_cbs(s, 0, SSL3_RT_CHANGE_CIPHER_SPEC,
+           tls_content_cbs(s->s3->rcontent));
 
        /* Check that we have a cipher to change to. */
        if (s->s3->hs.cipher == NULL) {
@@ -830,7 +815,7 @@ ssl3_read_change_cipher_spec(SSL *s)
                         * handshake messages are still missing, so just
                         * drop it.
                         */
-                       rr->length = 0;
+                       tls_content_clear(s->s3->rcontent);
                        return 1;
                }
                s->d1->change_cipher_spec_ok = 0;
@@ -844,7 +829,7 @@ ssl3_read_change_cipher_spec(SSL *s)
                s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
        }
 
-       rr->length = 0;
+       tls_content_clear(s->s3->rcontent);
 
        s->s3->change_cipher_spec = 1;
        if (!ssl3_do_change_cipher_spec(s))
@@ -1053,9 +1038,8 @@ ssl3_read_handshake_unexpected(SSL *s)
 int
 ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 {
-       SSL3_RECORD_INTERNAL *rr;
        int rrcount = 0;
-       unsigned int n;
+       ssize_t ssret;
        int ret;
 
        if (s->s3->rbuf.buf == NULL) {
@@ -1063,6 +1047,11 @@ ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
                        return -1;
        }
 
+       if (s->s3->rcontent == NULL) {
+               if ((s->s3->rcontent = tls_content_new()) == NULL)
+                       return -1;
+       }
+
        if (len < 0) {
                SSLerror(s, ERR_R_INTERNAL_ERROR);
                return -1;
@@ -1120,16 +1109,15 @@ ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
        s->rwstate = SSL_NOTHING;
 
-       rr = &s->s3->rrec;
-
-       if (rr->length == 0 || s->rstate == SSL_ST_READ_BODY) {
+       if (tls_content_remaining(s->s3->rcontent) == 0) {
                if ((ret = ssl3_get_record(s)) <= 0)
                        return ret;
        }
 
        /* We now have a packet which can be read and processed. */
 
-       if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE) {
+       if (s->s3->change_cipher_spec &&
+           tls_content_type(s->s3->rcontent) != SSL3_RT_HANDSHAKE) {
                SSLerror(s, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
                return -1;
@@ -1141,12 +1129,13 @@ ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
         */
        if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
                s->rwstate = SSL_NOTHING;
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
                return 0;
        }
 
        /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
-       if (type == rr->type) {
+       if (tls_content_type(s->s3->rcontent) == type) {
                /*
                 * Make sure that we are not getting application data when we
                 * are doing a handshake for the first time.
@@ -1162,34 +1151,28 @@ ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
                if (len <= 0)
                        return len;
 
-               if ((unsigned int)len > rr->length)
-                       n = rr->length;
-               else
-                       n = (unsigned int)len;
-
-               memcpy(buf, &rr->data[rr->off], n);
-               if (!peek) {
-                       memset(&rr->data[rr->off], 0, n);
-                       rr->length -= n;
-                       rr->off += n;
-                       if (rr->length == 0) {
-                               s->rstate = SSL_ST_READ_HEADER;
-                               rr->off = 0;
-                               if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
-                                   s->s3->rbuf.left == 0)
-                                       ssl3_release_read_buffer(s);
-                       }
+               if (peek) {
+                       ssret = tls_content_peek(s->s3->rcontent, buf, len);
+               } else {
+                       ssret = tls_content_read(s->s3->rcontent, buf, len);
                }
+               if (ssret < INT_MIN || ssret > INT_MAX)
+                       return -1;
+               if (ssret < 0)
+                       return (int)ssret;
 
-               return n;
-       }
+               if (tls_content_remaining(s->s3->rcontent) == 0) {
+                       s->rstate = SSL_ST_READ_HEADER;
 
-       /*
-        * If we get here, then type != rr->type; if we have a handshake
-        * message, then it was unexpected (Hello Request or Client Hello).
-        */
+                       if (s->mode & SSL_MODE_RELEASE_BUFFERS &&
+                           s->s3->rbuf.left == 0)
+                               ssl3_release_read_buffer(s);
+               }
+
+               return ssret;
+       }
 
-       if (rr->type == SSL3_RT_ALERT) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_ALERT) {
                if ((ret = ssl3_read_alert(s)) <= 0)
                        return ret;
                goto start;
@@ -1197,11 +1180,12 @@ ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
 
        if (s->shutdown & SSL_SENT_SHUTDOWN) {
                s->rwstate = SSL_NOTHING;
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
+               s->s3->rrec.length = 0;
                return 0;
        }
 
-       if (rr->type == SSL3_RT_APPLICATION_DATA) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_APPLICATION_DATA) {
                /*
                 * At this point, we were expecting handshake data, but have
                 * application data. If the library was running inside
@@ -1227,13 +1211,13 @@ ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
                }
        }
 
-       if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_CHANGE_CIPHER_SPEC) {
                if ((ret = ssl3_read_change_cipher_spec(s)) <= 0)
                        return ret;
                goto start;
        }
 
-       if (rr->type == SSL3_RT_HANDSHAKE) {
+       if (tls_content_type(s->s3->rcontent) == SSL3_RT_HANDSHAKE) {
                if ((ret = ssl3_read_handshake_unexpected(s)) <= 0)
                        return ret;
                goto start;
@@ -1244,7 +1228,7 @@ ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
         * earlier versions silently ignore the record.
         */
        if (ssl_effective_tls_version(s) <= TLS1_1_VERSION) {
-               rr->length = 0;
+               tls_content_clear(s->s3->rcontent);
                goto start;
        }
        SSLerror(s, SSL_R_UNEXPECTED_RECORD);
index 3568e18..a659066 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls12_record_layer.c,v 1.36 2022/01/14 09:12:15 tb Exp $ */
+/* $OpenBSD: tls12_record_layer.c,v 1.37 2022/11/11 17:15:26 jsing Exp $ */
 /*
  * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
  *
@@ -864,28 +864,25 @@ tls12_record_layer_aead_xored_nonce(struct tls12_record_layer *rl,
 
 static int
 tls12_record_layer_open_record_plaintext(struct tls12_record_layer *rl,
-    uint8_t content_type, CBS *fragment, uint8_t **out, size_t *out_len)
+    uint8_t content_type, CBS *fragment, struct tls_content *out)
 {
        if (tls12_record_protection_engaged(rl->read))
                return 0;
 
-       /* XXX - decrypt/process in place for now. */
-       *out = (uint8_t *)CBS_data(fragment);
-       *out_len = CBS_len(fragment);
-
-       return 1;
+       return tls_content_dup_data(out, content_type, CBS_data(fragment),
+           CBS_len(fragment));
 }
 
 static int
 tls12_record_layer_open_record_protected_aead(struct tls12_record_layer *rl,
-    uint8_t content_type, CBS *seq_num, CBS *fragment, uint8_t **out,
-    size_t *out_len)
+    uint8_t content_type, CBS *seq_num, CBS *fragment, struct tls_content *out)
 {
        struct tls12_record_protection *rp = rl->read;
        uint8_t *header = NULL;
        size_t header_len = 0;
-       uint8_t *plain;
-       size_t plain_len;
+       uint8_t *content = NULL;
+       size_t content_len = 0;
+       size_t out_len = 0;
        CBS var_nonce;
        int ret = 0;
 
@@ -913,43 +910,47 @@ tls12_record_layer_open_record_protected_aead(struct tls12_record_layer *rl,
                goto err;
        }
 
-       /* XXX - decrypt/process in place for now. */
-       plain = (uint8_t *)CBS_data(fragment);
-       plain_len = CBS_len(fragment) - rp->aead_tag_len;
+       content_len = CBS_len(fragment) - rp->aead_tag_len;
+       if ((content = calloc(1, CBS_len(fragment))) == NULL) {
+               content_len = 0;
+               goto err;
+       }
 
-       if (!tls12_record_layer_pseudo_header(rl, content_type, plain_len,
+       if (!tls12_record_layer_pseudo_header(rl, content_type, content_len,
            seq_num, &header, &header_len))
                goto err;
 
-       if (!EVP_AEAD_CTX_open(rp->aead_ctx, plain, out_len, plain_len,
+       if (!EVP_AEAD_CTX_open(rp->aead_ctx, content, &out_len, content_len,
            rp->aead_nonce, rp->aead_nonce_len, CBS_data(fragment),
            CBS_len(fragment), header, header_len)) {
                rl->alert_desc = SSL_AD_BAD_RECORD_MAC;
                goto err;
        }
 
-       if (*out_len > SSL3_RT_MAX_PLAIN_LENGTH) {
+       if (out_len > SSL3_RT_MAX_PLAIN_LENGTH) {
                rl->alert_desc = SSL_AD_RECORD_OVERFLOW;
                goto err;
        }
 
-       if (*out_len != plain_len)
+       if (out_len != content_len)
                goto err;
 
-       *out = plain;
+       tls_content_set_data(out, content_type, content, content_len);
+       content = NULL;
+       content_len = 0;
 
        ret = 1;
 
  err:
        freezero(header, header_len);
+       freezero(content, content_len);
 
        return ret;
 }
 
 static int
 tls12_record_layer_open_record_protected_cipher(struct tls12_record_layer *rl,
-    uint8_t content_type, CBS *seq_num, CBS *fragment, uint8_t **out,
-    size_t *out_len)
+    uint8_t content_type, CBS *seq_num, CBS *fragment, struct tls_content *out)
 {
        EVP_CIPHER_CTX *enc = rl->read->cipher_ctx;
        SSL3_RECORD_INTERNAL rrec;
@@ -958,8 +959,8 @@ tls12_record_layer_open_record_protected_cipher(struct tls12_record_layer *rl,
        size_t mac_len = 0;
        uint8_t *out_mac = NULL;
        size_t out_mac_len = 0;
-       uint8_t *plain;
-       size_t plain_len;
+       uint8_t *content = NULL;
+       size_t content_len = 0;
        size_t min_len;
        CBB cbb_mac;
        int ret = 0;
@@ -1001,16 +1002,16 @@ tls12_record_layer_open_record_protected_cipher(struct tls12_record_layer *rl,
                goto err;
        }
 
-       /* XXX - decrypt/process in place for now. */
-       plain = (uint8_t *)CBS_data(fragment);
-       plain_len = CBS_len(fragment);
+       if ((content = calloc(1, CBS_len(fragment))) == NULL)
+               goto err;
+       content_len = CBS_len(fragment);
 
-       if (!EVP_Cipher(enc, plain, CBS_data(fragment), plain_len))
+       if (!EVP_Cipher(enc, content, CBS_data(fragment), CBS_len(fragment)))
                goto err;
 
-       rrec.data = plain;
-       rrec.input = plain;
-       rrec.length = plain_len;
+       rrec.data = content;
+       rrec.input = content;
+       rrec.length = content_len;
 
        /*
         * We now have to remove padding, extract MAC, calculate MAC
@@ -1058,8 +1059,13 @@ tls12_record_layer_open_record_protected_cipher(struct tls12_record_layer *rl,
                goto err;
        }
 
-       *out = rrec.data;
-       *out_len = rrec.length;
+       tls_content_set_data(out, content_type, content, content_len);
+       content = NULL;
+       content_len = 0;
+
+       /* Actual content is after EIV, minus padding and MAC. */
+       if (!tls_content_set_bounds(out, eiv_len, rrec.length))
+               goto err;
 
        ret = 1;
 
@@ -1067,13 +1073,14 @@ tls12_record_layer_open_record_protected_cipher(struct tls12_record_layer *rl,
        CBB_cleanup(&cbb_mac);
        freezero(mac, mac_len);
        freezero(out_mac, out_mac_len);
+       freezero(content, content_len);
 
        return ret;
 }
 
 int
 tls12_record_layer_open_record(struct tls12_record_layer *rl, uint8_t *buf,
-    size_t buf_len, uint8_t **out, size_t *out_len)
+    size_t buf_len, struct tls_content *out)
 {
        CBS cbs, fragment, seq_num;
        uint16_t version;
@@ -1105,15 +1112,15 @@ tls12_record_layer_open_record(struct tls12_record_layer *rl, uint8_t *buf,
 
        if (rl->read->aead_ctx != NULL) {
                if (!tls12_record_layer_open_record_protected_aead(rl,
-                   content_type, &seq_num, &fragment, out, out_len))
+                   content_type, &seq_num, &fragment, out))
                        return 0;
        } else if (rl->read->cipher_ctx != NULL) {
                if (!tls12_record_layer_open_record_protected_cipher(rl,
-                   content_type, &seq_num, &fragment, out, out_len))
+                   content_type, &seq_num, &fragment, out))
                        return 0;
        } else {
                if (!tls12_record_layer_open_record_plaintext(rl,
-                   content_type, &fragment, out, out_len))
+                   content_type, &fragment, out))
                        return 0;
        }
 
index 423b405..4ae4e29 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls13_record_layer.c,v 1.71 2022/09/11 13:50:41 jsing Exp $ */
+/* $OpenBSD: tls13_record_layer.c,v 1.72 2022/11/11 17:15:27 jsing Exp $ */
 /*
  * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org>
  *
@@ -561,6 +561,7 @@ tls13_record_layer_open_record_protected(struct tls13_record_layer *rl)
        if (!tls13_record_content(rl->rrec, &enc_record))
                goto err;
 
+       /* XXX - minus tag len? */
        if ((content = calloc(1, CBS_len(&enc_record))) == NULL)
                goto err;
        content_len = CBS_len(&enc_record);
index ede178f..726de0f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_content.c,v 1.1 2021/09/04 16:26:12 jsing Exp $ */
+/* $OpenBSD: tls_content.c,v 1.2 2022/11/11 17:15:27 jsing Exp $ */
 /*
  * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
  *
@@ -26,7 +26,7 @@ struct tls_content {
        uint16_t epoch;
 
        const uint8_t *data;
-       size_t len;
+       size_t data_len;
        CBS cbs;
 };
 
@@ -39,7 +39,7 @@ tls_content_new(void)
 void
 tls_content_clear(struct tls_content *content)
 {
-       freezero((void *)content->data, content->len);
+       freezero((void *)content->data, content->data_len);
        memset(content, 0, sizeof(*content));
 }
 
@@ -113,9 +113,24 @@ tls_content_set_data(struct tls_content *content, uint8_t type,
 
        content->type = type;
        content->data = data;
-       content->len = data_len;
+       content->data_len = data_len;
 
-       CBS_init(&content->cbs, content->data, content->len);
+       CBS_init(&content->cbs, content->data, content->data_len);
+}
+
+int
+tls_content_set_bounds(struct tls_content *content, size_t offset, size_t len)
+{
+       size_t content_len;
+
+       content_len = offset + len;
+       if (content_len < len)
+               return 0;
+       if (content_len > content->data_len)
+               return 0;
+
+       CBS_init(&content->cbs, content->data, content_len);
+       return CBS_skip(&content->cbs, offset);
 }
 
 static ssize_t
index 173af2a..b807248 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_content.h,v 1.1 2021/09/04 16:26:12 jsing Exp $ */
+/* $OpenBSD: tls_content.h,v 1.2 2022/11/11 17:15:27 jsing Exp $ */
 /*
  * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
  *
@@ -38,6 +38,8 @@ int tls_content_dup_data(struct tls_content *content, uint8_t type,
     const uint8_t *data, size_t data_len);
 void tls_content_set_data(struct tls_content *content, uint8_t type,
     const uint8_t *data, size_t data_len);
+int tls_content_set_bounds(struct tls_content *content, size_t offset,
+    size_t len);
 void tls_content_set_epoch(struct tls_content *content, uint16_t epoch);
 
 ssize_t tls_content_peek(struct tls_content *content, uint8_t *buf, size_t n);