summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTodd Short <tshort@akamai.com>2017-04-05 12:35:25 -0400
committerMatt Caswell <matt@openssl.org>2017-05-02 09:44:43 +0100
commitc649d10d3fee9fe22e4ae6bdf7f8117b91b92b03 (patch)
treee72effbded8ac2531b21ead7c2d95ee26d1652cc
parent20ee2bf138323c6688b6e8d71d695cf2bd53f857 (diff)
TLS1.3 Padding
Add padding callback for application control Standard block_size callback Documentation and tests included Configuration file/s_client/s_srver option Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/3130)
-rw-r--r--apps/apps.h6
-rw-r--r--doc/man3/SSL_CONF_cmd.pod12
-rw-r--r--doc/man3/SSL_CTX_set_record_padding_callback.pod96
-rw-r--r--include/openssl/ssl.h15
-rw-r--r--ssl/packet.c15
-rw-r--r--ssl/packet_locl.h3
-rw-r--r--ssl/record/rec_layer_s3.c37
-rw-r--r--ssl/ssl_conf.c22
-rw-r--r--ssl/ssl_lib.c61
-rw-r--r--ssl/ssl_locl.h10
-rw-r--r--test/recipes/80-test_ssl_new.t3
-rw-r--r--test/ssl-tests/24-padding.conf34
-rw-r--r--test/ssl-tests/24-padding.conf.in25
-rw-r--r--util/libssl.num8
14 files changed, 340 insertions, 7 deletions
diff --git a/apps/apps.h b/apps/apps.h
index a8de2dc0aa..de50de5907 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -214,7 +214,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate,
OPT_S_SERVERPREF, OPT_S_LEGACYRENEG, OPT_S_LEGACYCONN, \
OPT_S_ONRESUMP, OPT_S_NOLEGACYCONN, OPT_S_STRICT, OPT_S_SIGALGS, \
OPT_S_CLIENTSIGALGS, OPT_S_CURVES, OPT_S_NAMEDCURVE, OPT_S_CIPHER, \
- OPT_S_DHPARAM, OPT_S_DEBUGBROKE, OPT_S_COMP, \
+ OPT_S_DHPARAM, OPT_S_RECORD_PADDING, OPT_S_DEBUGBROKE, OPT_S_COMP, \
OPT_S__LAST
# define OPT_S_OPTIONS \
@@ -251,9 +251,12 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate,
{"cipher", OPT_S_CIPHER, 's', "Specify cipher list to be used"}, \
{"dhparam", OPT_S_DHPARAM, '<', \
"DH parameter file to use, in cert file if not specified"}, \
+ {"record_padding", OPT_S_RECORD_PADDING, 's', \
+ "Block size to pad TLS 1.3 records to."}, \
{"debug_broken_protocol", OPT_S_DEBUGBROKE, '-', \
"Perform all sorts of protocol violations for testing purposes"}
+
# define OPT_S_CASES \
OPT_S__FIRST: case OPT_S__LAST: break; \
case OPT_S_NOSSL3: \
@@ -277,6 +280,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate,
case OPT_S_NAMEDCURVE: \
case OPT_S_CIPHER: \
case OPT_S_DHPARAM: \
+ case OPT_S_RECORD_PADDING: \
case OPT_S_DEBUGBROKE
#define IS_NO_PROT_FLAG(o) \
diff --git a/doc/man3/SSL_CONF_cmd.pod b/doc/man3/SSL_CONF_cmd.pod
index f5c6576ed0..efd766d7db 100644
--- a/doc/man3/SSL_CONF_cmd.pod
+++ b/doc/man3/SSL_CONF_cmd.pod
@@ -110,6 +110,12 @@ Attempts to use the file B<value> as the set of temporary DH parameters for
the appropriate context. This option is only supported if certificate
operations are permitted.
+=item B<-record_padding>
+
+Attempts to pad TLS 1.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.
+
=item B<-min_protocol>, B<-max_protocol>
Sets the minimum and maximum supported protocol.
@@ -236,6 +242,12 @@ Attempts to use the file B<value> as the set of temporary DH parameters for
the appropriate context. This option is only supported if certificate
operations are permitted.
+=item B<RecordPadding>
+
+Attempts to pad TLS 1.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.
+
=item B<SignatureAlgorithms>
This sets the supported signature algorithms for TLS v1.2. For clients this
diff --git a/doc/man3/SSL_CTX_set_record_padding_callback.pod b/doc/man3/SSL_CTX_set_record_padding_callback.pod
new file mode 100644
index 0000000000..9eea2bc9df
--- /dev/null
+++ b/doc/man3/SSL_CTX_set_record_padding_callback.pod
@@ -0,0 +1,96 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_record_padding_callback,
+SSL_set_record_padding_callback,
+SSL_CTX_set_record_padding_callback_arg,
+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
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ void SSL_CTX_set_record_padding_callback(SSL_CTX *ctx, size_t (*cb)(SSL *s, int type, size_t len, void *arg));
+ void SSL_set_record_padding_callback(SSL *ssl, size_t (*cb)(SSL *s, int type, size_t len, void *arg));
+
+ void SSL_CTX_set_record_padding_callback_arg(SSL_CTX *ctx, void *arg);
+ void *SSL_CTX_get_record_padding_callback_arg(SSL_CTX *ctx);
+
+ void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg);
+ void *SSL_get_record_padding_callback_arg(SSL *ssl);
+
+ int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size);
+ int SSL_set_block_padding(SSL *ssl, size_t block_size);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_record_padding_callback() or SSL_set_record_padding_callback()
+can be used to assign a callback function I<cb> to specify the padding
+for TLS 1.3 records. The value set in B<ctx> is copied to a new SSL by SSL_new().
+
+SSL_CTX_set_record_padding_callback_arg() and SSL_set_record_padding_callback_arg()
+assign a value B<arg> that is passed to the callback when it is invoked. The value
+set in B<ctx> is copied to a new SSL by SSL_new().
+
+SSL_CTX_get_record_padding_callback_arg() and SSL_get_record_padding_callback_arg()
+retrieve the B<arg> value that is passed to the callback.
+
+SSL_CTX_set_block_padding() and SSL_set_block_padding() pads the record to a multiple
+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.
+
+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.
+The B<len> parameter is the current plaintext length of the record before encryption.
+The B<arg> parameter is the value set via SSL_CTX_set_record_padding_callback_arg()
+or SSL_set_record_padding_callback_arg().
+
+=head1 RETURN VALUES
+
+The SSL_CTX_get_record_padding_callback_arg() and SSL_get_record_padding_callback_arg()
+functions return the B<arg> value assignd in the corresponding set functions.
+
+The SSL_CTX_set_block_padding() and SSL_set_block_padding() functions return 1 on success
+or 0 if B<block_size> is too large.
+
+The B<cb> returns the number of padding bytes to add to the record. A return of 0
+indicates no padding will be added. A return value that causes the record to
+exceed the maximum record size (SSL3_RT_MAX_PLAIN_LENGTH) will pad out to the
+maximum record size.
+
+=head1 NOTES
+
+The default behavior is to add no padding to the record.
+
+A user-supplied padding callback function will override the behavior set by
+SSL_set_block_padding() or SSL_CTX_set_block_padding(). Setting the user-supplied
+callback to NULL will restore the configured block padding behavior.
+
+These functions only apply to TLS 1.3 records being written.
+
+Padding bytes are not added in constant-time.
+
+=head1 SEE ALSO
+
+L<ssl(7)>, L<SSL_new(3)>
+
+=head1 HISTORY
+
+The record padding API was added for TLS 1.3 support in OpenSSL 1.1.1.
+
+=head1 COPYRIGHT
+
+Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index d533a0c881..b1da6c5a69 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1952,6 +1952,21 @@ void SSL_set_not_resumable_session_callback(SSL *ssl,
int (*cb) (SSL *ssl,
int
is_forward_secure));
+
+void SSL_CTX_set_record_padding_callback(SSL_CTX *ctx,
+ size_t (*cb) (SSL *ssl, int type,
+ size_t len, void *arg));
+void SSL_CTX_set_record_padding_callback_arg(SSL_CTX *ctx, void *arg);
+void *SSL_CTX_get_record_padding_callback_arg(SSL_CTX *ctx);
+int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size);
+
+void SSL_set_record_padding_callback(SSL *ssl,
+ size_t (*cb) (SSL *ssl, int type,
+ size_t len, void *arg));
+void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg);
+void *SSL_get_record_padding_callback_arg(SSL *ssl);
+int SSL_set_block_padding(SSL *ssl, size_t block_size);
+
# if OPENSSL_API_COMPAT < 0x10100000L
# define SSL_cache_hit(s) SSL_session_reused(s)
# endif
diff --git a/ssl/packet.c b/ssl/packet.c
index 3479f1fed8..d081f557e7 100644
--- a/ssl/packet.c
+++ b/ssl/packet.c
@@ -350,6 +350,21 @@ int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
return 1;
}
+int WPACKET_memset(WPACKET *pkt, int ch, size_t len)
+{
+ unsigned char *dest;
+
+ if (len == 0)
+ return 1;
+
+ if (!WPACKET_allocate_bytes(pkt, len, &dest))
+ return 0;
+
+ memset(dest, ch, len);
+
+ return 1;
+}
+
int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
{
unsigned char *dest;
diff --git a/ssl/packet_locl.h b/ssl/packet_locl.h
index 67b49994f7..8e553e62b5 100644
--- a/ssl/packet_locl.h
+++ b/ssl/packet_locl.h
@@ -833,6 +833,9 @@ int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize);
/* Copy |len| bytes of data from |*src| into the WPACKET. */
int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len);
+/* Set |len| bytes of data to |ch| into the WPACKET. */
+int WPACKET_memset(WPACKET *pkt, int ch, size_t len);
+
/*
* Copy |len| bytes of data from |*src| into the WPACKET and prefix with its
* length (consuming |lenbytes| of data for the length). Don't call this
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 14c6778ae6..43c4a949d7 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -860,15 +860,44 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
}
if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) {
+ size_t padding = 0;
+
if (!WPACKET_put_bytes_u8(thispkt, type)) {
SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
goto err;
}
SSL3_RECORD_add_length(thiswr, 1);
- /*
- * TODO(TLS1.3): Padding goes here. Do we need an API to add this?
- * For now, use no padding
- */
+
+ /* Add TLS1.3 padding */
+ if (s->record_padding_cb != NULL) {
+ size_t rlen = SSL3_RECORD_get_length(thiswr);
+
+ padding = s->record_padding_cb(s, type, rlen, s->record_padding_arg);
+ /* do not allow the record to exceed max plaintext length */
+ if (padding > (SSL3_RT_MAX_PLAIN_LENGTH - rlen))
+ padding = SSL3_RT_MAX_PLAIN_LENGTH - rlen;
+ } else if (s->block_padding > 0) {
+ size_t mask = s->block_padding - 1;
+ size_t remainder;
+
+ /* optimize for power of 2 */
+ if ((s->block_padding & mask) == 0)
+ remainder = SSL3_RECORD_get_length(thiswr) & mask;
+ else
+ remainder = SSL3_RECORD_get_length(thiswr) % s->block_padding;
+ /* don't want to add a block of padding if we don't have to */
+ if (remainder == 0)
+ padding = 0;
+ else
+ padding = s->block_padding - remainder;
+ }
+ if (padding > 0) {
+ if (!WPACKET_memset(thispkt, 0, padding)) {
+ SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ SSL3_RECORD_add_length(thiswr, padding);
+ }
}
/*
diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
index 4b4619279e..484bb61feb 100644
--- a/ssl/ssl_conf.c
+++ b/ssl/ssl_conf.c
@@ -520,6 +520,25 @@ static int cmd_DHParameters(SSL_CONF_CTX *cctx, const char *value)
return rv > 0;
}
#endif
+
+static int cmd_RecordPadding(SSL_CONF_CTX *cctx, const char *value)
+{
+ int rv = 0;
+ int block_size = atoi(value);
+
+ /*
+ * All we care about is a non-negative value,
+ * the setters check the range
+ */
+ if (block_size >= 0) {
+ if (cctx->ctx)
+ rv = SSL_CTX_set_block_padding(cctx->ctx, block_size);
+ if (cctx->ssl)
+ rv = SSL_set_block_padding(cctx->ssl, block_size);
+ }
+ return rv;
+}
+
typedef struct {
int (*cmd) (SSL_CONF_CTX *cctx, const char *value);
const char *str_file;
@@ -598,8 +617,9 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
#ifndef OPENSSL_NO_DH
SSL_CONF_CMD(DHParameters, "dhparam",
SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CERTIFICATE,
- SSL_CONF_TYPE_FILE)
+ SSL_CONF_TYPE_FILE),
#endif
+ SSL_CONF_CMD_STRING(RecordPadding, "record_padding", 0)
};
/* Supported switches: must match order of switches in ssl_conf_cmds */
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index c59aa847e4..d1a1f027d9 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -571,6 +571,9 @@ SSL *SSL_new(SSL_CTX *ctx)
s->msg_callback_arg = ctx->msg_callback_arg;
s->verify_mode = ctx->verify_mode;
s->not_resumable_session_cb = ctx->not_resumable_session_cb;
+ s->record_padding_cb = ctx->record_padding_cb;
+ s->record_padding_arg = ctx->record_padding_arg;
+ s->block_padding = ctx->block_padding;
s->sid_ctx_length = ctx->sid_ctx_length;
OPENSSL_assert(s->sid_ctx_length <= sizeof s->sid_ctx);
memcpy(&s->sid_ctx, &ctx->sid_ctx, sizeof(s->sid_ctx));
@@ -3889,6 +3892,64 @@ void SSL_set_not_resumable_session_callback(SSL *ssl,
(void (*)(void))cb);
}
+void SSL_CTX_set_record_padding_callback(SSL_CTX *ctx,
+ size_t (*cb) (SSL *ssl, int type,
+ size_t len, void *arg))
+{
+ ctx->record_padding_cb = cb;
+}
+
+void SSL_CTX_set_record_padding_callback_arg(SSL_CTX *ctx, void *arg)
+{
+ ctx->record_padding_arg = arg;
+}
+
+void *SSL_CTX_get_record_padding_callback_arg(SSL_CTX *ctx)
+{
+ return ctx->record_padding_arg;
+}
+
+int SSL_CTX_set_block_padding(SSL_CTX *ctx, size_t block_size)
+{
+ /* block size of 0 or 1 is basically no padding */
+ if (block_size == 1)
+ ctx->block_padding = 0;
+ else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
+ ctx->block_padding = block_size;
+ else
+ return 0;
+ return 1;
+}
+
+void SSL_set_record_padding_callback(SSL *ssl,
+ size_t (*cb) (SSL *ssl, int type,
+ size_t len, void *arg))
+{
+ ssl->record_padding_cb = cb;
+}
+
+void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg)
+{
+ ssl->record_padding_arg = arg;
+}
+
+void *SSL_get_record_padding_callback_arg(SSL *ssl)
+{
+ return ssl->record_padding_arg;
+}
+
+int SSL_set_block_padding(SSL *ssl, size_t block_size)
+{
+ /* block size of 0 or 1 is basically no padding */
+ if (block_size == 1)
+ ssl->block_padding = 0;
+ else if (block_size <= SSL3_RT_MAX_PLAIN_LENGTH)
+ ssl->block_padding = block_size;
+ else
+ return 0;
+ return 1;
+}
+
/*
* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
* variable, freeing EVP_MD_CTX previously stored in that variable, if any.
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 15065c7d98..1d3a207c78 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -973,6 +973,11 @@ struct ssl_ctx_st {
/* The maximum number of bytes that can be sent as early data */
uint32_t max_early_data;
+
+ /* TLS1.3 padding callback */
+ size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg);
+ void *record_padding_arg;
+ size_t block_padding;
};
struct ssl_st {
@@ -1289,6 +1294,11 @@ struct ssl_st {
*/
uint32_t early_data_count;
+ /* TLS1.3 padding callback */
+ size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg);
+ void *record_padding_arg;
+ size_t block_padding;
+
CRYPTO_RWLOCK *lock;
};
diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t
index fbcb46a8fb..100b8528c8 100644
--- a/test/recipes/80-test_ssl_new.t
+++ b/test/recipes/80-test_ssl_new.t
@@ -29,7 +29,7 @@ map { s/\^// } @conf_files if $^O eq "VMS";
# We hard-code the number of tests to double-check that the globbing above
# finds all files as expected.
-plan tests => 23; # = scalar @conf_srcs
+plan tests => 24; # = scalar @conf_srcs
# Some test results depend on the configuration of enabled protocols. We only
# verify generated sources in the default configuration.
@@ -94,6 +94,7 @@ my %skip = (
"22-compression.conf" => disabled("zlib") || $no_tls,
"23-srp.conf" => (disabled("tls1") && disabled ("tls1_1")
&& disabled("tls1_2")) || disabled("srp"),
+ "24-padding.conf" => disabled("tls1_3"),
);
foreach my $conf (@conf_files) {
diff --git a/test/ssl-tests/24-padding.conf b/test/ssl-tests/24-padding.conf
new file mode 100644
index 0000000000..3c9f450102
--- /dev/null
+++ b/test/ssl-tests/24-padding.conf
@@ -0,0 +1,34 @@
+# Generated with generate_ssl_tests.pl
+
+num_tests = 1
+
+test-0 = 0-default
+# ===========================================================
+
+[0-default]
+ssl_conf = 0-default-ssl
+
+[0-default-ssl]
+server = 0-default-server
+client = 0-default-client
+
+[0-default-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+MaxProtocol = TLSv1.3
+MinProtocol = TLSv1.3
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+RecordPadding = 64
+
+[0-default-client]
+CipherString = DEFAULT
+MaxProtocol = TLSv1.3
+MinProtocol = TLSv1.3
+RecordPadding = 11
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-0]
+ExpectedResult = Success
+
+
diff --git a/test/ssl-tests/24-padding.conf.in b/test/ssl-tests/24-padding.conf.in
new file mode 100644
index 0000000000..7bf256c8db
--- /dev/null
+++ b/test/ssl-tests/24-padding.conf.in
@@ -0,0 +1,25 @@
+# -*- mode: perl; -*-
+# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+
+## SSL test configurations
+
+package ssltests;
+
+our @tests = (
+ {
+ name => "default",
+ server => { "RecordPadding" => 64,
+ "MaxProtocol" => "TLSv1.3",
+ "MinProtocol" => "TLSv1.3" },
+ client => { "RecordPadding" => 11,
+ "MaxProtocol" => "TLSv1.3",
+ "MinProtocol" => "TLSv1.3" },
+ test => { "ExpectedResult" => "Success" },
+ },
+);
diff --git a/util/libssl.num b/util/libssl.num
index ccaf4bce6f..a17ebbc6ad 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -441,3 +441,11 @@ SSL_CTX_add1_CA_list 441 1_1_1 EXIST::FUNCTION:
SSL_CTX_get0_CA_list 442 1_1_1 EXIST::FUNCTION:
SSL_CTX_add_custom_ext 443 1_1_1 EXIST::FUNCTION:
SSL_SESSION_is_resumable 444 1_1_1 EXIST::FUNCTION:
+SSL_CTX_set_record_padding_callback 445 1_1_1 EXIST::FUNCTION:
+SSL_set_record_padding_callback 446 1_1_1 EXIST::FUNCTION:
+SSL_CTX_set_block_padding 447 1_1_1 EXIST::FUNCTION:
+SSL_CTX_get_record_padding_callback_arg 448 1_1_1 EXIST::FUNCTION:
+SSL_get_record_padding_callback_arg 449 1_1_1 EXIST::FUNCTION:
+SSL_set_block_padding 450 1_1_1 EXIST::FUNCTION:
+SSL_set_record_padding_callback_arg 451 1_1_1 EXIST::FUNCTION:
+SSL_CTX_set_record_padding_callback_arg 452 1_1_1 EXIST::FUNCTION: