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:
parent
3c92e80d7a
commit
512a289a8a
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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[] = {
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user