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