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
9 #include <fizz/server/AsyncFizzServer.h>
10
11 namespace fizz {
12 namespace server {
13
14 template <typename SM>
AsyncFizzServerT(folly::AsyncTransportWrapper::UniquePtr socket,const std::shared_ptr<const FizzServerContext> & fizzContext,const std::shared_ptr<ServerExtensions> & extensions,AsyncFizzBase::TransportOptions transportOptions)15 AsyncFizzServerT<SM>::AsyncFizzServerT(
16 folly::AsyncTransportWrapper::UniquePtr socket,
17 const std::shared_ptr<const FizzServerContext>& fizzContext,
18 const std::shared_ptr<ServerExtensions>& extensions,
19 AsyncFizzBase::TransportOptions transportOptions)
20 : AsyncFizzBase(std::move(socket), std::move(transportOptions)),
21 fizzContext_(fizzContext),
22 extensions_(extensions),
23 visitor_(*this),
24 fizzServer_(state_, transportReadBuf_, readAeadOptions_, visitor_, this) {
25 }
26
27 template <typename SM>
accept(HandshakeCallback * callback)28 void AsyncFizzServerT<SM>::accept(HandshakeCallback* callback) {
29 handshakeCallback_ = callback;
30
31 fizzServer_.accept(transport_->getEventBase(), fizzContext_, extensions_);
32 startTransportReads();
33 }
34
35 template <typename SM>
good()36 bool AsyncFizzServerT<SM>::good() const {
37 return !error() && !fizzServer_.inTerminalState() && transport_->good();
38 }
39
40 template <typename SM>
readable()41 bool AsyncFizzServerT<SM>::readable() const {
42 return transport_->readable();
43 }
44
45 template <typename SM>
connecting()46 bool AsyncFizzServerT<SM>::connecting() const {
47 return handshakeCallback_ || transport_->connecting();
48 }
49
50 template <typename SM>
error()51 bool AsyncFizzServerT<SM>::error() const {
52 return transport_->error() || fizzServer_.inErrorState();
53 }
54
55 template <typename SM>
isDetachable()56 bool AsyncFizzServerT<SM>::isDetachable() const {
57 return !fizzServer_.actionProcessing() && AsyncFizzBase::isDetachable();
58 }
59
60 template <typename SM>
attachEventBase(folly::EventBase * evb)61 void AsyncFizzServerT<SM>::attachEventBase(folly::EventBase* evb) {
62 state_.executor() = evb;
63 AsyncFizzBase::attachEventBase(evb);
64 }
65
66 template <typename SM>
getPeerCertificate()67 const Cert* AsyncFizzServerT<SM>::getPeerCertificate() const {
68 return getState().clientCert().get();
69 }
70
71 template <typename SM>
getSelfCertificate()72 const Cert* AsyncFizzServerT<SM>::getSelfCertificate() const {
73 return getState().serverCert().get();
74 }
75
76 template <typename SM>
isReplaySafe()77 bool AsyncFizzServerT<SM>::isReplaySafe() const {
78 // Server always provides replay protection.
79 return true;
80 }
81
82 template <typename SM>
setReplaySafetyCallback(folly::AsyncTransport::ReplaySafetyCallback *)83 void AsyncFizzServerT<SM>::setReplaySafetyCallback(
84 folly::AsyncTransport::ReplaySafetyCallback*) {
85 LOG(FATAL) << "setReplaySafetyCallback() called on replay safe transport";
86 }
87
88 template <typename SM>
getApplicationProtocol()89 std::string AsyncFizzServerT<SM>::getApplicationProtocol() const noexcept {
90 if (getState().alpn()) {
91 return *getState().alpn();
92 } else {
93 return "";
94 }
95 }
96
97 template <typename SM>
close()98 void AsyncFizzServerT<SM>::close() {
99 if (transport_->good()) {
100 fizzServer_.appCloseImmediate();
101 } else {
102 DelayedDestruction::DestructorGuard dg(this);
103 folly::AsyncSocketException ase(
104 folly::AsyncSocketException::END_OF_FILE, "socket closed locally");
105 deliverAllErrors(ase, false);
106 transport_->close();
107 }
108 }
109
110 template <typename SM>
tlsShutdown()111 void AsyncFizzServerT<SM>::tlsShutdown() {
112 if (transport_->good()) {
113 // do not immediately close, wait to receive a close notify from the other
114 // end
115 fizzServer_.appClose();
116 }
117 }
118
119 template <typename SM>
closeWithReset()120 void AsyncFizzServerT<SM>::closeWithReset() {
121 DelayedDestruction::DestructorGuard dg(this);
122 if (transport_->good()) {
123 fizzServer_.appCloseImmediate();
124 }
125 folly::AsyncSocketException ase(
126 folly::AsyncSocketException::END_OF_FILE, "socket closed locally");
127 deliverAllErrors(ase, false);
128 transport_->closeWithReset();
129 }
130
131 template <typename SM>
closeNow()132 void AsyncFizzServerT<SM>::closeNow() {
133 DelayedDestruction::DestructorGuard dg(this);
134 if (transport_->good()) {
135 fizzServer_.appCloseImmediate();
136 }
137 folly::AsyncSocketException ase(
138 folly::AsyncSocketException::END_OF_FILE, "socket closed locally");
139 deliverAllErrors(ase, false);
140 transport_->closeNow();
141 }
142
143 template <typename SM>
sendTicketWithAppToken(Buf appToken)144 void AsyncFizzServerT<SM>::sendTicketWithAppToken(Buf appToken) {
145 WriteNewSessionTicket nst;
146 nst.appToken = std::move(appToken);
147 fizzServer_.writeNewSessionTicket(std::move(nst));
148 }
149
150 template <typename SM>
getCipher()151 folly::Optional<CipherSuite> AsyncFizzServerT<SM>::getCipher() const {
152 return getState().cipher();
153 }
154
155 template <typename SM>
getSupportedSigSchemes()156 std::vector<SignatureScheme> AsyncFizzServerT<SM>::getSupportedSigSchemes()
157 const {
158 return getState().context()->getSupportedSigSchemes();
159 }
160
161 template <typename SM>
getEkm(folly::StringPiece label,const Buf & context,uint16_t length)162 Buf AsyncFizzServerT<SM>::getEkm(
163 folly::StringPiece label,
164 const Buf& context,
165 uint16_t length) const {
166 return fizzServer_.getEkm(
167 *fizzContext_->getFactory(), label, context, length);
168 }
169
170 template <typename SM>
getEarlyEkm(folly::StringPiece label,const Buf & context,uint16_t length)171 Buf AsyncFizzServerT<SM>::getEarlyEkm(
172 folly::StringPiece label,
173 const Buf& context,
174 uint16_t length) const {
175 return fizzServer_.getEarlyEkm(
176 *fizzContext_->getFactory(), label, context, length);
177 }
178
179 template <typename SM>
writeAppData(folly::AsyncTransportWrapper::WriteCallback * callback,std::unique_ptr<folly::IOBuf> && buf,folly::WriteFlags flags)180 void AsyncFizzServerT<SM>::writeAppData(
181 folly::AsyncTransportWrapper::WriteCallback* callback,
182 std::unique_ptr<folly::IOBuf>&& buf,
183 folly::WriteFlags flags) {
184 if (!good()) {
185 if (callback) {
186 callback->writeErr(
187 0,
188 folly::AsyncSocketException(
189 folly::AsyncSocketException::INVALID_STATE,
190 "fizz app write in error state"));
191 }
192 return;
193 }
194
195 AppWrite write;
196 write.callback = callback;
197 write.data = std::move(buf);
198 write.flags = flags;
199 write.aeadOptions = writeAeadOptions_;
200 fizzServer_.appWrite(std::move(write));
201 }
202
203 template <typename SM>
transportError(const folly::AsyncSocketException & ex)204 void AsyncFizzServerT<SM>::transportError(
205 const folly::AsyncSocketException& ex) {
206 DelayedDestruction::DestructorGuard dg(this);
207 deliverAllErrors(ex);
208 }
209
210 template <typename SM>
transportDataAvailable()211 void AsyncFizzServerT<SM>::transportDataAvailable() {
212 fizzServer_.newTransportData();
213 }
214
215 template <typename SM>
pauseEvents()216 void AsyncFizzServerT<SM>::pauseEvents() {
217 fizzServer_.pause();
218 }
219
220 template <typename SM>
resumeEvents()221 void AsyncFizzServerT<SM>::resumeEvents() {
222 fizzServer_.resume();
223 }
224
225 template <typename SM>
deliverAllErrors(const folly::AsyncSocketException & ex,bool closeTransport)226 void AsyncFizzServerT<SM>::deliverAllErrors(
227 const folly::AsyncSocketException& ex,
228 bool closeTransport) {
229 deliverHandshakeError(ex);
230 fizzServer_.moveToErrorState(ex);
231 deliverError(ex, closeTransport);
232 }
233
234 template <typename SM>
deliverHandshakeError(folly::exception_wrapper ex)235 void AsyncFizzServerT<SM>::deliverHandshakeError(folly::exception_wrapper ex) {
236 if (handshakeCallback_) {
237 auto callback = handshakeCallback_;
238 handshakeCallback_ = nullptr;
239 callback->fizzHandshakeError(this, std::move(ex));
240 }
241 }
242
243 template <typename SM>
getClientRandom()244 folly::Optional<Random> AsyncFizzServerT<SM>::getClientRandom() const {
245 return getState().clientRandom();
246 }
247
248 template <typename SM>
operator()249 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(DeliverAppData& data) {
250 server_.deliverAppData(std::move(data.data));
251 }
252
253 template <typename SM>
operator()254 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(WriteToSocket& data) {
255 DCHECK(!data.contents.empty());
256 Buf allData = std::move(data.contents.front().data);
257 for (size_t i = 1; i < data.contents.size(); ++i) {
258 allData->prependChain(std::move(data.contents[i].data));
259 }
260 server_.transport_->writeChain(data.callback, std::move(allData), data.flags);
261 }
262
263 template <typename SM>
operator()264 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(
265 ReportEarlyHandshakeSuccess&) {
266 // Since the server can handle async events, it is possible for the
267 // transport to become not good once we return from processing async events.
268 // We want to error out the connection in this case.
269 if (!server_.good()) {
270 folly::AsyncSocketException ase(
271 folly::AsyncSocketException::NOT_OPEN, "Transport is not good");
272 server_.transportError(ase);
273 return;
274 }
275 if (server_.handshakeCallback_) {
276 auto callback = server_.handshakeCallback_;
277 server_.handshakeCallback_ = nullptr;
278 callback->fizzHandshakeSuccess(&server_);
279 }
280 }
281
282 template <typename SM>
operator()283 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(
284 ReportHandshakeSuccess&) {
285 // Since the server can handle async events, it is possible for the
286 // transport to become not good once we return from processing async events.
287 // We want to error out the connection in this case.
288 if (!server_.good()) {
289 folly::AsyncSocketException ase(
290 folly::AsyncSocketException::NOT_OPEN, "Transport is not good");
291 server_.transportError(ase);
292 return;
293 }
294
295 // Disable record aligned reads. At this point, we are aligned on a record
296 // boundary (if handshakeRecordAlignedReads = true).
297 server_.updateReadHint(0);
298
299 if (server_.handshakeCallback_) {
300 auto callback = server_.handshakeCallback_;
301 server_.handshakeCallback_ = nullptr;
302 callback->fizzHandshakeSuccess(&server_);
303 }
304 }
305
306 template <typename SM>
operator()307 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(ReportError& error) {
308 folly::AsyncSocketException ase(
309 folly::AsyncSocketException::SSL_ERROR, error.error.what().toStdString());
310 server_.deliverHandshakeError(std::move(error.error));
311 server_.deliverAllErrors(ase);
312 }
313
314 template <typename SM>
operator()315 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(WaitForData& wfd) {
316 server_.fizzServer_.waitForData();
317 server_.updateReadHint(wfd.recordSizeHint);
318
319 if (server_.handshakeCallback_) {
320 // Make sure that the read callback is installed.
321 server_.startTransportReads();
322 }
323 }
324
325 template <typename SM>
operator()326 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(MutateState& mutator) {
327 mutator(server_.state_);
328 }
329
330 template <typename SM>
operator()331 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(
332 AttemptVersionFallback& fallback) {
333 if (!server_.handshakeCallback_) {
334 VLOG(2) << "fizz fallback without callback";
335 return;
336 }
337 auto callback = server_.handshakeCallback_;
338 server_.handshakeCallback_ = nullptr;
339 if (!server_.transportReadBuf_.empty()) {
340 fallback.clientHello->prependChain(server_.transportReadBuf_.move());
341 }
342 callback->fizzHandshakeAttemptFallback(std::move(fallback.clientHello));
343 }
344
345 template <typename SM>
operator()346 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(
347 SecretAvailable& secret) {
348 server_.secretAvailable(secret.secret);
349 }
350
351 template <typename SM>
operator()352 void AsyncFizzServerT<SM>::ActionMoveVisitor::operator()(EndOfData& eod) {
353 server_.endOfTLS(std::move(eod.postTlsData));
354 }
355 } // namespace server
356 } // namespace fizz
357