Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@google.com>2016-09-03 04:35:25 +0300
committerCQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>2016-09-24 00:11:15 +0300
commit65ac997f20cb83eb6c7edd6712be63fe1d0f466f (patch)
tree0e6e9e307027dcb6c2f80a8a55c21885e101a13e
parent0c0a94d07bedf2db47bcc93dacd1e33e6b17855e (diff)
Implement draft-davidben-tls-grease-01.
This GREASEs cipher suites, groups, and extensions. For now, we'll always place them in a hard-coded position. We can experiment with more interesting strategies later. If we add new ciphers and curves, presumably we prefer them over current ones, so place GREASE values at the front. This prevents implementations from parsing only the first value and ignoring the rest. Add two new extensions, one empty and one non-empty. Place the empty one in front (IBM WebSphere can't handle trailing empty extensions) and the non-empty one at the end. Change-Id: If2e009936bc298cedf2a7a593ce7d5d5ddbb841a Reviewed-on: https://boringssl-review.googlesource.com/11241 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
-rw-r--r--include/openssl/ssl.h14
-rw-r--r--ssl/handshake_client.c18
-rw-r--r--ssl/internal.h16
-rw-r--r--ssl/ssl_lib.c4
-rw-r--r--ssl/t1_lib.c44
-rw-r--r--ssl/test/bssl_shim.cc4
-rw-r--r--ssl/test/runner/common.go4
-rw-r--r--ssl/test/runner/handshake_messages.go8
-rw-r--r--ssl/test/runner/handshake_server.go44
-rw-r--r--ssl/test/runner/runner.go20
-rw-r--r--ssl/test/test_config.cc1
-rw-r--r--ssl/test/test_config.h1
-rw-r--r--tool/client.cc8
13 files changed, 180 insertions, 6 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 8454c307..3cf4e03b 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -3101,6 +3101,10 @@ OPENSSL_EXPORT const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl);
OPENSSL_EXPORT void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx,
int enable);
+/* SSL_CTX_set_grease_enabled configures whether client sockets on |ctx| should
+ * enable GREASE. See draft-davidben-tls-grease-01. */
+OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled);
+
/* Deprecated functions. */
@@ -3992,11 +3996,15 @@ struct ssl_ctx_st {
/* If true, a client will request certificate timestamps. */
unsigned signed_cert_timestamps_enabled:1;
- /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server,
- * means that we'll accept Channel IDs from clients. For a client, means that
- * we'll advertise support. */
+ /* tlsext_channel_id_enabled is one if Channel ID is enabled and zero
+ * otherwise. For a server, means that we'll accept Channel IDs from clients.
+ * For a client, means that we'll advertise support. */
unsigned tlsext_channel_id_enabled:1;
+ /* grease_enabled is one if draft-davidben-tls-grease-01 is enabled and zero
+ * otherwise. */
+ unsigned grease_enabled:1;
+
/* extra_certs is a dummy value included for compatibility.
* TODO(agl): remove once node.js no longer references this. */
STACK_OF(X509)* extra_certs;
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index d78d0a4f..584e9ea7 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -579,6 +579,18 @@ end:
return ret;
}
+uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) {
+ /* Use the client_random for entropy. This both avoids calling |RAND_bytes| on
+ * a single byte repeatedly and ensures the values are deterministic. This
+ * allows the same ClientHello be sent twice for a HelloRetryRequest or the
+ * same group be advertised in both supported_groups and key_shares. */
+ uint16_t ret = ssl->s3->client_random[index];
+ /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
+ ret = (ret & 0xf0) | 0x0a;
+ ret |= ret << 8;
+ return ret;
+}
+
static int ssl_write_client_cipher_list(SSL *ssl, CBB *out,
uint16_t min_version,
uint16_t max_version) {
@@ -590,6 +602,12 @@ static int ssl_write_client_cipher_list(SSL *ssl, CBB *out,
return 0;
}
+ /* Add a fake cipher suite. See draft-davidben-tls-grease-01. */
+ if (ssl->ctx->grease_enabled &&
+ !CBB_add_u16(&child, ssl_get_grease_value(ssl, ssl_grease_cipher))) {
+ return 0;
+ }
+
STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
int any_enabled = 0;
diff --git a/ssl/internal.h b/ssl/internal.h
index 232364ee..fca2dda7 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1014,6 +1014,22 @@ int ssl_client_cipher_list_contains_cipher(
const struct ssl_early_callback_ctx *client_hello, uint16_t id);
+/* GREASE. */
+
+enum ssl_grease_index_t {
+ ssl_grease_cipher = 0,
+ ssl_grease_group,
+ ssl_grease_extension1,
+ ssl_grease_extension2,
+};
+
+/* ssl_get_grease_value returns a GREASE value for |ssl|. For a given
+ * connection, the values for each index will be deterministic. This allows the
+ * same ClientHello be sent twice for a HelloRetryRequest or the same group be
+ * advertised in both supported_groups and key_shares. */
+uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index);
+
+
/* Underdocumented functions.
*
* Functions below here haven't been touched up and may be underdocumented. */
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a51688de..51c16f08 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2884,6 +2884,10 @@ void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enabled) {
ctx->retain_only_sha256_of_client_certs = !!enabled;
}
+void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled) {
+ ctx->grease_enabled = !!enabled;
+}
+
int SSL_clear(SSL *ssl) {
if (ssl->method == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 8db132f0..baa2d45e 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2106,6 +2106,15 @@ static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) {
group_id = ssl->s3->hs->retry_group;
} else {
+ /* Add a fake group. See draft-davidben-tls-grease-01. */
+ if (ssl->ctx->grease_enabled &&
+ (!CBB_add_u16(&kse_bytes,
+ ssl_get_grease_value(ssl, ssl_grease_group)) ||
+ !CBB_add_u16(&kse_bytes, 1 /* length */) ||
+ !CBB_add_u8(&kse_bytes, 0 /* one byte key share */))) {
+ return 0;
+ }
+
/* Predict the most preferred group. */
const uint16_t *groups;
size_t groups_len;
@@ -2293,6 +2302,13 @@ static int ext_supported_groups_add_clienthello(SSL *ssl, CBB *out) {
return 0;
}
+ /* Add a fake group. See draft-davidben-tls-grease-01. */
+ if (ssl->ctx->grease_enabled &&
+ !CBB_add_u16(&groups_bytes,
+ ssl_get_grease_value(ssl, ssl_grease_group))) {
+ return 0;
+ }
+
const uint16_t *groups;
size_t groups_len;
tls1_get_grouplist(ssl, 0, &groups, &groups_len);
@@ -2546,6 +2562,16 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) {
}
}
+ uint16_t grease_ext1 = 0;
+ if (ssl->ctx->grease_enabled) {
+ /* Add a fake empty extension. See draft-davidben-tls-grease-01. */
+ grease_ext1 = ssl_get_grease_value(ssl, ssl_grease_extension1);
+ if (!CBB_add_u16(&extensions, grease_ext1) ||
+ !CBB_add_u16(&extensions, 0 /* zero length */)) {
+ goto err;
+ }
+ }
+
for (size_t i = 0; i < kNumExtensions; i++) {
const size_t len_before = CBB_len(&extensions);
if (!kExtensions[i].add_clienthello(ssl, &extensions)) {
@@ -2563,6 +2589,24 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) {
goto err;
}
+ if (ssl->ctx->grease_enabled) {
+ /* Add a fake non-empty extension. See draft-davidben-tls-grease-01. */
+ uint16_t grease_ext2 = ssl_get_grease_value(ssl, ssl_grease_extension2);
+
+ /* The two fake extensions must not have the same value. GREASE values are
+ * of the form 0x1a1a, 0x2a2a, 0x3a3a, etc., so XOR to generate a different
+ * one. */
+ if (grease_ext1 == grease_ext2) {
+ grease_ext2 ^= 0x1010;
+ }
+
+ if (!CBB_add_u16(&extensions, grease_ext2) ||
+ !CBB_add_u16(&extensions, 1 /* one byte length */) ||
+ !CBB_add_u8(&extensions, 0 /* single zero byte as contents */)) {
+ goto err;
+ }
+ }
+
if (!SSL_is_dtls(ssl)) {
header_len += 2 + CBB_len(&extensions);
if (header_len > 0xff && header_len < 0x200) {
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 533e7b27..0064e40a 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -942,6 +942,10 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) {
SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
}
+ if (config->enable_grease) {
+ SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
+ }
+
return ssl_ctx;
}
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 3300d33d..02ab23b0 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1084,6 +1084,10 @@ type ProtocolBugs struct {
// InvalidChannelIDSignature, if true, causes the client to generate an
// invalid Channel ID signature.
InvalidChannelIDSignature bool
+
+ // ExpectGREASE, if true, causes the server to reject a ClientHello
+ // unless it contains GREASE values. See draft-davidben-tls-grease-01.
+ ExpectGREASE bool
}
func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 63290fb4..8cec98b1 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -159,6 +159,7 @@ type clientHelloMsg struct {
srtpMasterKeyIdentifier string
sctListSupported bool
customExtension string
+ hasGREASEExtension bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -199,7 +200,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) &&
m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier &&
m.sctListSupported == m1.sctListSupported &&
- m.customExtension == m1.customExtension
+ m.customExtension == m1.customExtension &&
+ m.hasGREASEExtension == m1.hasGREASEExtension
}
func (m *clientHelloMsg) marshal() []byte {
@@ -705,6 +707,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.customExtension = string(data[:length])
}
data = data[length:]
+
+ if isGREASEValue(extension) {
+ m.hasGREASEExtension = true
+ }
}
return true
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index e04075cd..604fa140 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -246,11 +246,13 @@ func (hs *serverHandshakeState) readClientHello() error {
}
c.haveVers = true
- var scsvFound bool
+ var scsvFound, greaseFound bool
for _, cipherSuite := range hs.clientHello.cipherSuites {
if cipherSuite == fallbackSCSV {
scsvFound = true
- break
+ }
+ if isGREASEValue(cipherSuite) {
+ greaseFound = true
}
}
@@ -260,6 +262,36 @@ func (hs *serverHandshakeState) readClientHello() error {
return errors.New("tls: fallback SCSV found when not expected")
}
+ if !greaseFound && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE cipher suite value found")
+ }
+
+ greaseFound = false
+ for _, curve := range hs.clientHello.supportedCurves {
+ if isGREASEValue(uint16(curve)) {
+ greaseFound = true
+ break
+ }
+ }
+
+ if !greaseFound && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE curve value found")
+ }
+
+ if len(hs.clientHello.keyShares) > 0 {
+ greaseFound = false
+ for _, keyShare := range hs.clientHello.keyShares {
+ if isGREASEValue(uint16(keyShare.group)) {
+ greaseFound = true
+ break
+ }
+ }
+
+ if !greaseFound && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE curve value found")
+ }
+ }
+
if config.Bugs.IgnorePeerSignatureAlgorithmPreferences {
hs.clientHello.signatureAlgorithms = config.signSignatureAlgorithms()
}
@@ -1002,6 +1034,10 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server
serverExtensions.ticketSupported = true
}
+ if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE {
+ return errors.New("tls: no GREASE extension found")
+ }
+
return nil
}
@@ -1673,3 +1709,7 @@ func isTLS12Cipher(id uint16) bool {
// Unknown cipher.
return false
}
+
+func isGREASEValue(val uint16) bool {
+ return val&0x0f0f == 0x0a0a && val&0xff == val >> 8
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 0d2e6eff..ea660abe 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2309,6 +2309,26 @@ func addBasicTests() {
expectedError: ":INVALID_COMPRESSION_LIST:",
expectedLocalError: "remote error: illegal parameter",
},
+ {
+ name: "GREASE-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectGREASE: true,
+ },
+ },
+ flags: []string{"-enable-grease"},
+ },
+ {
+ name: "GREASE-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectGREASE: true,
+ },
+ },
+ flags: []string{"-enable-grease"},
+ },
}
testCases = append(testCases, basicTests...)
}
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index b7dc511b..bca194ea 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -105,6 +105,7 @@ const Flag<bool> kBoolFlags[] = {
{ "-use-null-client-ca-list", &TestConfig::use_null_client_ca_list },
{ "-send-alert", &TestConfig::send_alert },
{ "-peek-then-read", &TestConfig::peek_then_read },
+ { "-enable-grease", &TestConfig::enable_grease },
};
const Flag<std::string> kStringFlags[] = {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index e0029a5b..d20d1c6a 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -113,6 +113,7 @@ struct TestConfig {
bool use_null_client_ca_list = false;
bool send_alert = false;
bool peek_then_read = false;
+ bool enable_grease = false;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/tool/client.cc b/tool/client.cc
index 04a217a7..b9f1c13b 100644
--- a/tool/client.cc
+++ b/tool/client.cc
@@ -89,6 +89,10 @@ static const struct argument kArguments[] = {
" values: 'smtp'",
},
{
+ "-grease", kBooleanArgument,
+ "Enable GREASE",
+ },
+ {
"", kOptionalArgument, "",
},
};
@@ -269,6 +273,10 @@ bool Client(const std::vector<std::string> &args) {
SSL_CTX_sess_set_new_cb(ctx.get(), NewSessionCallback);
}
+ if (args_map.count("-grease") != 0) {
+ SSL_CTX_set_grease_enabled(ctx.get(), 1);
+ }
+
int sock = -1;
if (!Connect(&sock, args_map["-connect"])) {
return false;