=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>
=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>
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
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
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.
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,
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);
/* TLSv1.3 record padding */
size_t block_padding;
+ size_t hs_padding;
/* Only used by SSLv3 */
unsigned char mac_secret[EVP_MAX_MD_SIZE];
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 */
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) {
} 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();
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;
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;
}
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;
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))
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);
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;
* 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)
{
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,
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)))
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);
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:
'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