Add support for dummy PQ padding.

This extension will be used to measure the latency impact of potentially
sending a post-quantum key share by default. At this time it's purely
measuring the impact of the client sending the key share, not the server
replying with a ciphertext.

We could use the existing padding extension for this but that extension
doesn't allow the server to echo it, so we would need a different
extension in the future anyway. Thus we just create one now.

We can assume that modern clients will be using TLS 1.3 by the time that
PQ key-exchange is established and thus the key share will be sent in
all ClientHello messages. However, since TLS 1.3 isn't quite here yet,
this extension is also sent for TLS 1.0–1.2 ClientHellos. The latency
impact should be the same either way.

Change-Id: Ie4a17551f6589b28505797e8c54cddbe3338dfe5
Reviewed-on: https://boringssl-review.googlesource.com/24585
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
This commit is contained in:
Adam Langley 2017-12-30 08:04:39 -08:00 committed by CQ bot account: commit-bot@chromium.org
parent 3c92e80d7a
commit 512a289a8a
12 changed files with 128 additions and 1 deletions

View File

@ -2909,6 +2909,21 @@ OPENSSL_EXPORT const char *SSL_get_psk_identity_hint(const SSL *ssl);
OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl);
// Dummy post-quantum padding.
//
// Dummy post-quantum padding invovles the client (and later server) sending
// useless, random-looking bytes in an extension in their ClientHello or
// ServerHello. These extensions are sized to simulate a post-quantum
// key-exchange and so enable measurement of the latency impact of the
// additional bandwidth.
// SSL_set_dummy_pq_padding_size enables the sending of a dummy PQ padding
// extension and configures its size. This is only effective for a client: a
// server will echo an extension with one of equal length when we get to that
// phase of the experiment. It returns one for success and zero otherwise.
OPENSSL_EXPORT int SSL_set_dummy_pq_padding_size(SSL *ssl, size_t num_bytes);
// Early data.
//
// WARNING: 0-RTT support in BoringSSL is currently experimental and not fully

View File

@ -229,6 +229,9 @@ extern "C" {
// This is not an IANA defined extension number
#define TLSEXT_TYPE_channel_id 30032
// This is not an IANA defined extension number
#define TLSEXT_TYPE_dummy_pq_padding 54537
// status request value from RFC 3546
#define TLSEXT_STATUSTYPE_ocsp 1

View File

@ -2581,6 +2581,7 @@ struct SSLConnection {
uint32_t options; // protocol behaviour
uint32_t mode; // API behaviour
uint32_t max_cert_list;
uint16_t dummy_pq_padding_len;
char *tlsext_hostname;
size_t supported_group_list_len;
uint16_t *supported_group_list; // our list

View File

@ -2385,6 +2385,15 @@ void SSL_CTX_set_psk_server_callback(
ctx->psk_server_callback = cb;
}
int SSL_set_dummy_pq_padding_size(SSL *ssl, size_t num_bytes) {
if (num_bytes > 0xffff) {
return 0;
}
ssl->dummy_pq_padding_len = num_bytes;
return 1;
}
void SSL_CTX_set_msg_callback(SSL_CTX *ctx,
void (*cb)(int write_p, int version,
int content_type, const void *buf,

View File

@ -116,6 +116,7 @@
#include <utility>
#include <openssl/bytestring.h>
#include <openssl/chacha.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/evp.h>
@ -559,6 +560,11 @@ static bool ignore_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
return true;
}
static bool ignore_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
return true;
}
static bool dont_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
return true;
}
@ -2318,6 +2324,42 @@ static bool ext_cookie_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
}
// Dummy PQ Padding extension
//
// Dummy post-quantum padding invovles the client (and later server) sending
// useless, random-looking bytes in an extension in their ClientHello or
// ServerHello. These extensions are sized to simulate a post-quantum
// key-exchange and so enable measurement of the latency impact of the
// additional bandwidth.
static bool ext_dummy_pq_padding_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
const size_t len = hs->ssl->dummy_pq_padding_len;
if (len == 0) {
return true;
}
CBB contents;
uint8_t *buffer;
if (!CBB_add_u16(out, TLSEXT_TYPE_dummy_pq_padding) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
!CBB_add_space(&contents, &buffer, len)) {
return false;
}
// The length is used as the nonce so that different length extensions have
// different contents. There's no reason this has to be the case, it just
// makes things a little more obvious in a packet dump.
uint8_t nonce[12] = {0};
memcpy(nonce, &len, sizeof(len));
memset(buffer, 0, len);
static const uint8_t kZeroKey[32] = {0};
CRYPTO_chacha_20(buffer, buffer, len, kZeroKey, nonce, 0);
return CBB_flush(out);
}
// Negotiated Groups
//
// https://tools.ietf.org/html/rfc4492#section-5.1.2
@ -2547,6 +2589,14 @@ static const struct tls_extension kExtensions[] = {
ignore_parse_clienthello,
dont_add_serverhello,
},
{
TLSEXT_TYPE_dummy_pq_padding,
NULL,
ext_dummy_pq_padding_add_clienthello,
ignore_parse_serverhello,
ignore_parse_clienthello,
dont_add_serverhello,
},
// The final extension must be non-empty. WebSphere Application Server 7.0 is
// intolerant to the last extension being zero-length. See
// https://crbug.com/363583.

View File

@ -2054,6 +2054,10 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
if (config->max_send_fragment > 0) {
SSL_set_max_send_fragment(ssl.get(), config->max_send_fragment);
}
if (config->dummy_pq_padding_len > 0 &&
!SSL_set_dummy_pq_padding_size(ssl.get(), config->dummy_pq_padding_len)) {
return false;
}
int sock = Connect(config->port);
if (sock == -1) {

View File

@ -136,6 +136,7 @@ const (
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
extensionChannelID uint16 = 30032 // not IANA assigned
extensionDummyPQPadding uint16 = 54537 // not IANA assigned
)
// TLS signaling cipher suite values
@ -1525,6 +1526,11 @@ type ProtocolBugs struct {
// ExpectDraftTLS13DowngradeRandom, if true, causes the client to
// require the server send the draft TLS 1.3 anti-downgrade signal.
ExpectDraftTLS13DowngradeRandom bool
// ExpectDummyPQPaddingLength, if not zero, causes the server to
// require that the client sent a dummy PQ padding extension of this
// length.
ExpectDummyPQPaddingLength int
}
func (c *Config) serverInit() {

View File

@ -292,6 +292,7 @@ type clientHelloMsg struct {
omitExtensions bool
emptyExtensions bool
pad int
dummyPQPaddingLen int
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@ -340,7 +341,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.pskBinderFirst == m1.pskBinderFirst &&
m.omitExtensions == m1.omitExtensions &&
m.emptyExtensions == m1.emptyExtensions &&
m.pad == m1.pad
m.pad == m1.pad &&
m.dummyPQPaddingLen == m1.dummyPQPaddingLen
}
func (m *clientHelloMsg) marshal() []byte {
@ -853,6 +855,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.sctListSupported = true
case extensionCustom:
m.customExtension = string(body)
case extensionDummyPQPadding:
if len(body) == 0 {
return false
}
m.dummyPQPaddingLen = len(body)
}
if isGREASEValue(extension) {

View File

@ -345,6 +345,10 @@ func (hs *serverHandshakeState) readClientHello() error {
}
}
if expected := hs.clientHello.dummyPQPaddingLen; expected != config.Bugs.ExpectDummyPQPaddingLength {
return fmt.Errorf("tls: expected dummy PQ padding extension of length %d, but got one of length %d", expected, config.Bugs.ExpectDummyPQPaddingLength)
}
applyBugsToClientHello(hs.clientHello, config)
return nil

View File

@ -6750,6 +6750,32 @@ func addExtensionTests() {
shouldFail: true,
expectedError: ":INVALID_SCT_LIST:",
})
for _, version := range allVersions(tls) {
if version.version < VersionTLS12 {
continue
}
for _, paddingLen := range []int{1, 9700} {
flags := []string{
"-max-version", version.shimFlag(tls),
"-dummy-pq-padding-len", strconv.Itoa(paddingLen),
}
testCases = append(testCases, testCase{
name: fmt.Sprintf("DummyPQPadding-%d-%s", paddingLen, version.name),
testType: clientTest,
tls13Variant: version.tls13Variant,
config: Config{
MaxVersion: version.version,
Bugs: ProtocolBugs{
ExpectDummyPQPaddingLength: paddingLen,
},
},
flags: flags,
})
}
}
}
func addResumptionVersionTests() {

View File

@ -194,6 +194,7 @@ const Flag<int> kIntFlags[] = {
{ "-read-size", &TestConfig::read_size },
{ "-expect-ticket-age-skew", &TestConfig::expect_ticket_age_skew },
{ "-tls13-variant", &TestConfig::tls13_variant },
{ "-dummy-pq-padding-len", &TestConfig::dummy_pq_padding_len },
};
const Flag<std::vector<int>> kIntVectorFlags[] = {

View File

@ -147,6 +147,7 @@ struct TestConfig {
std::string expect_msg_callback;
bool allow_false_start_without_alpn = false;
bool expect_draft_downgrade = false;
int dummy_pq_padding_len = 0;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_initial,