]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Extend TLSv1.3 record layer padding API calls
authorStephen Farrell <stephen.farrell@cs.tcd.ie>
Thu, 4 Jul 2024 16:34:47 +0000 (17:34 +0100)
committerTomas Mraz <tomas@openssl.org>
Wed, 10 Jul 2024 09:44:39 +0000 (11:44 +0200)
Added SSL_set_block_padding_ex() and SSL_CTX_set_block_padding_ex()
to allow separate padding block size values for handshake messages
and application data messages.

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

14 files changed:
doc/man3/SSL_CONF_cmd.pod
doc/man3/SSL_CTX_set_record_padding_callback.pod
include/openssl/ssl.h.in
ssl/record/methods/recmethod_local.h
ssl/record/methods/tls13_meth.c
ssl/record/methods/tls_common.c
ssl/record/rec_layer_s3.c
ssl/record/record.h
ssl/ssl_conf.c
ssl/ssl_lib.c
ssl/ssl_local.h
test/sslapitest.c
util/libssl.num
util/perl/OpenSSL/paramnames.pm

index d9596b82317ee6f5a8a873ae3010673733d2f969..d2fba6a876a5fd55e1b44d0b2eba65eaafefd7fd 100644 (file)
@@ -227,9 +227,15 @@ deprecated alternative commands below.
 
 =item B<-record_padding> I<padding>
 
-Attempts to pad TLSv1.3 records so that they are a multiple of B<padding>
-in length on send. A B<padding> of 0 or 1 turns off padding. Otherwise,
-the B<padding> must be >1 or <=16384.
+Controls use of TLSv1.3 record layer padding.  B<padding> is a string of the
+form "number[,number]" where the (required) first number is the padding block
+size (in octets) for application data, and the optional second number is the
+padding block size for handshake and alert messages.  If the optional second
+number is omitted, the same padding will be applied to all messages.
+
+Padding attempts to pad TLSv1.3 records so that they are a multiple of the set
+length on send. A value of 0 or 1 turns off padding as relevant. Otherwise, the
+values must be >1 or <=16384.
 
 =item B<-debug_broken_protocol>
 
@@ -359,9 +365,15 @@ operations are permitted.
 
 =item B<RecordPadding>
 
-Attempts to pad TLSv1.3 records so that they are a multiple of B<value> in
-length on send. A B<value> of 0 or 1 turns off padding. Otherwise, the
-B<value> must be >1 or <=16384.
+Controls use of TLSv1.3 record layer padding.  B<value> is a string of the form
+"number[,number]" where the (required) first number is the padding block size
+(in octets) for application data, and the optional second number is the padding
+block size for handshake and alert messages.  If the optional second number is
+omitted, the same padding will be applied to all messages.
+
+Padding attempts to pad TLSv1.3 records so that they are a multiple of the set
+length on send. A value of 0 or 1 turns off padding as relevant. Otherwise, the
+values must be >1 or <=16384.
 
 =item B<SignatureAlgorithms>
 
index e91f903b0154a5a89008f9686ce1cc2eb41f3a9a..6d70ebd90073bd626c63dd523a4c79d326df7b41 100644 (file)
@@ -9,7 +9,9 @@ SSL_set_record_padding_callback_arg,
 SSL_CTX_get_record_padding_callback_arg,
 SSL_get_record_padding_callback_arg,
 SSL_CTX_set_block_padding,
-SSL_set_block_padding - install callback to specify TLS 1.3 record padding
+SSL_CTX_set_block_padding_ex,
+SSL_set_block_padding,
+SSL_set_block_padding_ex - install callback to specify TLS 1.3 record padding
 
 =head1 SYNOPSIS
 
@@ -26,6 +28,8 @@ SSL_set_block_padding - install callback to specify TLS 1.3 record padding
 
  int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size);
  int SSL_set_block_padding(SSL *ssl, size_t block_size);
+ int SSL_CTX_set_block_padding_ex(SSL_CTX *ctx, size_t app_block_size, size_t hs_block_size);
+ int SSL_set_block_padding_ex(SSL *ssl, size_t app_block_size, size_t hs_block_size);
 
 =head1 DESCRIPTION
 
@@ -46,6 +50,10 @@ SSL_CTX_set_block_padding() and SSL_set_block_padding() pads the record to a mul
 of the B<block_size>. A B<block_size> of 0 or 1 disables block padding. The limit of
 B<block_size> is SSL3_RT_MAX_PLAIN_LENGTH.
 
+SSL_CTX_set_block_padding_ex() and SSL_set_block_padding_ex() do similarly but
+allow the caller to separately specify the padding block size to be applied to
+handshake and application data messages.
+
 The callback is invoked for every record before encryption.
 The B<type> parameter is the TLS record type that is being processed; may be
 one of SSL3_RT_APPLICATION_DATA, SSL3_RT_HANDSHAKE, or SSL3_RT_ALERT.
index c4a40c95c34a8d029355a972b242304150f9195b..4bab2ac767f5589c9077983308618a5c98ec0d3a 100644 (file)
@@ -2263,6 +2263,8 @@ void SSL_CTX_set_record_padding_callback(SSL_CTX *ctx,
 void SSL_CTX_set_record_padding_callback_arg(SSL_CTX *ctx, void *arg);
 void *SSL_CTX_get_record_padding_callback_arg(const SSL_CTX *ctx);
 int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size);
+int SSL_CTX_set_block_padding_ex(SSL_CTX *ctx, size_t app_block_size,
+                                 size_t hs_block_size);
 
 int SSL_set_record_padding_callback(SSL *ssl,
                                     size_t (*cb) (SSL *ssl, int type,
@@ -2270,7 +2272,8 @@ int SSL_set_record_padding_callback(SSL *ssl,
 void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg);
 void *SSL_get_record_padding_callback_arg(const SSL *ssl);
 int SSL_set_block_padding(SSL *ssl, size_t block_size);
-
+int SSL_set_block_padding_ex(SSL *ssl, size_t app_block_size,
+                             size_t hs_block_size);
 int SSL_set_num_tickets(SSL *s, size_t num_tickets);
 size_t SSL_get_num_tickets(const SSL *s);
 int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets);
index 5a3d010503a869f15e1632ec40a44e7669a1a37a..e08737eb76f992b3d48a9d74de119c18b85cecfa 100644 (file)
@@ -324,6 +324,7 @@ struct ossl_record_layer_st
 
     /* TLSv1.3 record padding */
     size_t block_padding;
+    size_t hs_padding;
 
     /* Only used by SSLv3 */
     unsigned char mac_secret[EVP_MAX_MD_SIZE];
index afae14ad22b20158cc4ff889ad58549b41abf003..706a0b8623fdf09de160eca843704bbcf6489223 100644 (file)
@@ -335,22 +335,51 @@ static int tls13_add_record_padding(OSSL_RECORD_LAYER *rl,
         size_t padding = 0;
         size_t max_padding = rl->max_frag_len - rlen;
 
+        /*
+         * We might want to change the "else if" below so that
+         * library-added padding can still happen even if there
+         * is an application-layer callback. The reason being
+         * the application may not be aware that the effectivness
+         * of ECH could be damaged if the callback e.g. only
+         * padded application data. However, doing so would be
+         * a change that could break some application that has
+         * a client and server that both know what padding they
+         * like, and that dislike any other padding. That'd need
+         * one of those to have been updated though so the 
+         * probability may be low enough that we could change
+         * the "else if" below to just an "if" and pick the
+         * larger of the library and callback's idea of padding.
+         * (Still subject to max_padding though.)
+         */
         if (rl->padding != NULL) {
             padding = rl->padding(rl->cbarg, thistempl->type, rlen);
-        } else if (rl->block_padding > 0) {
-            size_t mask = rl->block_padding - 1;
-            size_t remainder;
-
-            /* optimize for power of 2 */
-            if ((rl->block_padding & mask) == 0)
-                remainder = rlen & mask;
-            else
-                remainder = rlen % rl->block_padding;
-            /* don't want to add a block of padding if we don't have to */
-            if (remainder == 0)
-                padding = 0;
-            else
-                padding = rl->block_padding - remainder;
+        } else if (rl->block_padding > 0 || rl->hs_padding > 0) {
+            size_t mask, bp = 0, remainder;
+
+            /*
+             * pad handshake or alert messages based on |hs_padding|
+             * but application data based on |block_padding|
+             */
+            if (thistempl->type == SSL3_RT_HANDSHAKE && rl->hs_padding > 0)
+                bp = rl->hs_padding;
+            else if (thistempl->type == SSL3_RT_ALERT && rl->hs_padding > 0)
+                bp = rl->hs_padding;
+            else if (thistempl->type == SSL3_RT_APPLICATION_DATA
+                     && rl->block_padding > 0)
+                bp = rl->block_padding;
+            if (bp > 0) {
+                mask = bp - 1;
+                /* optimize for power of 2 */
+                if ((bp & mask) == 0)
+                    remainder = rlen & mask;
+                else
+                    remainder = rlen % bp;
+                /* don't want to add a block of padding if we don't have to */
+                if (remainder == 0)
+                    padding = 0;
+                else
+                    padding = bp - remainder;
+            }
         }
         if (padding > 0) {
             /* do not allow the record to exceed max plaintext length */
index b09991cafb1d7c7cd1b874846da6157e492db32b..0d92bdce9b7201c7d844196f2a399acdf4ca96c3 100644 (file)
@@ -1218,6 +1218,12 @@ int tls_set_options(OSSL_RECORD_LAYER *rl, const OSSL_PARAM *options)
             ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
             return 0;
         }
+        p = OSSL_PARAM_locate_const(options,
+                                    OSSL_LIBSSL_RECORD_LAYER_PARAM_HS_PADDING);
+        if (p != NULL && !OSSL_PARAM_get_size_t(p, &rl->hs_padding)) {
+            ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+            return 0;
+        }
     }
 
     if (rl->level == OSSL_RECORD_PROTECTION_LEVEL_APPLICATION) {
index e61861d9fd16ed6d288244dc338d51e87fe6c10a..14db7dab2cd777ec03797728e41ba55c835ac490 100644 (file)
@@ -1288,6 +1288,8 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
     } else {
         *opts++ = OSSL_PARAM_construct_size_t(OSSL_LIBSSL_RECORD_LAYER_PARAM_BLOCK_PADDING,
                                               &s->rlayer.block_padding);
+        *opts++ = OSSL_PARAM_construct_size_t(OSSL_LIBSSL_RECORD_LAYER_PARAM_HS_PADDING,
+                                              &s->rlayer.hs_padding);
     }
     *opts = OSSL_PARAM_construct_end();
 
index 9a076a1fb8865e663cccdc3aa46b50098db55422..13f09fda8ccb771d70ab9d9ca727f91f16187f93 100644 (file)
@@ -113,6 +113,7 @@ typedef struct record_layer_st {
     size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg);
     void *record_padding_arg;
     size_t block_padding;
+    size_t hs_padding;
 
     /* How many records we have read from the record layer */
     size_t num_recs;
index 77de00542b06aaa0848c9559b0b341e2b6fb8a47..0deae1604f7b65cb440e11adba86a72a7ee7d1e1 100644 (file)
@@ -649,20 +649,44 @@ static int cmd_DHParameters(SSL_CONF_CTX *cctx, const char *value)
     return rv > 0;
 }
 
+/*
+ * |value| input is "<number[,number]>"
+ * where the first number is the padding block size for
+ * application data, and the optional second is the
+ * padding block size for handshake messages
+ */
 static int cmd_RecordPadding(SSL_CONF_CTX *cctx, const char *value)
 {
     int rv = 0;
-    int block_size = atoi(value);
+    size_t block_padding = 0, hs_padding = 0;
+    char *commap = NULL, *copy = NULL;
 
+    copy = OPENSSL_strdup(value);
+    if (copy == NULL)
+        return 0;
+    commap = strstr(copy, ",");
+    if (commap != NULL) {
+        *commap = '\0';
+        if (*(commap + 1) == '\0') {
+            OPENSSL_free(copy);
+            return 0;
+        }
+        hs_padding = (size_t) atoi(commap + 1);
+    }
+    block_padding = (size_t) atoi(copy);
+    if (commap == NULL)
+        hs_padding = block_padding;
+    OPENSSL_free(copy);
     /*
-     * All we care about is a non-negative value,
+     * All we care about are non-negative values,
      * the setters check the range
      */
-    if (block_size >= 0) {
+    if (block_padding >= 0 || hs_padding >= 0) {
         if (cctx->ctx)
-            rv = SSL_CTX_set_block_padding(cctx->ctx, block_size);
+            rv = SSL_CTX_set_block_padding_ex(cctx->ctx, block_padding,
+                                              hs_padding);
         if (cctx->ssl)
-            rv = SSL_set_block_padding(cctx->ssl, block_size);
+            rv = SSL_set_block_padding_ex(cctx->ssl, block_padding, hs_padding);
     }
     return rv;
 }
index 589ed2c64d4f9c9b3bcb83439378554fce63c75d..3b82673957503a59cfdd11ac67dd1835c042e10d 100644 (file)
@@ -785,6 +785,7 @@ SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, const SSL_METHOD *method)
     s->rlayer.record_padding_cb = ctx->record_padding_cb;
     s->rlayer.record_padding_arg = ctx->record_padding_arg;
     s->rlayer.block_padding = ctx->block_padding;
+    s->rlayer.hs_padding = ctx->hs_padding;
     s->sid_ctx_length = ctx->sid_ctx_length;
     if (!ossl_assert(s->sid_ctx_length <= sizeof(s->sid_ctx)))
         goto err;
@@ -5713,21 +5714,35 @@ void *SSL_CTX_get_record_padding_callback_arg(const SSL_CTX *ctx)
     return ctx->record_padding_arg;
 }
 
-int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size)
+int SSL_CTX_set_block_padding_ex(SSL_CTX *ctx, size_t app_block_size,
+                                 size_t hs_block_size)
 {
-    if (IS_QUIC_CTX(ctx) && block_size > 1)
+    if (IS_QUIC_CTX(ctx) && (app_block_size > 1 || hs_block_size > 1))
         return 0;
 
     /* block size of 0 or 1 is basically no padding */
-    if (block_size == 1)
+    if (app_block_size == 1) {
         ctx->block_padding = 0;
-    else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
-        ctx->block_padding = block_size;
-    else
+    } else if (app_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) {
+        ctx->block_padding = app_block_size;
+    } else {
+        return 0;
+    }
+    if (hs_block_size == 1) {
+        ctx->hs_padding = 0;
+    } else if (hs_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) {
+        ctx->hs_padding = hs_block_size;
+    } else {
         return 0;
+    }
     return 1;
 }
 
+int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size)
+{
+    return SSL_CTX_set_block_padding_ex(ctx, block_size, block_size);
+}
+
 int SSL_set_record_padding_callback(SSL *ssl,
                                      size_t (*cb) (SSL *ssl, int type,
                                                    size_t len, void *arg))
@@ -5766,23 +5781,39 @@ void *SSL_get_record_padding_callback_arg(const SSL *ssl)
     return sc->rlayer.record_padding_arg;
 }
 
-int SSL_set_block_padding(SSL *ssl, size_t block_size)
+int SSL_set_block_padding_ex(SSL *ssl, size_t app_block_size,
+                             size_t hs_block_size)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
 
-    if (sc == NULL || (IS_QUIC(ssl) && block_size > 1))
+    if (sc == NULL
+        || (IS_QUIC(ssl)
+            && (app_block_size > 1 || hs_block_size > 1)))
         return 0;
 
     /* block size of 0 or 1 is basically no padding */
-    if (block_size == 1)
+    if (app_block_size == 1) {
         sc->rlayer.block_padding = 0;
-    else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
-        sc->rlayer.block_padding = block_size;
-    else
+    } else if (app_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) {
+        sc->rlayer.block_padding = app_block_size;
+    } else {
+        return 0;
+    }
+    if (hs_block_size == 1) {
+        sc->rlayer.hs_padding = 0;
+    } else if (hs_block_size <= SSL3_RT_MAX_PLAIN_LENGTH) {
+        sc->rlayer.hs_padding = hs_block_size;
+    } else {
         return 0;
+    }
     return 1;
 }
 
+int SSL_set_block_padding(SSL *ssl, size_t block_size)
+{
+    return SSL_set_block_padding_ex(ssl, block_size, block_size);
+}
+
 int SSL_set_num_tickets(SSL *s, size_t num_tickets)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
index daab329133cb8bcce3eff714691705e3b8e561f9..d76a014cabf26dbed9f9a3f85461bf481b4db239 100644 (file)
@@ -1126,6 +1126,7 @@ struct ssl_ctx_st {
     size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg);
     void *record_padding_arg;
     size_t block_padding;
+    size_t hs_padding;
 
     /* Session ticket appdata */
     SSL_CTX_generate_session_ticket_fn generate_ticket_cb;
index 7ad12f29713f74411c1d86bffa2489bbfdf05c2f..4cd469174d6e614f198dcade8da6a2d2428e1524 100644 (file)
@@ -11104,6 +11104,8 @@ static size_t record_pad_cb(SSL *s, int type, size_t len, void *arg)
  * Test 1: Record padding callback on the SSL
  * Test 2: Record block padding on the SSL_CTX
  * Test 3: Record block padding on the SSL
+ * Test 4: Extended record block padding on the SSL_CTX
+ * Test 5: Extended record block padding on the SSL
  */
 static int test_tls13_record_padding(int idx)
 {
@@ -11133,6 +11135,10 @@ static int test_tls13_record_padding(int idx)
             goto end;
         if (!TEST_true(SSL_CTX_set_block_padding(cctx, 512)))
             goto end;
+    } else if (idx == 4) {
+        /* pad only handshake/alert messages */
+        if (!TEST_true(SSL_CTX_set_block_padding_ex(cctx, 0, 512)))
+            goto end;
     }
 
     if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
@@ -11151,6 +11157,16 @@ static int test_tls13_record_padding(int idx)
             goto end;
         if (!TEST_true(SSL_set_block_padding(clientssl, 512)))
             goto end;
+    } else if (idx == 5) {
+        /* Exceeding the max plain length should fail */
+        if (!TEST_false(SSL_set_block_padding_ex(clientssl, 0,
+                                                 SSL3_RT_MAX_PLAIN_LENGTH + 1)))
+            goto end;
+        /* pad server and client handshake only */
+        if (!TEST_true(SSL_set_block_padding_ex(clientssl, 0, 512)))
+            goto end;
+        if (!TEST_true(SSL_set_block_padding_ex(serverssl, 0, 512)))
+            goto end;
     }
 
     if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
@@ -12637,7 +12653,7 @@ int setup_tests(void)
     ADD_TEST(test_load_dhfile);
 #ifndef OSSL_NO_USABLE_TLS1_3
     ADD_TEST(test_read_ahead_key_change);
-    ADD_ALL_TESTS(test_tls13_record_padding, 4);
+    ADD_ALL_TESTS(test_tls13_record_padding, 6);
 #endif
 #if !defined(OPENSSL_NO_TLS1_2) && !defined(OSSL_NO_USABLE_TLS1_3)
     ADD_ALL_TESTS(test_serverinfo_custom, 4);
index e232d3efd4c515daa968b9ab45a76a9114874302..cd2c7f06a16d7c720a5afaaf3eafec0d9bc70c40 100644 (file)
@@ -584,3 +584,5 @@ SSL_poll                                584 3_3_0   EXIST::FUNCTION:
 SSL_SESSION_get_time_ex                 585    3_3_0   EXIST::FUNCTION:
 SSL_SESSION_set_time_ex                 586    3_3_0   EXIST::FUNCTION:
 SSL_CTX_flush_sessions_ex               587    3_4_0   EXIST::FUNCTION:
+SSL_CTX_set_block_padding_ex            ?      3_4_0   EXIST::FUNCTION:
+SSL_set_block_padding_ex                ?      3_4_0   EXIST::FUNCTION:
index 204a8bb213e6dd6e1abc8dd0ef90c1ab5da23f20..6e5c027a223dfc99799f858bd4f2f99fea1dd4f1 100644 (file)
@@ -506,6 +506,7 @@ my %params = (
     'LIBSSL_RECORD_LAYER_PARAM_MAX_FRAG_LEN' =>   "max_frag_len",
     'LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA' => "max_early_data",
     'LIBSSL_RECORD_LAYER_PARAM_BLOCK_PADDING' =>  "block_padding",
+    'LIBSSL_RECORD_LAYER_PARAM_HS_PADDING' =>     "hs_padding",
 );
 
 # Generate string based macros for public consumption