Implement a handshake hint for certificate compression.
While decompression is deterministic, compression is not. New revisions
of the compression algorithm may start using different (hopefully
smaller!) compressions. So this doesn't cause hint mismatches, add a
certificate compression hint. If the shim's Certificate message matches
the handshaker, we'll reuse the already compressed message.
This also adds what appears to be a missing test for when the server
cannot find compression algorithms in common.
Change-Id: Idbedaceb20208463d8f61581ee27971c17fcd126
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/48005
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/tls13_both.cc b/ssl/tls13_both.cc
index 5837187..0354f39 100644
--- a/ssl/tls13_both.cc
+++ b/ssl/tls13_both.cc
@@ -534,9 +534,37 @@
SSL3_MT_COMPRESSED_CERTIFICATE) ||
!CBB_add_u16(body, hs->cert_compression_alg_id) ||
!CBB_add_u24(body, msg.size()) ||
- !CBB_add_u24_length_prefixed(body, &compressed) ||
- !alg->compress(ssl, &compressed, msg.data(), msg.size()) ||
- !ssl_add_message_cbb(ssl, cbb.get())) {
+ !CBB_add_u24_length_prefixed(body, &compressed)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
+ if (hints && !hs->hints_requested &&
+ hints->cert_compression_alg_id == hs->cert_compression_alg_id &&
+ hints->cert_compression_input == MakeConstSpan(msg) &&
+ !hints->cert_compression_output.empty()) {
+ if (!CBB_add_bytes(&compressed, hints->cert_compression_output.data(),
+ hints->cert_compression_output.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ } else {
+ if (!alg->compress(ssl, &compressed, msg.data(), msg.size())) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+ if (hints && hs->hints_requested) {
+ hints->cert_compression_alg_id = hs->cert_compression_alg_id;
+ if (!hints->cert_compression_input.CopyFrom(msg) ||
+ !hints->cert_compression_output.CopyFrom(
+ MakeConstSpan(CBB_data(&compressed), CBB_len(&compressed)))) {
+ return false;
+ }
+ }
+ }
+
+ if (!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}