Change-Id: I6df623f3e9bc88acc52043f16b34649b7af67663 Reviewed-on: https://boringssl-review.googlesource.com/5531 Reviewed-by: Adam Langley <alangley@gmail.com>kris/onging/CECPQ3_patch15
@@ -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| | * it is an error to call |sign_complete| if there is no pending |sign| | ||||
* operation in progress on |ssl|. */ | * operation in progress on |ssl|. */ | ||||
enum ssl_private_key_result_t (*sign_complete)(SSL *ssl, uint8_t *out, | 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_PRIVATE_KEY_METHOD; | ||||
/* SSL_set_private_key_method configures a custom private key on |ssl|. | /* SSL_set_private_key_method configures a custom private key on |ssl|. | ||||
@@ -382,6 +382,7 @@ OPENSSL_COMPILE_ASSERT( | |||||
#define SSL3_ST_SR_CERT_B (0x181 | SSL_ST_ACCEPT) | #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_A (0x190 | SSL_ST_ACCEPT) | ||||
#define SSL3_ST_SR_KEY_EXCH_B (0x191 | 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_A (0x1A0 | SSL_ST_ACCEPT) | ||||
#define SSL3_ST_SR_CERT_VRFY_B (0x1A1 | SSL_ST_ACCEPT) | #define SSL3_ST_SR_CERT_VRFY_B (0x1A1 | SSL_ST_ACCEPT) | ||||
#define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT) | #define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT) | ||||
@@ -330,6 +330,7 @@ int dtls1_accept(SSL *s) { | |||||
case SSL3_ST_SR_KEY_EXCH_A: | case SSL3_ST_SR_KEY_EXCH_A: | ||||
case SSL3_ST_SR_KEY_EXCH_B: | case SSL3_ST_SR_KEY_EXCH_B: | ||||
case SSL3_ST_SR_KEY_EXCH_C: | |||||
ret = ssl3_get_client_key_exchange(s); | ret = ssl3_get_client_key_exchange(s); | ||||
if (ret <= 0) { | if (ret <= 0) { | ||||
goto end; | goto end; | ||||
@@ -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( | enum ssl_private_key_result_t ssl_private_key_sign_complete( | ||||
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out); | 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 */ | /* Custom extensions */ | ||||
@@ -399,6 +399,7 @@ int ssl3_accept(SSL *s) { | |||||
case SSL3_ST_SR_KEY_EXCH_A: | case SSL3_ST_SR_KEY_EXCH_A: | ||||
case SSL3_ST_SR_KEY_EXCH_B: | case SSL3_ST_SR_KEY_EXCH_B: | ||||
case SSL3_ST_SR_KEY_EXCH_C: | |||||
ret = ssl3_get_client_key_exchange(s); | ret = ssl3_get_client_key_exchange(s); | ||||
if (ret <= 0) { | if (ret <= 0) { | ||||
goto end; | goto end; | ||||
@@ -1586,16 +1587,13 @@ uint64_t OPENSSL_get_d5_bug_use_count(void) { | |||||
} | } | ||||
int ssl3_get_client_key_exchange(SSL *s) { | int ssl3_get_client_key_exchange(SSL *s) { | ||||
int al, ok; | |||||
long n; | |||||
int al; | |||||
CBS client_key_exchange; | CBS client_key_exchange; | ||||
uint32_t alg_k; | uint32_t alg_k; | ||||
uint32_t alg_a; | uint32_t alg_a; | ||||
uint8_t *premaster_secret = NULL; | uint8_t *premaster_secret = NULL; | ||||
size_t premaster_secret_len = 0; | size_t premaster_secret_len = 0; | ||||
RSA *rsa = NULL; | |||||
uint8_t *decrypt_buf = NULL; | uint8_t *decrypt_buf = NULL; | ||||
EVP_PKEY *pkey = NULL; | |||||
BIGNUM *pub = NULL; | BIGNUM *pub = NULL; | ||||
DH *dh_srvr; | DH *dh_srvr; | ||||
@@ -1606,17 +1604,18 @@ int ssl3_get_client_key_exchange(SSL *s) { | |||||
unsigned int psk_len = 0; | unsigned int psk_len = 0; | ||||
uint8_t psk[PSK_MAX_PSK_LEN]; | 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_k = s->s3->tmp.new_cipher->algorithm_mkey; | ||||
alg_a = s->s3->tmp.new_cipher->algorithm_auth; | 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; | CBS encrypted_premaster_secret; | ||||
uint8_t rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH]; | uint8_t rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH]; | ||||
uint8_t good; | 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) { | if (decrypt_len != rsa_size) { | ||||
/* This should never happen, but do a check so we do not read | /* This should never happen, but do a check so we do not read | ||||
* uninitialized memory. */ | * uninitialized memory. */ | ||||
@@ -1782,6 +1791,15 @@ int ssl3_get_client_key_exchange(SSL *s) { | |||||
good &= constant_time_eq_8(premaster_secret[1], | good &= constant_time_eq_8(premaster_secret[1], | ||||
(unsigned)(s->client_version & 0xff)); | (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 | /* Now copy rand_premaster_secret over premaster_secret using | ||||
* decrypt_good_mask. */ | * decrypt_good_mask. */ | ||||
for (j = 0; j < sizeof(rand_premaster_secret); j++) { | for (j = 0; j < sizeof(rand_premaster_secret); j++) { | ||||
@@ -376,3 +376,33 @@ enum ssl_private_key_result_t ssl_private_key_sign_complete( | |||||
/* Only custom keys may be asynchronous. */ | /* Only custom keys may be asynchronous. */ | ||||
return ssl->cert->key_method->sign_complete(ssl, out, out_len, max_out); | 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); | |||||
} |
@@ -97,10 +97,10 @@ struct TestState { | |||||
bool handshake_done = false; | bool handshake_done = false; | ||||
// private_key is the underlying private key used when testing custom keys. | // private_key is the underlying private key used when testing custom keys. | ||||
ScopedEVP_PKEY private_key; | 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; | 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, | 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) { | const EVP_MD *md, const uint8_t *in, size_t in_len) { | ||||
TestState *test_state = GetTestState(ssl); | 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"); | fprintf(stderr, "AsyncPrivateKeySign called with operation pending.\n"); | ||||
abort(); | abort(); | ||||
} | } | ||||
@@ -171,42 +171,103 @@ static ssl_private_key_result_t AsyncPrivateKeySign( | |||||
!EVP_PKEY_sign(ctx.get(), nullptr, &len, in, in_len)) { | !EVP_PKEY_sign(ctx.get(), nullptr, &len, in, in_len)) { | ||||
return ssl_private_key_failure; | 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; | 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; | return ssl_private_key_retry; | ||||
} | } | ||||
static ssl_private_key_result_t AsyncPrivateKeySignComplete( | static ssl_private_key_result_t AsyncPrivateKeySignComplete( | ||||
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) { | SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out) { | ||||
TestState *test_state = GetTestState(ssl); | TestState *test_state = GetTestState(ssl); | ||||
if (test_state->signature.empty()) { | |||||
if (test_state->private_key_result.empty()) { | |||||
fprintf(stderr, | fprintf(stderr, | ||||
"AsyncPrivateKeySignComplete called without operation pending.\n"); | "AsyncPrivateKeySignComplete called without operation pending.\n"); | ||||
abort(); | 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 | // Only return the signature on the second attempt, to test both incomplete | ||||
// |sign| and |sign_complete|. | // |sign| and |sign_complete|. | ||||
return ssl_private_key_retry; | 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"); | fprintf(stderr, "Output buffer too small.\n"); | ||||
return ssl_private_key_failure; | 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; | return ssl_private_key_success; | ||||
} | } | ||||
@@ -215,6 +276,8 @@ static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = { | |||||
AsyncPrivateKeyMaxSignatureLen, | AsyncPrivateKeyMaxSignatureLen, | ||||
AsyncPrivateKeySign, | AsyncPrivateKeySign, | ||||
AsyncPrivateKeySignComplete, | AsyncPrivateKeySignComplete, | ||||
AsyncPrivateKeyDecrypt, | |||||
AsyncPrivateKeyDecryptComplete | |||||
}; | }; | ||||
template<typename T> | template<typename T> | ||||
@@ -250,7 +313,7 @@ static bool InstallCertificate(SSL *ssl) { | |||||
} | } | ||||
if (!config->key_file.empty()) { | if (!config->key_file.empty()) { | ||||
if (config->use_async_private_key) { | |||||
if (config->async) { | |||||
test_state->private_key = LoadPrivateKey(config->key_file.c_str()); | test_state->private_key = LoadPrivateKey(config->key_file.c_str()); | ||||
if (!test_state->private_key) { | if (!test_state->private_key) { | ||||
return false; | 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. | // The handshake will resume without a second call to the early callback. | ||||
return InstallCertificate(ssl); | return InstallCertificate(ssl); | ||||
case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION: | case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION: | ||||
test_state->signature_retries++; | |||||
test_state->private_key_retries++; | |||||
return true; | return true; | ||||
default: | default: | ||||
return false; | return false; | ||||
@@ -2585,7 +2585,7 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) | |||||
// TLS client auth. | // TLS client auth. | ||||
tests = append(tests, testCase{ | tests = append(tests, testCase{ | ||||
testType: clientTest, | testType: clientTest, | ||||
name: "ClientAuth-Client", | |||||
name: "ClientAuth-RSA-Client", | |||||
config: Config{ | config: Config{ | ||||
ClientAuth: RequireAnyClientCert, | ClientAuth: RequireAnyClientCert, | ||||
}, | }, | ||||
@@ -2594,35 +2594,50 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) | |||||
"-key-file", path.Join(*resourceDir, rsaKeyFile), | "-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 { | if async { | ||||
// Test async keys against each key exchange. | |||||
tests = append(tests, testCase{ | tests = append(tests, testCase{ | ||||
testType: clientTest, | |||||
name: "ClientAuth-Client-AsyncKey", | |||||
testType: serverTest, | |||||
name: "Basic-Server-RSA", | |||||
config: Config{ | config: Config{ | ||||
ClientAuth: RequireAnyClientCert, | |||||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, | |||||
}, | }, | ||||
flags: []string{ | flags: []string{ | ||||
"-cert-file", path.Join(*resourceDir, rsaCertificateFile), | "-cert-file", path.Join(*resourceDir, rsaCertificateFile), | ||||
"-key-file", path.Join(*resourceDir, rsaKeyFile), | "-key-file", path.Join(*resourceDir, rsaKeyFile), | ||||
"-use-async-private-key", | |||||
}, | }, | ||||
}) | }) | ||||
tests = append(tests, testCase{ | tests = append(tests, testCase{ | ||||
testType: serverTest, | 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{ | flags: []string{ | ||||
"-cert-file", path.Join(*resourceDir, rsaCertificateFile), | "-cert-file", path.Join(*resourceDir, rsaCertificateFile), | ||||
"-key-file", path.Join(*resourceDir, rsaKeyFile), | "-key-file", path.Join(*resourceDir, rsaKeyFile), | ||||
"-use-async-private-key", | |||||
}, | }, | ||||
}) | }) | ||||
tests = append(tests, testCase{ | tests = append(tests, testCase{ | ||||
testType: serverTest, | 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{ | flags: []string{ | ||||
"-cert-file", path.Join(*resourceDir, ecdsaCertificateFile), | "-cert-file", path.Join(*resourceDir, ecdsaCertificateFile), | ||||
"-key-file", path.Join(*resourceDir, ecdsaKeyFile), | "-key-file", path.Join(*resourceDir, ecdsaKeyFile), | ||||
"-use-async-private-key", | |||||
}, | }, | ||||
}) | }) | ||||
} | } | ||||
@@ -78,7 +78,6 @@ const Flag<bool> kBoolFlags[] = { | |||||
{ "-use-export-context", &TestConfig::use_export_context }, | { "-use-export-context", &TestConfig::use_export_context }, | ||||
{ "-no-legacy-server-connect", &TestConfig::no_legacy_server_connect }, | { "-no-legacy-server-connect", &TestConfig::no_legacy_server_connect }, | ||||
{ "-tls-unique", &TestConfig::tls_unique }, | { "-tls-unique", &TestConfig::tls_unique }, | ||||
{ "-use-async-private-key", &TestConfig::use_async_private_key }, | |||||
{ "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal }, | { "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal }, | ||||
{ "-expect-no-session", &TestConfig::expect_no_session }, | { "-expect-no-session", &TestConfig::expect_no_session }, | ||||
{ "-use-ticket-callback", &TestConfig::use_ticket_callback }, | { "-use-ticket-callback", &TestConfig::use_ticket_callback }, | ||||
@@ -79,7 +79,6 @@ struct TestConfig { | |||||
bool use_export_context = false; | bool use_export_context = false; | ||||
bool no_legacy_server_connect = false; | bool no_legacy_server_connect = false; | ||||
bool tls_unique = false; | bool tls_unique = false; | ||||
bool use_async_private_key = false; | |||||
bool expect_ticket_renewal = false; | bool expect_ticket_renewal = false; | ||||
bool expect_no_session = false; | bool expect_no_session = false; | ||||
bool use_ticket_callback = false; | bool use_ticket_callback = false; | ||||