Support handshake hints for TLS 1.2 full handshakes.
Follow-up work will add support for TLS 1.2 ticket decryption.
Bug: 504
Change-Id: Ieaee37d94562040f1d51227216359bd63db15198
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53525
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 3a2a861..633a15a 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -3977,8 +3977,9 @@
// those cases, BoringSSL will not predict a signature as there is no benefit.
// Callers must allow for handshakes to complete without a predicted signature.
//
-// For now, only TLS 1.3 is hinted. TLS 1.2 will work, but the hints will be
-// empty.
+// Handshake hints are supported for TLS 1.3 and partially supported for
+// TLS 1.2. TLS 1.2 resumption handshakes are not yet fully hinted. They will
+// still work, but may not be as efficient.
// SSL_serialize_capabilities writes an opaque byte string to |out| describing
// some of |ssl|'s capabilities. It returns one on success and zero on error.
diff --git a/ssl/handoff.cc b/ssl/handoff.cc
index 883f832..e414705 100644
--- a/ssl/handoff.cc
+++ b/ssl/handoff.cc
@@ -769,7 +769,7 @@
// implicit tagging to make it a little more compact.
//
// HandshakeHints ::= SEQUENCE {
-// serverRandom [0] IMPLICIT OCTET STRING OPTIONAL,
+// serverRandomTLS13 [0] IMPLICIT OCTET STRING OPTIONAL,
// keyShareHint [1] IMPLICIT KeyShareHint OPTIONAL,
// signatureHint [2] IMPLICIT SignatureHint OPTIONAL,
// -- At most one of decryptedPSKHint or ignorePSKHint may be present. It
@@ -779,6 +779,12 @@
// decryptedPSKHint [3] IMPLICIT OCTET STRING OPTIONAL,
// ignorePSKHint [4] IMPLICIT NULL OPTIONAL,
// compressCertificateHint [5] IMPLICIT CompressCertificateHint OPTIONAL,
+// -- TLS 1.2 and 1.3 use different server random hints because one contains
+// -- a timestamp while the other doesn't. If the hint was generated
+// -- assuming TLS 1.3 but we actually negotiate TLS 1.2, mixing the two
+// -- will break this.
+// serverRandomTLS12 [7] IMPLICIT OCTET STRING OPTIONAL,
+// ecdheHint [6] IMPLICIT ECDHEHint OPTIONAL
// }
//
// KeyShareHint ::= SEQUENCE {
@@ -799,9 +805,15 @@
// input OCTET STRING,
// compressed OCTET STRING,
// }
+//
+// ECDHEHint ::= SEQUENCE {
+// groupId INTEGER,
+// publicKey OCTET STRING,
+// privateKey OCTET STRING,
+// }
// HandshakeHints tags.
-static const unsigned kServerRandomTag = CBS_ASN1_CONTEXT_SPECIFIC | 0;
+static const unsigned kServerRandomTLS13Tag = CBS_ASN1_CONTEXT_SPECIFIC | 0;
static const unsigned kKeyShareHintTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
static const unsigned kSignatureHintTag =
@@ -809,6 +821,8 @@
static const unsigned kDecryptedPSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 3;
static const unsigned kIgnorePSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 4;
static const unsigned kCompressCertificateTag = CBS_ASN1_CONTEXT_SPECIFIC | 5;
+static const unsigned kServerRandomTLS12Tag = CBS_ASN1_CONTEXT_SPECIFIC | 6;
+static const unsigned kECDHEHintTag = CBS_ASN1_CONSTRUCTED | 7;
int SSL_serialize_handshake_hints(const SSL *ssl, CBB *out) {
const SSL_HANDSHAKE *hs = ssl->s3->hs.get();
@@ -823,10 +837,10 @@
return 0;
}
- if (!hints->server_random.empty()) {
- if (!CBB_add_asn1(&seq, &child, kServerRandomTag) ||
- !CBB_add_bytes(&child, hints->server_random.data(),
- hints->server_random.size())) {
+ if (!hints->server_random_tls13.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kServerRandomTLS13Tag) ||
+ !CBB_add_bytes(&child, hints->server_random_tls13.data(),
+ hints->server_random_tls13.size())) {
return 0;
}
}
@@ -884,6 +898,26 @@
}
}
+ if (!hints->server_random_tls12.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kServerRandomTLS12Tag) ||
+ !CBB_add_bytes(&child, hints->server_random_tls12.data(),
+ hints->server_random_tls12.size())) {
+ return 0;
+ }
+ }
+
+ if (hints->ecdhe_group_id != 0 && !hints->ecdhe_public_key.empty() &&
+ !hints->ecdhe_private_key.empty()) {
+ if (!CBB_add_asn1(&seq, &child, kECDHEHintTag) ||
+ !CBB_add_asn1_uint64(&child, hints->ecdhe_group_id) ||
+ !CBB_add_asn1_octet_string(&child, hints->ecdhe_public_key.data(),
+ hints->ecdhe_public_key.size()) ||
+ !CBB_add_asn1_octet_string(&child, hints->ecdhe_private_key.data(),
+ hints->ecdhe_private_key.size())) {
+ return 0;
+ }
+ }
+
return CBB_flush(out);
}
@@ -898,14 +932,14 @@
return 0;
}
- CBS cbs, seq, server_random, key_share, signature_hint, ticket, ignore_psk,
- cert_compression;
- int has_server_random, has_key_share, has_signature_hint, has_ticket,
- has_ignore_psk, has_cert_compression;
+ CBS cbs, seq, server_random_tls13, key_share, signature_hint, ticket,
+ ignore_psk, cert_compression, server_random_tls12, ecdhe;
+ int has_server_random_tls13, has_key_share, has_signature_hint, has_ticket,
+ has_ignore_psk, has_cert_compression, has_server_random_tls12, has_ecdhe;
CBS_init(&cbs, hints, hints_len);
if (!CBS_get_asn1(&cbs, &seq, CBS_ASN1_SEQUENCE) ||
- !CBS_get_optional_asn1(&seq, &server_random, &has_server_random,
- kServerRandomTag) ||
+ !CBS_get_optional_asn1(&seq, &server_random_tls13,
+ &has_server_random_tls13, kServerRandomTLS13Tag) ||
!CBS_get_optional_asn1(&seq, &key_share, &has_key_share,
kKeyShareHintTag) ||
!CBS_get_optional_asn1(&seq, &signature_hint, &has_signature_hint,
@@ -914,12 +948,16 @@
!CBS_get_optional_asn1(&seq, &ignore_psk, &has_ignore_psk,
kIgnorePSKTag) ||
!CBS_get_optional_asn1(&seq, &cert_compression, &has_cert_compression,
- kCompressCertificateTag)) {
+ kCompressCertificateTag) ||
+ !CBS_get_optional_asn1(&seq, &server_random_tls12,
+ &has_server_random_tls12, kServerRandomTLS12Tag) ||
+ !CBS_get_optional_asn1(&seq, &ecdhe, &has_ecdhe, kECDHEHintTag)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_COULD_NOT_PARSE_HINTS);
return 0;
}
- if (has_server_random && !hints_obj->server_random.CopyFrom(server_random)) {
+ if (has_server_random_tls13 &&
+ !hints_obj->server_random_tls13.CopyFrom(server_random_tls13)) {
return 0;
}
@@ -981,6 +1019,26 @@
hints_obj->cert_compression_alg_id = static_cast<uint16_t>(alg);
}
+ if (has_server_random_tls12 &&
+ !hints_obj->server_random_tls12.CopyFrom(server_random_tls12)) {
+ return 0;
+ }
+
+ if (has_ecdhe) {
+ uint64_t group_id;
+ CBS public_key, private_key;
+ if (!CBS_get_asn1_uint64(&ecdhe, &group_id) || //
+ group_id == 0 || group_id > 0xffff ||
+ !CBS_get_asn1(&ecdhe, &public_key, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->ecdhe_public_key.CopyFrom(public_key) ||
+ !CBS_get_asn1(&ecdhe, &private_key, CBS_ASN1_OCTETSTRING) ||
+ !hints_obj->ecdhe_private_key.CopyFrom(private_key)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_COULD_NOT_PARSE_HINTS);
+ return 0;
+ }
+ hints_obj->ecdhe_group_id = static_cast<uint16_t>(group_id);
+ }
+
ssl->s3->hs->hints = std::move(hints_obj);
return 1;
}
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index 4a2ada0..fa6e9d6 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -801,12 +801,6 @@
// or below.
assert(ssl->s3->ech_status != ssl_ech_accepted);
- // TODO(davidben): Also compute hints for TLS 1.2. When doing so, update the
- // check in bssl_shim.cc to test this.
- if (hs->hints_requested) {
- return ssl_hs_hints_ready;
- }
-
ssl->s3->early_data_reason = ssl_early_data_protocol_version;
SSLMessage msg_unused;
@@ -988,14 +982,23 @@
hs->channel_id_negotiated = false;
}
- struct OPENSSL_timeval now;
- ssl_get_current_time(ssl, &now);
- ssl->s3->server_random[0] = now.tv_sec >> 24;
- ssl->s3->server_random[1] = now.tv_sec >> 16;
- ssl->s3->server_random[2] = now.tv_sec >> 8;
- ssl->s3->server_random[3] = now.tv_sec;
- if (!RAND_bytes(ssl->s3->server_random + 4, SSL3_RANDOM_SIZE - 4)) {
- return ssl_hs_error;
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ if (hints && !hs->hints_requested &&
+ hints->server_random_tls12.size() == SSL3_RANDOM_SIZE) {
+ OPENSSL_memcpy(ssl->s3->server_random, hints->server_random_tls12.data(),
+ SSL3_RANDOM_SIZE);
+ } else {
+ struct OPENSSL_timeval now;
+ ssl_get_current_time(ssl, &now);
+ CRYPTO_store_u32_be(ssl->s3->server_random,
+ static_cast<uint32_t>(now.tv_sec));
+ if (!RAND_bytes(ssl->s3->server_random + 4, SSL3_RANDOM_SIZE - 4)) {
+ return ssl_hs_error;
+ }
+ if (hints && hs->hints_requested &&
+ !hints->server_random_tls12.CopyFrom(ssl->s3->server_random)) {
+ return ssl_hs_error;
+ }
}
// Implement the TLS 1.3 anti-downgrade feature.
@@ -1040,7 +1043,11 @@
return ssl_hs_error;
}
- if (ssl->session != NULL) {
+ if (ssl->session != nullptr) {
+ // No additional hints to generate in resumption.
+ if (hs->hints_requested) {
+ return ssl_hs_hints_ready;
+ }
hs->state = state12_send_server_finished;
} else {
hs->state = state12_send_server_certificate;
@@ -1113,18 +1120,51 @@
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
return ssl_hs_error;
- }
+ }
hs->new_session->group_id = group_id;
- // Set up ECDH, generate a key, and emit the public half.
hs->key_shares[0] = SSLKeyShare::Create(group_id);
if (!hs->key_shares[0] ||
!CBB_add_u8(cbb.get(), NAMED_CURVE_TYPE) ||
!CBB_add_u16(cbb.get(), group_id) ||
- !CBB_add_u8_length_prefixed(cbb.get(), &child) ||
- !hs->key_shares[0]->Offer(&child)) {
+ !CBB_add_u8_length_prefixed(cbb.get(), &child)) {
return ssl_hs_error;
}
+
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ bool hint_ok = false;
+ if (hints && !hs->hints_requested &&
+ hints->ecdhe_group_id == group_id &&
+ !hints->ecdhe_public_key.empty() &&
+ !hints->ecdhe_private_key.empty()) {
+ CBS cbs = MakeConstSpan(hints->ecdhe_private_key);
+ hint_ok = hs->key_shares[0]->DeserializePrivateKey(&cbs);
+ }
+ if (hint_ok) {
+ // Reuse the ECDH key from handshake hints.
+ if (!CBB_add_bytes(&child, hints->ecdhe_public_key.data(),
+ hints->ecdhe_public_key.size())) {
+ return ssl_hs_error;
+ }
+ } else {
+ // Generate a key, and emit the public half.
+ if (!hs->key_shares[0]->Offer(&child)) {
+ return ssl_hs_error;
+ }
+ // If generating hints, save the ECDHE key.
+ if (hints && hs->hints_requested) {
+ bssl::ScopedCBB private_key_cbb;
+ if (!hints->ecdhe_public_key.CopyFrom(
+ MakeConstSpan(CBB_data(&child), CBB_len(&child))) ||
+ !CBB_init(private_key_cbb.get(), 32) ||
+ !hs->key_shares[0]->SerializePrivateKey(private_key_cbb.get()) ||
+ !CBBFinishArray(private_key_cbb.get(),
+ &hints->ecdhe_private_key)) {
+ return ssl_hs_error;
+ }
+ hints->ecdhe_group_id = group_id;
+ }
+ }
} else {
assert(alg_k & SSL_kPSK);
}
@@ -1214,6 +1254,9 @@
static enum ssl_hs_wait_t do_send_server_hello_done(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ if (hs->hints_requested) {
+ return ssl_hs_hints_ready;
+ }
ScopedCBB cbb;
CBB body;
diff --git a/ssl/internal.h b/ssl/internal.h
index 41630f5..1a78f63 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1697,7 +1697,8 @@
struct SSL_HANDSHAKE_HINTS {
static constexpr bool kAllowUniquePtr = true;
- Array<uint8_t> server_random;
+ Array<uint8_t> server_random_tls12;
+ Array<uint8_t> server_random_tls13;
uint16_t key_share_group_id = 0;
Array<uint8_t> key_share_public_key;
@@ -1714,6 +1715,10 @@
uint16_t cert_compression_alg_id = 0;
Array<uint8_t> cert_compression_input;
Array<uint8_t> cert_compression_output;
+
+ uint16_t ecdhe_group_id = 0;
+ Array<uint8_t> ecdhe_public_key;
+ Array<uint8_t> ecdhe_private_key;
};
struct SSL_HANDSHAKE {
diff --git a/ssl/ssl_privkey.cc b/ssl/ssl_privkey.cc
index 41a13a2..0843e0b 100644
--- a/ssl/ssl_privkey.cc
+++ b/ssl/ssl_privkey.cc
@@ -201,6 +201,31 @@
SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out,
uint16_t sigalg, Span<const uint8_t> in) {
SSL *const ssl = hs->ssl;
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ Array<uint8_t> spki;
+ if (hints) {
+ ScopedCBB spki_cbb;
+ if (!CBB_init(spki_cbb.get(), 64) ||
+ !EVP_marshal_public_key(spki_cbb.get(), hs->local_pubkey.get()) ||
+ !CBBFinishArray(spki_cbb.get(), &spki)) {
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_private_key_failure;
+ }
+ }
+
+ // Replay the signature from handshake hints if available.
+ if (hints && !hs->hints_requested && //
+ sigalg == hints->signature_algorithm && //
+ in == hints->signature_input &&
+ MakeConstSpan(spki) == hints->signature_spki &&
+ !hints->signature.empty() && //
+ hints->signature.size() <= max_out) {
+ // Signature algorithm and input both match. Reuse the signature from hints.
+ *out_len = hints->signature.size();
+ OPENSSL_memcpy(out, hints->signature.data(), hints->signature.size());
+ return ssl_private_key_success;
+ }
+
const SSL_PRIVATE_KEY_METHOD *key_method = hs->config->cert->key_method;
EVP_PKEY *privatekey = hs->config->cert->privatekey.get();
assert(!hs->can_release_private_key);
@@ -214,21 +239,33 @@
if (hs->pending_private_key_op) {
ret = key_method->complete(ssl, out, out_len, max_out);
} else {
- ret = key_method->sign(ssl, out, out_len, max_out,
- sigalg, in.data(), in.size());
+ ret = key_method->sign(ssl, out, out_len, max_out, sigalg, in.data(),
+ in.size());
}
if (ret == ssl_private_key_failure) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PRIVATE_KEY_OPERATION_FAILED);
}
hs->pending_private_key_op = ret == ssl_private_key_retry;
- return ret;
+ if (ret != ssl_private_key_success) {
+ return ret;
+ }
+ } else {
+ *out_len = max_out;
+ ScopedEVP_MD_CTX ctx;
+ if (!setup_ctx(ssl, ctx.get(), privatekey, sigalg, false /* sign */) ||
+ !EVP_DigestSign(ctx.get(), out, out_len, in.data(), in.size())) {
+ return ssl_private_key_failure;
+ }
}
- *out_len = max_out;
- ScopedEVP_MD_CTX ctx;
- if (!setup_ctx(ssl, ctx.get(), privatekey, sigalg, false /* sign */) ||
- !EVP_DigestSign(ctx.get(), out, out_len, in.data(), in.size())) {
- return ssl_private_key_failure;
+ // Save the hint if applicable.
+ if (hints && hs->hints_requested) {
+ hints->signature_algorithm = sigalg;
+ hints->signature_spki = std::move(spki);
+ if (!hints->signature_input.CopyFrom(in) ||
+ !hints->signature.CopyFrom(MakeConstSpan(out, *out_len))) {
+ return ssl_private_key_failure;
+ }
}
return ssl_private_key_success;
}
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 510328b..35086f8 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -667,24 +667,34 @@
}
// Test that handshake hints correctly skipped the expected operations.
- //
- // TODO(davidben): Add support for TLS 1.2 hints and remove the version check.
- // Also add a check for the session cache lookup.
- if (config->handshake_hints && !config->allow_hint_mismatch &&
- SSL_version(ssl) == TLS1_3_VERSION) {
+ if (config->handshake_hints && !config->allow_hint_mismatch) {
const TestState *state = GetTestState(ssl);
- if (!SSL_used_hello_retry_request(ssl) && state->used_private_key) {
+ // If the private key operation is performed in the first roundtrip, a hint
+ // match should have skipped it. This is ECDHE-based cipher suites in TLS
+ // 1.2 and non-HRR handshakes in TLS 1.3.
+ bool private_key_allowed;
+ if (SSL_version(ssl) == TLS1_3_VERSION) {
+ private_key_allowed = SSL_used_hello_retry_request(ssl);
+ } else {
+ private_key_allowed =
+ SSL_CIPHER_get_kx_nid(SSL_get_current_cipher(ssl)) == NID_kx_rsa;
+ }
+ if (!private_key_allowed && state->used_private_key) {
fprintf(
stderr,
"Performed private key operation, but hint should have skipped it\n");
return false;
}
- if (state->ticket_decrypt_done) {
+ // TODO(davidben): Make handshake hints skip TLS 1.2 ticket decryption.
+ if (SSL_version(ssl) == TLS1_3_VERSION && state->ticket_decrypt_done) {
fprintf(stderr,
"Performed ticket decryption, but hint should have skipped it\n");
return false;
}
+
+ // TODO(davidben): Decide what we want to do with TLS 1.2 stateful
+ // resumption.
}
return true;
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 65ed278..9291605 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -18770,6 +18770,27 @@
curveID: CurveX25519,
},
})
+ if protocol != quic {
+ testCases = append(testCases, testCase{
+ name: protocol.String() + "-HintMismatch-ECDHE-Group",
+ testType: serverTest,
+ protocol: protocol,
+ skipSplitHandshake: true,
+ config: Config{
+ MinVersion: VersionTLS12,
+ MaxVersion: VersionTLS12,
+ DefaultCurves: []CurveID{CurveX25519, CurveP256},
+ },
+ flags: []string{
+ "-allow-hint-mismatch",
+ "-on-shim-curves", strconv.Itoa(int(CurveX25519)),
+ "-on-handshaker-curves", strconv.Itoa(int(CurveP256)),
+ },
+ expectations: connectionExpectations{
+ curveID: CurveX25519,
+ },
+ })
+ }
// If the handshaker does HelloRetryRequest, it will omit most hints.
// The shim should still work.
@@ -18818,7 +18839,7 @@
// The shim and handshaker may have different signature algorithm
// preferences.
testCases = append(testCases, testCase{
- name: protocol.String() + "-HintMismatch-SignatureAlgorithm",
+ name: protocol.String() + "-HintMismatch-SignatureAlgorithm-TLS13",
testType: serverTest,
protocol: protocol,
skipSplitHandshake: true,
@@ -18841,6 +18862,32 @@
peerSignatureAlgorithm: signatureRSAPSSWithSHA256,
},
})
+ if protocol != quic {
+ testCases = append(testCases, testCase{
+ name: protocol.String() + "-HintMismatch-SignatureAlgorithm-TLS12",
+ testType: serverTest,
+ protocol: protocol,
+ skipSplitHandshake: true,
+ config: Config{
+ MinVersion: VersionTLS12,
+ MaxVersion: VersionTLS12,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ signatureRSAPSSWithSHA384,
+ },
+ },
+ flags: []string{
+ "-allow-hint-mismatch",
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-on-shim-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA256)),
+ "-on-handshaker-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)),
+ },
+ expectations: connectionExpectations{
+ peerSignatureAlgorithm: signatureRSAPSSWithSHA256,
+ },
+ })
+ }
// The shim and handshaker may disagree on whether resumption is allowed.
// We run the first connection with tickets enabled, so the client is
@@ -19029,6 +19076,51 @@
ocspResponse: testOCSPResponse,
},
})
+
+ // The shim and handshaker may disagree on cipher suite, to the point
+ // that one selects RSA key exchange (no applicable hint) and the other
+ // selects ECDHE_RSA (hints are useful).
+ if protocol != quic {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: protocol.String() + "-HintMismatch-CipherMismatch1",
+ protocol: protocol,
+ skipSplitHandshake: true,
+ config: Config{
+ MinVersion: VersionTLS12,
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{
+ "-allow-hint-mismatch",
+ "-on-shim-cipher", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "-on-handshaker-cipher", "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ },
+ expectations: connectionExpectations{
+ cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: protocol.String() + "-HintMismatch-CipherMismatch2",
+ protocol: protocol,
+ skipSplitHandshake: true,
+ config: Config{
+ MinVersion: VersionTLS12,
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{
+ // There is no need to pass -allow-hint-mismatch. The
+ // handshaker will unnecessarily generate a signature hints.
+ // This is not reported as a mismatch because hints would
+ // not have helped the shim anyway.
+ "-on-shim-cipher", "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ "-on-handshaker-cipher", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ },
+ expectations: connectionExpectations{
+ cipher: TLS_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ })
+ }
}
}
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc
index 208c6ff..d7997c7 100644
--- a/ssl/tls13_both.cc
+++ b/ssl/tls13_both.cc
@@ -576,7 +576,6 @@
return ssl_private_key_failure;
}
- // Sign the digest.
CBB child;
const size_t max_sig_len = EVP_PKEY_size(hs->local_pubkey.get());
uint8_t *sig;
@@ -595,40 +594,10 @@
return ssl_private_key_failure;
}
- SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
- Array<uint8_t> spki;
- if (hints) {
- ScopedCBB spki_cbb;
- if (!CBB_init(spki_cbb.get(), 64) ||
- !EVP_marshal_public_key(spki_cbb.get(), hs->local_pubkey.get()) ||
- !CBBFinishArray(spki_cbb.get(), &spki)) {
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return ssl_private_key_failure;
- }
- }
-
- if (hints && !hs->hints_requested &&
- signature_algorithm == hints->signature_algorithm &&
- MakeConstSpan(msg) == hints->signature_input &&
- MakeConstSpan(spki) == hints->signature_spki &&
- !hints->signature.empty() && hints->signature.size() <= max_sig_len) {
- // Signature algorithm and input both match. Reuse the signature from hints.
- sig_len = hints->signature.size();
- OPENSSL_memcpy(sig, hints->signature.data(), sig_len);
- } else {
- enum ssl_private_key_result_t sign_result = ssl_private_key_sign(
- hs, sig, &sig_len, max_sig_len, signature_algorithm, msg);
- if (sign_result != ssl_private_key_success) {
- return sign_result;
- }
- if (hints && hs->hints_requested) {
- hints->signature_algorithm = signature_algorithm;
- hints->signature_input = std::move(msg);
- hints->signature_spki = std::move(spki);
- if (!hints->signature.CopyFrom(MakeSpan(sig, sig_len))) {
- return ssl_private_key_failure;
- }
- }
+ enum ssl_private_key_result_t sign_result = ssl_private_key_sign(
+ hs, sig, &sig_len, max_sig_len, signature_algorithm, msg);
+ if (sign_result != ssl_private_key_success) {
+ return sign_result;
}
if (!CBB_did_write(&child, sig_len) ||
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index eca63f7..ca43624 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -738,12 +738,13 @@
SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
if (hints && !hs->hints_requested &&
- hints->server_random.size() == random.size()) {
- OPENSSL_memcpy(random.data(), hints->server_random.data(), random.size());
+ hints->server_random_tls13.size() == random.size()) {
+ OPENSSL_memcpy(random.data(), hints->server_random_tls13.data(),
+ random.size());
} else {
RAND_bytes(random.data(), random.size());
if (hints && hs->hints_requested &&
- !hints->server_random.CopyFrom(random)) {
+ !hints->server_random_tls13.CopyFrom(random)) {
return ssl_hs_error;
}
}