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>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 17a91ad..3f4e9cf 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -97,10 +97,10 @@
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 @@
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 @@
!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 @@
AsyncPrivateKeyMaxSignatureLen,
AsyncPrivateKeySign,
AsyncPrivateKeySignComplete,
+ AsyncPrivateKeyDecrypt,
+ AsyncPrivateKeyDecryptComplete
};
template<typename T>
@@ -250,7 +313,7 @@
}
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 @@
// 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;
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index fb1e46f..17fdff9 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2585,7 +2585,7 @@
// TLS client auth.
tests = append(tests, testCase{
testType: clientTest,
- name: "ClientAuth-Client",
+ name: "ClientAuth-RSA-Client",
config: Config{
ClientAuth: RequireAnyClientCert,
},
@@ -2594,35 +2594,50 @@
"-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",
},
})
}
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 54492df..abec0e1 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -78,7 +78,6 @@
{ "-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 },
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index af1dd80..23fa1f11 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -79,7 +79,6 @@
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;