Просмотр исходного кода

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>
kris/onging/CECPQ3_patch15
David Benjamin 8 лет назад
committed by CQ bot account: commit-bot@chromium.org
Родитель
Сommit
65ac997f20
13 измененных файлов: 180 добавлений и 6 удалений
  1. +11
    -3
      include/openssl/ssl.h
  2. +18
    -0
      ssl/handshake_client.c
  3. +16
    -0
      ssl/internal.h
  4. +4
    -0
      ssl/ssl_lib.c
  5. +44
    -0
      ssl/t1_lib.c
  6. +4
    -0
      ssl/test/bssl_shim.cc
  7. +4
    -0
      ssl/test/runner/common.go
  8. +7
    -1
      ssl/test/runner/handshake_messages.go
  9. +42
    -2
      ssl/test/runner/handshake_server.go
  10. +20
    -0
      ssl/test/runner/runner.go
  11. +1
    -0
      ssl/test/test_config.cc
  12. +1
    -0
      ssl/test/test_config.h
  13. +8
    -0
      tool/client.cc

+ 11
- 3
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;


+ 18
- 0
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;


+ 16
- 0
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. */


+ 4
- 0
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);


+ 44
- 0
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) {


+ 4
- 0
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;
}



+ 4
- 0
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() {


+ 7
- 1
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


+ 42
- 2
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
}

+ 20
- 0
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...)
}


+ 1
- 0
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[] = {


+ 1
- 0
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);


+ 8
- 0
tool/client.cc Просмотреть файл

@@ -88,6 +88,10 @@ static const struct argument kArguments[] = {
"A STARTTLS mini-protocol to run before the TLS handshake. Supported"
" 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;


Загрузка…
Отмена
Сохранить