Browse Source

Add server-side support for asynchronous RSA decryption.

Change-Id: I6df623f3e9bc88acc52043f16b34649b7af67663
Reviewed-on: https://boringssl-review.googlesource.com/5531
Reviewed-by: Adam Langley <alangley@gmail.com>
kris/onging/CECPQ3_patch15
nagendra modadugu 9 years ago
committed by Adam Langley
parent
commit
3398dbf279
10 changed files with 263 additions and 100 deletions
  1. +31
    -1
      include/openssl/ssl.h
  2. +1
    -0
      include/openssl/ssl3.h
  3. +1
    -0
      ssl/d1_srvr.c
  4. +7
    -0
      ssl/internal.h
  5. +86
    -68
      ssl/s3_srvr.c
  6. +30
    -0
      ssl/ssl_rsa.c
  7. +83
    -20
      ssl/test/bssl_shim.cc
  8. +24
    -9
      ssl/test/runner/runner.go
  9. +0
    -1
      ssl/test/test_config.cc
  10. +0
    -1
      ssl/test/test_config.h

+ 31
- 1
include/openssl/ssl.h View File

@@ -966,7 +966,37 @@ typedef struct ssl_private_key_method_st {
* it is an error to call |sign_complete| if there is no pending |sign|
* operation in progress on |ssl|. */
enum ssl_private_key_result_t (*sign_complete)(SSL *ssl, uint8_t *out,
size_t *out_len, size_t max_out);
size_t *out_len,
size_t max_out);

/* decrypt decrypts |in_len| bytes of encrypted data from |in|. On success it
* returns |ssl_private_key_success|, writes at most |max_out| bytes of
* decrypted data to |out| and sets |*out_len| to the actual number of bytes
* written. On failure it returns |ssl_private_key_failure|. If the operation
* has not completed, it returns |ssl_private_key_retry|. The caller should
* arrange for the high-level operation on |ssl| to be retried when the
* operation is completed, which will result in a call to |decrypt_complete|.
* This function only works with RSA keys and should perform a raw RSA
* decryption operation with no padding.
*
* It is an error to call |decrypt| while another private key operation is in
* progress on |ssl|. */
enum ssl_private_key_result_t (*decrypt)(SSL *ssl, uint8_t *out,
size_t *out_len, size_t max_out,
const uint8_t *in, size_t in_len);

/* decrypt_complete completes a pending |decrypt| operation. If the operation
* has completed, it returns |ssl_private_key_success| and writes the result
* to |out| as in |decrypt|. Otherwise, it returns |ssl_private_key_failure|
* on failure and |ssl_private_key_retry| if the operation is still in
* progress.
*
* |decrypt_complete| may be called arbitrarily many times before completion,
* but it is an error to call |decrypt_complete| if there is no pending
* |decrypt| operation in progress on |ssl|. */
enum ssl_private_key_result_t (*decrypt_complete)(SSL *ssl, uint8_t *out,
size_t *out_len,
size_t max_out);
} SSL_PRIVATE_KEY_METHOD;

/* SSL_set_private_key_method configures a custom private key on |ssl|.


+ 1
- 0
include/openssl/ssl3.h View File

@@ -382,6 +382,7 @@ OPENSSL_COMPILE_ASSERT(
#define SSL3_ST_SR_CERT_B (0x181 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_KEY_EXCH_A (0x190 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_KEY_EXCH_B (0x191 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_KEY_EXCH_C (0x192 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_CERT_VRFY_A (0x1A0 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_CERT_VRFY_B (0x1A1 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT)


+ 1
- 0
ssl/d1_srvr.c View File

@@ -330,6 +330,7 @@ int dtls1_accept(SSL *s) {

case SSL3_ST_SR_KEY_EXCH_A:
case SSL3_ST_SR_KEY_EXCH_B:
case SSL3_ST_SR_KEY_EXCH_C:
ret = ssl3_get_client_key_exchange(s);
if (ret <= 0) {
goto end;


+ 7
- 0
ssl/internal.h View File

@@ -464,6 +464,13 @@ enum ssl_private_key_result_t ssl_private_key_sign(
enum ssl_private_key_result_t ssl_private_key_sign_complete(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out);

enum ssl_private_key_result_t ssl_private_key_decrypt(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
const uint8_t *in, size_t in_len);

enum ssl_private_key_result_t ssl_private_key_decrypt_complete(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out);


/* Custom extensions */



+ 86
- 68
ssl/s3_srvr.c View File

@@ -399,6 +399,7 @@ int ssl3_accept(SSL *s) {

case SSL3_ST_SR_KEY_EXCH_A:
case SSL3_ST_SR_KEY_EXCH_B:
case SSL3_ST_SR_KEY_EXCH_C:
ret = ssl3_get_client_key_exchange(s);
if (ret <= 0) {
goto end;
@@ -1586,16 +1587,13 @@ uint64_t OPENSSL_get_d5_bug_use_count(void) {
}

int ssl3_get_client_key_exchange(SSL *s) {
int al, ok;
long n;
int al;
CBS client_key_exchange;
uint32_t alg_k;
uint32_t alg_a;
uint8_t *premaster_secret = NULL;
size_t premaster_secret_len = 0;
RSA *rsa = NULL;
uint8_t *decrypt_buf = NULL;
EVP_PKEY *pkey = NULL;
BIGNUM *pub = NULL;
DH *dh_srvr;

@@ -1606,17 +1604,18 @@ int ssl3_get_client_key_exchange(SSL *s) {
unsigned int psk_len = 0;
uint8_t psk[PSK_MAX_PSK_LEN];

n = s->method->ssl_get_message(s, SSL3_ST_SR_KEY_EXCH_A,
SSL3_ST_SR_KEY_EXCH_B,
SSL3_MT_CLIENT_KEY_EXCHANGE, 2048, /* ??? */
ssl_hash_message, &ok);

if (!ok) {
return n;
if (s->state == SSL3_ST_SR_KEY_EXCH_A ||
s->state == SSL3_ST_SR_KEY_EXCH_B) {
int ok;
const long n = s->method->ssl_get_message(
s, SSL3_ST_SR_KEY_EXCH_A, SSL3_ST_SR_KEY_EXCH_B,
SSL3_MT_CLIENT_KEY_EXCHANGE, 2048 /* ??? */, ssl_hash_message, &ok);
if (!ok) {
return n;
}
}

CBS_init(&client_key_exchange, s->init_msg, n);

CBS_init(&client_key_exchange, s->init_msg, s->init_num);
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
alg_a = s->s3->tmp.new_cipher->algorithm_auth;

@@ -1673,72 +1672,82 @@ int ssl3_get_client_key_exchange(SSL *s) {
CBS encrypted_premaster_secret;
uint8_t rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
uint8_t good;
size_t rsa_size, decrypt_len, premaster_index, j;
size_t decrypt_len, premaster_index, j;
const size_t rsa_size = ssl_private_key_max_signature_len(s);

pkey = s->cert->privatekey;
if (pkey == NULL || pkey->type != EVP_PKEY_RSA || pkey->pkey.rsa == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE);
goto f_err;
/* Allocate a buffer large enough for an RSA decryption. */
decrypt_buf = OPENSSL_malloc(rsa_size);
if (decrypt_buf == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
rsa = pkey->pkey.rsa;

/* TLS and [incidentally] DTLS{0xFEFF} */
if (s->version > SSL3_VERSION) {
CBS copy = client_key_exchange;
if (!CBS_get_u16_length_prefixed(&client_key_exchange,
&encrypted_premaster_secret) ||
CBS_len(&client_key_exchange) != 0) {
if (!(s->options & SSL_OP_TLS_D5_BUG)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
goto f_err;
} else {
CRYPTO_STATIC_MUTEX_lock_write(&g_d5_bug_lock);
g_d5_bug_use_count++;
CRYPTO_STATIC_MUTEX_unlock(&g_d5_bug_lock);

encrypted_premaster_secret = copy;
enum ssl_private_key_result_t decrypt_result;
if (s->state == SSL3_ST_SR_KEY_EXCH_B) {
if (!ssl_has_private_key(s) || ssl_private_key_type(s) != EVP_PKEY_RSA) {
al = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE);
goto f_err;
}
/* TLS and [incidentally] DTLS{0xFEFF} */
if (s->version > SSL3_VERSION) {
CBS copy = client_key_exchange;
if (!CBS_get_u16_length_prefixed(&client_key_exchange,
&encrypted_premaster_secret) ||
CBS_len(&client_key_exchange) != 0) {
if (!(s->options & SSL_OP_TLS_D5_BUG)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL,
SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
goto f_err;
} else {
CRYPTO_STATIC_MUTEX_lock_write(&g_d5_bug_lock);
g_d5_bug_use_count++;
CRYPTO_STATIC_MUTEX_unlock(&g_d5_bug_lock);

encrypted_premaster_secret = copy;
}
}
} else {
encrypted_premaster_secret = client_key_exchange;
}
} else {
encrypted_premaster_secret = client_key_exchange;
}

/* Reject overly short RSA keys because we want to be sure that the buffer
* size makes it safe to iterate over the entire size of a premaster secret
* (SSL_MAX_MASTER_KEY_LENGTH). The actual expected size is larger due to
* RSA padding, but the bound is sufficient to be safe. */
rsa_size = RSA_size(rsa);
if (rsa_size < SSL_MAX_MASTER_KEY_LENGTH) {
al = SSL_AD_DECRYPT_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
goto f_err;
}
/* Reject overly short RSA keys because we want to be sure that the buffer
* size makes it safe to iterate over the entire size of a premaster
* secret (SSL_MAX_MASTER_KEY_LENGTH). The actual expected size is larger
* due to RSA padding, but the bound is sufficient to be safe. */
if (rsa_size < SSL_MAX_MASTER_KEY_LENGTH) {
al = SSL_AD_DECRYPT_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED);
goto f_err;
}

/* We must not leak whether a decryption failure occurs because of
* Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
* section 7.4.7.1). The code follows that advice of the TLS RFC and
* generates a random premaster secret for the case that the decrypt fails.
* See https://tools.ietf.org/html/rfc5246#section-7.4.7.1 */
if (!RAND_bytes(rand_premaster_secret, sizeof(rand_premaster_secret))) {
goto err;
/* Decrypt with no padding. PKCS#1 padding will be removed as part of the
* timing-sensitive code below. */
decrypt_result = ssl_private_key_decrypt(
s, decrypt_buf, &decrypt_len, rsa_size,
CBS_data(&encrypted_premaster_secret),
CBS_len(&encrypted_premaster_secret));
} else {
assert(s->state == SSL3_ST_SR_KEY_EXCH_C);
/* Complete async decrypt. */
decrypt_result = ssl_private_key_decrypt_complete(
s, decrypt_buf, &decrypt_len, rsa_size);
}

/* Allocate a buffer large enough for an RSA decryption. */
decrypt_buf = OPENSSL_malloc(rsa_size);
if (decrypt_buf == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
switch (decrypt_result) {
case ssl_private_key_success:
s->rwstate = SSL_NOTHING;
break;
case ssl_private_key_failure:
s->rwstate = SSL_NOTHING;
goto err;
case ssl_private_key_retry:
s->rwstate = SSL_PRIVATE_KEY_OPERATION;
s->state = SSL3_ST_SR_KEY_EXCH_C;
goto err;
}

/* Decrypt with no padding. PKCS#1 padding will be removed as part of the
* timing-sensitive code below. */
if (!RSA_decrypt(rsa, &decrypt_len, decrypt_buf, rsa_size,
CBS_data(&encrypted_premaster_secret),
CBS_len(&encrypted_premaster_secret), RSA_NO_PADDING)) {
goto err;
}
if (decrypt_len != rsa_size) {
/* This should never happen, but do a check so we do not read
* uninitialized memory. */
@@ -1782,6 +1791,15 @@ int ssl3_get_client_key_exchange(SSL *s) {
good &= constant_time_eq_8(premaster_secret[1],
(unsigned)(s->client_version & 0xff));

/* We must not leak whether a decryption failure occurs because of
* Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
* section 7.4.7.1). The code follows that advice of the TLS RFC and
* generates a random premaster secret for the case that the decrypt
* fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1 */
if (!RAND_bytes(rand_premaster_secret, sizeof(rand_premaster_secret))) {
goto err;
}

/* Now copy rand_premaster_secret over premaster_secret using
* decrypt_good_mask. */
for (j = 0; j < sizeof(rand_premaster_secret); j++) {


+ 30
- 0
ssl/ssl_rsa.c View File

@@ -376,3 +376,33 @@ enum ssl_private_key_result_t ssl_private_key_sign_complete(
/* Only custom keys may be asynchronous. */
return ssl->cert->key_method->sign_complete(ssl, out, out_len, max_out);
}

enum ssl_private_key_result_t ssl_private_key_decrypt(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
const uint8_t *in, size_t in_len) {
if (ssl->cert->key_method != NULL) {
return ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in,
in_len);
}

if (ssl_private_key_type(ssl) != EVP_PKEY_RSA) {
/* Decrypt operations are only supported for RSA keys. */
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_private_key_failure;
}

enum ssl_private_key_result_t ret = ssl_private_key_failure;
RSA *rsa = ssl->cert->privatekey->pkey.rsa;
/* Decrypt with no padding. PKCS#1 padding will be removed as part
* of the timing-sensitive code by the caller. */
if (RSA_decrypt(rsa, out_len, out, max_out, in, in_len, RSA_NO_PADDING)) {
ret = ssl_private_key_success;
}
return ret;
}

enum ssl_private_key_result_t ssl_private_key_decrypt_complete(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) {
/* Only custom keys may be asynchronous. */
return ssl->cert->key_method->decrypt_complete(ssl, out, out_len, max_out);
}

+ 83
- 20
ssl/test/bssl_shim.cc View File

@@ -97,10 +97,10 @@ struct TestState {
bool handshake_done = false;
// private_key is the underlying private key used when testing custom keys.
ScopedEVP_PKEY private_key;
std::vector<uint8_t> signature;
// signature_retries is the number of times an asynchronous sign operation has
// been retried.
unsigned signature_retries = 0;
std::vector<uint8_t> private_key_result;
// private_key_retries is the number of times an asynchronous private key
// operation has been retried.
unsigned private_key_retries = 0;
bool got_new_session = false;
};

@@ -153,7 +153,7 @@ static ssl_private_key_result_t AsyncPrivateKeySign(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
const EVP_MD *md, const uint8_t *in, size_t in_len) {
TestState *test_state = GetTestState(ssl);
if (!test_state->signature.empty()) {
if (!test_state->private_key_result.empty()) {
fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n");
abort();
}
@@ -171,42 +171,103 @@ static ssl_private_key_result_t AsyncPrivateKeySign(
!EVP_PKEY_sign(ctx.get(), nullptr, &len, in, in_len)) {
return ssl_private_key_failure;
}
test_state->signature.resize(len);
if (!EVP_PKEY_sign(ctx.get(), bssl::vector_data(&test_state->signature), &len,
in, in_len)) {
test_state->private_key_result.resize(len);
if (!EVP_PKEY_sign(ctx.get(), bssl::vector_data(
&test_state->private_key_result), &len, in, in_len)) {
return ssl_private_key_failure;
}
test_state->signature.resize(len);
test_state->private_key_result.resize(len);

// The signature will be released asynchronously in |AsyncPrivateKeySignComplete|.
// The signature will be released asynchronously in
// |AsyncPrivateKeySignComplete|.
return ssl_private_key_retry;
}

static ssl_private_key_result_t AsyncPrivateKeySignComplete(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) {
TestState *test_state = GetTestState(ssl);
if (test_state->signature.empty()) {
if (test_state->private_key_result.empty()) {
fprintf(stderr,
"AsyncPrivateKeySignComplete called without operation pending.\n");
abort();
}

if (test_state->signature_retries < 2) {
if (test_state->private_key_retries < 2) {
// Only return the signature on the second attempt, to test both incomplete
// |sign| and |sign_complete|.
return ssl_private_key_retry;
}

if (max_out < test_state->signature.size()) {
if (max_out < test_state->private_key_result.size()) {
fprintf(stderr, "Output buffer too small.\n");
return ssl_private_key_failure;
}
memcpy(out, bssl::vector_data(&test_state->signature),
test_state->signature.size());
*out_len = test_state->signature.size();
memcpy(out, bssl::vector_data(&test_state->private_key_result),
test_state->private_key_result.size());
*out_len = test_state->private_key_result.size();

test_state->signature.clear();
test_state->signature_retries = 0;
test_state->private_key_result.clear();
test_state->private_key_retries = 0;
return ssl_private_key_success;
}

static ssl_private_key_result_t AsyncPrivateKeyDecrypt(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
const uint8_t *in, size_t in_len) {
TestState *test_state = GetTestState(ssl);
if (!test_state->private_key_result.empty()) {
fprintf(stderr,
"AsyncPrivateKeyDecrypt called with operation pending.\n");
abort();
}

EVP_PKEY *pkey = test_state->private_key.get();
if (pkey->type != EVP_PKEY_RSA || pkey->pkey.rsa == NULL) {
fprintf(stderr,
"AsyncPrivateKeyDecrypt called with incorrect key type.\n");
abort();
}
RSA *rsa = pkey->pkey.rsa;
test_state->private_key_result.resize(RSA_size(rsa));
if (!RSA_decrypt(rsa, out_len,
bssl::vector_data(&test_state->private_key_result),
RSA_size(rsa), in, in_len, RSA_NO_PADDING)) {
return ssl_private_key_failure;
}

test_state->private_key_result.resize(*out_len);

// The decryption will be released asynchronously in
// |AsyncPrivateKeyDecryptComplete|.
return ssl_private_key_retry;
}

static ssl_private_key_result_t AsyncPrivateKeyDecryptComplete(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) {
TestState *test_state = GetTestState(ssl);
if (test_state->private_key_result.empty()) {
fprintf(stderr,
"AsyncPrivateKeyDecryptComplete called without operation "
"pending.\n");
abort();
}

if (test_state->private_key_retries < 2) {
// Only return the decryption on the second attempt, to test both incomplete
// |decrypt| and |decrypt_complete|.
return ssl_private_key_retry;
}

if (max_out < test_state->private_key_result.size()) {
fprintf(stderr, "Output buffer too small.\n");
return ssl_private_key_failure;
}
memcpy(out, bssl::vector_data(&test_state->private_key_result),
test_state->private_key_result.size());
*out_len = test_state->private_key_result.size();

test_state->private_key_result.clear();
test_state->private_key_retries = 0;
return ssl_private_key_success;
}

@@ -215,6 +276,8 @@ static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = {
AsyncPrivateKeyMaxSignatureLen,
AsyncPrivateKeySign,
AsyncPrivateKeySignComplete,
AsyncPrivateKeyDecrypt,
AsyncPrivateKeyDecryptComplete
};

template<typename T>
@@ -250,7 +313,7 @@ static bool InstallCertificate(SSL *ssl) {
}

if (!config->key_file.empty()) {
if (config->use_async_private_key) {
if (config->async) {
test_state->private_key = LoadPrivateKey(config->key_file.c_str());
if (!test_state->private_key) {
return false;
@@ -789,7 +852,7 @@ static bool RetryAsync(SSL *ssl, int ret) {
// The handshake will resume without a second call to the early callback.
return InstallCertificate(ssl);
case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION:
test_state->signature_retries++;
test_state->private_key_retries++;
return true;
default:
return false;


+ 24
- 9
ssl/test/runner/runner.go View File

@@ -2585,7 +2585,7 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
// TLS client auth.
tests = append(tests, testCase{
testType: clientTest,
name: "ClientAuth-Client",
name: "ClientAuth-RSA-Client",
config: Config{
ClientAuth: RequireAnyClientCert,
},
@@ -2594,35 +2594,50 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
"-key-file", path.Join(*resourceDir, rsaKeyFile),
},
})
tests = append(tests, testCase{
testType: clientTest,
name: "ClientAuth-ECDSA-Client",
config: Config{
ClientAuth: RequireAnyClientCert,
},
flags: []string{
"-cert-file", path.Join(*resourceDir, ecdsaCertificateFile),
"-key-file", path.Join(*resourceDir, ecdsaKeyFile),
},
})
if async {
// Test async keys against each key exchange.
tests = append(tests, testCase{
testType: clientTest,
name: "ClientAuth-Client-AsyncKey",
testType: serverTest,
name: "Basic-Server-RSA",
config: Config{
ClientAuth: RequireAnyClientCert,
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
},
flags: []string{
"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
"-key-file", path.Join(*resourceDir, rsaKeyFile),
"-use-async-private-key",
},
})
tests = append(tests, testCase{
testType: serverTest,
name: "Basic-Server-RSAAsyncKey",
name: "Basic-Server-ECDHE-RSA",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
},
flags: []string{
"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
"-key-file", path.Join(*resourceDir, rsaKeyFile),
"-use-async-private-key",
},
})
tests = append(tests, testCase{
testType: serverTest,
name: "Basic-Server-ECDSAAsyncKey",
name: "Basic-Server-ECDHE-ECDSA",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
},
flags: []string{
"-cert-file", path.Join(*resourceDir, ecdsaCertificateFile),
"-key-file", path.Join(*resourceDir, ecdsaKeyFile),
"-use-async-private-key",
},
})
}


+ 0
- 1
ssl/test/test_config.cc View File

@@ -78,7 +78,6 @@ const Flag<bool> kBoolFlags[] = {
{ "-use-export-context", &TestConfig::use_export_context },
{ "-no-legacy-server-connect", &TestConfig::no_legacy_server_connect },
{ "-tls-unique", &TestConfig::tls_unique },
{ "-use-async-private-key", &TestConfig::use_async_private_key },
{ "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal },
{ "-expect-no-session", &TestConfig::expect_no_session },
{ "-use-ticket-callback", &TestConfig::use_ticket_callback },


+ 0
- 1
ssl/test/test_config.h View File

@@ -79,7 +79,6 @@ struct TestConfig {
bool use_export_context = false;
bool no_legacy_server_connect = false;
bool tls_unique = false;
bool use_async_private_key = false;
bool expect_ticket_renewal = false;
bool expect_no_session = false;
bool use_ticket_callback = false;


Loading…
Cancel
Save