/proc/self/cwd/source/common/quic/cert_compression.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/common/quic/cert_compression.h" |
2 | | |
3 | | #include "source/common/common/assert.h" |
4 | | #include "source/common/runtime/runtime_features.h" |
5 | | |
6 | | #include "openssl/tls1.h" |
7 | | |
8 | | #define ZLIB_CONST |
9 | | #include "zlib.h" |
10 | | |
11 | | namespace Envoy { |
12 | | namespace Quic { |
13 | | |
14 | | namespace { |
15 | | |
16 | | class ScopedZStream { |
17 | | public: |
18 | | using CleanupFunc = int (*)(z_stream*); |
19 | | |
20 | 0 | ScopedZStream(z_stream& z, CleanupFunc cleanup) : z_(z), cleanup_(cleanup) {} |
21 | 0 | ~ScopedZStream() { cleanup_(&z_); } |
22 | | |
23 | | private: |
24 | | z_stream& z_; |
25 | | CleanupFunc cleanup_; |
26 | | }; |
27 | | |
28 | | } // namespace |
29 | | |
30 | 0 | void CertCompression::registerSslContext(SSL_CTX* ssl_ctx) { |
31 | 0 | if (Runtime::runtimeFeatureEnabled( |
32 | 0 | "envoy.reloadable_features.quic_support_certificate_compression")) { |
33 | 0 | auto ret = SSL_CTX_add_cert_compression_alg(ssl_ctx, TLSEXT_cert_compression_zlib, compressZlib, |
34 | 0 | decompressZlib); |
35 | 0 | ASSERT(ret == 1); |
36 | 0 | } |
37 | 0 | } |
38 | | |
39 | 0 | int CertCompression::compressZlib(SSL*, CBB* out, const uint8_t* in, size_t in_len) { |
40 | |
|
41 | 0 | z_stream z = {}; |
42 | 0 | int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION); |
43 | 0 | if (rv != Z_OK) { |
44 | 0 | IS_ENVOY_BUG(fmt::format("Cert compression failure in deflateInit: {}", rv)); |
45 | 0 | return FAILURE; |
46 | 0 | } |
47 | | |
48 | 0 | ScopedZStream deleter(z, deflateEnd); |
49 | |
|
50 | 0 | const auto upper_bound = deflateBound(&z, in_len); |
51 | |
|
52 | 0 | uint8_t* out_buf = nullptr; |
53 | 0 | if (!CBB_reserve(out, &out_buf, upper_bound)) { |
54 | 0 | IS_ENVOY_BUG(fmt::format("Cert compression failure in allocating output CBB buffer of size {}", |
55 | 0 | upper_bound)); |
56 | 0 | return FAILURE; |
57 | 0 | } |
58 | | |
59 | 0 | z.next_in = in; |
60 | 0 | z.avail_in = in_len; |
61 | 0 | z.next_out = out_buf; |
62 | 0 | z.avail_out = upper_bound; |
63 | |
|
64 | 0 | rv = deflate(&z, Z_FINISH); |
65 | 0 | if (rv != Z_STREAM_END) { |
66 | 0 | IS_ENVOY_BUG(fmt::format( |
67 | 0 | "Cert compression failure in deflate: {}, z.total_out {}, in_len {}, z.avail_in {}", rv, |
68 | 0 | z.avail_in, in_len, z.avail_in)); |
69 | 0 | return FAILURE; |
70 | 0 | } |
71 | | |
72 | 0 | if (!CBB_did_write(out, z.total_out)) { |
73 | 0 | IS_ENVOY_BUG("CBB_did_write failed"); |
74 | 0 | return FAILURE; |
75 | 0 | } |
76 | | |
77 | 0 | ENVOY_LOG(trace, "Cert compression successful"); |
78 | |
|
79 | 0 | return SUCCESS; |
80 | 0 | } |
81 | | |
82 | | int CertCompression::decompressZlib(SSL*, CRYPTO_BUFFER** out, size_t uncompressed_len, |
83 | 0 | const uint8_t* in, size_t in_len) { |
84 | 0 | z_stream z = {}; |
85 | 0 | int rv = inflateInit(&z); |
86 | 0 | if (rv != Z_OK) { |
87 | 0 | IS_ENVOY_BUG(fmt::format("Cert decompression failure in inflateInit: {}", rv)); |
88 | 0 | return FAILURE; |
89 | 0 | } |
90 | | |
91 | 0 | ScopedZStream deleter(z, inflateEnd); |
92 | |
|
93 | 0 | z.next_in = in; |
94 | 0 | z.avail_in = in_len; |
95 | 0 | bssl::UniquePtr<CRYPTO_BUFFER> decompressed_data( |
96 | 0 | CRYPTO_BUFFER_alloc(&z.next_out, uncompressed_len)); |
97 | 0 | z.avail_out = uncompressed_len; |
98 | |
|
99 | 0 | rv = inflate(&z, Z_FINISH); |
100 | 0 | if (rv != Z_STREAM_END) { |
101 | 0 | ENVOY_LOG_PERIODIC(error, std::chrono::seconds(10), |
102 | 0 | "Cert decompression failure in inflate, possibly caused by invalid " |
103 | 0 | "compressed cert from peer: {}, z.total_out {}, uncompressed_len {}", |
104 | 0 | rv, z.total_out, uncompressed_len); |
105 | 0 | return FAILURE; |
106 | 0 | } |
107 | | |
108 | 0 | if (z.total_out != uncompressed_len) { |
109 | 0 | ENVOY_LOG_PERIODIC(error, std::chrono::seconds(10), |
110 | 0 | "Decompression length did not match peer provided uncompressed length, " |
111 | 0 | "caused by either invalid peer handshake data or decompression error."); |
112 | 0 | return FAILURE; |
113 | 0 | } |
114 | | |
115 | 0 | ENVOY_LOG(trace, "Cert decompression successful"); |
116 | |
|
117 | 0 | *out = decompressed_data.release(); |
118 | 0 | return SUCCESS; |
119 | 0 | } |
120 | | |
121 | | } // namespace Quic |
122 | | } // namespace Envoy |