proxygen
ServerProtocol.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 <fizz/crypto/Utils.h>
13 #include <fizz/protocol/Protocol.h>
15 #include <fizz/record/Extensions.h>
18 #include <fizz/server/Negotiator.h>
20 #include <folly/Overload.h>
21 #include <algorithm>
22 
23 using folly::Future;
24 using folly::Optional;
25 
26 using namespace fizz::server;
27 using namespace fizz::server::detail;
28 
29 // We only ever use the first PSK sent.
30 static constexpr uint16_t kPskIndex = 0;
31 
32 namespace fizz {
33 namespace sm {
34 
40 
50 
56 
62 
68 
75 
81 
87 
93 
99 
101  ServerTypes,
105 
107  ServerTypes,
111 
113  ServerTypes,
117 } // namespace sm
118 
119 namespace server {
120 
122  const State& state,
124  std::shared_ptr<const FizzServerContext> context,
125  const std::shared_ptr<ServerExtensions>& extensions) {
126  Accept accept;
127  accept.executor = executor;
128  accept.context = std::move(context);
129  accept.extensions = extensions;
130  return detail::processEvent(state, std::move(accept));
131 }
132 
134  const State& state,
135  folly::IOBufQueue& buf) {
136  try {
137  if (!state.readRecordLayer()) {
138  return detail::handleError(
139  state,
140  ReportError("attempting to process data without record layer"),
141  folly::none);
142  }
143  auto param = state.readRecordLayer()->readEvent(buf);
144  if (!param.hasValue()) {
145  return actions(WaitForData());
146  }
147  return detail::processEvent(state, std::move(*param));
148  } catch (const std::exception& e) {
149  return detail::handleError(
150  state,
151  ReportError(folly::exception_wrapper(std::current_exception(), e)),
153  }
154 }
155 
157  const State& state,
159  return detail::processEvent(state, std::move(write));
160 }
161 
163  const State& state,
164  AppWrite write) {
165  return detail::processEvent(state, std::move(write));
166 }
167 
169  const State& state,
171  return detail::processEvent(state, std::move(write));
172 }
173 
175  return detail::handleAppClose(state);
176 }
177 
178 namespace detail {
179 
181  auto event = boost::apply_visitor(EventVisitor(), param);
182  // We can have an exception directly in the handler or in a future so we need
183  // to handle both types.
184  try {
186  state.state(), event)(state, std::move(param));
187 
188  return folly::variant_match(
189  actions,
190  [&state](folly::Future<Actions>& futureActions) -> AsyncActions {
191  return std::move(futureActions)
192  .onError([&state](folly::exception_wrapper ew) {
193  auto ex = ew.get_exception<FizzException>();
194  if (ex) {
195  return detail::handleError(
196  state, ReportError(std::move(ew)), ex->getAlert());
197  }
198  return detail::handleError(
199  state,
200  ReportError(std::move(ew)),
202  });
203  },
204  [](Actions& immediateActions) -> AsyncActions {
205  return std::move(immediateActions);
206  });
207  } catch (const FizzException& e) {
208  return detail::handleError(
209  state,
210  ReportError(folly::exception_wrapper(std::current_exception(), e)),
211  e.getAlert());
212  } catch (const std::exception& e) {
213  return detail::handleError(
214  state,
215  ReportError(folly::exception_wrapper(std::current_exception(), e)),
217  }
218 }
219 
221  const State& state,
223  Optional<AlertDescription> alertDesc) {
224  if (state.state() == StateEnum::Error) {
225  return actions();
226  }
227  auto transition = [](State& newState) {
228  newState.state() = StateEnum::Error;
229  newState.writeRecordLayer() = nullptr;
230  newState.readRecordLayer() = nullptr;
231  };
232  if (alertDesc && state.writeRecordLayer()) {
233  Alert alert(*alertDesc);
235  write.contents.emplace_back(
236  state.writeRecordLayer()->writeAlert(std::move(alert)));
237  return actions(std::move(transition), std::move(write), std::move(error));
238  } else {
239  return actions(std::move(transition), std::move(error));
240  }
241 }
242 
244  auto transition = [](State& newState) {
245  newState.state() = StateEnum::Error;
246  newState.writeRecordLayer() = nullptr;
247  newState.readRecordLayer() = nullptr;
248  };
249  if (state.writeRecordLayer()) {
252  write.contents.emplace_back(
253  state.writeRecordLayer()->writeAlert(std::move(alert)));
254  return actions(std::move(transition), std::move(write));
255  } else {
256  return actions(std::move(transition));
257  }
258 }
259 
261  if (event == Event::Alert) {
262  auto& alert = boost::get<Alert>(param);
263  throw FizzException(
264  folly::to<std::string>(
265  "received alert: ",
266  toString(alert.description),
267  ", in state ",
268  toString(state.state())),
269  folly::none);
270  } else {
271  throw FizzException(
272  folly::to<std::string>(
273  "invalid event: ",
274  toString(event),
275  ", in state ",
276  toString(state.state())),
278  }
279 }
280 } // namespace detail
281 } // namespace server
282 
283 namespace sm {
284 
286 EventHandler<ServerTypes, StateEnum::Uninitialized, Event::Accept>::handle(
287  const State& /*state*/,
288  Param param) {
289  auto& accept = boost::get<Accept>(param);
290  auto factory = accept.context->getFactory();
291  auto readRecordLayer = factory->makePlaintextReadRecordLayer();
292  auto writeRecordLayer = factory->makePlaintextWriteRecordLayer();
293  auto handshakeLogging = std::make_unique<HandshakeLogging>();
294  return actions(
295  [executor = accept.executor,
296  rrl = std::move(readRecordLayer),
297  wrl = std::move(writeRecordLayer),
298  context = std::move(accept.context),
299  handshakeLogging = std::move(handshakeLogging),
300  extensions = accept.extensions](State& newState) mutable {
301  newState.executor() = executor;
302  newState.context() = std::move(context);
303  newState.readRecordLayer() = std::move(rrl);
304  newState.writeRecordLayer() = std::move(wrl);
305  newState.handshakeLogging() = std::move(handshakeLogging);
306  newState.extensions() = std::move(extensions);
307  },
308  &Transition<StateEnum::ExpectingClientHello>);
309 }
310 
311 static void addHandshakeLogging(const State& state, const ClientHello& chlo) {
312  if (state.handshakeLogging()) {
314  auto supportedVersions = getExtension<SupportedVersions>(chlo.extensions);
315  if (supportedVersions) {
317  supportedVersions->versions;
318  }
320  state.handshakeLogging()->clientExtensions.clear();
321  for (const auto& extension : chlo.extensions) {
322  state.handshakeLogging()->clientExtensions.push_back(
323  extension.extension_type);
324  }
325  auto plaintextReadRecord =
326  dynamic_cast<PlaintextReadRecordLayer*>(state.readRecordLayer());
327  if (plaintextReadRecord) {
329  plaintextReadRecord->getReceivedRecordVersion();
330  }
331  auto sni = getExtension<ServerNameList>(chlo.extensions);
332  if (sni && !sni->server_name_list.empty()) {
333  state.handshakeLogging()->clientSni = sni->server_name_list.front()
334  .hostname->moveToFbString()
335  .toStdString();
336  }
337  auto supportedGroups = getExtension<SupportedGroups>(chlo.extensions);
338  if (supportedGroups) {
340  std::move(supportedGroups->named_group_list);
341  }
342 
343  auto keyShare = getExtension<ClientKeyShare>(chlo.extensions);
344  if (keyShare && !state.handshakeLogging()->clientKeyShares) {
345  std::vector<NamedGroup> shares;
346  for (const auto& entry : keyShare->client_shares) {
347  shares.push_back(entry.group);
348  }
349  state.handshakeLogging()->clientKeyShares = std::move(shares);
350  }
351 
352  auto exchangeModes = getExtension<PskKeyExchangeModes>(chlo.extensions);
353  if (exchangeModes) {
355  std::move(exchangeModes->modes);
356  }
357 
358  auto clientSigSchemes = getExtension<SignatureAlgorithms>(chlo.extensions);
359  if (clientSigSchemes) {
361  std::move(clientSigSchemes->supported_signature_algorithms);
362  }
363 
365  chlo.legacy_session_id && !chlo.legacy_session_id->empty();
366  state.handshakeLogging()->clientRandom = chlo.random;
367  }
368 }
369 
370 static void validateClientHello(const ClientHello& chlo) {
371  if (chlo.legacy_compression_methods.size() != 1 ||
372  chlo.legacy_compression_methods.front() != 0x00) {
373  throw FizzException(
374  "client compression methods not exactly NULL",
376  }
378 }
379 
381  const ClientHello& chlo,
382  const std::vector<ProtocolVersion>& versions) {
383  const auto& clientVersions = getExtension<SupportedVersions>(chlo.extensions);
384  if (!clientVersions) {
385  return folly::none;
386  }
387  auto version = negotiate(versions, clientVersions->versions);
388  if (!version) {
389  return folly::none;
390  }
391  return version;
392 }
393 
395  const ClientHello& chlo,
398  const CookieCipher* cookieCipher) {
399  auto cookieExt = getExtension<Cookie>(chlo.extensions);
400  if (!cookieExt) {
401  return folly::none;
402  }
403 
404  // If the client sent a cookie we can't use we have to consider it a fatal
405  // error since we can't reconstruct the handshake transcript.
406  if (!cookieCipher) {
407  throw FizzException(
408  "no cookie cipher", AlertDescription::unsupported_extension);
409  }
410 
411  auto cookieState = cookieCipher->decrypt(std::move(cookieExt->cookie));
412 
413  if (!cookieState) {
414  throw FizzException(
415  "could not decrypt cookie", AlertDescription::decrypt_error);
416  }
417 
418  if (cookieState->version != version) {
419  throw FizzException(
420  "version mismatch with cookie", AlertDescription::protocol_version);
421  }
422 
423  if (cookieState->cipher != cipher) {
424  throw FizzException(
425  "cipher mismatch with cookie", AlertDescription::handshake_failure);
426  }
427 
428  return cookieState;
429 }
430 
431 namespace {
432 struct ResumptionStateResult {
433  explicit ResumptionStateResult(
434  Future<std::pair<PskType, Optional<ResumptionState>>> futureResStateArg,
436  Optional<uint32_t> obfuscatedAgeArg = folly::none)
437  : futureResState(std::move(futureResStateArg)),
438  pskMode(std::move(pskModeArg)),
439  obfuscatedAge(std::move(obfuscatedAgeArg)) {}
440 
444 };
445 } // namespace
446 
447 static ResumptionStateResult getResumptionState(
448  const ClientHello& chlo,
449  const TicketCipher* ticketCipher,
450  const std::vector<PskKeyExchangeMode>& supportedModes) {
451  auto psks = getExtension<ClientPresharedKey>(chlo.extensions);
452  auto clientModes = getExtension<PskKeyExchangeModes>(chlo.extensions);
453  if (psks && !clientModes) {
454  throw FizzException("no psk modes", AlertDescription::missing_extension);
455  }
456 
458  if (clientModes) {
459  pskMode = negotiate(supportedModes, clientModes->modes);
460  }
461  if (!psks && !pskMode) {
462  return ResumptionStateResult(
463  std::make_pair(PskType::NotSupported, folly::none));
464  } else if (!psks || psks->identities.size() <= kPskIndex) {
465  return ResumptionStateResult(
466  std::make_pair(PskType::NotAttempted, folly::none));
467  } else if (!ticketCipher) {
468  VLOG(8) << "No ticket cipher, rejecting PSK.";
469  return ResumptionStateResult(
470  std::make_pair(PskType::Rejected, folly::none));
471  } else if (!pskMode) {
472  VLOG(8) << "No psk mode match, rejecting PSK.";
473  return ResumptionStateResult(
474  std::make_pair(PskType::Rejected, folly::none));
475  } else {
476  const auto& ident = psks->identities[kPskIndex].psk_identity;
477  return ResumptionStateResult(
478  ticketCipher->decrypt(ident->clone()),
479  pskMode,
480  psks->identities[kPskIndex].obfuscated_ticket_age);
481  }
482 }
483 
485  const ClientHello& chlo,
486  bool zeroRttEnabled,
487  ReplayCache* replayCache) {
488  if (!zeroRttEnabled || !replayCache ||
489  !getExtension<ClientEarlyData>(chlo.extensions)) {
491  }
492 
493  return replayCache->check(folly::range(chlo.random));
494 }
495 
497  const ResumptionState& resState,
498  PskKeyExchangeMode /* mode */,
501  if (resState.version != version) {
502  VLOG(8) << "Protocol version mismatch, rejecting PSK.";
503  return false;
504  }
505 
506  if (getHashFunction(resState.cipher) != getHashFunction(cipher)) {
507  VLOG(8) << "Hash mismatch, rejecting PSK.";
508  return false;
509  }
510 
511  return true;
512 }
513 
515  const ClientHello& chlo,
516  const std::vector<std::vector<CipherSuite>>& supportedCiphers) {
517  auto cipher = negotiate(supportedCiphers, chlo.cipher_suites);
518  if (!cipher) {
519  throw FizzException("no cipher match", AlertDescription::handshake_failure);
520  }
521  return *cipher;
522 }
523 
524 /*
525  * Sets up a KeyScheduler and HandshakeContext for the connection. The
526  * KeyScheduler will have the early secret derived if applicable, and the
527  * ClientHello will be added to the HandshakeContext. This also verifies the
528  * PSK binder if applicable.
529  *
530  * If the passed in handshakeContext is non-null it is used instead of a new
531  * context. This is used after a HelloRetryRequest when there is already a
532  * handshake transcript before the current ClientHello.
533  */
534 static std::
535  pair<std::unique_ptr<KeyScheduler>, std::unique_ptr<HandshakeContext>>
537  const Factory& factory,
539  const ClientHello& chlo,
540  const Optional<ResumptionState>& resState,
541  const Optional<CookieState>& cookieState,
542  PskType pskType,
543  std::unique_ptr<HandshakeContext> handshakeContext,
544  ProtocolVersion /*version*/) {
545  auto scheduler = factory.makeKeyScheduler(cipher);
546 
547  if (cookieState) {
548  if (handshakeContext) {
549  throw FizzException(
550  "cookie after statefull hrr", AlertDescription::illegal_parameter);
551  }
552 
553  handshakeContext = factory.makeHandshakeContext(cipher);
554 
555  message_hash chloHash;
556  chloHash.hash = cookieState->chloHash->clone();
557  handshakeContext->appendToTranscript(encodeHandshake(std::move(chloHash)));
558 
559  auto cookie = getExtension<Cookie>(chlo.extensions);
560  handshakeContext->appendToTranscript(getStatelessHelloRetryRequest(
561  cookieState->version,
562  cookieState->cipher,
563  cookieState->group,
564  std::move(cookie->cookie)));
565  } else if (!handshakeContext) {
566  handshakeContext = factory.makeHandshakeContext(cipher);
567  }
568 
569  if (resState) {
570  scheduler->deriveEarlySecret(resState->resumptionSecret->coalesce());
571 
572  auto binderKey = scheduler->getSecret(
575  handshakeContext->getBlankContext());
576 
578  chloQueue.append((*chlo.originalEncoding)->clone());
579  auto chloPrefix =
580  chloQueue.split(chloQueue.chainLength() - getBinderLength(chlo));
581  handshakeContext->appendToTranscript(chloPrefix);
582 
583  const auto& psks = getExtension<ClientPresharedKey>(chlo.extensions);
584  if (!psks || psks->binders.size() <= kPskIndex) {
586  }
587  auto expectedBinder =
588  handshakeContext->getFinishedData(folly::range(binderKey));
589  if (!CryptoUtils::equal(
590  expectedBinder->coalesce(),
591  psks->binders[kPskIndex].binder->coalesce())) {
592  throw FizzException(
593  "binder does not match", AlertDescription::bad_record_mac);
594  }
595 
596  handshakeContext->appendToTranscript(chloQueue.move());
597  return std::make_pair(std::move(scheduler), std::move(handshakeContext));
598  } else {
599  handshakeContext->appendToTranscript(*chlo.originalEncoding);
600  return std::make_pair(std::move(scheduler), std::move(handshakeContext));
601  }
602 }
603 
604 static void validateGroups(const std::vector<KeyShareEntry>& client_shares) {
605  std::set<NamedGroup> setOfNamedGroups;
606 
607  for (const auto& share : client_shares) {
608  if (setOfNamedGroups.find(share.group) != setOfNamedGroups.end()) {
609  throw FizzException(
610  "duplicate client key share", AlertDescription::illegal_parameter);
611  }
612 
613  setOfNamedGroups.insert(share.group);
614  }
615 }
616 
617 static std::tuple<NamedGroup, Optional<Buf>> negotiateGroup(
619  const ClientHello& chlo,
620  const std::vector<NamedGroup>& supportedGroups) {
621  auto groups = getExtension<SupportedGroups>(chlo.extensions);
622  if (!groups) {
623  throw FizzException("no named groups", AlertDescription::missing_extension);
624  }
625  auto group = negotiate(supportedGroups, groups->named_group_list);
626  if (!group) {
627  throw FizzException("no group match", AlertDescription::handshake_failure);
628  }
629  auto clientShares = getExtension<ClientKeyShare>(chlo.extensions);
630  if (!clientShares) {
631  throw FizzException(
632  "no client shares", AlertDescription::missing_extension);
633  }
634 
635  auto realVersion = getRealDraftVersion(version);
636  if (realVersion == ProtocolVersion::tls_1_3_20 ||
637  realVersion == ProtocolVersion::tls_1_3_21 ||
638  realVersion == ProtocolVersion::tls_1_3_22) {
639  if (!clientShares->preDraft23) {
640  throw FizzException(
641  "post-23 client share", AlertDescription::illegal_parameter);
642  }
643  } else {
644  if (clientShares->preDraft23) {
645  throw FizzException(
646  "pre-23 client share", AlertDescription::illegal_parameter);
647  }
648  }
649 
650  validateGroups(clientShares->client_shares);
651  for (const auto& share : clientShares->client_shares) {
652  if (share.group == *group) {
653  return std::make_tuple(*group, share.key_exchange->clone());
654  }
655  }
657 }
658 
659 static Buf doKex(
660  const Factory& factory,
662  const Buf& clientShare,
664  auto kex = factory.makeKeyExchange(group);
665  kex->generateKeyPair();
666  auto sharedSecret = kex->generateSharedSecret(clientShare->coalesce());
667  scheduler.deriveHandshakeSecret(sharedSecret->coalesce());
668  return kex->getKeyShare();
669 }
670 
675  Buf legacySessionId,
676  HandshakeContext& handshakeContext) {
677  Buf encodedHelloRetryRequest;
678  auto realVersion = getRealDraftVersion(version);
679  if (realVersion == ProtocolVersion::tls_1_3_20 ||
680  realVersion == ProtocolVersion::tls_1_3_21) {
681  throw std::runtime_error("pre-22 HRR");
682  }
683 
684  HelloRetryRequest hrr;
686  hrr.legacy_session_id_echo = std::move(legacySessionId);
687  hrr.cipher_suite = cipher;
688  ServerSupportedVersions versionExt;
689  versionExt.selected_version = version;
690  hrr.extensions.push_back(encodeExtension(std::move(versionExt)));
691  HelloRetryRequestKeyShare keyShare;
692 
693  if (realVersion == ProtocolVersion::tls_1_3_20 ||
694  realVersion == ProtocolVersion::tls_1_3_21 ||
695  realVersion == ProtocolVersion::tls_1_3_22) {
696  keyShare.preDraft23 = true;
697  }
698 
699  keyShare.selected_group = group;
700  hrr.extensions.push_back(encodeExtension(std::move(keyShare)));
701  encodedHelloRetryRequest = encodeHandshake(std::move(hrr));
702 
703  handshakeContext.appendToTranscript(encodedHelloRetryRequest);
704  return encodedHelloRetryRequest;
705 }
706 
709  Random random,
711  bool psk,
713  Optional<Buf> serverShare,
714  Buf legacy_session_id,
715  HandshakeContext& handshakeContext) {
716  ServerHello serverHello;
717 
718  auto realVersion = getRealDraftVersion(version);
719  if (realVersion == ProtocolVersion::tls_1_3_20 ||
720  realVersion == ProtocolVersion::tls_1_3_21) {
721  serverHello.legacy_version = version;
722  } else {
724  ServerSupportedVersions versionExt;
725  versionExt.selected_version = version;
726  serverHello.extensions.push_back(encodeExtension(std::move(versionExt)));
727  serverHello.legacy_session_id_echo = std::move(legacy_session_id);
728  }
729 
730  serverHello.random = std::move(random);
731  serverHello.cipher_suite = cipher;
732  if (group) {
733  ServerKeyShare serverKeyShare;
734  serverKeyShare.server_share.group = *group;
735  serverKeyShare.server_share.key_exchange = std::move(*serverShare);
736 
737  if (realVersion == ProtocolVersion::tls_1_3_20 ||
738  realVersion == ProtocolVersion::tls_1_3_21 ||
739  realVersion == ProtocolVersion::tls_1_3_22) {
740  serverKeyShare.preDraft23 = true;
741  }
742 
743  serverHello.extensions.push_back(
744  encodeExtension(std::move(serverKeyShare)));
745  }
746  if (psk) {
747  ServerPresharedKey serverPsk;
748  serverPsk.selected_identity = kPskIndex;
749  serverHello.extensions.push_back(encodeExtension(std::move(serverPsk)));
750  }
751  auto encodedServerHello = encodeHandshake(std::move(serverHello));
752  handshakeContext.appendToTranscript(encodedServerHello);
753  return encodedServerHello;
754 }
755 
757  const ClientHello& chlo,
758  folly::Optional<std::string> zeroRttAlpn,
759  const FizzServerContext& context) {
760  auto ext = getExtension<ProtocolNameList>(chlo.extensions);
761  std::vector<std::string> clientProtocols;
762  if (ext) {
763  for (auto& protocol : ext->protocol_name_list) {
764  clientProtocols.push_back(protocol.name->moveToFbString().toStdString());
765  }
766  } else {
767  VLOG(6) << "Client did not send ALPN extension";
768  }
769  auto selected = context.negotiateAlpn(clientProtocols, zeroRttAlpn);
770  if (!selected) {
771  VLOG(6) << "ALPN mismatch";
772  } else {
773  VLOG(6) << "ALPN: " << *selected;
774  }
775  return selected;
776 }
777 
779  const Optional<ResumptionState>& psk,
781  if (!psk || !obfuscatedAge) {
782  return folly::none;
783  }
784 
785  auto age = std::chrono::milliseconds(
786  static_cast<uint32_t>(*obfuscatedAge - psk->ticketAgeAdd));
787 
788  auto expected = std::chrono::duration_cast<std::chrono::milliseconds>(
790 
791  return std::chrono::milliseconds(age - expected);
792 }
793 
795  bool acceptEarlyData,
796  const ClientHello& chlo,
797  const Optional<ResumptionState>& psk,
799  Optional<KeyExchangeType> keyExchangeType,
800  const Optional<CookieState>& cookieState,
802  ReplayCacheResult replayCacheResult,
804  ClockSkewTolerance clockSkewTolerance,
805  const AppTokenValidator* appTokenValidator) {
806  if (!getExtension<ClientEarlyData>(chlo.extensions)) {
808  }
809 
810  if (!acceptEarlyData) {
811  VLOG(5) << "Rejecting early data: disabled";
813  }
814 
815  if (!psk) {
816  VLOG(5) << "Rejected early data: psk rejected";
818  }
819 
820  if (psk->cipher != cipher) {
821  VLOG(5) << "Rejected early data: cipher mismatch";
823  }
824 
825  if (psk->alpn != alpn) {
826  VLOG(5) << "Rejecting early data: alpn mismatch";
828  }
829 
830  if (keyExchangeType &&
831  *keyExchangeType == KeyExchangeType::HelloRetryRequest) {
832  VLOG(5) << "Rejecting early data: HelloRetryRequest";
834  }
835 
836  if (cookieState) {
837  VLOG(5) << "Rejecting early data: Cookie";
839  }
840 
841  if (replayCacheResult != ReplayCacheResult::NotReplay) {
842  VLOG(5) << "Rejecting early data: replay";
844  }
845 
846  if (!clockSkew || *clockSkew < clockSkewTolerance.before ||
847  *clockSkew > clockSkewTolerance.after) {
848  VLOG(5) << "Rejecting early data: clock skew clockSkew="
849  << (clockSkew ? folly::to<std::string>(clockSkew->count())
850  : "(none)")
851  << " toleranceBefore=" << clockSkewTolerance.before.count()
852  << " toleranceAfter=" << clockSkewTolerance.after.count();
854  }
855 
856  if (appTokenValidator && !appTokenValidator->validate(*psk)) {
857  VLOG(5) << "Rejecting early data: invalid app token";
859  }
860 
862 }
863 
865  HandshakeContext& handshakeContext,
866  const folly::Optional<std::string>& selectedAlpn,
867  EarlyDataType earlyData,
868  std::vector<Extension> otherExtensions) {
869  EncryptedExtensions encryptedExt;
870  if (selectedAlpn) {
872  ProtocolName protocol;
873  protocol.name = folly::IOBuf::copyBuffer(*selectedAlpn);
874  alpn.protocol_name_list.push_back(std::move(protocol));
875  encryptedExt.extensions.push_back(encodeExtension(std::move(alpn)));
876  }
877 
878  if (earlyData == EarlyDataType::Accepted) {
879  encryptedExt.extensions.push_back(encodeExtension(ServerEarlyData()));
880  }
881 
882  for (auto& ext : otherExtensions) {
883  encryptedExt.extensions.push_back(std::move(ext));
884  }
885  auto encodedEncryptedExt =
886  encodeHandshake<EncryptedExtensions>(std::move(encryptedExt));
887  handshakeContext.appendToTranscript(encodedEncryptedExt);
888  return encodedEncryptedExt;
889 }
890 
891 static std::pair<std::shared_ptr<SelfCert>, SignatureScheme> chooseCert(
892  const FizzServerContext& context,
893  const ClientHello& chlo) {
894  const auto& clientSigSchemes =
895  getExtension<SignatureAlgorithms>(chlo.extensions);
896  if (!clientSigSchemes) {
897  throw FizzException("no sig schemes", AlertDescription::missing_extension);
898  }
900  auto serverNameList = getExtension<ServerNameList>(chlo.extensions);
901  if (serverNameList && !serverNameList->server_name_list.empty()) {
902  sni = serverNameList->server_name_list.front()
903  .hostname->moveToFbString()
904  .toStdString();
905  }
906 
907  auto certAndScheme =
908  context.getCert(sni, clientSigSchemes->supported_signature_algorithms);
909  if (!certAndScheme) {
910  throw FizzException(
911  "could not find suitable cert", AlertDescription::handshake_failure);
912  }
913  return *certAndScheme;
914 }
915 
916 static std::tuple<Buf, folly::Optional<CertificateCompressionAlgorithm>>
918  const std::shared_ptr<const SelfCert>& serverCert,
919  const FizzServerContext& context,
920  const ClientHello& chlo,
921  HandshakeContext& handshakeContext) {
922  // Check for compression support first, and if so, send compressed.
925  auto compAlgos =
926  getExtension<CertificateCompressionAlgorithms>(chlo.extensions);
927  if (compAlgos && !context.getSupportedCompressionAlgorithms().empty()) {
928  algo = negotiate(
929  context.getSupportedCompressionAlgorithms(), compAlgos->algorithms);
930  }
931 
932  if (algo) {
933  encodedCertificate = encodeHandshake(serverCert->getCompressedCert(*algo));
934  } else {
935  encodedCertificate = encodeHandshake(serverCert->getCertMessage());
936  }
937  handshakeContext.appendToTranscript(encodedCertificate);
938  return std::make_tuple(std::move(encodedCertificate), std::move(algo));
939 }
940 
942  SignatureScheme sigScheme,
943  Buf signature,
944  HandshakeContext& handshakeContext) {
946  verify.algorithm = sigScheme;
947  verify.signature = std::move(signature);
948  auto encodedCertificateVerify = encodeHandshake(std::move(verify));
949  handshakeContext.appendToTranscript(encodedCertificateVerify);
950  return encodedCertificateVerify;
951 }
952 
954  const std::vector<SignatureScheme>& acceptableSigSchemes,
955  const CertificateVerifier* const verifier,
956  HandshakeContext& handshakeContext) {
957  CertificateRequest request;
958  SignatureAlgorithms algos;
959  algos.supported_signature_algorithms = acceptableSigSchemes;
960  request.extensions.push_back(encodeExtension(std::move(algos)));
961  if (verifier) {
962  auto verifierExtensions = verifier->getCertificateRequestExtensions();
963  for (auto& ext : verifierExtensions) {
964  request.extensions.push_back(std::move(ext));
965  }
966  }
967  auto encodedCertificateRequest = encodeHandshake(std::move(request));
968  handshakeContext.appendToTranscript(encodedCertificateRequest);
969  return encodedCertificateRequest;
970 }
971 
974  handle(const State& state, Param param) {
975  auto chlo = std::move(boost::get<ClientHello>(param));
976 
977  addHandshakeLogging(state, chlo);
978 
979  if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
980  throw FizzException(
981  "data after client hello", AlertDescription::unexpected_message);
982  }
983 
984  auto version =
986 
987  if (state.version().hasValue() &&
988  (!version || *version != *state.version())) {
989  throw FizzException(
990  "version mismatch with previous negotiation",
992  }
993 
994  if (!version) {
995  if (getExtension<ClientEarlyData>(chlo.extensions)) {
996  throw FizzException(
997  "supported version mismatch with early data",
999  }
1000  if (state.context()->getVersionFallbackEnabled()) {
1001  AttemptVersionFallback fallback;
1002  // Re-encode to put the record layer header back on. This won't
1003  // necessarily preserve it byte-for-byte, but it isn't authenticated so
1004  // should be ok.
1005  fallback.clientHello =
1007  .writeInitialClientHello(std::move(*chlo.originalEncoding))
1008  .data;
1009  return actions(&Transition<StateEnum::Error>, std::move(fallback));
1010  } else {
1011  throw FizzException(
1012  "supported version mismatch", AlertDescription::protocol_version);
1013  }
1014  }
1015 
1017 
1019 
1021 
1022  auto cookieState = getCookieState(
1023  chlo, *version, cipher, state.context()->getCookieCipher());
1024 
1025  auto resStateResult = getResumptionState(
1026  chlo,
1027  state.context()->getTicketCipher(),
1028  state.context()->getSupportedPskModes());
1029 
1030  auto replayCacheResultFuture = getReplayCacheResult(
1031  chlo,
1032  state.context()->getAcceptEarlyData(*version),
1033  state.context()->getReplayCache());
1034 
1035  auto results =
1036  collectAll(resStateResult.futureResState, replayCacheResultFuture);
1037 
1038  using FutureResultType = std::tuple<
1041  return results.via(state.executor())
1042  .thenValue([&state,
1043  chlo = std::move(chlo),
1044  cookieState = std::move(cookieState),
1045  version = *version,
1046  cipher,
1047  pskMode = resStateResult.pskMode,
1048  obfuscatedAge = resStateResult.obfuscatedAge](
1049  FutureResultType result) mutable {
1050  auto& resumption = *std::get<0>(result);
1051  auto pskType = resumption.first;
1052  auto resState = std::move(resumption.second);
1053  auto replayCacheResult = *std::get<1>(result);
1054 
1055  if (resState) {
1056  if (!validateResumptionState(*resState, *pskMode, version, cipher)) {
1057  pskType = PskType::Rejected;
1058  pskMode = folly::none;
1059  resState = folly::none;
1060  }
1061  } else {
1062  pskMode = folly::none;
1063  }
1064 
1065  Buf legacySessionId;
1066  auto realVersion = getRealDraftVersion(version);
1067  if (realVersion == ProtocolVersion::tls_1_3_20 ||
1068  realVersion == ProtocolVersion::tls_1_3_21) {
1069  legacySessionId = nullptr;
1070  } else {
1071  legacySessionId = chlo.legacy_session_id->clone();
1072  }
1073 
1074  std::unique_ptr<KeyScheduler> scheduler;
1075  std::unique_ptr<HandshakeContext> handshakeContext;
1076  std::tie(scheduler, handshakeContext) = setupSchedulerAndContext(
1077  *state.context()->getFactory(),
1078  cipher,
1079  chlo,
1080  resState,
1081  cookieState,
1082  pskType,
1083  std::move(state.handshakeContext()),
1084  version);
1085 
1086  if (state.cipher().hasValue() && cipher != *state.cipher()) {
1087  throw FizzException(
1088  "cipher mismatch with previous negotiation",
1090  }
1091 
1092  auto alpn = negotiateAlpn(chlo, folly::none, *state.context());
1093 
1094  auto clockSkew = getClockSkew(resState, obfuscatedAge);
1095 
1096  auto earlyDataType = negotiateEarlyDataType(
1098  chlo,
1099  resState,
1100  cipher,
1101  state.keyExchangeType(),
1102  cookieState,
1103  alpn,
1104  replayCacheResult,
1105  clockSkew,
1106  state.context()->getClockSkewTolerance(),
1107  state.appTokenValidator());
1108 
1109  std::unique_ptr<EncryptedReadRecordLayer> earlyReadRecordLayer;
1110  Buf earlyExporterMaster;
1111  if (earlyDataType == EarlyDataType::Accepted) {
1112  auto earlyContext = handshakeContext->getHandshakeContext();
1113 
1114  earlyReadRecordLayer =
1117  earlyReadRecordLayer->setProtocolVersion(version);
1118  auto earlyReadSecret = scheduler->getSecret(
1119  EarlySecrets::ClientEarlyTraffic, earlyContext->coalesce());
1121  *earlyReadRecordLayer,
1122  cipher,
1123  folly::range(earlyReadSecret),
1124  *state.context()->getFactory(),
1125  *scheduler);
1126 
1127  earlyExporterMaster =
1128  folly::IOBuf::copyBuffer(folly::range(scheduler->getSecret(
1129  EarlySecrets::EarlyExporter, earlyContext->coalesce())));
1130  }
1131 
1133  Optional<Buf> serverShare;
1134  KeyExchangeType keyExchangeType;
1135  if (!pskMode || *pskMode != PskKeyExchangeMode::psk_ke) {
1136  Optional<Buf> clientShare;
1137  std::tie(group, clientShare) = negotiateGroup(
1138  version, chlo, state.context()->getSupportedGroups());
1139  if (!clientShare) {
1140  VLOG(8) << "Did not find key share for " << toString(*group);
1141  if (state.group().hasValue() || cookieState) {
1142  throw FizzException(
1143  "key share not found for already negotiated group",
1145  }
1146 
1147  // If we were otherwise going to accept early data we now need to
1148  // reject it. It's a little ugly to change our previous early data
1149  // decision, but doing it this way allows us to move the key
1150  // schedule forward as we do the key exchange.
1151  if (earlyDataType == EarlyDataType::Accepted) {
1152  earlyDataType = EarlyDataType::Rejected;
1153  }
1154 
1155  message_hash chloHash;
1156  chloHash.hash = handshakeContext->getHandshakeContext();
1157  handshakeContext =
1158  state.context()->getFactory()->makeHandshakeContext(cipher);
1159  handshakeContext->appendToTranscript(
1160  encodeHandshake(std::move(chloHash)));
1161 
1162  auto encodedHelloRetryRequest = getHelloRetryRequest(
1163  version,
1164  cipher,
1165  *group,
1166  legacySessionId ? legacySessionId->clone() : nullptr,
1167  *handshakeContext);
1168 
1169  WriteToSocket serverFlight;
1170  serverFlight.contents.emplace_back(
1172  std::move(encodedHelloRetryRequest)));
1173 
1174  if (legacySessionId && !legacySessionId->empty()) {
1175  TLSContent writeCCS;
1179  serverFlight.contents.emplace_back(std::move(writeCCS));
1180  }
1181 
1182  // Create a new record layer in case we need to skip early data.
1183  auto newReadRecordLayer =
1185  newReadRecordLayer->setSkipEncryptedRecords(
1186  earlyDataType == EarlyDataType::Rejected);
1187 
1188  return Future<Actions>(actions(
1189  [handshakeContext = std::move(handshakeContext),
1190  version,
1191  cipher,
1192  group,
1193  earlyDataType,
1194  replayCacheResult,
1195  newReadRecordLayer =
1196  std::move(newReadRecordLayer)](State& newState) mutable {
1197  // Save some information about the current state to be
1198  // validated when we get the second client hello. We don't
1199  // validate that the second client hello matches the first as
1200  // strictly as we could according to the spec however.
1201  newState.handshakeContext() = std::move(handshakeContext);
1202  newState.version() = version;
1203  newState.cipher() = cipher;
1204  newState.group() = group;
1205  newState.keyExchangeType() =
1207  newState.earlyDataType() = earlyDataType;
1208  newState.replayCacheResult() = replayCacheResult;
1209  newState.readRecordLayer() = std::move(newReadRecordLayer);
1210  },
1211  std::move(serverFlight),
1212  &Transition<StateEnum::ExpectingClientHello>));
1213  }
1214 
1215  if (state.keyExchangeType().hasValue()) {
1216  keyExchangeType = *state.keyExchangeType();
1217  } else {
1218  keyExchangeType = KeyExchangeType::OneRtt;
1219  }
1220 
1221  serverShare = doKex(
1222  *state.context()->getFactory(), *group, *clientShare, *scheduler);
1223  } else {
1224  keyExchangeType = KeyExchangeType::None;
1225  scheduler->deriveHandshakeSecret();
1226  }
1227 
1228  std::vector<Extension> additionalExtensions;
1229  if (state.extensions()) {
1230  additionalExtensions = state.extensions()->getExtensions(chlo);
1231  }
1232 
1233  if (state.group().hasValue() && (!group || *group != *state.group())) {
1234  throw FizzException(
1235  "group mismatch with previous negotiation",
1237  }
1238 
1239  // Cookies are not required to have already negotiated the group but if
1240  // they did it must match (psk_ke is still allowed as we may not know if
1241  // we are accepting the psk when sending the cookie).
1242  if (cookieState && cookieState->group && group &&
1243  *group != *cookieState->group) {
1244  throw FizzException(
1245  "group mismatch with cookie",
1247  }
1248 
1249  auto encodedServerHello = getServerHello(
1250  version,
1251  state.context()->getFactory()->makeRandom(),
1252  cipher,
1253  resState.hasValue(),
1254  group,
1255  std::move(serverShare),
1256  legacySessionId ? legacySessionId->clone() : nullptr,
1257  *handshakeContext);
1258 
1259  // Derive handshake keys.
1260  auto handshakeWriteRecordLayer =
1263  handshakeWriteRecordLayer->setProtocolVersion(version);
1264  auto handshakeWriteSecret = scheduler->getSecret(
1266  handshakeContext->getHandshakeContext()->coalesce());
1268  *handshakeWriteRecordLayer,
1269  cipher,
1270  folly::range(handshakeWriteSecret),
1271  *state.context()->getFactory(),
1272  *scheduler);
1273 
1274  auto handshakeReadRecordLayer =
1277  handshakeReadRecordLayer->setProtocolVersion(version);
1278  handshakeReadRecordLayer->setSkipFailedDecryption(
1279  earlyDataType == EarlyDataType::Rejected);
1280  auto handshakeReadSecret = scheduler->getSecret(
1282  handshakeContext->getHandshakeContext()->coalesce());
1284  *handshakeReadRecordLayer,
1285  cipher,
1286  folly::range(handshakeReadSecret),
1287  *state.context()->getFactory(),
1288  *scheduler);
1289  auto clientHandshakeSecret =
1290  folly::IOBuf::copyBuffer(folly::range(handshakeReadSecret));
1291 
1292  auto encodedEncryptedExt = getEncryptedExt(
1293  *handshakeContext,
1294  alpn,
1295  earlyDataType,
1296  std::move(additionalExtensions));
1297 
1298  /*
1299  * Determine we are requesting client auth.
1300  * If yes, add CertificateRequest to handshake write and transcript.
1301  */
1302  bool requestClientAuth =
1304  !resState;
1306  if (requestClientAuth) {
1307  encodedCertRequest = getCertificateRequest(
1308  state.context()->getSupportedSigSchemes(),
1309  state.context()->getClientCertVerifier().get(),
1310  *handshakeContext);
1311  }
1312 
1313  /*
1314  * Set the cert and signature scheme we are using.
1315  * If sending new cert, add Certificate to handshake write and
1316  * transcript.
1317  */
1319  Future<Optional<Buf>> signature = folly::none;
1320  Optional<SignatureScheme> sigScheme;
1322  std::shared_ptr<const Cert> clientCert;
1323  Optional<CertificateCompressionAlgorithm> certCompressionAlgo;
1324  if (!resState) { // TODO or reauth
1325  std::shared_ptr<const SelfCert> originalSelfCert;
1326  std::tie(originalSelfCert, sigScheme) =
1327  chooseCert(*state.context(), chlo);
1328 
1329  std::tie(encodedCertificate, certCompressionAlgo) = getCertificate(
1330  originalSelfCert, *state.context(), chlo, *handshakeContext);
1331 
1332  auto toBeSigned = handshakeContext->getHandshakeContext();
1333  auto asyncSelfCert =
1334  dynamic_cast<const AsyncSelfCert*>(originalSelfCert.get());
1335  if (asyncSelfCert) {
1336  signature = asyncSelfCert->signFuture(
1337  *sigScheme,
1339  toBeSigned->coalesce());
1340  } else {
1341  signature = originalSelfCert->sign(
1342  *sigScheme,
1344  toBeSigned->coalesce());
1345  }
1346  serverCert = std::move(originalSelfCert);
1347  } else {
1348  serverCert = std::move(resState->serverCert);
1349  clientCert = std::move(resState->clientCert);
1350  }
1351 
1352  return signature.via(state.executor())
1353  .thenValue([&state,
1354  scheduler = std::move(scheduler),
1355  handshakeContext = std::move(handshakeContext),
1356  cipher,
1357  group,
1358  encodedServerHello = std::move(encodedServerHello),
1359  handshakeWriteRecordLayer =
1360  std::move(handshakeWriteRecordLayer),
1361  handshakeWriteSecret = std::move(handshakeWriteSecret),
1362  handshakeReadRecordLayer =
1363  std::move(handshakeReadRecordLayer),
1364  earlyReadRecordLayer = std::move(earlyReadRecordLayer),
1365  earlyExporterMaster = std::move(earlyExporterMaster),
1366  clientHandshakeSecret =
1367  std::move(clientHandshakeSecret),
1368  encodedEncryptedExt = std::move(encodedEncryptedExt),
1369  encodedCertificate = std::move(encodedCertificate),
1370  encodedCertRequest = std::move(encodedCertRequest),
1371  requestClientAuth,
1372  pskType,
1373  pskMode,
1374  sigScheme,
1375  version,
1376  keyExchangeType,
1377  earlyDataType,
1378  replayCacheResult,
1379  serverCert = std::move(serverCert),
1380  clientCert = std::move(clientCert),
1381  alpn = std::move(alpn),
1382  clockSkew,
1383  legacySessionId = std::move(legacySessionId),
1384  serverCertCompAlgo =
1385  certCompressionAlgo](Optional<Buf> sig) mutable {
1386  Optional<Buf> encodedCertificateVerify;
1387  if (sig) {
1388  encodedCertificateVerify = getCertificateVerify(
1389  *sigScheme, std::move(*sig), *handshakeContext);
1390  }
1391 
1392  auto encodedFinished = Protocol::getFinished(
1393  folly::range(handshakeWriteSecret), *handshakeContext);
1394 
1395  folly::IOBufQueue combined;
1396  if (encodedCertificate) {
1397  if (encodedCertRequest) {
1398  combined.append(std::move(encodedEncryptedExt));
1399  combined.append(std::move(*encodedCertRequest));
1400  combined.append(std::move(*encodedCertificate));
1401  combined.append(std::move(*encodedCertificateVerify));
1402  combined.append(std::move(encodedFinished));
1403  } else {
1404  combined.append(std::move(encodedEncryptedExt));
1405  combined.append(std::move(*encodedCertificate));
1406  combined.append(std::move(*encodedCertificateVerify));
1407  combined.append(std::move(encodedFinished));
1408  }
1409  } else {
1410  combined.append(std::move(encodedEncryptedExt));
1411  combined.append(std::move(encodedFinished));
1412  }
1413 
1414  // Some middleboxes appear to break if the first encrypted record
1415  // is larger than ~1300 bytes (likely if it does not fit in the
1416  // first packet).
1417  auto serverEncrypted = handshakeWriteRecordLayer->writeHandshake(
1418  combined.splitAtMost(1000));
1419  if (!combined.empty()) {
1420  auto splitRecord =
1421  handshakeWriteRecordLayer->writeHandshake(combined.move());
1422  // Split record must have the same encryption level as the main
1423  // handshake.
1424  DCHECK(
1425  splitRecord.encryptionLevel ==
1426  serverEncrypted.encryptionLevel);
1427  serverEncrypted.data->prependChain(std::move(splitRecord.data));
1428  }
1429 
1430  WriteToSocket serverFlight;
1431  serverFlight.contents.emplace_back(
1433  std::move(encodedServerHello)));
1434  if (legacySessionId && !legacySessionId->empty()) {
1435  TLSContent ccsWrite;
1439  serverFlight.contents.emplace_back(std::move(ccsWrite));
1440  }
1441  serverFlight.contents.emplace_back(std::move(serverEncrypted));
1442 
1443  scheduler->deriveMasterSecret();
1444  auto clientFinishedContext =
1445  handshakeContext->getHandshakeContext();
1446  auto exporterMasterVector = scheduler->getSecret(
1448  clientFinishedContext->coalesce());
1449  auto exporterMaster =
1450  folly::IOBuf::copyBuffer(folly::range(exporterMasterVector));
1451 
1452  scheduler->deriveAppTrafficSecrets(
1453  clientFinishedContext->coalesce());
1454  auto appTrafficWriteRecordLayer =
1457  appTrafficWriteRecordLayer->setProtocolVersion(version);
1458  auto writeSecret =
1459  scheduler->getSecret(AppTrafficSecrets::ServerAppTraffic);
1461  *appTrafficWriteRecordLayer,
1462  cipher,
1463  folly::range(writeSecret),
1464  *state.context()->getFactory(),
1465  *scheduler);
1466 
1467  // If we have previously dealt with early data (before a
1468  // HelloRetryRequest), don't overwrite the previous result.
1469  auto earlyDataTypeSave = state.earlyDataType()
1470  ? *state.earlyDataType()
1471  : earlyDataType;
1472 
1473  // Save all the necessary state except for the read record layer,
1474  // which is done separately as it varies if early data was
1475  // accepted.
1476  auto saveState = [appTrafficWriteRecordLayer =
1477  std::move(appTrafficWriteRecordLayer),
1478  handshakeContext = std::move(handshakeContext),
1479  scheduler = std::move(scheduler),
1480  exporterMaster = std::move(exporterMaster),
1481  serverCert = std::move(serverCert),
1482  clientCert = std::move(clientCert),
1483  cipher,
1484  group,
1485  sigScheme,
1486  clientHandshakeSecret =
1487  std::move(clientHandshakeSecret),
1488  pskType,
1489  pskMode,
1490  version,
1491  keyExchangeType,
1492  alpn = std::move(alpn),
1493  earlyDataTypeSave,
1494  replayCacheResult,
1495  clockSkew,
1496  serverCertCompAlgo](State& newState) mutable {
1497  newState.writeRecordLayer() =
1498  std::move(appTrafficWriteRecordLayer);
1499  newState.handshakeContext() = std::move(handshakeContext);
1500  newState.keyScheduler() = std::move(scheduler);
1501  newState.exporterMasterSecret() = std::move(exporterMaster);
1502  newState.serverCert() = std::move(*serverCert);
1503  newState.clientCert() = std::move(clientCert);
1504  newState.version() = version;
1505  newState.cipher() = cipher;
1506  newState.group() = group;
1507  newState.sigScheme() = sigScheme;
1508  newState.clientHandshakeSecret() =
1509  std::move(clientHandshakeSecret);
1510  newState.pskType() = pskType;
1511  newState.pskMode() = pskMode;
1512  newState.keyExchangeType() = keyExchangeType;
1513  newState.earlyDataType() = earlyDataTypeSave;
1514  newState.replayCacheResult() = replayCacheResult;
1515  newState.alpn() = std::move(alpn);
1516  newState.clientClockSkew() = clockSkew;
1517  newState.serverCertCompAlgo() = serverCertCompAlgo;
1518  };
1519 
1520  if (earlyDataType == EarlyDataType::Accepted) {
1521  return actions(
1522  [handshakeReadRecordLayer =
1523  std::move(handshakeReadRecordLayer),
1524  earlyReadRecordLayer = std::move(earlyReadRecordLayer),
1525  earlyExporterMaster = std::move(earlyExporterMaster)](
1526  State& newState) mutable {
1527  newState.readRecordLayer() =
1528  std::move(earlyReadRecordLayer);
1529  newState.handshakeReadRecordLayer() =
1530  std::move(handshakeReadRecordLayer);
1531  newState.earlyExporterMasterSecret() =
1532  std::move(earlyExporterMaster);
1533  },
1534  std::move(saveState),
1535  std::move(serverFlight),
1536  &Transition<StateEnum::AcceptingEarlyData>,
1538  } else {
1539  auto transition = requestClientAuth
1540  ? Transition<StateEnum::ExpectingCertificate>
1541  : Transition<StateEnum::ExpectingFinished>;
1542  return actions(
1543  [handshakeReadRecordLayer = std::move(
1544  handshakeReadRecordLayer)](State& newState) mutable {
1545  newState.readRecordLayer() =
1546  std::move(handshakeReadRecordLayer);
1547  },
1548  std::move(saveState),
1549  std::move(serverFlight),
1550  transition);
1551  }
1552  });
1553  });
1554 }
1555 
1558  handle(const State&, Param param) {
1559  auto& appData = boost::get<AppData>(param);
1560 
1561  return actions(DeliverAppData{std::move(appData.data)});
1562 }
1563 
1566  handle(const State& state, Param param) {
1567  auto& appWrite = boost::get<AppWrite>(param);
1568 
1570  write.callback = appWrite.callback;
1571  write.contents.emplace_back(
1573  write.flags = appWrite.flags;
1574 
1575  return actions(std::move(write));
1576 }
1577 
1579  ServerTypes,
1581  Event::EndOfEarlyData>::handle(const State& state, Param param) {
1582  auto& eoed = boost::get<EndOfEarlyData>(param);
1583 
1584  if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1585  throw FizzException(
1586  "data after eoed", AlertDescription::unexpected_message);
1587  }
1588 
1589  state.handshakeContext()->appendToTranscript(*eoed.originalEncoding);
1590 
1591  auto readRecordLayer = std::move(state.handshakeReadRecordLayer());
1592 
1593  return actions(
1594  [readRecordLayer = std::move(readRecordLayer)](State& newState) mutable {
1595  newState.readRecordLayer() = std::move(readRecordLayer);
1596  },
1597  &Transition<StateEnum::ExpectingFinished>);
1598 }
1599 
1602  handle(const State& state, Param param) {
1603  auto& appWrite = boost::get<AppWrite>(param);
1604 
1606  write.callback = appWrite.callback;
1607  write.contents.emplace_back(
1609  write.flags = appWrite.flags;
1610 
1611  return actions(std::move(write));
1612 }
1613 
1615  const FizzServerContext& context,
1616  const WriteRecordLayer& recordLayer,
1617  std::chrono::seconds ticketLifetime,
1618  uint32_t ticketAgeAdd,
1619  Buf nonce,
1620  Buf ticket,
1623  nst.ticket_lifetime = ticketLifetime.count();
1624  nst.ticket_age_add = ticketAgeAdd;
1625  nst.ticket_nonce = std::move(nonce);
1626  nst.ticket = std::move(ticket);
1627 
1628  if (context.getAcceptEarlyData(version)) {
1629  TicketEarlyData early;
1630  early.max_early_data_size = context.getMaxEarlyDataSize();
1631  nst.extensions.push_back(encodeExtension(std::move(early)));
1632  }
1633 
1634  auto encodedNst = encodeHandshake(std::move(nst));
1635  WriteToSocket nstWrite;
1636  nstWrite.contents.emplace_back(
1637  recordLayer.writeHandshake(std::move(encodedNst)));
1638  return nstWrite;
1639 }
1640 
1642  const State& state,
1643  const std::vector<uint8_t>& resumptionMasterSecret,
1644  Buf appToken = nullptr) {
1645  auto ticketCipher = state.context()->getTicketCipher();
1646 
1647  if (!ticketCipher || *state.pskType() == PskType::NotSupported) {
1648  return folly::none;
1649  }
1650 
1651  Buf ticketNonce;
1652  Buf resumptionSecret;
1653  auto realDraftVersion = getRealDraftVersion(*state.version());
1654  if (realDraftVersion == ProtocolVersion::tls_1_3_20) {
1655  ticketNonce = nullptr;
1656  resumptionSecret =
1657  folly::IOBuf::copyBuffer(folly::range(resumptionMasterSecret));
1658  } else {
1659  ticketNonce = folly::IOBuf::create(0);
1660  resumptionSecret = state.keyScheduler()->getResumptionSecret(
1661  folly::range(resumptionMasterSecret), ticketNonce->coalesce());
1662  }
1663 
1664  ResumptionState resState;
1665  resState.version = *state.version();
1666  resState.cipher = *state.cipher();
1667  resState.resumptionSecret = std::move(resumptionSecret);
1668  resState.serverCert = state.serverCert();
1669  resState.clientCert = state.clientCert();
1670  resState.alpn = state.alpn();
1671  resState.ticketAgeAdd = state.context()->getFactory()->makeTicketAgeAdd();
1673  resState.appToken = std::move(appToken);
1674 
1675  auto ticketFuture = ticketCipher->encrypt(std::move(resState));
1676  return ticketFuture.via(state.executor())
1677  .thenValue(
1678  [&state,
1679  ticketAgeAdd = resState.ticketAgeAdd,
1680  ticketNonce = std::move(ticketNonce)](
1683  if (!ticket) {
1684  return folly::none;
1685  }
1686  return writeNewSessionTicket(
1687  *state.context(),
1688  *state.writeRecordLayer(),
1689  ticket->second,
1690  ticketAgeAdd,
1691  std::move(ticketNonce),
1692  std::move(ticket->first),
1693  *state.version());
1694  });
1695 }
1696 
1699  handle(const State& state, Param param) {
1700  auto certMsg = std::move(boost::get<CertificateMsg>(param));
1701 
1702  state.handshakeContext()->appendToTranscript(*certMsg.originalEncoding);
1703 
1704  if (!certMsg.certificate_request_context->empty()) {
1705  throw FizzException(
1706  "certificate request context must be empty",
1708  }
1709 
1710  std::vector<std::shared_ptr<const PeerCert>> clientCerts;
1711  for (auto& certEntry : certMsg.certificate_list) {
1712  // We don't request any extensions, so this ought to be empty
1713  if (!certEntry.extensions.empty()) {
1714  throw FizzException(
1715  "certificate extensions must be empty",
1717  }
1718 
1719  clientCerts.emplace_back(state.context()->getFactory()->makePeerCert(
1720  std::move(certEntry.cert_data)));
1721  }
1722 
1723  if (clientCerts.empty()) {
1725  VLOG(6) << "Client authentication not sent";
1726  return actions(
1727  [](State& newState) { newState.unverifiedCertChain() = folly::none; },
1728  &Transition<StateEnum::ExpectingFinished>);
1729  } else {
1730  throw FizzException(
1731  "certificate requested but none received",
1733  }
1734  } else {
1735  return actions(
1736  [certs = std::move(clientCerts)](State& newState) mutable {
1737  newState.unverifiedCertChain() = std::move(certs);
1738  },
1739  &Transition<StateEnum::ExpectingCertificateVerify>);
1740  }
1741 }
1742 
1744  ServerTypes,
1746  Event::CertificateVerify>::handle(const State& state, Param param) {
1747  auto certVerify = std::move(boost::get<CertificateVerify>(param));
1748 
1749  if (std::find(
1750  state.context()->getSupportedSigSchemes().begin(),
1751  state.context()->getSupportedSigSchemes().end(),
1752  certVerify.algorithm) ==
1753  state.context()->getSupportedSigSchemes().end()) {
1754  throw FizzException(
1755  folly::to<std::string>(
1756  "client chose unsupported sig scheme: ",
1757  toString(certVerify.algorithm)),
1759  }
1760 
1761  const auto& certs = *state.unverifiedCertChain();
1762  auto leafCert = certs.front();
1763  leafCert->verify(
1764  certVerify.algorithm,
1766  state.handshakeContext()->getHandshakeContext()->coalesce(),
1767  certVerify.signature->coalesce());
1768 
1769  try {
1770  const auto& verifier = state.context()->getClientCertVerifier();
1771  if (verifier) {
1772  verifier->verify(certs);
1773  }
1774  } catch (const FizzException&) {
1775  throw;
1776  } catch (const std::exception& e) {
1778  folly::to<std::string>("client certificate failure: ", e.what()),
1780  }
1781 
1782  state.handshakeContext()->appendToTranscript(*certVerify.originalEncoding);
1783 
1784  return actions(
1785  [cert = std::move(leafCert)](State& newState) {
1786  newState.unverifiedCertChain() = folly::none;
1787  newState.clientCert() = std::move(cert);
1788  },
1789  &Transition<StateEnum::ExpectingFinished>);
1790 }
1791 
1794  handle(const State& state, Param param) {
1795  auto& finished = boost::get<Finished>(param);
1796 
1797  auto expectedFinished = state.handshakeContext()->getFinishedData(
1798  state.clientHandshakeSecret()->coalesce());
1799  if (!CryptoUtils::equal(
1800  expectedFinished->coalesce(), finished.verify_data->coalesce())) {
1801  throw FizzException("client finished verify failure", folly::none);
1802  }
1803 
1804  if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1805  throw FizzException("data after finished", folly::none);
1806  }
1807 
1808  auto readRecordLayer =
1811  readRecordLayer->setProtocolVersion(*state.version());
1812  auto readSecret =
1815  *readRecordLayer,
1816  *state.cipher(),
1817  folly::range(readSecret),
1818  *state.context()->getFactory(),
1819  *state.keyScheduler());
1820 
1821  state.handshakeContext()->appendToTranscript(*finished.originalEncoding);
1822 
1823  auto resumptionMasterSecret = state.keyScheduler()->getSecret(
1825  state.handshakeContext()->getHandshakeContext()->coalesce());
1826  state.keyScheduler()->clearMasterSecret();
1827 
1828  auto saveState = [readRecordLayer = std::move(readRecordLayer),
1829  resumptionMasterSecret](State& newState) mutable {
1830  newState.readRecordLayer() = std::move(readRecordLayer);
1831 
1832  newState.resumptionMasterSecret() = std::move(resumptionMasterSecret);
1833  };
1834 
1835  if (!state.context()->getSendNewSessionTicket()) {
1836  return actions(
1837  std::move(saveState),
1838  &Transition<StateEnum::AcceptingData>,
1840  } else {
1841  auto ticketFuture = generateTicket(state, resumptionMasterSecret);
1842  return ticketFuture.via(state.executor())
1843  .thenValue([saveState = std::move(saveState)](
1844  Optional<WriteToSocket> nstWrite) mutable {
1845  if (!nstWrite) {
1846  return actions(
1847  std::move(saveState),
1848  &Transition<StateEnum::AcceptingData>,
1850  }
1851 
1852  return actions(
1853  std::move(saveState),
1854  &Transition<StateEnum::AcceptingData>,
1855  std::move(*nstWrite),
1857  });
1858  }
1859 }
1860 
1862  ServerTypes,
1864  Event::WriteNewSessionTicket>::handle(const State& state, Param param) {
1865  auto& writeNewSessionTicket = boost::get<WriteNewSessionTicket>(param);
1866  auto ticketFuture = generateTicket(
1867  state,
1868  state.resumptionMasterSecret(),
1869  std::move(writeNewSessionTicket.appToken));
1870  return ticketFuture.via(state.executor())
1871  .thenValue([](Optional<WriteToSocket> nstWrite) {
1872  if (!nstWrite) {
1873  return actions();
1874  }
1875  return actions(std::move(*nstWrite));
1876  });
1877 }
1878 
1881  const State& /*state*/,
1882  Param param) {
1883  auto& appData = boost::get<AppData>(param);
1884 
1885  return actions(DeliverAppData{std::move(appData.data)});
1886 }
1887 
1890  const State& state,
1891  Param param) {
1892  auto& appWrite = boost::get<AppWrite>(param);
1893 
1895  write.callback = appWrite.callback;
1896  write.contents.emplace_back(
1898  write.flags = appWrite.flags;
1899 
1900  return actions(std::move(write));
1901 }
1902 
1905  const State& state,
1906  Param param) {
1907  auto& keyUpdate = boost::get<KeyUpdate>(param);
1908 
1909  if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1910  throw FizzException("data after key_update", folly::none);
1911  }
1912  state.keyScheduler()->clientKeyUpdate();
1913  auto readRecordLayer =
1916  readRecordLayer->setProtocolVersion(*state.version());
1917  auto readSecret =
1920  *readRecordLayer,
1921  *state.cipher(),
1922  folly::range(readSecret),
1923  *state.context()->getFactory(),
1924  *state.keyScheduler());
1925 
1926  if (keyUpdate.request_update == KeyUpdateRequest::update_not_requested) {
1927  return actions(
1928  [rRecordLayer = std::move(readRecordLayer)](State& newState) mutable {
1929  newState.readRecordLayer() = std::move(rRecordLayer);
1930  });
1931  }
1932 
1933  auto encodedKeyUpdated =
1936  write.contents.emplace_back(
1937  state.writeRecordLayer()->writeHandshake(std::move(encodedKeyUpdated)));
1938 
1939  state.keyScheduler()->serverKeyUpdate();
1940 
1941  auto writeRecordLayer =
1944  writeRecordLayer->setProtocolVersion(*state.version());
1945  auto writeSecret =
1948  *writeRecordLayer,
1949  *state.cipher(),
1950  folly::range(writeSecret),
1951  *state.context()->getFactory(),
1952  *state.keyScheduler());
1953 
1954  return actions(
1955  [rRecordLayer = std::move(readRecordLayer),
1956  wRecordLayer = std::move(writeRecordLayer)](State& newState) mutable {
1957  newState.readRecordLayer() = std::move(rRecordLayer);
1958  newState.writeRecordLayer() = std::move(wRecordLayer);
1959  },
1960  std::move(write));
1961 }
1962 
1963 } // namespace sm
1964 } // namespace fizz
std::vector< Extension > extensions
Definition: Types.h:218
std::vector< Extension > extensions
Definition: Types.h:228
Future< T > via(Executor *executor, int8_t priority=Executor::MID_PRI)&&
Definition: Future-inl.h:1024
Buf getStatelessHelloRetryRequest(ProtocolVersion version, CipherSuite cipher, folly::Optional< NamedGroup > group, Buf cookie)
std::unique_ptr< folly::IOBuf > split(size_t n)
Definition: IOBufQueue.h:420
TLSContent writeHandshake(Buf &&encodedHandshakeMsg, Args &&...args) const
Definition: RecordLayer.h:74
std::shared_ptr< const server::FizzServerContext > context
Definition: Params.h:34
Future< ReplayCacheResult > getReplayCacheResult(const ClientHello &chlo, bool zeroRttEnabled, ReplayCache *replayCache)
std::vector< typename std::enable_if< !std::is_same< invoke_result_t< typename std::iterator_traits< InputIterator >::value_type >, void >::value, invoke_result_t< typename std::iterator_traits< InputIterator >::value_type > >::type > collectAll(InputIterator first, InputIterator last)
Definition: WhenN-inl.h:147
folly::Optional< std::pair< std::shared_ptr< SelfCert >, SignatureScheme > > getCert(const folly::Optional< std::string > &sni, const std::vector< SignatureScheme > &peerSigSchemes) const
const auto & getSupportedCompressionAlgorithms() const
static void setAead(Type &recordLayer, CipherSuite cipher, folly::ByteRange secret, const Factory &factory, const KeyScheduler &scheduler)
Definition: Protocol.h:20
virtual std::vector< Extension > getCertificateRequestExtensions() const =0
const auto & getSupportedSigSchemes() const
Buf encodeHandshake(T &&handshakeMsg)
Definition: Types-inl.h:515
Integral2 random(Integral1 low, Integral2 up)
void setProtocolVersion(ProtocolVersion version) const
Definition: RecordLayer.h:80
folly::StringPiece toString(StateEnum state)
Definition: State.cpp:16
virtual bool hasUnparsedHandshakeData() const
ServerExtensions * extensions() const
Definition: State.h:241
static Buf getFinished(folly::ByteRange handshakeWriteSecret, HandshakeContext &handshakeContext)
Definition: Protocol.h:33
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
size_t getBinderLength(const ClientHello &chlo)
static Buf getEncryptedExt(HandshakeContext &handshakeContext, const folly::Optional< std::string > &selectedAlpn, EarlyDataType earlyData, std::vector< Extension > otherExtensions)
static std::tuple< NamedGroup, Optional< Buf > > negotiateGroup(ProtocolVersion version, const ClientHello &chlo, const std::vector< NamedGroup > &supportedGroups)
static EarlyDataType negotiateEarlyDataType(bool acceptEarlyData, const ClientHello &chlo, const Optional< ResumptionState > &psk, CipherSuite cipher, Optional< KeyExchangeType > keyExchangeType, const Optional< CookieState > &cookieState, Optional< std::string > alpn, ReplayCacheResult replayCacheResult, Optional< std::chrono::milliseconds > clockSkew, ClockSkewTolerance clockSkewTolerance, const AppTokenValidator *appTokenValidator)
Actions handleAppClose(const State &state)
const auto & getSupportedPskModes() const
void verify(int extras)
size_t chainLength() const
Definition: IOBufQueue.h:492
#define FIZZ_DECLARE_EVENT_HANDLER(sm, statename, eventname,...)
std::vector< CipherSuite > clientCiphers
Definition: State.h:42
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
uint32_t max_early_data_size
Definition: Extensions.h:83
TLSContent writeAlert(Alert &&alert) const
Definition: RecordLayer.h:65
static Buf getServerHello(ProtocolVersion version, Random random, CipherSuite cipher, bool psk, Optional< NamedGroup > group, Optional< Buf > serverShare, Buf legacy_session_id, HandshakeContext &handshakeContext)
folly::Optional< ProtocolVersion > version() const
Definition: State.h:104
folly::Optional< ProtocolVersion > clientRecordVersion
Definition: State.h:44
boost::variant< ClientHello, ServerHello, EndOfEarlyData, HelloRetryRequest, EncryptedExtensions, CertificateRequest, CompressedCertificate, CertificateMsg, CertificateVerify, Finished, NewSessionTicket, KeyUpdate, Alert, Accept, Connect, AppData, AppWrite, EarlyAppWrite, WriteNewSessionTicket > Param
Definition: Params.h:90
EarlyDataType
Definition: Types.h:33
static const std::string chlo
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
Actions actions(Args &&...act)
Definition: Actions.h:57
static ResumptionStateResult getResumptionState(const ClientHello &chlo, const TicketCipher *ticketCipher, const std::vector< PskKeyExchangeMode > &supportedModes)
folly::Optional< bool > clientSessionIdSent
Definition: State.h:50
auto & handshakeReadRecordLayer() const
Definition: State.h:307
PUSHMI_INLINE_VAR constexpr detail::share_fn< TN... > share
Definition: share.h:53
static std::unique_ptr< IOBuf > wrapBuffer(const void *buf, std::size_t capacity)
Definition: IOBuf.cpp:353
folly::Executor * executor
Definition: Params.h:33
StateEnum state() const
Definition: State.h:69
virtual std::vector< uint8_t > getSecret(EarlySecrets s, folly::ByteRange transcript) const
StringPiece cookie
CookieState getCookieState(const Factory &factory, const std::vector< ProtocolVersion > &supportedVersions, const std::vector< std::vector< CipherSuite >> &supportedCiphers, const std::vector< NamedGroup > &supportedGroups, const ClientHello &chlo, Buf appToken)
virtual std::unique_ptr< PlaintextReadRecordLayer > makePlaintextReadRecordLayer() const
Definition: Factory.h:37
static bool equal(folly::ByteRange a, folly::ByteRange b)
Definition: Utils.cpp:31
static void validateGroups(const std::vector< KeyShareEntry > &client_shares)
virtual void appendToTranscript(const Buf &transcript)=0
context
Definition: CMakeCache.txt:563
std::shared_ptr< ServerExtensions > extensions
Definition: Params.h:35
std::unique_ptr< folly::IOBuf > hash
Definition: Types.h:82
const folly::Optional< Buf > & earlyExporterMasterSecret() const
Definition: State.h:275
KeyShareEntry server_share
Definition: Extensions.h:41
const TicketCipher * getTicketCipher() const
NamedGroup
Definition: Types.h:302
folly::Optional< T > negotiate(const std::vector< std::vector< T >> &serverPref, const std::vector< T > &clientPref)
Definition: Negotiator.h:22
bool empty() const
Definition: IOBufQueue.h:503
std::chrono::steady_clock::time_point now()
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
folly::small_vector< TLSContent, 4 > contents
Definition: Actions.h:41
boost::variant< Actions, folly::Future< Actions >> AsyncActions
Definition: Actions.h:52
virtual TLSContent writeInitialClientHello(Buf encodedClientHello) const
SignatureScheme
Definition: Types.h:257
CipherSuite
Definition: Types.h:153
StringPiece alpn
virtual std::unique_ptr< KeyScheduler > makeKeyScheduler(CipherSuite cipher) const
Definition: Factory.h:56
const auto & getSupportedVersions() const
virtual folly::Future< ReplayCacheResult > check(folly::ByteRange identifier)=0
folly::Optional< std::vector< NamedGroup > > clientKeyShares
Definition: State.h:47
virtual std::vector< Extension > getExtensions(const ClientHello &chlo)=0
std::vector< PskKeyExchangeMode > clientKeyExchangeModes
Definition: State.h:48
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
virtual folly::Optional< CookieState > decrypt(Buf) const =0
Buf legacy_session_id_echo
Definition: Types.h:202
static bool validateResumptionState(const ResumptionState &resState, PskKeyExchangeMode, ProtocolVersion version, CipherSuite cipher)
virtual AsyncActions processEarlyAppWrite(const State &, EarlyAppWrite)
static AppWrite appWrite(const std::string &str)
folly::Optional< std::string > alpn
ProtocolVersion legacy_version
Definition: Types.h:188
virtual std::unique_ptr< KeyExchange > makeKeyExchange(NamedGroup group) const
Definition: Factory.h:90
constexpr folly::StringPiece FakeChangeCipherSpec
Definition: Types.h:59
std::shared_ptr< folly::FunctionScheduler > scheduler
Definition: FilePoller.cpp:50
std::vector< Extension > extensions
Definition: Types.h:289
static constexpr uint16_t kPskIndex
virtual bool validate(const ResumptionState &) const =0
std::chrono::system_clock::time_point ticketIssueTime
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
tuple make_tuple()
Definition: gtest-tuple.h:675
KeyScheduler * keyScheduler() const
Definition: State.h:203
virtual AsyncActions processAppWrite(const State &, AppWrite)
static std::pair< std::shared_ptr< SelfCert >, SignatureScheme > chooseCert(const FizzServerContext &context, const ClientHello &chlo)
PUSHMI_INLINE_VAR constexpr __adl::get_executor_fn executor
folly::Optional< KeyExchangeType > keyExchangeType() const
Definition: State.h:147
CipherSuite cipher
static void validateClientHello(const ClientHello &chlo)
static constexpr StringPiece ticket
Random random
Definition: Types.h:189
NamedGroup group
Definition: Extensions.h:29
folly::Optional< Random > clientRandom
Definition: State.h:51
virtual std::shared_ptr< PeerCert > makePeerCert(Buf certData) const
Definition: Factory.h:128
ProtocolVersion
Definition: Types.h:24
static Buf doKex(const Factory &factory, NamedGroup group, const Buf &clientShare, KeyScheduler &scheduler)
HashFunction getHashFunction(CipherSuite cipher)
Definition: Types.cpp:13
virtual std::unique_ptr< EncryptedReadRecordLayer > makeEncryptedReadRecordLayer(EncryptionLevel encryptionLevel) const
Definition: Factory.h:47
ProtocolVersion version
static void checkDuplicateExtensions(const std::vector< Extension > &exts)
Definition: Protocol.h:117
bool getAcceptEarlyData(ProtocolVersion version) const
Buf legacy_session_id
Definition: Types.h:190
virtual Actions processAppClose(const State &)
ProtocolVersion selected_version
Definition: Extensions.h:99
std::exception * get_exception() noexcept
folly::Optional< std::string > negotiateAlpn(const std::vector< std::string > &clientProtocols, const folly::Optional< std::string > &zeroRttAlpn) const
static CipherSuite negotiateCipher(const ClientHello &chlo, const std::vector< std::vector< CipherSuite >> &supportedCiphers)
Future< std::pair< PskType, Optional< ResumptionState > > > futureResState
virtual void deriveHandshakeSecret()
virtual folly::Future< std::pair< PskType, folly::Optional< ResumptionState > > > decrypt(std::unique_ptr< folly::IOBuf > encryptedTicket) const =0
virtual uint32_t serverKeyUpdate()
folly::Executor * executor() const
Definition: State.h:76
static const std::string encodedCertificate
static Options cacheChainLength()
Definition: IOBufQueue.h:83
ReadRecordLayer * readRecordLayer() const
Definition: State.h:213
virtual AsyncActions processSocketData(const State &, folly::IOBufQueue &)
const Factory * getFactory() const
folly::Optional< AlertDescription > getAlert() const
Definition: Types.h:324
virtual AsyncActions processAccept(const State &, folly::Executor *executor, std::shared_ptr< const FizzServerContext > context, const std::shared_ptr< ServerExtensions > &extensions)
const std::shared_ptr< const Cert > & clientCert() const
Definition: State.h:97
const WriteRecordLayer * writeRecordLayer() const
Definition: State.h:223
folly::Optional< std::string > clientSni
Definition: State.h:45
virtual folly::Optional< Param > readEvent(folly::IOBufQueue &socketBuf)
Definition: RecordLayer.cpp:18
static Buf getCertificateVerify(SignatureScheme sigScheme, Buf signature, HandshakeContext &handshakeContext)
static std::tuple< Buf, folly::Optional< CertificateCompressionAlgorithm > > getCertificate(const std::shared_ptr< const SelfCert > &serverCert, const FizzServerContext &context, const ClientHello &chlo, HandshakeContext &handshakeContext)
std::vector< Extension > extensions
Definition: Types.h:254
folly::Optional< ProtocolVersion > clientLegacyVersion
Definition: State.h:40
static EventHandlerFun getHandler(typename SM::StateEnum state, typename SM::Event event)
std::vector< ProtocolVersion > clientSupportedVersions
Definition: State.h:41
std::vector< SignatureScheme > clientSignatureAlgorithms
Definition: State.h:49
virtual Buf getResumptionSecret(folly::ByteRange resumptionMasterSecret, folly::ByteRange ticketNonce) const
folly::Optional< ReplayCacheResult > replayCacheResult() const
Definition: State.h:161
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
Definition: Optional.h:300
static Optional< std::string > negotiateAlpn(const ClientHello &chlo, folly::Optional< std::string > zeroRttAlpn, const FizzServerContext &context)
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
std::vector< SignatureScheme > supported_signature_algorithms
Definition: Extensions.h:17
static Buf getCertificateRequest(const std::vector< SignatureScheme > &acceptableSigSchemes, const CertificateVerifier *const verifier, HandshakeContext &handshakeContext)
Random random
Definition: Types.h:199
EncryptionLevel encryptionLevel
Definition: RecordLayer.h:21
constexpr detail::Sig< Sig > const sig
Definition: Poly.h:1165
Definition: Actions.h:16
virtual std::unique_ptr< HandshakeContext > makeHandshakeContext(CipherSuite cipher) const
Definition: Factory.h:76
std::vector< Extension > extensions
Definition: Types.h:193
Actions handleError(const State &state, ReportError error, Optional< AlertDescription > alertDesc)
std::shared_ptr< const Cert > serverCert
const CookieCipher * getCookieCipher() const
std::array< uint8_t, 32 > Random
Definition: Types.h:184
std::vector< CipherSuite > cipher_suites
Definition: Types.h:191
ReplayCache * getReplayCache() const
folly::Optional< PskType > pskType() const
Definition: State.h:133
Definition: Try.h:51
const std::vector< uint8_t > & resumptionMasterSecret() const
Definition: State.h:248
HandshakeLogging * handshakeLogging() const
Definition: State.h:193
ProtocolVersion legacy_version
Definition: Types.h:210
const std::shared_ptr< const CertificateVerifier > & getClientCertVerifier() const
Actions handleInvalidEvent(const State &state, Event event, Param param)
ProtocolVersion version
Definition: CookieCipher.h:18
const folly::Optional< std::vector< std::shared_ptr< const PeerCert > > > & unverifiedCertChain() const
Definition: State.h:258
Optional< NamedGroup > group
PskType
Definition: Types.h:18
SignatureScheme algorithm
Definition: Types.h:273
static Optional< ProtocolVersion > negotiateVersion(const ClientHello &chlo, const std::vector< ProtocolVersion > &versions)
static Buf getHelloRetryRequest(ProtocolVersion version, CipherSuite cipher, NamedGroup group, Buf legacySessionId, HandshakeContext &handshakeContext)
virtual std::unique_ptr< EncryptedWriteRecordLayer > makeEncryptedWriteRecordLayer(EncryptionLevel encryptionLevel) const
Definition: Factory.h:52
virtual uint32_t makeTicketAgeAdd() const
Definition: Factory.h:124
std::chrono::milliseconds after
std::vector< Extension > extensions
Definition: Types.h:205
Event
Definition: Events.h:15
static const std::string encodedCertRequest
StringPiece sni
Optional< uint32_t > obfuscatedAge
static const std::string nst
const FizzServerContext * context() const
Definition: State.h:83
folly::Optional< Buf > originalEncoding
Definition: Types.h:92
ClockSkewTolerance getClockSkewTolerance() const
virtual AsyncActions processWriteNewSessionTicket(const State &, WriteNewSessionTicket)
virtual void clearMasterSecret()
ClientAuthMode getClientAuthMode() const
AsyncActions processEvent(const State &state, Param param)
ContentType contentType
Definition: RecordLayer.h:20
decltype(auto) apply_visitor(Visitor &&visitor, const DiscriminatedPtr< Args... > &variant)
std::unique_ptr< folly::IOBuf > Buf
Definition: Types.h:22
std::vector< ExtensionType > clientExtensions
Definition: State.h:43
const auto & getSupportedCiphers() const
CipherSuite cipher_suite
Definition: Types.h:216
folly::Optional< NamedGroup > group() const
Definition: State.h:118
folly::Optional< NamedGroup > group
Definition: CookieCipher.h:20
const Buf & clientHandshakeSecret() const
Definition: State.h:232
const AppTokenValidator * appTokenValidator() const
Definition: State.h:184
Optional< PskKeyExchangeMode > pskMode
uint32_t ticket_lifetime
Definition: Types.h:284
std::shared_ptr< const Cert > clientCert
decltype(auto) variant_match(Variant &&variant, Cases &&...cases)
Definition: Overload.h:74
ProtocolVersion getRealDraftVersion(ProtocolVersion version)
Definition: Types.cpp:16
std::vector< ProtocolName > protocol_name_list
Definition: Extensions.h:115
static Buf getKeyUpdated(KeyUpdateRequest request_update)
Definition: Protocol.h:44
std::chrono::milliseconds before
auto & handshakeContext() const
Definition: State.h:310
std::vector< uint8_t > legacy_compression_methods
Definition: Types.h:192
const folly::Optional< std::string > & alpn() const
Definition: State.h:168
static void addHandshakeLogging(const State &state, const ClientHello &chlo)
TLSContent writeAppData(std::unique_ptr< folly::IOBuf > &&appData) const
Definition: RecordLayer.h:69
std::shared_ptr< const Cert > serverCert
Extension encodeExtension(const TokenBindingParameters &params)
Definition: Types.cpp:113
static Optional< std::chrono::milliseconds > getClockSkew(const Optional< ResumptionState > &psk, Optional< uint32_t > obfuscatedAge)
virtual Random makeRandom() const
Definition: Factory.h:120
const auto & getSupportedGroups() const
static std::unique_ptr< IOBuf > copyBuffer(const void *buf, std::size_t size, std::size_t headroom=0, std::size_t minTailroom=0)
Definition: IOBuf.h:1587
folly::Optional< EarlyDataType > earlyDataType() const
Definition: State.h:154
std::vector< NamedGroup > clientSupportedGroups
Definition: State.h:46
static Future< Optional< WriteToSocket > > generateTicket(const State &state, const std::vector< uint8_t > &resumptionMasterSecret, Buf appToken=nullptr)
std::shared_ptr< const Cert > clientCert
PskKeyExchangeMode
Definition: Types.h:163
CipherSuite cipher_suite
Definition: Types.h:203
std::shared_ptr< const Cert > serverCert() const
Definition: State.h:90
folly::Optional< CipherSuite > cipher() const
Definition: State.h:111
ProtocolVersion legacy_version
Definition: Types.h:198
std::unique_ptr< folly::IOBuf > data
Definition: Params.h:54
KeyExchangeType
Definition: Types.h:31
static std::pair< std::unique_ptr< KeyScheduler >, std::unique_ptr< HandshakeContext > > setupSchedulerAndContext(const Factory &factory, CipherSuite cipher, const ClientHello &chlo, const Optional< ResumptionState > &resState, const Optional< CookieState > &cookieState, PskType pskType, std::unique_ptr< HandshakeContext > handshakeContext, ProtocolVersion)
std::unique_ptr< folly::IOBuf > clientHello
Definition: Actions.h:27
uint32_t ticket_age_add
Definition: Types.h:285
state
Definition: http_parser.c:272
constexpr None none
Definition: Optional.h:87
folly::WriteFlags flags
Definition: Params.h:55
folly::AsyncTransportWrapper::WriteCallback * callback
Definition: Params.h:53
static WriteToSocket writeNewSessionTicket(const FizzServerContext &context, const WriteRecordLayer &recordLayer, std::chrono::seconds ticketLifetime, uint32_t ticketAgeAdd, Buf nonce, Buf ticket, ProtocolVersion version)
NetworkSocket accept(NetworkSocket s, sockaddr *addr, socklen_t *addrlen)
Definition: NetOps.cpp:71
virtual uint32_t clientKeyUpdate()