mock_quic_transport.cc
Go to the documentation of this file.
1 /* Copyright (c) 2019, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include "mock_quic_transport.h"
16 
17 #include <openssl/span.h>
18 
19 #include <cstring>
20 #include <limits>
21 
22 MockQuicTransport::MockQuicTransport(bssl::UniquePtr<BIO> bio, SSL *ssl)
23  : bio_(std::move(bio)),
24  read_levels_(ssl_encryption_application + 1),
25  write_levels_(ssl_encryption_application + 1),
26  ssl_(ssl) {}
27 
28 bool MockQuicTransport::SetReadSecret(enum ssl_encryption_level_t level,
29  const SSL_CIPHER *cipher,
30  const uint8_t *secret,
31  size_t secret_len) {
32  // TODO(davidben): Assert the various encryption secret invariants.
34  read_levels_[level].secret.assign(secret, secret + secret_len);
35  return true;
36 }
37 
38 bool MockQuicTransport::SetWriteSecret(enum ssl_encryption_level_t level,
39  const SSL_CIPHER *cipher,
40  const uint8_t *secret,
41  size_t secret_len) {
42  // TODO(davidben): Assert the various encryption secret invariants.
44  write_levels_[level].secret.assign(secret, secret + secret_len);
45  return true;
46 }
47 
48 namespace {
49 
50 bool ReadAll(BIO *bio, bssl::Span<uint8_t> out) {
51  size_t len = out.size();
52  uint8_t *buf = out.data();
53  while (len > 0) {
54  int chunk_len = std::numeric_limits<int>::max();
55  if (len <= static_cast<unsigned int>(std::numeric_limits<int>::max())) {
56  chunk_len = len;
57  }
58  int ret = BIO_read(bio, buf, chunk_len);
59  if (ret <= 0) {
60  return false;
61  }
62  buf += ret;
63  len -= ret;
64  }
65  return true;
66 }
67 
68 const char *LevelToString(ssl_encryption_level_t level) {
69  switch (level) {
71  return "initial";
73  return "early_data";
75  return "handshake";
77  return "application";
78  }
79  return "";
80 }
81 
82 } // namespace
83 
85  enum ssl_encryption_level_t *out_level,
86  size_t *out_len) {
87  for (;;) {
88  uint8_t header[8];
89  if (!ReadAll(bio_.get(), header)) {
90  // TODO(davidben): Distinguish between errors and EOF. See
91  // ReadApplicationData.
92  return false;
93  }
94 
95  CBS cbs;
96  uint8_t level_id;
97  uint16_t cipher_suite;
98  uint32_t remaining_bytes;
99  CBS_init(&cbs, header, sizeof(header));
100  if (!CBS_get_u8(&cbs, out_type) ||
101  !CBS_get_u8(&cbs, &level_id) ||
102  !CBS_get_u16(&cbs, &cipher_suite) ||
103  !CBS_get_u32(&cbs, &remaining_bytes) ||
104  level_id >= read_levels_.size()) {
105  fprintf(stderr, "Error parsing record header.\n");
106  return false;
107  }
108 
109  auto level = static_cast<ssl_encryption_level_t>(level_id);
110  // Non-initial levels must be configured before use.
111  uint16_t expect_cipher = read_levels_[level].cipher;
112  if (expect_cipher == 0 && level != ssl_encryption_initial) {
114  // If we receive early data records without any early data keys, skip
115  // the record. This means early data was rejected.
116  std::vector<uint8_t> discard(remaining_bytes);
117  if (!ReadAll(bio_.get(), bssl::MakeSpan(discard))) {
118  return false;
119  }
120  continue;
121  }
122  fprintf(stderr,
123  "Got record at level %s, but keys were not configured.\n",
125  return false;
126  }
127  if (cipher_suite != expect_cipher) {
128  fprintf(stderr, "Got cipher suite 0x%04x at level %s, wanted 0x%04x.\n",
129  cipher_suite, LevelToString(level), expect_cipher);
130  return false;
131  }
132  const std::vector<uint8_t> &secret = read_levels_[level].secret;
133  std::vector<uint8_t> read_secret(secret.size());
134  if (remaining_bytes < secret.size()) {
135  fprintf(stderr, "Record at level %s too small.\n", LevelToString(level));
136  return false;
137  }
138  remaining_bytes -= secret.size();
139  if (!ReadAll(bio_.get(), bssl::MakeSpan(read_secret))) {
140  fprintf(stderr, "Error reading record secret.\n");
141  return false;
142  }
143  if (read_secret != secret) {
144  fprintf(stderr, "Encryption secret at level %s did not match.\n",
146  return false;
147  }
148  *out_level = level;
149  *out_len = remaining_bytes;
150  return true;
151  }
152 }
153 
155  uint8_t type;
156  ssl_encryption_level_t level;
157  size_t len;
158  if (!ReadHeader(&type, &level, &len)) {
159  return false;
160  }
161  if (type != SSL3_RT_HANDSHAKE) {
162  return false;
163  }
164 
165  std::vector<uint8_t> buf(len);
166  if (!ReadAll(bio_.get(), bssl::MakeSpan(buf))) {
167  return false;
168  }
169  return SSL_provide_quic_data(ssl_, level, buf.data(), buf.size());
170 }
171 
173  if (pending_app_data_.size() > 0) {
174  size_t len = pending_app_data_.size() - app_data_offset_;
175  if (len > max_out) {
176  len = max_out;
177  }
180  if (app_data_offset_ == pending_app_data_.size()) {
181  pending_app_data_.clear();
182  app_data_offset_ = 0;
183  }
184  return len;
185  }
186 
187  uint8_t type = 0;
188  ssl_encryption_level_t level;
189  size_t len;
190  while (true) {
191  if (!ReadHeader(&type, &level, &len)) {
192  // Assume that a failure to read the header means there's no more to read,
193  // not an error reading.
194  return 0;
195  }
197  break;
198  }
199  if (type != SSL3_RT_HANDSHAKE) {
200  return -1;
201  }
202 
203  std::vector<uint8_t> buf(len);
204  if (!ReadAll(bio_.get(), bssl::MakeSpan(buf))) {
205  return -1;
206  }
207  if (SSL_provide_quic_data(ssl_, level, buf.data(), buf.size()) != 1) {
208  return -1;
209  }
210  if (SSL_in_init(ssl_)) {
211  int ret = SSL_do_handshake(ssl_);
212  if (ret < 0) {
213  int ssl_err = SSL_get_error(ssl_, ret);
214  if (ssl_err == SSL_ERROR_WANT_READ) {
215  continue;
216  }
217  return -1;
218  }
219  } else if (SSL_process_quic_post_handshake(ssl_) != 1) {
220  return -1;
221  }
222  }
223 
224  uint8_t *buf = out;
225  if (len > max_out) {
226  pending_app_data_.resize(len);
227  buf = pending_app_data_.data();
228  }
229  app_data_offset_ = 0;
230  if (!ReadAll(bio_.get(), bssl::MakeSpan(buf, len))) {
231  return -1;
232  }
233  if (len > max_out) {
234  memcpy(out, buf, max_out);
235  app_data_offset_ = max_out;
236  return max_out;
237  }
238  return len;
239 }
240 
241 bool MockQuicTransport::WriteRecord(enum ssl_encryption_level_t level,
242  uint8_t type, const uint8_t *data,
243  size_t len) {
244  uint16_t cipher_suite = write_levels_[level].cipher;
245  const std::vector<uint8_t> &secret = write_levels_[level].secret;
246  size_t tlv_len = secret.size() + len;
247  uint8_t header[8];
248  header[0] = type;
249  header[1] = level;
250  header[2] = (cipher_suite >> 8) & 0xff;
251  header[3] = cipher_suite & 0xff;
252  header[4] = (tlv_len >> 24) & 0xff;
253  header[5] = (tlv_len >> 16) & 0xff;
254  header[6] = (tlv_len >> 8) & 0xff;
255  header[7] = tlv_len & 0xff;
256  return BIO_write_all(bio_.get(), header, sizeof(header)) &&
257  BIO_write_all(bio_.get(), secret.data(), secret.size()) &&
258  BIO_write_all(bio_.get(), data, len);
259 }
260 
261 bool MockQuicTransport::WriteHandshakeData(enum ssl_encryption_level_t level,
262  const uint8_t *data, size_t len) {
264 }
265 
267  enum ssl_encryption_level_t level = ssl_encryption_application;
270  }
272 }
273 
274 bool MockQuicTransport::Flush() { return BIO_flush(bio_.get()) > 0; }
275 
276 bool MockQuicTransport::SendAlert(enum ssl_encryption_level_t level,
277  uint8_t alert) {
278  uint8_t alert_msg[] = {2, alert};
279  return WriteRecord(level, SSL3_RT_ALERT, alert_msg, sizeof(alert_msg));
280 }
MockQuicTransport::Flush
bool Flush()
Definition: mock_quic_transport.cc:274
ssl_cipher_st
Definition: third_party/boringssl-with-bazel/src/ssl/internal.h:520
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
CBS_get_u16
#define CBS_get_u16
Definition: boringssl_prefix_symbols.h:1073
cbs_st
Definition: bytestring.h:39
bio_st
Definition: bio.h:822
uint16_t
unsigned short uint16_t
Definition: stdint-msvc2008.h:79
SSL_ERROR_WANT_READ
#define SSL_ERROR_WANT_READ
Definition: ssl.h:494
SSL3_RT_ALERT
#define SSL3_RT_ALERT
Definition: ssl3.h:272
CBS_get_u32
#define CBS_get_u32
Definition: boringssl_prefix_symbols.h:1078
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
MockQuicTransport::WriteRecord
bool WriteRecord(enum ssl_encryption_level_t level, uint8_t type, const uint8_t *data, size_t len)
Definition: mock_quic_transport.cc:241
MockQuicTransport::WriteApplicationData
bool WriteApplicationData(const uint8_t *in, size_t len)
Definition: mock_quic_transport.cc:266
mock_quic_transport.h
SSL_do_handshake
#define SSL_do_handshake
Definition: boringssl_prefix_symbols.h:297
cbs
const CBS * cbs
Definition: third_party/boringssl-with-bazel/src/crypto/trust_token/internal.h:107
BIO_read
#define BIO_read
Definition: boringssl_prefix_symbols.h:831
CBS_init
#define CBS_init
Definition: boringssl_prefix_symbols.h:1085
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
MockQuicTransport::ReadHeader
bool ReadHeader(uint8_t *out_type, enum ssl_encryption_level_t *out_level, size_t *out_len)
Definition: mock_quic_transport.cc:84
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
MockQuicTransport::MockQuicTransport
MockQuicTransport(bssl::UniquePtr< BIO > bio, SSL *ssl)
Definition: mock_quic_transport.cc:22
SSL_process_quic_post_handshake
#define SSL_process_quic_post_handshake
Definition: boringssl_prefix_symbols.h:418
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
in
const char * in
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:391
SSL_get_error
#define SSL_get_error
Definition: boringssl_prefix_symbols.h:340
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
MockQuicTransport::read_levels_
std::vector< EncryptionLevel > read_levels_
Definition: mock_quic_transport.h:70
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
MockQuicTransport::app_data_offset_
size_t app_data_offset_
Definition: mock_quic_transport.h:63
ssl_st
Definition: third_party/boringssl-with-bazel/src/ssl/internal.h:3698
MockQuicTransport::pending_app_data_
std::vector< uint8_t > pending_app_data_
Definition: mock_quic_transport.h:62
SSL_provide_quic_data
#define SSL_provide_quic_data
Definition: boringssl_prefix_symbols.h:420
ssl_encryption_initial
ssl_encryption_initial
Definition: ssl.h:3282
MockQuicTransport::bio_
bssl::UniquePtr< BIO > bio_
Definition: mock_quic_transport.h:60
header
struct absl::base_internal::@2940::AllocList::Header header
CBS_get_u8
#define CBS_get_u8
Definition: boringssl_prefix_symbols.h:1082
SSL_is_server
#define SSL_is_server
Definition: boringssl_prefix_symbols.h:404
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
MockQuicTransport::SetReadSecret
bool SetReadSecret(enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len)
Definition: mock_quic_transport.cc:28
MockQuicTransport::SendAlert
bool SendAlert(enum ssl_encryption_level_t level, uint8_t alert)
Definition: mock_quic_transport.cc:276
SSL3_RT_HANDSHAKE
#define SSL3_RT_HANDSHAKE
Definition: ssl3.h:273
SSL_in_init
#define SSL_in_init
Definition: boringssl_prefix_symbols.h:401
MockQuicTransport::ReadApplicationData
int ReadApplicationData(uint8_t *out, size_t max_out)
Definition: mock_quic_transport.cc:172
ssl_encryption_application
ssl_encryption_application
Definition: ssl.h:3285
ReadAll
bool ReadAll(std::vector< uint8_t > *out, FILE *file)
Definition: boringssl-with-bazel/src/tool/file.cc:27
MockQuicTransport::SetWriteSecret
bool SetWriteSecret(enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len)
Definition: mock_quic_transport.cc:38
MockQuicTransport::ReadHandshake
bool ReadHandshake()
Definition: mock_quic_transport.cc:154
MockQuicTransport::ssl_
SSL * ssl_
Definition: mock_quic_transport.h:73
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
BSSL_NAMESPACE_BEGIN::LevelToString
const char * LevelToString(ssl_encryption_level_t level)
Definition: ssl_test.cc:5805
ssl_encryption_early_data
ssl_encryption_early_data
Definition: ssl.h:3283
span.h
client.level
level
Definition: examples/python/async_streaming/client.py:118
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
BIO_write_all
#define BIO_write_all
Definition: boringssl_prefix_symbols.h:871
SSL_in_early_data
#define SSL_in_early_data
Definition: boringssl_prefix_symbols.h:399
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
BIO_flush
#define BIO_flush
Definition: boringssl_prefix_symbols.h:786
MockQuicTransport::WriteHandshakeData
bool WriteHandshakeData(enum ssl_encryption_level_t level, const uint8_t *data, size_t len)
Definition: mock_quic_transport.cc:261
SSL3_RT_APPLICATION_DATA
#define SSL3_RT_APPLICATION_DATA
Definition: ssl3.h:274
ssl_encryption_handshake
ssl_encryption_handshake
Definition: ssl.h:3284
SSL_CIPHER_get_protocol_id
#define SSL_CIPHER_get_protocol_id
Definition: boringssl_prefix_symbols.h:55
absl::MakeSpan
constexpr Span< T > MakeSpan(T *ptr, size_t size) noexcept
Definition: abseil-cpp/absl/types/span.h:661
MockQuicTransport::write_levels_
std::vector< EncryptionLevel > write_levels_
Definition: mock_quic_transport.h:71


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:30