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>
chromium-5359
David Benjamin 3 years ago committed by Boringssl LUCI CQ
parent 24c01865dc
commit 4a6c8fde18
  1. 5
      include/openssl/ssl.h
  2. 86
      ssl/handoff.cc
  3. 81
      ssl/handshake_server.cc
  4. 7
      ssl/internal.h
  5. 53
      ssl/ssl_privkey.cc
  6. 24
      ssl/test/bssl_shim.cc
  7. 94
      ssl/test/runner/runner.go
  8. 39
      ssl/tls13_both.cc
  9. 7
      ssl/tls13_server.cc

@ -3977,8 +3977,9 @@ OPENSSL_EXPORT int SSL_CTX_set_record_protocol_version(SSL_CTX *ctx,
// 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.

@ -769,7 +769,7 @@ int SSL_request_handshake_hints(SSL *ssl, const uint8_t *client_hello,
// 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 @@ int SSL_request_handshake_hints(SSL *ssl, const uint8_t *client_hello,
// 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 @@ int SSL_request_handshake_hints(SSL *ssl, const uint8_t *client_hello,
// 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 kSignatureHintTag =
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 @@ int SSL_serialize_handshake_hints(const SSL *ssl, CBB *out) {
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 @@ int SSL_serialize_handshake_hints(const SSL *ssl, CBB *out) {
}
}
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 @@ int SSL_set_handshake_hints(SSL *ssl, const uint8_t *hints, size_t hints_len) {
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 @@ int SSL_set_handshake_hints(SSL *ssl, const uint8_t *hints, size_t hints_len) {
!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 @@ int SSL_set_handshake_hints(SSL *ssl, const uint8_t *hints, size_t hints_len) {
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;
}

@ -801,12 +801,6 @@ static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
// 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 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
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 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
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 @@ static enum ssl_hs_wait_t do_send_server_certificate(SSL_HANDSHAKE *hs) {
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_key_exchange(SSL_HANDSHAKE *hs) {
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;

@ -1697,7 +1697,8 @@ enum handback_t {
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 @@ struct SSL_HANDSHAKE_HINTS {
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 {

@ -201,6 +201,31 @@ enum ssl_private_key_result_t ssl_private_key_sign(
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 @@ enum ssl_private_key_result_t ssl_private_key_sign(
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;
}

@ -667,24 +667,34 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume,
}
// 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;
}

@ -18770,6 +18770,27 @@ func addHintMismatchTests() {
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 @@ func addHintMismatchTests() {
// 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 @@ func addHintMismatchTests() {
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 @@ func addHintMismatchTests() {
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,
},
})
}
}
}

@ -576,7 +576,6 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) {
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 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) {
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) ||

@ -738,12 +738,13 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
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;
}
}

Loading…
Cancel
Save