]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Support DTLS 1.3 Unified Headers
authorFrederik Wedel-Heinen <frederik.wedel-heinen@dencrypt.dk>
Mon, 21 Oct 2024 09:05:25 +0000 (11:05 +0200)
committerTomas Mraz <tomas@openssl.org>
Tue, 18 Mar 2025 17:56:41 +0000 (18:56 +0100)
Also set correct AAD for DTLS 1.3 message de-/encryption.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/25668)

doc/designs/dtlsv1_3/dtlsv1_3-main.md
doc/man3/SSL_get_version.pod
include/openssl/dtls1.h
ssl/d1_lib.c
ssl/record/methods/dtls_meth.c
ssl/record/methods/recmethod_local.h
ssl/record/methods/tls13_meth.c
ssl/record/methods/tls1_meth.c
ssl/record/methods/tls_common.c
test/helpers/ssltestlib.c
util/perl/TLSProxy/Record.pm

index 88d985d5e8fbc12a0b477e4cc93c84d2c8ef8de5..a97b6e273ab175a2df287a2db9f7afa3bd892e63 100644 (file)
@@ -40,7 +40,7 @@ as a feature request in issue ###########.
 
 ### DTLSv1.3 connection id
 
-OpenSSL does not support Connection ID's (RFC 9146). Notably Openssl DTLSv1.3 clients
+OpenSSL does not support Connection IDs (RFC 9146). Notably Openssl DTLSv1.3 clients
 will not offer the "connection_id" extension even though RFC 9147 states:
 
 > DTLS clients which do not want to receive a Connection ID SHOULD still offer
@@ -88,14 +88,12 @@ A summary of larger work items that needs to be addressed.
 Notice that some of the requirements mentioned in [List of DTLSv1.3 requirements](#list-of-dtls-13-requirements)
 is not covered by these workitems and must be implemented separately.
 
-| Summary                                             | #PR            |
-|-----------------------------------------------------|----------------|
-| ACK messages                                        | -              |
-| Use HelloRetryRequest instead of HelloVerifyRequest | #22985, #22400 |
-| ClientHello                                         | #23320         |
-| EndOfEarlyData message                              | -              |
-| Variable length header                              | -              |
-| DTLSv1.3 Fuzzer                                     | -              |
+| Summary                                             | #PR    |
+|-----------------------------------------------------|--------|
+| ACK messages                                        | #25119 |
+| Use HelloRetryRequest instead of HelloVerifyRequest | #22985 |
+| EndOfEarlyData message                              | -      |
+| DTLSv1.3 Fuzzer                                     | -      |
 
 ### Changes from DTLS 1.2 and/or TLS 1.3
 
index a6f5e7fb84bbcca03115d73a851baec61acfcd1f..0b041d7dddfdf01f36642d161ed787b9f4330b3b 100644 (file)
@@ -77,6 +77,10 @@ The connection uses the DTLSv1 protocol
 
 The connection uses the DTLSv1.2 protocol
 
+=item DTLSv1.3
+
+The connection uses the DTLSv1.3 protocol
+
 =item QUICv1
 
 The connection uses the QUICv1 protocol.
index e5096d1ef5344b2b47e3cb69cda090bc117b6edd..6ad1c061d33456c6cbe1d61b64805bd7006314f6 100644 (file)
@@ -22,7 +22,7 @@
 extern "C" {
 #endif
 
-#include <openssl/opensslconf.h>
+# include <openssl/opensslconf.h>
 
 /* DTLS*_VERSION constants are defined in prov_ssl.h */
 # ifndef OPENSSL_NO_DEPRECATED_3_0
@@ -39,6 +39,7 @@ extern "C" {
 # define DTLS1_COOKIE_LENGTH                     255
 
 # define DTLS1_RT_HEADER_SEQ_OFFS                5
+# define DTLS1_RT_HEADER_SEQ_LEN                 6
 # define DTLS1_RT_HEADER_LENGTH                  13
 
 # define DTLS1_HM_HEADER_LENGTH                  12
@@ -52,7 +53,19 @@ extern "C" {
 
 # define DTLS1_TMO_ALERT_COUNT                     12
 
-#ifdef  __cplusplus
+/* DTLS 1.3 Unified header */
+# define DTLS13_UNI_HDR_FIXED_LENGTH     5
+# define DTLS13_UNI_HDR_FIX_BITS         0x20
+# define DTLS13_UNI_HDR_CID_BIT          0x10
+# define DTLS13_UNI_HDR_SEQ_BIT          0x08
+# define DTLS13_UNI_HDR_SEQ_OFF          1
+# define DTLS13_UNI_HDR_LEN_BIT          0x04
+# define DTLS13_UNI_HDR_FIX_BITS_MASK    0xe0
+# define DTLS13_UNI_HDR_EPOCH_BITS_MASK  0x03
+
+# define DTLS13_CIPHERTEXT_MINSIZE 16
+
+# ifdef __cplusplus
 }
-#endif
+# endif
 #endif
index 91419ae8908e08ff88d3b3df6188698962960197..5a9c32c261cf2c09d2d4b0337fa76181f9d6a14a 100644 (file)
@@ -923,7 +923,7 @@ size_t dtls1_min_mtu(SSL_CONNECTION *s)
 
 size_t DTLS_get_data_mtu(const SSL *ssl)
 {
-    size_t mac_overhead, int_overhead, blocksize, ext_overhead;
+    size_t mac_overhead, int_overhead, blocksize, ext_overhead, rechdrlen = 0;
     const SSL_CIPHER *ciph = SSL_get_current_cipher(ssl);
     size_t mtu;
     const SSL_CONNECTION *s = SSL_CONNECTION_FROM_CONST_SSL_ONLY(ssl);
@@ -945,10 +945,33 @@ size_t DTLS_get_data_mtu(const SSL *ssl)
     else
         int_overhead += mac_overhead;
 
+    if (SSL_version(ssl) == DTLS1_3_VERSION) {
+        switch (SSL_get_state(ssl)) {
+        case TLS_ST_BEFORE:
+        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+        case TLS_ST_CR_SRVR_HELLO:
+        case TLS_ST_CW_CLNT_HELLO:
+        case TLS_ST_CW_COMP_CERT:
+        case TLS_ST_CW_KEY_EXCH:
+        case TLS_ST_SW_HELLO_REQ:
+        case TLS_ST_SR_CLNT_HELLO:
+        case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        case TLS_ST_SW_SRVR_HELLO:
+        case TLS_ST_CR_HELLO_REQ:
+            rechdrlen = DTLS1_RT_HEADER_LENGTH;
+            break;
+        default:
+            rechdrlen = DTLS13_UNI_HDR_FIXED_LENGTH;
+            break;
+        }
+    } else {
+        rechdrlen = DTLS1_RT_HEADER_LENGTH;
+    }
+
     /* Subtract external overhead (e.g. IV/nonce, separate MAC) */
-    if (ext_overhead + DTLS1_RT_HEADER_LENGTH >= mtu)
+    if (ext_overhead + rechdrlen >= mtu)
         return 0;
-    mtu -= ext_overhead + DTLS1_RT_HEADER_LENGTH;
+    mtu -= ext_overhead + rechdrlen;
 
     /* Round encrypted payload down to cipher block size (for CBC etc.)
      * No check for overflow since 'mtu % blocksize' cannot exceed mtu. */
index de497c57858adbad48ecb33b09e18d62c03334f9..bfa411520d89daaa2f70d2029368d0823ed60eb4 100644 (file)
@@ -105,6 +105,24 @@ static void dtls_set_in_init(OSSL_RECORD_LAYER *rl, int in_init)
     rl->in_init = in_init;
 }
 
+size_t dtls_get_rec_header_size(uint8_t hdr_first_byte)
+{
+    size_t size = 0;
+
+    if (DTLS13_UNI_HDR_FIX_BITS_IS_SET(hdr_first_byte)
+        && ossl_assert(!DTLS13_UNI_HDR_CID_BIT_IS_SET(hdr_first_byte))) {
+        /* DTLSv1.3 unified record header */
+        size = 1;
+        size += DTLS13_UNI_HDR_SEQ_BIT_IS_SET(hdr_first_byte) ? 2 : 1;
+        size += DTLS13_UNI_HDR_LEN_BIT_IS_SET(hdr_first_byte) ? 2 : 0;
+    } else {
+        /* DTLSv1.0, DTLSv1.2 or unencrypted DTLSv1.3 record header */
+        size = DTLS1_RT_HEADER_LENGTH;
+    }
+
+    return size;
+}
+
 static int dtls_process_record(OSSL_RECORD_LAYER *rl, DTLS_BITMAP *bitmap)
 {
     int i;
@@ -112,6 +130,7 @@ static int dtls_process_record(OSSL_RECORD_LAYER *rl, DTLS_BITMAP *bitmap)
     TLS_RL_RECORD *rr;
     int imac_size;
     size_t mac_size = 0;
+    size_t rechdrsize = dtls_get_rec_header_size(rl->packet[0]);
     unsigned char md[EVP_MAX_MD_SIZE];
     SSL_MAC_BUF macbuf = { NULL, 0 };
     int ret = 0;
@@ -119,10 +138,10 @@ static int dtls_process_record(OSSL_RECORD_LAYER *rl, DTLS_BITMAP *bitmap)
     rr = &rl->rrec[0];
 
     /*
-     * At this point, rl->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length,
+     * At this point, rl->packet_length == rechdrsize + rr->length,
      * and we have that many bytes in rl->packet
      */
-    rr->input = &(rl->packet[DTLS1_RT_HEADER_LENGTH]);
+    rr->input = rl->packet + rechdrsize;
 
     /*
      * ok, we can now read from 'rl->packet' data into 'rr'. rr->input
@@ -342,7 +361,8 @@ static int dtls_copy_rlayer_record(OSSL_RECORD_LAYER *rl, pitem *item)
     memcpy(&rl->rrec[0], &(rdata->rrec), sizeof(TLS_RL_RECORD));
 
     /* Set proper sequence number for mac calculation */
-    memcpy(&(rl->sequence[2]), &(rdata->packet[5]), 6);
+    assert(sizeof(rl->sequence) == sizeof(rdata->rrec.seq_num));
+    memcpy(rl->sequence, rdata->rrec.seq_num, sizeof(rl->sequence));
 
     return 1;
 }
@@ -366,14 +386,13 @@ static int dtls_retrieve_rlayer_buffered_record(OSSL_RECORD_LAYER *rl,
 }
 
 /* rfc9147 section 4.2.3 */
-int dtls_crypt_sequence_number(EVP_CIPHER_CTX *ctx, unsigned char *seq,
+int dtls_crypt_sequence_number(EVP_CIPHER_CTX *ctx, unsigned char *seq, size_t seqlen,
                                unsigned char *rec_data, size_t rec_data_offs)
 {
     unsigned char mask[16];
     int outlen, inlen;
     unsigned char *iv, *in;
     size_t i;
-    size_t seq_len = 6;
 
     if (ossl_assert(sizeof(mask) > rec_data_offs))
         inlen = (int)(sizeof(mask) - rec_data_offs);
@@ -393,7 +412,10 @@ int dtls_crypt_sequence_number(EVP_CIPHER_CTX *ctx, unsigned char *seq,
             || outlen != 0)
         return 0;
 
-    for (i = 0; i < seq_len; i++)
+    if (!ossl_assert(seqlen <= sizeof(mask)))
+        return 0;
+
+    for (i = 0; i < seqlen; i++)
         seq[i] ^= mask[i];
 
     OPENSSL_cleanse(mask, sizeof(mask));
@@ -412,13 +434,17 @@ int dtls_crypt_sequence_number(EVP_CIPHER_CTX *ctx, unsigned char *seq,
  */
 int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
 {
-    int ssl_major, ssl_minor;
     int rret;
-    size_t more, n;
+    size_t more, nread = 0;
     TLS_RL_RECORD *rr;
-    unsigned char *p = NULL;
     DTLS_BITMAP *bitmap;
     unsigned int is_next_epoch;
+    unsigned char recseqnum[6];
+    size_t recseqnumlen = 0;
+    size_t rechdrlen = 0;
+    size_t recseqnumoffs = 0;
+
+    memset(recseqnum, 0, sizeof(recseqnum));
 
     rl->num_recs = 0;
     rl->curr_rec = 0;
@@ -443,10 +469,13 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
     /* get something from the wire */
 
     /* check if we have the header */
-    if ((rl->rstate != SSL_ST_READ_BODY) ||
-        (rl->packet_length < DTLS1_RT_HEADER_LENGTH)) {
+    if (rl->rstate != SSL_ST_READ_BODY
+            || rl->packet_length < DTLS1_RT_HEADER_LENGTH) {
+        PACKET dtlsrecord;
+        unsigned int record_type, record_version, epoch, length;
+
         rret = rl->funcs->read_n(rl, DTLS1_RT_HEADER_LENGTH,
-                                 TLS_BUFFER_get_len(&rl->rbuf), 0, 1, &n);
+                                 TLS_BUFFER_get_len(&rl->rbuf), 0, 1, &nread);
         /* read timeout is handled by dtls1_read_bytes */
         if (rret < OSSL_RECORD_RETURN_SUCCESS) {
             /* RLAYERfatal() already called if appropriate */
@@ -461,25 +490,112 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
 
         rl->rstate = SSL_ST_READ_BODY;
 
-        p = rl->packet;
+        if (!PACKET_buf_init(&dtlsrecord, rl->packet, rl->packet_length)
+            || !PACKET_get_1(&dtlsrecord, &record_type)) {
+            rl->packet_length = 0;
+            goto again;
+        }
 
         /* Pull apart the header into the DTLS1_RECORD */
-        rr->type = *(p++);
-        ssl_major = *(p++);
-        ssl_minor = *(p++);
-        rr->rec_version = (ssl_major << 8) | ssl_minor;
+        rr->type = (int)record_type;
+
+        /*-
+         * rfc9147:
+         * Implementations can demultiplex DTLS 1.3 records by examining the first
+         * byte as follows:
+         *   * If the first byte is alert(21), handshake(22), or ack(proposed, 26),
+         *     the record MUST be interpreted as a DTLSPlaintext record.
+         *   * If the first byte is any other value, then receivers MUST check to
+         *     see if the leading bits of the first byte are 001. If so, the implementation
+         *     MUST process the record as DTLSCiphertext; the true content type
+         *     will be inside the protected portion.
+         *   * Otherwise, the record MUST be rejected as if it had failed deprotection,
+         *     as described in Section 4.5.2.
+         */
+        if (rl->version == DTLS1_3_VERSION
+            && rr->type != SSL3_RT_ALERT
+            && rr->type != SSL3_RT_HANDSHAKE
+            /* TODO(DTLSv1.3): && rr->type != SSL3_RT_ACK depends on acknowledge implementation */
+            && !DTLS13_UNI_HDR_FIX_BITS_IS_SET(rr->type)) {
+            /* Silently discard */
+            rr->length = 0;
+            rl->packet_length = 0;
+            goto again;
+        }
 
-        /* sequence number is 64 bits, with top 2 bytes = epoch */
-        n2s(p, rr->epoch);
+        if (DTLS13_UNI_HDR_FIX_BITS_IS_SET(rr->type)) {
+            /*
+             * rfc9147:
+             * receivers MUST check to if the leading bits of the first byte are 001.
+             * If so, the implementation MUST process the record as DTLSCiphertext;
+             */
+            int cbitisset = DTLS13_UNI_HDR_CID_BIT_IS_SET(rr->type);
+            int sbitisset = DTLS13_UNI_HDR_SEQ_BIT_IS_SET(rr->type);
+            int lbitisset = DTLS13_UNI_HDR_LEN_BIT_IS_SET(rr->type);
+            uint16_t eebits = rr->type & DTLS13_UNI_HDR_EPOCH_BITS_MASK;
+
+            record_version = DTLS1_2_VERSION;
+            epoch = rl->epoch;
+            recseqnumlen = sbitisset ? 2 : 1;
+            recseqnumoffs = sizeof(recseqnum) - recseqnumlen;
+
+            if (/* OpenSSL does not support connection IDs: silently discard */
+                cbitisset
+                /*
+                 * Naive approach? We expect sequence number to be filled already
+                 * and then override the last bytes of the sequence number.
+                 */
+                || !PACKET_copy_bytes(&dtlsrecord, recseqnum + recseqnumoffs, recseqnumlen)) {
+                rr->length = 0;
+                rl->packet_length = 0;
+                goto again;
+            }
 
-        memcpy(&(rl->sequence[2]), p, 6);
-        p += 6;
+            /*
+             * rfc9147:
+             * The length field MAY be omitted by clearing the L bit, which means
+             * that the record consumes the entire rest of the datagram in the
+             * lower level transport
+             */
+            length = TLS_BUFFER_get_len(&rl->rbuf) - dtls_get_rec_header_size(rr->type);
 
-        n2s(p, rr->length);
+            if ((lbitisset && !PACKET_get_net_2(&dtlsrecord, &length))
+                || length == 0) {
+                rr->length = 0;
+                rl->packet_length = 0;
+                goto again;
+            }
+
+            /*
+             * We should not be getting records from a previous epoch so
+             * choose the current epoch if the bits match or else choose the
+             * next epoch with matching bits
+             */
+            while (eebits != (epoch & DTLS13_UNI_HDR_EPOCH_BITS_MASK))
+                epoch++;
+
+        } else {
+            if (!PACKET_get_net_2(&dtlsrecord, &record_version)
+                || !PACKET_get_net_2(&dtlsrecord, &epoch)
+                || !PACKET_copy_bytes(&dtlsrecord, recseqnum, 6)
+                || !PACKET_get_net_2(&dtlsrecord, &length)) {
+                rr->length = 0;
+                rl->packet_length = 0;
+                goto again;
+            }
+
+            recseqnumoffs = 0;
+            recseqnumlen = 6;
+        }
+
+        rechdrlen = PACKET_data(&dtlsrecord) - rl->packet;
+        rr->rec_version = (int)record_version;
+        rr->epoch = epoch;
+        rr->length = length;
 
         if (rl->msg_callback != NULL)
-            rl->msg_callback(0, rr->rec_version, SSL3_RT_HEADER, rl->packet, DTLS1_RT_HEADER_LENGTH,
-                             rl->cbarg);
+            rl->msg_callback(0, rr->rec_version, SSL3_RT_HEADER, rl->packet,
+                             rechdrlen, rl->cbarg);
 
         /*
          * Lets check the version. We tolerate alerts that don't have the exact
@@ -497,9 +613,9 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
             }
         }
 
-        if (ssl_major !=
-                (rl->version == DTLS_ANY_VERSION ? DTLS1_VERSION_MAJOR
-                                                 : rl->version >> 8)) {
+        if (rr->rec_version >> 8 !=
+            (rl->version == DTLS_ANY_VERSION ? DTLS1_VERSION_MAJOR
+                                             : rl->version >> 8)) {
             /* wrong version, silently discard record */
             rr->length = 0;
             rl->packet_length = 0;
@@ -531,10 +647,10 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
 
     if (rr->length > rl->packet_length - DTLS1_RT_HEADER_LENGTH) {
         /* now rl->packet_length == DTLS1_RT_HEADER_LENGTH */
-        more = rr->length;
-        rret = rl->funcs->read_n(rl, more, more, 1, 1, &n);
+        more = rr->length - (nread - rechdrlen);
+        rret = rl->funcs->read_n(rl, more, more, 1, 1, &nread);
         /* this packet contained a partial record, dump it */
-        if (rret < OSSL_RECORD_RETURN_SUCCESS || n != more) {
+        if (rret < OSSL_RECORD_RETURN_SUCCESS || nread != more) {
             if (rl->alert != SSL_AD_NO_ALERT) {
                 /* read_n() called RLAYERfatal() */
                 return OSSL_RECORD_RETURN_FATAL;
@@ -554,15 +670,18 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
 
     /*
      * rfc9147:
-     * This procedure requires the ciphertext length to be at least 16 bytes.
+     * This procedure requires the ciphertext length to be at least
+     * DTLS13_CIPHERTEXT_MINSIZE (16) bytes.
      * Receivers MUST reject shorter records as if they had failed deprotection
-     * TODO(DTLSv1.3): This check will need to be modified when support for variable
-     * length headers is added.
      */
-    if (rl->sn_enc_ctx != NULL
-            && (rl->packet_length < DTLS1_RT_HEADER_LENGTH + 16
-                || !dtls_crypt_sequence_number(rl->sn_enc_ctx, &(rl->sequence[2]),
-                                               rl->packet + DTLS1_RT_HEADER_LENGTH,
+    if (DTLS13_UNI_HDR_FIX_BITS_IS_SET(rr->type)
+            && rl->version == DTLS1_3_VERSION
+            && (!ossl_assert(rl->sn_enc_ctx != NULL)
+                || !ossl_assert(rl->packet_length >= rechdrlen + DTLS13_CIPHERTEXT_MINSIZE)
+                || !dtls_crypt_sequence_number(rl->sn_enc_ctx,
+                                               recseqnum + recseqnumoffs,
+                                               recseqnumlen,
+                                               rl->packet + rechdrlen,
                                                rl->sn_enc_offs))) {
         /* sequence number encryption failed dump record */
         rr->length = 0;
@@ -570,6 +689,9 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
         goto again;
     }
 
+    memset(rl->sequence, 0, sizeof(rl->sequence));
+    memcpy(rl->sequence + 2, recseqnum, sizeof(recseqnum));
+
     /* match epochs.  NULL means the packet is dropped on the floor */
     bitmap = dtls_get_bitmap(rl, rr, &is_next_epoch);
     if (bitmap == NULL) {
@@ -742,6 +864,7 @@ int dtls_prepare_record_header(OSSL_RECORD_LAYER *rl,
                                unsigned char **recdata)
 {
     size_t maxcomplen;
+    int unifiedheader = rl->version == DTLS1_3_VERSION && rl->epoch > 0;
 
     *recdata = NULL;
 
@@ -749,7 +872,26 @@ int dtls_prepare_record_header(OSSL_RECORD_LAYER *rl,
     if (rl->compctx != NULL)
         maxcomplen += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
 
-    if (!WPACKET_put_bytes_u8(thispkt, rectype)
+    if (unifiedheader) {
+        uint8_t fixedbits = 0x20;
+        uint8_t cbit = 0;
+        uint8_t sbit = DTLS13_UNI_HDR_SEQ_BIT;
+        uint8_t lbit = DTLS13_UNI_HDR_LEN_BIT;
+        uint8_t ebits = rl->epoch & DTLS13_UNI_HDR_EPOCH_BITS_MASK;
+        uint8_t unifiedhdrbits = fixedbits | cbit | sbit | lbit | ebits;
+
+        if (!WPACKET_put_bytes_u8(thispkt, unifiedhdrbits)
+            || !WPACKET_memcpy(thispkt, rl->sequence + 6, 2)
+            || !WPACKET_start_sub_packet_u16(thispkt)
+            || (rl->eivlen > 0
+                && !WPACKET_allocate_bytes(thispkt, rl->eivlen, NULL))
+            || (maxcomplen > 0
+                && !WPACKET_reserve_bytes(thispkt, maxcomplen, recdata))) {
+            RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    } else {
+        if (!WPACKET_put_bytes_u8(thispkt, rectype)
             || !WPACKET_put_bytes_u16(thispkt, templ->version)
             || !WPACKET_put_bytes_u16(thispkt, rl->epoch)
             || !WPACKET_memcpy(thispkt, &(rl->sequence[2]), 6)
@@ -757,10 +899,10 @@ int dtls_prepare_record_header(OSSL_RECORD_LAYER *rl,
             || (rl->eivlen > 0
                 && !WPACKET_allocate_bytes(thispkt, rl->eivlen, NULL))
             || (maxcomplen > 0
-                && !WPACKET_reserve_bytes(thispkt, maxcomplen,
-                                          recdata))) {
-        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-        return 0;
+                && !WPACKET_reserve_bytes(thispkt, maxcomplen, recdata))) {
+            RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 
     return 1;
@@ -784,6 +926,7 @@ int dtls_post_encryption_processing(OSSL_RECORD_LAYER *rl,
 static size_t dtls_get_max_record_overhead(OSSL_RECORD_LAYER *rl)
 {
     size_t blocksize = 0, contenttypelen = 0;
+    size_t rchdrlen = tls_get_record_header_len(rl);
 
     if (rl->enc_ctx != NULL &&
         (EVP_CIPHER_CTX_get_mode(rl->enc_ctx) == EVP_CIPH_CBC_MODE))
@@ -815,8 +958,7 @@ static size_t dtls_get_max_record_overhead(OSSL_RECORD_LAYER *rl)
      * MTU size - so isn't very helpful. We just ignore potential expansion
      * due to compression.
      */
-    return DTLS1_RT_HEADER_LENGTH + rl->eivlen + blocksize + rl->taglen
-           + contenttypelen;
+    return rchdrlen + rl->eivlen + blocksize + rl->taglen + contenttypelen;
 }
 
 const OSSL_RECORD_METHOD ossl_dtls_record_method = {
index 8cf1141ee0124e45c30ec03a6fc8877c374170c7..8da1c8a28243cc71f351a7a3b703a429f5b365b4 100644 (file)
@@ -423,7 +423,24 @@ int tls_default_read_n(OSSL_RECORD_LAYER *rl, size_t n, size_t max, int extend,
                        int clearold, size_t *readbytes);
 int tls_get_more_records(OSSL_RECORD_LAYER *rl);
 
-int dtls_crypt_sequence_number(EVP_CIPHER_CTX *ctx, unsigned char *seq,
+/* Returns true if the unified header fixed bits are set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_FIX_BITS_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_FIX_BITS_MASK) == DTLS13_UNI_HDR_FIX_BITS)
+
+/* Returns true if the unified header connection id bit is set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_CID_BIT_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_CID_BIT) == DTLS13_UNI_HDR_CID_BIT)
+
+/* Returns true if the unified header sequence number bit is set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_SEQ_BIT_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_SEQ_BIT) == DTLS13_UNI_HDR_SEQ_BIT)
+
+/* Returns true if the unified header length bit is set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_LEN_BIT_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_LEN_BIT) == DTLS13_UNI_HDR_LEN_BIT)
+
+size_t dtls_get_rec_header_size(uint8_t hdr_first_byte);
+int dtls_crypt_sequence_number(EVP_CIPHER_CTX *ctx, unsigned char *seq, size_t seqlen,
                                unsigned char *rec_data, size_t rec_data_offs);
 int dtls_get_more_records(OSSL_RECORD_LAYER *rl);
 
@@ -440,6 +457,7 @@ int dtls_post_encryption_processing(OSSL_RECORD_LAYER *rl,
 
 int tls_default_set_protocol_version(OSSL_RECORD_LAYER *rl, int version);
 int tls_default_validate_record_header(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *re);
+size_t tls_get_record_header_len(OSSL_RECORD_LAYER *rl);
 int tls_do_compress(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *wr);
 int tls_do_uncompress(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *rec);
 int tls_default_post_process_record(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *rec);
@@ -469,7 +487,6 @@ int tls_read_record(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion,
                     uint8_t *type, const unsigned char **data, size_t *datalen,
                     uint16_t *epoch, unsigned char *seq_num);
 int tls_release_record(OSSL_RECORD_LAYER *rl, void *rechandle, size_t length);
-int tls_default_set_protocol_version(OSSL_RECORD_LAYER *rl, int version);
 int tls_set_protocol_version(OSSL_RECORD_LAYER *rl, int version);
 void tls_set_plain_alerts(OSSL_RECORD_LAYER *rl, int allow);
 void tls_set_first_handshake(OSSL_RECORD_LAYER *rl, int first);
@@ -493,6 +510,8 @@ size_t tls_get_max_records_default(OSSL_RECORD_LAYER *rl, uint8_t type,
 size_t tls_get_max_records_multiblock(OSSL_RECORD_LAYER *rl, uint8_t type,
                                       size_t len, size_t maxfrag,
                                       size_t *preffrag);
+size_t tls_get_record_body_alignment_offset(OSSL_RECORD_LAYER *rl,
+                                            const unsigned char *rec);
 int tls_allocate_write_buffers_default(OSSL_RECORD_LAYER *rl,
                                        OSSL_RECORD_TEMPLATE *templates,
                                        size_t numtempl, size_t *prefix);
index dd44764059c718c1b14769288e3fef67a6b2fc75..e66f5865e84a8ae2e99afe73b750e34cf257eba3 100644 (file)
@@ -112,7 +112,8 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
     EVP_CIPHER_CTX *enc_ctx;
     unsigned char recheader[SSL3_RT_HEADER_LENGTH];
     unsigned char tag[EVP_MAX_MD_SIZE];
-    size_t nonce_len, offset, loop, hdrlen, taglen;
+    size_t nonce_len, offset, loop, hdrlen, taglen, exphdrlen;
+    int isdtls, sbit = 0, addlen;
     unsigned char *staticiv;
     unsigned char *nonce;
     unsigned char *seq = rl->sequence;
@@ -132,6 +133,7 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
     enc_ctx = rl->enc_ctx; /* enc_ctx is ignored when rl->mac_ctx != NULL */
     staticiv = rl->iv;
     nonce = rl->nonce;
+    isdtls = rl->isdtls;
 
     if (enc_ctx == NULL && rl->mac_ctx == NULL) {
         RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
@@ -185,18 +187,46 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
     for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
         nonce[offset + loop] = staticiv[offset + loop] ^ seq[loop];
 
-    if (!tls_increment_sequence_ctr(rl)) {
+    if (!isdtls && !tls_increment_sequence_ctr(rl)) {
         /* RLAYERfatal already called */
         return 0;
     }
 
-    /* Set up the AAD */
-    if (!WPACKET_init_static_len(&wpkt, recheader, sizeof(recheader), 0)
+    /*-
+     * Set up the additional data as described in rfc8446 section 5.2:
+     *   "and the additional data input is the record header.
+     *   I.e.,
+     *      additional_data = TLSCiphertext.opaque_type ||
+     *                        TLSCiphertext.legacy_record_version ||
+     *                        TLSCiphertext.length"
+     * and in rfc1947 section 4:
+     *   "The entire header value shown in Figure 4 (but prior to record number
+     *   encryption; see Section 4.2.3) is used as the additional data value for
+     *   the AEAD function. For instance, if the minimal variant is used, the
+     *   Associated Data (AD) is 2 octets long."
+     *
+     *   For DTLS: at this point rec->type is just the first byte of the variable
+     *   header. So it is not an actual record type. The record type is set in
+     *   tls13_post_process_record() for incoming records.
+     */
+    if (isdtls) {
+        exphdrlen = dtls_get_rec_header_size(rec->type);
+        sbit = DTLS13_UNI_HDR_SEQ_BIT_IS_SET(rec->type);
+        addlen = DTLS13_UNI_HDR_LEN_BIT_IS_SET(rec->type);
+    } else {
+        exphdrlen = SSL3_RT_HEADER_LENGTH;
+        addlen = 1;
+    }
+
+    if ((isdtls && !ossl_assert(!DTLS13_UNI_HDR_CID_BIT_IS_SET(rec->type)))
+            || !WPACKET_init_static_len(&wpkt, recheader, sizeof(recheader), 0)
             || !WPACKET_put_bytes_u8(&wpkt, rec->type)
-            || !WPACKET_put_bytes_u16(&wpkt, rec->rec_version)
-            || !WPACKET_put_bytes_u16(&wpkt, rec->length + rl->taglen)
+            || (isdtls && (sbit ? !WPACKET_memcpy(&wpkt, rl->sequence + 6, 2)
+                                : !WPACKET_memcpy(&wpkt, rl->sequence + 7, 1)))
+            || (!isdtls && !WPACKET_put_bytes_u16(&wpkt, rec->rec_version))
+            || (addlen && !WPACKET_put_bytes_u16(&wpkt, rec->length + rl->taglen))
             || !WPACKET_get_total_written(&wpkt, &hdrlen)
-            || hdrlen != SSL3_RT_HEADER_LENGTH
+            || hdrlen != exphdrlen
             || !WPACKET_finish(&wpkt)) {
         RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         WPACKET_cleanup(&wpkt);
@@ -208,7 +238,7 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
 
         if ((mac_ctx = EVP_MAC_CTX_dup(rl->mac_ctx)) == NULL
             || !EVP_MAC_update(mac_ctx, nonce, nonce_len)
-            || !EVP_MAC_update(mac_ctx, recheader, sizeof(recheader))
+            || !EVP_MAC_update(mac_ctx, recheader, hdrlen)
             || !EVP_MAC_update(mac_ctx, rec->input, rec->length)
             || !EVP_MAC_final(mac_ctx, tag, &taglen, rl->taglen)) {
             RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
@@ -248,12 +278,9 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
      * any AAD.
      */
     if ((mode == EVP_CIPH_CCM_MODE
-                 && EVP_CipherUpdate(enc_ctx, NULL, &lenu, NULL,
-                                     (unsigned int)rec->length) <= 0)
-            || EVP_CipherUpdate(enc_ctx, NULL, &lenu, recheader,
-                                sizeof(recheader)) <= 0
-            || EVP_CipherUpdate(enc_ctx, rec->data, &lenu, rec->input,
-                                (unsigned int)rec->length) <= 0
+         && EVP_CipherUpdate(enc_ctx, NULL, &lenu, NULL, (int)rec->length) <= 0)
+            || EVP_CipherUpdate(enc_ctx, NULL, &lenu, recheader, (int)hdrlen) <= 0
+            || EVP_CipherUpdate(enc_ctx, rec->data, &lenu, rec->input, (int)rec->length) <= 0
             || EVP_CipherFinal_ex(enc_ctx, rec->data + lenu, &lenf) <= 0
             || (size_t)(lenu + lenf) != rec->length) {
         return 0;
@@ -302,7 +329,8 @@ static int tls13_post_process_record(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *rec)
         size_t end;
 
         if (rec->length == 0
-                || rec->type != SSL3_RT_APPLICATION_DATA) {
+                || rl->isdtls ? !DTLS13_UNI_HDR_FIX_BITS_IS_SET(rec->type)
+                              : rec->type != SSL3_RT_APPLICATION_DATA) {
             RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE,
                         SSL_R_BAD_RECORD_TYPE);
             return 0;
@@ -340,6 +368,15 @@ static uint8_t tls13_get_record_type(OSSL_RECORD_LAYER *rl,
      * when encrypting in TLSv1.3. The "inner" record type encodes the "real"
      * record type from the template.
      */
+    if (rl->isdtls) {
+        const unsigned char fixed = DTLS13_UNI_HDR_FIX_BITS;
+        const unsigned char sbit = DTLS13_UNI_HDR_SEQ_BIT;
+        const unsigned char lbit = DTLS13_UNI_HDR_LEN_BIT;
+        const unsigned char epochbits = DTLS13_UNI_HDR_EPOCH_BITS_MASK & rl->epoch;
+
+        return fixed | sbit | lbit | epochbits;
+    }
+
     return SSL3_RT_APPLICATION_DATA;
 }
 
index aaf13051c476ccfd1af1224283355c725003a2b1..2bc0cbc72e320ae60bafec6781fef5e541027cbd 100644 (file)
@@ -626,12 +626,7 @@ int tls1_initialise_write_packets(OSSL_RECORD_LAYER *rl,
         prefixtempl->type = SSL3_RT_APPLICATION_DATA;
 
         wb = &bufs[0];
-
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
-        align = (size_t)TLS_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
-        align = SSL3_ALIGN_PAYLOAD - 1
-                - ((align - 1) % SSL3_ALIGN_PAYLOAD);
-#endif
+        align = tls_get_record_body_alignment_offset(rl, TLS_BUFFER_get_buf(wb));
         TLS_BUFFER_set_offset(wb, align);
 
         if (!WPACKET_init_static_len(&pkt[0], TLS_BUFFER_get_buf(wb),
index 77b09720136d75371f9638f82676e1a1a83e02b2..dfbb7decc1e5e3e591a5bab9ec897dcccc8605bc 100644 (file)
@@ -151,10 +151,7 @@ int tls_setup_write_buffer(OSSL_RECORD_LAYER *rl, size_t numwpipes,
     const int version1_3 = rl->isdtls ? DTLS1_3_VERSION : TLS1_3_VERSION;
 
     if (firstlen == 0 || (numwpipes > 1 && nextlen == 0)) {
-        if (rl->isdtls)
-            headerlen = DTLS1_RT_HEADER_LENGTH + 1;
-        else
-            headerlen = SSL3_RT_HEADER_LENGTH;
+        headerlen = tls_get_record_header_len(rl);
 
         /* (D)TLSv1.3 adds an extra content type byte after payload data */
         if (rl->version == version1_3)
@@ -235,10 +232,7 @@ int tls_setup_read_buffer(OSSL_RECORD_LAYER *rl)
 
     b = &rl->rbuf;
 
-    if (rl->isdtls)
-        headerlen = DTLS1_RT_HEADER_LENGTH;
-    else
-        headerlen = SSL3_RT_HEADER_LENGTH;
+    headerlen = tls_get_record_header_len(rl);
 
 #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
     maxalign = SSL3_ALIGN_PAYLOAD - 1;
@@ -636,7 +630,7 @@ int tls_get_more_records(OSSL_RECORD_LAYER *rl)
                         || !PACKET_get_net_2(&pkt, &version)
                         || !PACKET_get_net_2_len(&pkt, &thisrr->length)) {
                     if (rl->msg_callback != NULL)
-                        rl->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, rl->cbarg);
+                        rl->msg_callback(0, 0, SSL3_RT_HEADER, p, SSL3_RT_HEADER_LENGTH, rl->cbarg);
                     RLAYERfatal(rl, SSL_AD_DECODE_ERROR, ERR_R_INTERNAL_ERROR);
                     return OSSL_RECORD_RETURN_FATAL;
                 }
@@ -656,7 +650,8 @@ int tls_get_more_records(OSSL_RECORD_LAYER *rl)
                 }
 
                 if (rl->msg_callback != NULL)
-                    rl->msg_callback(0, version, SSL3_RT_HEADER, p, 5, rl->cbarg);
+                    rl->msg_callback(0, version, SSL3_RT_HEADER, p,
+                                     SSL3_RT_HEADER_LENGTH, rl->cbarg);
 
                 if (thisrr->length >
                     TLS_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) {
@@ -1562,6 +1557,21 @@ int tls_allocate_write_buffers_default(OSSL_RECORD_LAYER *rl,
     return 1;
 }
 
+size_t tls_get_record_body_alignment_offset(OSSL_RECORD_LAYER *rl,
+                                            const unsigned char *rec)
+{
+    size_t alignoffset = 0;
+    size_t headersize = tls_get_record_header_len(rl);
+
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
+    alignoffset = (size_t)rec;
+    alignoffset += headersize;
+    alignoffset = SSL3_ALIGN_PAYLOAD - 1 - ((alignoffset - 1) % SSL3_ALIGN_PAYLOAD);
+#endif
+
+    return alignoffset;
+}
+
 int tls_initialise_write_packets_default(OSSL_RECORD_LAYER *rl,
                                          OSSL_RECORD_TEMPLATE *templates,
                                          size_t numtempl,
@@ -1579,13 +1589,7 @@ int tls_initialise_write_packets_default(OSSL_RECORD_LAYER *rl,
         wb = &bufs[j];
 
         wb->type = templates[j].type;
-
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
-        align = (size_t)TLS_BUFFER_get_buf(wb);
-        align += rl->isdtls ? DTLS1_RT_HEADER_LENGTH : SSL3_RT_HEADER_LENGTH;
-        align = SSL3_ALIGN_PAYLOAD - 1
-                - ((align - 1) % SSL3_ALIGN_PAYLOAD);
-#endif
+        align = tls_get_record_body_alignment_offset(rl, TLS_BUFFER_get_buf(wb));
         TLS_BUFFER_set_offset(wb, align);
 
         if (!WPACKET_init_static_len(thispkt, TLS_BUFFER_get_buf(wb),
@@ -1689,8 +1693,9 @@ int tls_post_encryption_processing_default(OSSL_RECORD_LAYER *rl,
                                            TLS_RL_RECORD *thiswr)
 {
     size_t origlen, len;
-    size_t headerlen = rl->isdtls ? DTLS1_RT_HEADER_LENGTH
-                                  : SSL3_RT_HEADER_LENGTH;
+    unsigned char *recordstart;
+    size_t rechdrlen;
+    size_t written;
 
     /* Allocate bytes for the encryption overhead */
     if (!WPACKET_get_length(thispkt, &origlen)
@@ -1719,31 +1724,37 @@ int tls_post_encryption_processing_default(OSSL_RECORD_LAYER *rl,
     }
 
     if (!WPACKET_get_length(thispkt, &len)
-            || !WPACKET_close(thispkt)) {
+            || !WPACKET_close(thispkt)
+            || !WPACKET_get_total_written(thispkt, &written)) {
         RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         return 0;
     }
 
-    if (rl->sn_enc_ctx != NULL) {
-        unsigned char *recordstart;
+    recordstart = WPACKET_get_curr(thispkt) - written;
+    recordstart += tls_get_record_body_alignment_offset(rl, recordstart);
+
+    if (rl->isdtls)
+        rechdrlen = dtls_get_rec_header_size(*recordstart);
+    else
+        rechdrlen = SSL3_RT_HEADER_LENGTH;
 
-        recordstart = WPACKET_get_curr(thispkt) - len - headerlen;
+    if (rl->isdtls && DTLS13_UNI_HDR_FIX_BITS_IS_SET(*recordstart)) {
+        size_t seqnumlen = DTLS13_UNI_HDR_SEQ_BIT_IS_SET(*recordstart) ? 2 : 1;
 
-        if (!dtls_crypt_sequence_number(rl->sn_enc_ctx, recordstart + DTLS1_RT_HEADER_SEQ_OFFS,
-                                        recordstart + DTLS1_RT_HEADER_LENGTH,
-                                        rl->sn_enc_offs)) {
+        if (!ossl_assert(DTLS13_UNI_HDR_SEQ_OFF + seqnumlen <= rechdrlen)
+            || !dtls_crypt_sequence_number(rl->sn_enc_ctx, recordstart + DTLS13_UNI_HDR_SEQ_OFF,
+                                           seqnumlen, recordstart + rechdrlen,
+                                           rl->sn_enc_offs)) {
             RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
             return 0;
         }
     }
 
     if (rl->msg_callback != NULL) {
-        unsigned char *recordstart;
         const int version1_3 = rl->isdtls ? DTLS1_3_VERSION : TLS1_3_VERSION;
 
-        recordstart = WPACKET_get_curr(thispkt) - len - headerlen;
         rl->msg_callback(1, thiswr->rec_version, SSL3_RT_HEADER, recordstart,
-                         headerlen, rl->cbarg);
+                         rechdrlen, rl->cbarg);
 
         if (rl->version == version1_3 && rl->enc_ctx != NULL) {
             unsigned char ctype = thistempl->type;
@@ -1758,7 +1769,7 @@ int tls_post_encryption_processing_default(OSSL_RECORD_LAYER *rl,
         return 0;
     }
 
-    TLS_RL_RECORD_add_length(thiswr, headerlen);
+    TLS_RL_RECORD_add_length(thiswr, rechdrlen);
 
     return 1;
 }
@@ -2017,6 +2028,22 @@ int tls_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio)
     return 1;
 }
 
+size_t tls_get_record_header_len(OSSL_RECORD_LAYER *rl)
+{
+    size_t headerlen;
+
+    if (rl->isdtls) {
+        if (rl->version == DTLS1_3_VERSION && rl->epoch > 0)
+            headerlen = DTLS13_UNI_HDR_FIXED_LENGTH;
+        else
+            headerlen = DTLS1_RT_HEADER_LENGTH;
+    } else {
+        headerlen = SSL3_RT_HEADER_LENGTH;
+    }
+
+    return headerlen;
+}
+
 /* Shared by most methods except tlsany_meth */
 int tls_default_set_protocol_version(OSSL_RECORD_LAYER *rl, int version)
 {
index 07e0756803cadfe2b7721d853a34911cb214e682..dcb562e34a1a95d8078f60d4faa5df169c374641 100644 (file)
@@ -120,6 +120,21 @@ static void copy_flags(BIO *bio)
 #define MSG_FRAG_LEN_MID        10
 #define MSG_FRAG_LEN_LO         11
 
+/* Returns true if the unified header fixed bits are set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_FIX_BITS_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_FIX_BITS_MASK) == DTLS13_UNI_HDR_FIX_BITS)
+
+/* Returns true if the unified header connection id bit is set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_CID_BIT_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_CID_BIT) == DTLS13_UNI_HDR_CID_BIT)
+
+/* Returns true if the unified header sequence number bit is set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_SEQ_BIT_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_SEQ_BIT) == DTLS13_UNI_HDR_SEQ_BIT)
+
+/* Returns true if the unified header length bit is set (rfc9147 section 4) */
+#define DTLS13_UNI_HDR_LEN_BIT_IS_SET(byte) \
+    (((byte) & DTLS13_UNI_HDR_LEN_BIT) == DTLS13_UNI_HDR_LEN_BIT)
 
 static void dump_data(const char *data, int len)
 {
@@ -135,6 +150,9 @@ static void dump_data(const char *data, int len)
         if (rem != len)
             printf("*\n");
         printf("*---- START OF RECORD ----\n");
+        /*
+         * TODO(DTLSv1.3): support variable length headers
+         */
         if (rem < DTLS1_RT_HEADER_LENGTH) {
             printf("*---- RECORD TRUNCATED ----\n");
             break;
@@ -543,8 +561,22 @@ int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum,
     MEMPACKET *thispkt = NULL, *looppkt, *nextpkt, *allpkts[3];
     int i, duprec;
     const unsigned char *inu = (const unsigned char *)in;
-    size_t len = ((inu[RECORD_LEN_HI] << 8) | inu[RECORD_LEN_LO])
-                 + DTLS1_RT_HEADER_LENGTH;
+    size_t len;
+
+    if (DTLS13_UNI_HDR_FIX_BITS_IS_SET(*in)
+            /* The following code does not handle connection ids */
+            && ossl_assert(!DTLS13_UNI_HDR_CID_BIT_IS_SET(*in))) {
+        if (DTLS13_UNI_HDR_LEN_BIT_IS_SET(*in)) {
+            len = 3; /* 2 bytes for len field and 1 byte for record type */
+            len += DTLS13_UNI_HDR_SEQ_BIT_IS_SET(*in) ? 2 : 1;
+        } else {
+            /* We assert that inl is the correct record length */
+            len = inl;
+        }
+    } else {
+        len = ((inu[RECORD_LEN_HI] << 8) | inu[RECORD_LEN_LO]);
+        len += DTLS1_RT_HEADER_LENGTH;
+    }
 
     if (ctx == NULL)
         return -1;
index 4d4a48498f284575a3fc0de6d92ddd4f845bfab2..8f90dea4be5e3d3f015cf219b209cb6e7323d9a1 100644 (file)
@@ -20,11 +20,15 @@ use constant TLS_RECORD_HEADER_LENGTH => 5;
 
 #Record types
 use constant {
-    RT_APPLICATION_DATA => 23,
-    RT_HANDSHAKE => 22,
-    RT_ALERT => 21,
-    RT_CCS => 20,
-    RT_UNKNOWN => 100
+    RT_APPLICATION_DATA   => 23,
+    RT_HANDSHAKE          => 22,
+    RT_ALERT              => 21,
+    RT_CCS                => 20,
+    RT_UNKNOWN            => 100,
+    RT_DTLS_UNIHDR_EPOCH4 => 0x2c,
+    RT_DTLS_UNIHDR_EPOCH1 => 0x2d,
+    RT_DTLS_UNIHDR_EPOCH2 => 0x2e,
+    RT_DTLS_UNIHDR_EPOCH3 => 0x2f,
 };
 
 my %record_type = (
@@ -32,7 +36,11 @@ my %record_type = (
     RT_HANDSHAKE, "HANDSHAKE",
     RT_ALERT, "ALERT",
     RT_CCS, "CCS",
-    RT_UNKNOWN, "UNKNOWN"
+    RT_UNKNOWN, "UNKNOWN",
+    RT_DTLS_UNIHDR_EPOCH4, "DTLS UNIFIED HEADER (EPOCH 4)",
+    RT_DTLS_UNIHDR_EPOCH1, "DTLS UNIFIED HEADER (EPOCH 1)",
+    RT_DTLS_UNIHDR_EPOCH2, "DTLS UNIFIED HEADER (EPOCH 2)",
+    RT_DTLS_UNIHDR_EPOCH3, "DTLS UNIFIED HEADER (EPOCH 3)",
 );
 
 use constant {
@@ -71,14 +79,12 @@ sub get_records
     my $partial = "";
     my @record_list = ();
     my @message_list = ();
-    my $record_hdr_len = $isdtls ? DTLS_RECORD_HEADER_LENGTH
-                                 : TLS_RECORD_HEADER_LENGTH;
 
     my $recnum = 1;
     while (length ($packet) > 0) {
         print " Record $recnum ", $server ? "(server -> client)\n"
                                           : "(client -> server)\n";
-
+        my $record_hdr_len;
         my $content_type;
         my $version;
         my $len;
@@ -86,16 +92,56 @@ sub get_records
         my $seq;
 
         if ($isdtls) {
-            my $seqhi;
-            my $seqmi;
-            my $seqlo;
-            #Get the record header (unpack can't fail if $packet is too short)
-            ($content_type, $version, $epoch,
-                $seqhi, $seqmi, $seqlo, $len) = unpack('Cnnnnnn', $packet);
-            $seq = ($seqhi << 32) | ($seqmi << 16) | $seqlo
+            my $isunifiedhdr;
+
+            $content_type = unpack('B[8]', $packet);
+            $isunifiedhdr = substr($content_type, 0, 3) == "001";
+
+            if ($isunifiedhdr == 1) {
+                my $cbit = substr($content_type, 3, 1);
+                my $sbit = substr($content_type, 4, 1);
+                my $lbit = substr($content_type, 5, 1);
+                my $eebits = substr($content_type, 6, 2);
+
+                if ($cbit == "1" || $lbit == "0") {
+                    die("TLSProxy does not support variable DTLSv1.3 unified header bits");
+                }
+
+                # This is a unified header
+                if ($sbit == "1") {
+                    ($content_type, $seq, $len) = unpack('Cnn', $packet);
+                    $record_hdr_len = 5;
+                } else {
+                    ($content_type, $seq, $len) = unpack('CCn', $packet);
+                    $record_hdr_len = 4;
+                }
+                $version = VERS_DTLS_1_2; # DTLSv1.3 headers has DTLSv1.2 in its legacy_version field
+
+                if ($eebits == "00") {
+                    $epoch = 4; # must be at least 4 since 0 epoch are not sent with unified hdr
+                } elsif ($eebits == "01") {
+                    $epoch = 1;
+                } elsif ($eebits == "10") {
+                    $epoch = 2;
+                } elsif ($eebits == "11") {
+                    $epoch = 3;
+                } else {
+                    die("Epoch bits is not 0's or 1's: should not happen")
+                }
+            } else {
+                my $seqhi;
+                my $seqmi;
+                my $seqlo;
+                #Get the record header (unpack can't fail if $packet is too short)
+                ($content_type, $version, $epoch,
+                    $seqhi, $seqmi, $seqlo, $len) = unpack('Cnnnnnn', $packet);
+                $seq = ($seqhi << 32) | ($seqmi << 16) | $seqlo;
+                $record_hdr_len = DTLS_RECORD_HEADER_LENGTH;
+            }
         } else {
             #Get the record header (unpack can't fail if $packet is too short)
             ($content_type, $version, $len) = unpack('Cnn', $packet);
+            $record_hdr_len = TLS_RECORD_HEADER_LENGTH;
         }
 
         if (length($packet) < $record_hdr_len + ($len // 0)) {
@@ -295,7 +341,7 @@ sub init
         orig_decrypt_data => $decrypt_data,
         sent => 0,
         encrypted => 0,
-        outer_content_type => RT_APPLICATION_DATA
+        outer_content_type => $content_type,
     };
 
     return bless $self, $class;
@@ -397,11 +443,16 @@ sub reconstruct_record
         my $content_type = (TLSProxy::Proxy->is_tls13() && $self->encrypted)
                            ? $self->outer_content_type : $self->content_type;
         if($self->{isdtls}) {
-            my $seqhi = ($self->seq >> 32) & 0xffff;
-            my $seqmi = ($self->seq >> 16) & 0xffff;
-            my $seqlo = ($self->seq >> 0) & 0xffff;
-            $data = pack('Cnnnnnn', $content_type, $self->version,
-                         $self->epoch, $seqhi, $seqmi, $seqlo, $self->len);
+            if (TLSProxy::Proxy->is_tls13() && $self->encrypted) {
+                # Prepare a unified header
+                $data = pack('Cnn', $content_type, $self->seq, $self->len);
+            } else {
+                my $seqhi = ($self->seq >> 32) & 0xffff;
+                my $seqmi = ($self->seq >> 16) & 0xffff;
+                my $seqlo = ($self->seq >> 0) & 0xffff;
+                $data = pack('Cnnnnnn', $content_type, $self->version,
+                    $self->epoch, $seqhi, $seqmi, $seqlo, $self->len);
+            }
         } else {
             $data = pack('Cnn', $content_type, $self->version,
                          $self->len);