proxygen
PlaintextRecordLayer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
10 
11 #include <folly/String.h>
12 
13 namespace fizz {
14 
16 using ProtocolVersionType =
18 
19 static constexpr uint16_t kMaxPlaintextRecordSize = 0x4000; // 16k
20 static constexpr size_t kPlaintextHeaderSize =
21  sizeof(ContentType) + sizeof(ProtocolVersion) + sizeof(uint16_t);
22 
24  folly::IOBufQueue& buf) {
25  while (true) {
26  folly::io::Cursor cursor(buf.front());
27 
28  if (buf.empty() || !cursor.canAdvance(kPlaintextHeaderSize)) {
29  return folly::none;
30  }
31 
32  TLSMessage msg;
33  msg.type = static_cast<ContentType>(cursor.readBE<ContentTypeType>());
34 
37  cursor.skip(sizeof(ProtocolVersion));
38  auto length = cursor.readBE<uint16_t>();
39  if (buf.chainLength() < (cursor - buf.front()) + length) {
40  return folly::none;
41  }
42  length +=
43  sizeof(ContentType) + sizeof(ProtocolVersion) + sizeof(uint16_t);
44  buf.trimStart(length);
45  continue;
46  } else if (msg.type != ContentType::change_cipher_spec) {
47  skipEncryptedRecords_ = false;
48  }
49  }
50 
51  switch (msg.type) {
53  case ContentType::alert:
54  break;
56  break;
57  default:
58  throw std::runtime_error(folly::to<std::string>(
59  "received plaintext content type ",
60  static_cast<ContentTypeType>(msg.type),
61  ", header: ",
62  folly::hexlify(buf.splitAtMost(10)->coalesce())));
63  }
64 
66  static_cast<ProtocolVersion>(cursor.readBE<ProtocolVersionType>());
67 
68  auto length = cursor.readBE<uint16_t>();
69  if (length > kMaxPlaintextRecordSize) {
70  throw std::runtime_error("received too long plaintext record");
71  }
72  if (length == 0) {
73  throw std::runtime_error("received empty plaintext record");
74  }
75  if (buf.chainLength() < (cursor - buf.front()) + length) {
76  return folly::none;
77  }
78 
79  cursor.clone(msg.fragment, length);
80 
81  buf.trimStart(cursor - buf.front());
82 
84  msg.fragment->coalesce();
85  if (msg.fragment->length() == 1 && *msg.fragment->data() == 0x01) {
86  continue;
87  } else {
88  throw FizzException(
89  "received ccs", AlertDescription::illegal_parameter);
90  }
91  }
92 
93  return std::move(msg);
94  }
95 }
96 
99 }
100 
102  return write(std::move(msg), recordVersion_);
103 }
104 
106  Buf encodedClientHello) const {
107  return write(
108  TLSMessage{ContentType::handshake, std::move(encodedClientHello)},
110 }
111 
113  TLSMessage msg,
114  ProtocolVersion recordVersion) const {
115  if (msg.type == ContentType::application_data) {
116  throw std::runtime_error("refusing to send plaintext application data");
117  }
118 
119  auto fragment = std::move(msg.fragment);
120  folly::io::Cursor cursor(fragment.get());
121  std::unique_ptr<folly::IOBuf> data;
122  while (!cursor.isAtEnd()) {
123  Buf thisFragment;
124  auto len = cursor.cloneAtMost(thisFragment, kMaxPlaintextRecordSize);
125 
126  auto header = folly::IOBuf::create(kPlaintextHeaderSize);
127  folly::io::Appender appender(header.get(), kPlaintextHeaderSize);
128  appender.writeBE(static_cast<ContentTypeType>(msg.type));
129  appender.writeBE(static_cast<ProtocolVersionType>(recordVersion));
130  appender.writeBE<uint16_t>(len);
131 
132  if (!data) {
133  data = std::move(header);
134  } else {
135  data->prependChain(std::move(header));
136  }
137  data->prependChain(std::move(thisFragment));
138  }
139  TLSContent content;
140  content.data = std::move(data);
141  content.contentType = msg.type;
143  return content;
144 }
145 
148 }
149 } // namespace fizz
Buf fragment
Definition: Types.h:56
const folly::IOBuf * front() const
Definition: IOBufQueue.h:476
size_t chainLength() const
Definition: IOBufQueue.h:492
folly::Optional< TLSMessage > read(folly::IOBufQueue &buf) override
std::unique_ptr< folly::IOBuf > splitAtMost(size_t n)
Definition: IOBufQueue.h:428
void write(const T &in, folly::io::Appender &appender)
Definition: Types-inl.h:112
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
PskType type
bool empty() const
Definition: IOBufQueue.h:503
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
virtual TLSContent writeInitialClientHello(Buf encodedClientHello) const
EncryptionLevel getEncryptionLevel() const override
ProtocolVersion
Definition: Types.h:24
EncryptionLevel
Definition: Types.h:29
EncryptionLevel getEncryptionLevel() const override
constexpr uint16_t kMaxPlaintextRecordSize
EncryptionLevel encryptionLevel
Definition: RecordLayer.h:21
Definition: Actions.h:16
static constexpr size_t kPlaintextHeaderSize
folly::Optional< ProtocolVersion > receivedRecordVersion_
typename std::underlying_type< ProtocolVersion >::type ProtocolVersionType
ContentType contentType
Definition: RecordLayer.h:20
std::unique_ptr< folly::IOBuf > Buf
Definition: Types.h:22
void trimStart(size_t amount)
Definition: IOBufQueue.cpp:255
TLSContent write(TLSMessage &&msg) const override
ContentType type
Definition: Types.h:55
bool hexlify(const InputString &input, OutputString &output, bool append_output)
Definition: String-inl.h:596
typename std::underlying_type< ContentType >::type ContentTypeType
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
ContentType
Definition: Types.h:46
constexpr None none
Definition: Optional.h:87
void writeBE(T value)
Definition: Cursor.h:744