proxygen
ClientProtocol.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/client/PskCache.h>
12 #include <fizz/crypto/Utils.h>
14 #include <fizz/protocol/Protocol.h>
16 #include <fizz/record/Extensions.h>
17 
18 using folly::Optional;
19 
20 using namespace fizz::client;
21 using namespace fizz::client::detail;
22 
23 namespace fizz {
24 namespace sm {
25 
31 
37 
43 
49 
56 
62 
68 
74 
80 
86 
92 
98 
100  ClientTypes,
104 
106  ClientTypes,
110 
112  ClientTypes,
116 
118  ClientTypes,
122 
124  ClientTypes,
128 
130  ClientTypes,
134 
136  ClientTypes,
140 } // namespace sm
141 
142 namespace client {
143 
145  const State& state,
146  std::shared_ptr<const FizzClientContext> context,
147  std::shared_ptr<const CertificateVerifier> verifier,
149  Optional<CachedPsk> cachedPsk,
150  const std::shared_ptr<ClientExtensions>& extensions) {
152  connect.context = std::move(context);
153  connect.sni = std::move(sni);
154  connect.verifier = std::move(verifier);
155  connect.extensions = extensions;
156  connect.cachedPsk = std::move(cachedPsk);
157  return detail::processEvent(state, std::move(connect));
158 }
159 
161  const State& state,
162  folly::IOBufQueue& buf) {
163  try {
164  if (!state.readRecordLayer()) {
165  return detail::handleError(
166  state,
167  ReportError("attempting to process data without record layer"),
168  folly::none);
169  }
170  auto param = state.readRecordLayer()->readEvent(buf);
171  if (!param.hasValue()) {
172  return actions(WaitForData());
173  }
174  return detail::processEvent(state, std::move(*param));
175  } catch (const std::exception& e) {
176  return detail::handleError(
177  state,
178  ReportError(folly::exception_wrapper(std::current_exception(), e)),
180  }
181 }
182 
184  const State& state,
186  return detail::processEvent(state, std::move(write));
187 }
188 
190  const State& state,
191  AppWrite write) {
192  return detail::processEvent(state, std::move(write));
193 }
194 
196  const State& state,
198  return detail::processEvent(state, std::move(write));
199 }
200 
202  return detail::handleAppClose(state);
203 }
204 
205 namespace detail {
206 
208  auto event = boost::apply_visitor(EventVisitor(), param);
209  try {
210  return sm::StateMachine<ClientTypes>::getHandler(state.state(), event)(
211  state, std::move(param));
212  } catch (const FizzException& e) {
213  return detail::handleError(
214  state,
215  ReportError(folly::exception_wrapper(std::current_exception(), e)),
216  e.getAlert());
217  } catch (const std::exception& e) {
218  return detail::handleError(
219  state,
220  ReportError(folly::exception_wrapper(std::current_exception(), e)),
222  }
223 }
224 
226  const State& state,
228  Optional<AlertDescription> alertDesc) {
229  if (state.state() == StateEnum::Error) {
230  return actions(std::move(error));
231  }
232  auto transition = [](State& newState) {
233  newState.state() = StateEnum::Error;
234  newState.writeRecordLayer() = nullptr;
235  newState.readRecordLayer() = nullptr;
236  };
237  if (alertDesc && state.writeRecordLayer()) {
238  Alert alert(*alertDesc);
240  write.contents.emplace_back(
241  state.writeRecordLayer()->writeAlert(std::move(alert)));
242  return actions(std::move(transition), std::move(write), std::move(error));
243  } else {
244  return actions(std::move(transition), std::move(error));
245  }
246 }
247 
249  auto transition = [](State& newState) {
250  newState.state() = StateEnum::Error;
251  newState.writeRecordLayer() = nullptr;
252  newState.readRecordLayer() = nullptr;
253  };
254  if (state.writeRecordLayer()) {
257  write.contents.emplace_back(
258  state.writeRecordLayer()->writeAlert(std::move(alert)));
259  return actions(std::move(transition), std::move(write));
260  } else {
261  return actions(std::move(transition));
262  }
263 }
264 
266  if (event == Event::Alert) {
267  auto& alert = boost::get<Alert>(param);
268  throw FizzException(
269  folly::to<std::string>(
270  "received alert: ",
271  toString(alert.description),
272  ", in state ",
273  toString(state.state())),
274  folly::none);
275  } else {
276  throw FizzException(
277  folly::to<std::string>(
278  "invalid event: ",
279  toString(event),
280  ", in state ",
281  toString(state.state())),
283  }
284 }
285 } // namespace detail
286 } // namespace client
287 
288 namespace sm {
289 
291  const FizzClientContext& context,
293  if (!psk) {
294  return folly::none;
295  }
296 
298  VLOG(1) << "Ignoring expired cached psk";
299  return folly::none;
300  }
301 
302  if (std::find(
303  context.getSupportedVersions().begin(),
304  context.getSupportedVersions().end(),
305  psk->version) == context.getSupportedVersions().end()) {
306  VLOG(1) << "Ignoring cached psk with protocol version "
307  << toString(psk->version);
308  return folly::none;
309  }
310  if (std::find(
311  context.getSupportedCiphers().begin(),
312  context.getSupportedCiphers().end(),
313  psk->cipher) == context.getSupportedCiphers().end()) {
314  VLOG(1) << "Ignoring cached psk with cipher " << toString(psk->cipher);
315  return folly::none;
316  }
317 
318  return psk;
319 }
320 
321 static std::map<NamedGroup, std::unique_ptr<KeyExchange>> getKeyExchangers(
322  const Factory& factory,
323  const std::vector<NamedGroup>& groups) {
324  std::map<NamedGroup, std::unique_ptr<KeyExchange>> keyExchangers;
325  for (auto group : groups) {
326  auto kex = factory.makeKeyExchange(group);
327  kex->generateKeyPair();
328  keyExchangers.emplace(group, std::move(kex));
329  }
330  return keyExchangers;
331 }
332 
334  const Factory& /*factory*/,
335  const Random& random,
336  const std::vector<CipherSuite>& supportedCiphers,
337  const std::vector<ProtocolVersion>& supportedVersions,
338  const std::vector<NamedGroup>& supportedGroups,
339  const std::map<NamedGroup, std::unique_ptr<KeyExchange>>& shares,
340  const std::vector<SignatureScheme>& supportedSigSchemes,
341  const std::vector<PskKeyExchangeMode>& supportedPskModes,
342  const folly::Optional<std::string>& hostname,
343  const std::vector<std::string>& supportedAlpns,
344  const std::vector<CertificateCompressionAlgorithm>& compressionAlgos,
345  const Optional<EarlyDataParams>& earlyDataParams,
346  const Buf& legacySessionId,
347  ClientExtensions* extensions,
348  Buf cookie = nullptr) {
351  chlo.random = random;
352  chlo.legacy_session_id = legacySessionId->clone();
353  chlo.cipher_suites = supportedCiphers;
354  chlo.legacy_compression_methods.push_back(0x00);
355 
356  SupportedVersions versions;
357  versions.versions = supportedVersions;
358  chlo.extensions.push_back(encodeExtension(std::move(versions)));
359 
360  SupportedGroups groups;
361  groups.named_group_list = supportedGroups;
362  chlo.extensions.push_back(encodeExtension(std::move(groups)));
363 
364  ClientKeyShare keyShare;
365  for (const auto& share : shares) {
366  KeyShareEntry entry;
367  entry.group = share.first;
368  entry.key_exchange = share.second->getKeyShare();
369  keyShare.client_shares.push_back(std::move(entry));
370  }
371  chlo.extensions.push_back(encodeExtension(std::move(keyShare)));
372 
373  SignatureAlgorithms sigAlgs;
374  sigAlgs.supported_signature_algorithms = supportedSigSchemes;
375  chlo.extensions.push_back(encodeExtension(std::move(sigAlgs)));
376 
377  if (hostname) {
379  ServerName sn;
380  sn.hostname = folly::IOBuf::copyBuffer(*hostname);
381  sni.server_name_list.push_back(std::move(sn));
382  chlo.extensions.push_back(encodeExtension(std::move(sni)));
383  }
384 
385  if (!supportedAlpns.empty()) {
387  for (const auto& protoName : supportedAlpns) {
388  ProtocolName proto;
389  proto.name = folly::IOBuf::copyBuffer(protoName);
390  alpn.protocol_name_list.push_back(std::move(proto));
391  }
392  chlo.extensions.push_back(encodeExtension(std::move(alpn)));
393  }
394 
395  if (!supportedPskModes.empty()) {
396  PskKeyExchangeModes modes;
397  modes.modes = supportedPskModes;
398  chlo.extensions.push_back(encodeExtension(std::move(modes)));
399  }
400 
401  if (earlyDataParams) {
402  chlo.extensions.push_back(encodeExtension(ClientEarlyData()));
403  }
404 
405  if (cookie) {
406  Cookie monster;
407  monster.cookie = std::move(cookie);
408  chlo.extensions.push_back(encodeExtension(std::move(monster)));
409  }
410 
411  if (!compressionAlgos.empty()) {
413  algos.algorithms = compressionAlgos;
414  chlo.extensions.push_back(encodeExtension(std::move(algos)));
415  }
416 
417  if (extensions) {
418  auto additionalExtensions = extensions->getClientHelloExtensions();
419  for (auto& ext : additionalExtensions) {
420  chlo.extensions.push_back(std::move(ext));
421  }
422  }
423 
424  return chlo;
425 }
426 
428  ClientPresharedKey pskExt;
429  PskIdentity ident;
431  ident.obfuscated_ticket_age =
432  std::chrono::duration_cast<std::chrono::milliseconds>(
434  .count();
435  ident.obfuscated_ticket_age += psk.ticketAgeAdd;
436  pskExt.identities.push_back(std::move(ident));
437  PskBinder binder;
438  size_t binderSize = getHashSize(getHashFunction(psk.cipher));
439  binder.binder = folly::IOBuf::create(binderSize);
440  memset(binder.binder->writableData(), 0, binderSize);
441  binder.binder->append(binderSize);
442  pskExt.binders.push_back(std::move(binder));
443  return pskExt;
444 }
445 
454  const CachedPsk& psk,
456  HandshakeContext& handshakeContext) {
457  scheduler.deriveEarlySecret(folly::range(psk.secret));
458 
459  auto binderKey = scheduler.getSecret(
462  handshakeContext.getBlankContext());
463 
464  auto pskExt = getPskExtension(psk);
465  chlo.extensions.push_back(encodeExtension(pskExt));
466 
467  size_t binderLength = getBinderLength(chlo);
468 
469  auto preEncoded = encodeHandshake(chlo);
470 
471  // Add the ClientHello up to the binder list to the transcript.
472  {
474  chloQueue.append(std::move(preEncoded));
475  auto chloPrefix = chloQueue.split(chloQueue.chainLength() - binderLength);
476  handshakeContext.appendToTranscript(chloPrefix);
477  }
478 
479  PskBinder binder;
480  binder.binder = handshakeContext.getFinishedData(folly::range(binderKey));
481  pskExt.binders.clear();
482  pskExt.binders.push_back(std::move(binder));
483 
484  chlo.extensions.pop_back();
485  chlo.extensions.push_back(encodeExtension(std::move(pskExt)));
486 
487  auto encoded = encodeHandshake(std::move(chlo));
488 
489  // Add the binder list to the transcript.
491  chloQueue.append(encoded->clone());
492  chloQueue.split(chloQueue.chainLength() - binderLength);
493  handshakeContext.appendToTranscript(chloQueue.move());
494 
495  return encoded;
496 }
497 
499  const FizzClientContext& context,
500  const Optional<CachedPsk>& psk) {
501  if (!context.getSendEarlyData()) {
502  return folly::none;
503  }
504 
505  if (!psk || psk->maxEarlyDataSize == 0) {
506  return folly::none;
507  }
508 
509  if (psk->alpn &&
510  std::find(
511  context.getSupportedAlpns().begin(),
512  context.getSupportedAlpns().end(),
513  *psk->alpn) == context.getSupportedAlpns().end()) {
514  return folly::none;
515  }
516 
518  params.version = psk->version;
519  params.cipher = psk->cipher;
520  params.serverCert = psk->serverCert;
521  params.clientCert = psk->clientCert;
522  params.alpn = psk->alpn;
523  return std::move(params);
524 }
525 
526 Actions
528  const State& /*state*/,
529  Param param) {
530  auto& connect = boost::get<Connect>(param);
531 
532  auto context = std::move(connect.context);
533 
535  validatePsk(*context, std::move(connect.cachedPsk));
536 
537  auto random = context->getFactory()->makeRandom();
538 
539  // If we have a saved PSK, use the group to choose which groups to
540  // send by default
541  std::vector<NamedGroup> selectedShares;
542  if (psk && psk->group &&
543  std::find(
544  context->getSupportedGroups().begin(),
545  context->getSupportedGroups().end(),
546  *psk->group) != context->getSupportedGroups().end()) {
547  // key exchange done last time
548  selectedShares = {*psk->group};
549  } else if (psk && !psk->group) {
550  // psk_ke last time
551  selectedShares = {};
552  } else {
553  selectedShares = context->getDefaultShares();
554  }
555 
556  auto earlyDataParams = getEarlyDataParams(*context, psk);
557 
558  Buf legacySessionId;
559  if (context->getCompatibilityMode()) {
560  legacySessionId =
561  folly::IOBuf::copyBuffer(context->getFactory()->makeRandom());
562  } else {
563  legacySessionId = folly::IOBuf::create(0);
564  }
565 
566  auto keyExchangers = getKeyExchangers(*context->getFactory(), selectedShares);
567 
568  auto chlo = getClientHello(
569  *context->getFactory(),
570  random,
571  context->getSupportedCiphers(),
572  context->getSupportedVersions(),
573  context->getSupportedGroups(),
574  keyExchangers,
575  context->getSupportedSigSchemes(),
576  context->getSupportedPskModes(),
577  connect.sni,
578  context->getSupportedAlpns(),
579  context->getSupportedCertDecompressionAlgorithms(),
580  earlyDataParams,
581  legacySessionId,
582  connect.extensions.get());
583 
584  std::vector<ExtensionType> requestedExtensions;
585  for (const auto& extension : chlo.extensions) {
586  requestedExtensions.push_back(extension.extension_type);
587  }
588 
589  Buf encodedClientHello;
590  std::unique_ptr<EncryptedWriteRecordLayer> earlyWriteRecordLayer;
591  Optional<ReportEarlyHandshakeSuccess> reportEarlySuccess;
592  if (psk) {
593  requestedExtensions.push_back(ExtensionType::pre_shared_key);
594  auto keyScheduler = context->getFactory()->makeKeyScheduler(psk->cipher);
595  auto handshakeContext =
596  context->getFactory()->makeHandshakeContext(psk->cipher);
597 
598  encodedClientHello = encodeAndAddBinders(
599  std::move(chlo), *psk, *keyScheduler, *handshakeContext);
600 
601  if (earlyDataParams) {
602  earlyWriteRecordLayer =
603  context->getFactory()->makeEncryptedWriteRecordLayer(
605  earlyWriteRecordLayer->setProtocolVersion(psk->version);
606  auto earlyWriteSecret = keyScheduler->getSecret(
608  handshakeContext->getHandshakeContext()->coalesce());
610  *earlyWriteRecordLayer,
611  psk->cipher,
612  folly::range(earlyWriteSecret),
613  *context->getFactory(),
614  *keyScheduler);
615 
616  auto earlyExporterVector = keyScheduler->getSecret(
618  handshakeContext->getHandshakeContext()->coalesce());
619  earlyDataParams->earlyExporterSecret =
620  folly::IOBuf::copyBuffer(folly::range(earlyExporterVector));
621 
622  reportEarlySuccess = ReportEarlyHandshakeSuccess();
623  reportEarlySuccess->maxEarlyDataSize = psk->maxEarlyDataSize;
624  }
625  } else {
626  encodedClientHello = encodeHandshake(std::move(chlo));
627  }
628 
629  auto readRecordLayer = context->getFactory()->makePlaintextReadRecordLayer();
630  auto writeRecordLayer =
631  context->getFactory()->makePlaintextWriteRecordLayer();
632 
634  write.contents.emplace_back(
635  writeRecordLayer->writeInitialClientHello(encodedClientHello->clone()));
636 
637  EarlyDataType earlyDataType =
639 
640  auto saveState = [context = std::move(context),
641  verifier = connect.verifier,
642  encodedClientHello = std::move(encodedClientHello),
643  readRecordLayer = std::move(readRecordLayer),
644  writeRecordLayer = std::move(writeRecordLayer),
645  keyExchangers = std::move(keyExchangers),
646  sni = std::move(connect.sni),
648  legacySessionId = std::move(legacySessionId),
649  psk = std::move(psk),
650  extensions = connect.extensions,
651  requestedExtensions = std::move(requestedExtensions),
652  earlyDataType](State& newState) mutable {
653  newState.context() = std::move(context);
654  newState.verifier() = verifier;
655  newState.encodedClientHello() = std::move(encodedClientHello);
656  newState.readRecordLayer() = std::move(readRecordLayer);
657  newState.writeRecordLayer() = std::move(writeRecordLayer);
658  newState.keyExchangers() = std::move(keyExchangers);
659  newState.sni() = std::move(sni);
660  newState.clientRandom() = std::move(random);
661  newState.legacySessionId() = std::move(legacySessionId);
662  newState.attemptedPsk() = std::move(psk);
663  newState.extensions() = extensions;
664  newState.requestedExtensions() = std::move(requestedExtensions);
665  newState.earlyDataType() = earlyDataType;
666  };
667 
668  if (reportEarlySuccess) {
669  return actions(
670  std::move(saveState),
671  [earlyDataParams = std::move(*earlyDataParams),
672  earlyWriteRecordLayer =
673  std::move(earlyWriteRecordLayer)](State& newState) mutable {
674  newState.earlyDataParams() = std::move(earlyDataParams);
675  newState.earlyWriteRecordLayer() = std::move(earlyWriteRecordLayer);
676  },
677  std::move(write),
678  std::move(*reportEarlySuccess),
679  &Transition<StateEnum::ExpectingServerHello>);
680  } else {
681  return actions(
682  std::move(saveState),
683  std::move(write),
684  &Transition<StateEnum::ExpectingServerHello>);
685  }
686 }
687 
688 template <typename ServerMessage>
689 static std::pair<ProtocolVersion, CipherSuite> getAndValidateVersionAndCipher(
690  const ServerMessage& msg,
691  const std::vector<ProtocolVersion>& supportedVersions,
692  const std::vector<CipherSuite>& supportedCiphers) {
693  if (msg.legacy_version != ProtocolVersion::tls_1_2) {
694  throw FizzException(
695  folly::to<std::string>(
696  "received server legacy version ", toString(msg.legacy_version)),
698  }
699 
700  if (msg.legacy_compression_method != 0x00) {
701  throw FizzException(
702  "compression method not null", AlertDescription::illegal_parameter);
703  }
704 
705  auto supportedVersionsExt =
706  getExtension<ServerSupportedVersions>(msg.extensions);
707  if (!supportedVersionsExt) {
708  throw FizzException(
709  "no supported versions in shlo", AlertDescription::protocol_version);
710  }
711  auto selectedVersion = supportedVersionsExt->selected_version;
712  auto selectedCipher = msg.cipher_suite;
713 
714  if (std::find(
715  supportedVersions.begin(),
716  supportedVersions.end(),
717  selectedVersion) == supportedVersions.end()) {
718  throw FizzException(
719  "received unsupported server version",
721  }
722  if (std::find(
723  supportedCiphers.begin(), supportedCiphers.end(), selectedCipher) ==
724  supportedCiphers.end()) {
725  throw FizzException(
726  "server choose unsupported cipher suite",
728  }
729 
730  return std::make_pair(selectedVersion, selectedCipher);
731 }
732 
734  const ServerHello& shlo,
735  const std::vector<ProtocolVersion>& supportedVersions,
736  const std::vector<CipherSuite>& supportedCiphers,
737  const std::map<NamedGroup, std::unique_ptr<KeyExchange>>& keyExchangers) {
740  std::tie(version, cipher) =
741  getAndValidateVersionAndCipher(shlo, supportedVersions, supportedCiphers);
742 
744  const auto serverShare = getExtension<ServerKeyShare>(shlo.extensions);
745  if (serverShare) {
746  auto kex = keyExchangers.find(serverShare->server_share.group);
747  if (kex == keyExchangers.end()) {
748  throw FizzException(
749  "server choose unsupported group",
751  }
752  exchange = std::make_tuple(
753  serverShare->server_share.group,
754  serverShare->server_share.key_exchange->clone(),
755  kex->second.get());
756  }
757 
758  return std::make_tuple(version, cipher, std::move(exchange));
759 }
760 
762  const State& state,
765  if (state.version() && *state.version() != version) {
766  throw FizzException(
767  "version does not match", AlertDescription::handshake_failure);
768  }
769  if (state.cipher() && *state.cipher() != cipher) {
770  throw FizzException(
771  "cipher does not match", AlertDescription::handshake_failure);
772  }
773 }
774 
775 namespace {
776 struct NegotiatedPsk {
779  std::shared_ptr<const Cert> serverCert;
780  std::shared_ptr<const Cert> clientCert;
781 
782  explicit NegotiatedPsk(
783  PskType type,
785  std::shared_ptr<const Cert> serverCert = nullptr,
786  std::shared_ptr<const Cert> clientCert = nullptr)
787  : type(type),
788  mode(mode),
789  serverCert(serverCert),
790  clientCert(clientCert) {}
791 };
792 } // namespace
793 
794 static NegotiatedPsk negotiatePsk(
795  const std::vector<PskKeyExchangeMode>& supportedPskModes,
796  const folly::Optional<CachedPsk>& attemptedPsk,
797  const ServerHello& shlo,
800  bool hasExchange) {
801  auto serverPsk = getExtension<ServerPresharedKey>(shlo.extensions);
802  if (!attemptedPsk) {
803  if (serverPsk) {
804  throw FizzException(
805  "server accepted unattempted psk",
807  } else if (!supportedPskModes.empty()) {
808  return NegotiatedPsk(PskType::NotAttempted);
809  } else {
810  return NegotiatedPsk(PskType::NotSupported);
811  }
812  } else {
813  if (!serverPsk) {
814  return NegotiatedPsk(PskType::Rejected);
815  }
816  if (serverPsk->selected_identity != 0) {
817  throw FizzException(
818  "server accepted non-0 psk", AlertDescription::illegal_parameter);
819  }
820 
821  if (version != attemptedPsk->version) {
822  throw FizzException(
823  "different version in psk", AlertDescription::handshake_failure);
824  }
825  if (getHashFunction(cipher) != getHashFunction(attemptedPsk->cipher)) {
826  throw FizzException(
827  "incompatible cipher in psk", AlertDescription::handshake_failure);
828  }
829 
832  if (std::find(supportedPskModes.begin(), supportedPskModes.end(), mode) ==
833  supportedPskModes.end()) {
834  throw FizzException(
835  "server choose unsupported psk mode",
837  }
838 
839  return NegotiatedPsk(
840  attemptedPsk->type,
841  mode,
842  attemptedPsk->serverCert,
843  attemptedPsk->clientCert);
844  }
845 }
846 
847 Actions
849  handle(const State& state, Param param) {
850  auto shlo = std::move(boost::get<ServerHello>(param));
851 
853 
857  std::tie(version, cipher, exchange) = negotiateParameters(
858  shlo,
859  state.context()->getSupportedVersions(),
860  state.context()->getSupportedCiphers(),
861  *state.keyExchangers());
862 
863  if (!folly::IOBufEqualTo()(
864  state.legacySessionId(), shlo.legacy_session_id_echo)) {
865  throw FizzException(
866  "session id echo mismatch", AlertDescription::illegal_parameter);
867  }
868 
869  validateNegotiationConsistency(state, version, cipher);
870 
871  auto negotiatedPsk = negotiatePsk(
872  state.context()->getSupportedPskModes(),
873  state.attemptedPsk(),
874  shlo,
875  version,
876  cipher,
877  exchange.hasValue());
878 
879  if (!exchange &&
880  !(negotiatedPsk.mode &&
881  *negotiatedPsk.mode == PskKeyExchangeMode::psk_ke)) {
882  throw FizzException(
883  "server did not send share", AlertDescription::handshake_failure);
884  }
885 
886  std::unique_ptr<HandshakeContext> handshakeContext;
887  if (state.handshakeContext()) {
888  handshakeContext = std::move(state.handshakeContext());
889  } else {
890  handshakeContext =
891  state.context()->getFactory()->makeHandshakeContext(cipher);
892  handshakeContext->appendToTranscript(state.encodedClientHello());
893  }
894  handshakeContext->appendToTranscript(*shlo.originalEncoding);
895 
896  auto scheduler = state.context()->getFactory()->makeKeyScheduler(cipher);
897 
898  if (negotiatedPsk.mode) {
899  scheduler->deriveEarlySecret(folly::range(state.attemptedPsk()->secret));
900  }
901 
903  Optional<KeyExchangeType> keyExchangeType;
904  if (exchange) {
905  if (state.keyExchangeType().hasValue()) {
906  keyExchangeType = *state.keyExchangeType();
907  } else {
908  keyExchangeType = KeyExchangeType::OneRtt;
909  }
910 
911  Buf serverShare;
912  const KeyExchange* kex;
913  std::tie(group, serverShare, kex) = std::move(*exchange);
914  auto sharedSecret = kex->generateSharedSecret(serverShare->coalesce());
915  scheduler->deriveHandshakeSecret(sharedSecret->coalesce());
916  } else {
917  keyExchangeType = KeyExchangeType::None;
918  scheduler->deriveHandshakeSecret();
919  }
920 
921  if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
922  throw FizzException(
923  "data after server hello", AlertDescription::unexpected_message);
924  }
925 
926  auto handshakeWriteRecordLayer =
929  handshakeWriteRecordLayer->setProtocolVersion(version);
930  auto handshakeWriteSecret = scheduler->getSecret(
932  handshakeContext->getHandshakeContext()->coalesce());
934  *handshakeWriteRecordLayer,
935  cipher,
936  folly::range(handshakeWriteSecret),
937  *state.context()->getFactory(),
938  *scheduler);
939 
940  auto handshakeReadRecordLayer =
943  handshakeReadRecordLayer->setProtocolVersion(version);
944  auto handshakeReadSecret = scheduler->getSecret(
946  handshakeContext->getHandshakeContext()->coalesce());
948  *handshakeReadRecordLayer,
949  cipher,
950  folly::range(handshakeReadSecret),
951  *state.context()->getFactory(),
952  *scheduler);
953 
954  auto clientHandshakeSecret =
955  folly::IOBuf::copyBuffer(folly::range(handshakeWriteSecret));
956  auto serverHandshakeSecret =
957  folly::IOBuf::copyBuffer(folly::range(handshakeReadSecret));
958 
960  if (negotiatedPsk.clientCert) {
961  authType = ClientAuthType::Stored;
962  } else if (negotiatedPsk.serverCert) {
963  authType = ClientAuthType::NotRequested;
964  }
965 
966  return actions(
967  [keyScheduler = std::move(scheduler),
968  readRecordLayer = std::move(handshakeReadRecordLayer),
969  writeRecordLayer = std::move(handshakeWriteRecordLayer),
970  handshakeContext = std::move(handshakeContext),
971  version,
972  cipher,
973  group,
974  clientHandshakeSecret = std::move(clientHandshakeSecret),
975  serverHandshakeSecret = std::move(serverHandshakeSecret),
976  keyExchangeType,
977  pskType = negotiatedPsk.type,
978  pskMode = negotiatedPsk.mode,
979  serverCert = std::move(negotiatedPsk.serverCert),
980  clientCert = std::move(negotiatedPsk.clientCert),
981  authType = std::move(authType)](State& newState) mutable {
982  newState.keyScheduler() = std::move(keyScheduler);
983  newState.readRecordLayer() = std::move(readRecordLayer);
984  newState.writeRecordLayer() = std::move(writeRecordLayer);
985  newState.handshakeContext() = std::move(handshakeContext);
986  newState.version() = version;
987  newState.cipher() = cipher;
988  newState.group() = group;
989  newState.encodedClientHello() = folly::none;
990  newState.keyExchangers() = folly::none;
991  newState.clientHandshakeSecret() = std::move(clientHandshakeSecret);
992  newState.serverHandshakeSecret() = std::move(serverHandshakeSecret);
993  newState.keyExchangeType() = keyExchangeType;
994  newState.pskType() = pskType;
995  newState.pskMode() = pskMode;
996  newState.serverCert() = std::move(serverCert);
997  newState.clientCert() = std::move(clientCert);
998  newState.clientAuthRequested() = std::move(authType);
999  },
1000  &Transition<StateEnum::ExpectingEncryptedExtensions>);
1001 }
1002 
1003 namespace {
1004 struct HrrParams {
1008 };
1009 } // namespace
1010 
1011 static HrrParams negotiateParameters(
1012  const HelloRetryRequest& hrr,
1013  const std::vector<ProtocolVersion>& supportedVersions,
1014  const std::vector<CipherSuite>& supportedCiphers,
1015  const std::vector<NamedGroup>& supportedGroups) {
1016  HrrParams negotiated;
1017  std::tie(negotiated.version, negotiated.cipher) =
1018  getAndValidateVersionAndCipher(hrr, supportedVersions, supportedCiphers);
1019 
1020  auto keyShare = getExtension<HelloRetryRequestKeyShare>(hrr.extensions);
1021  if (keyShare) {
1022  if (std::find(
1023  supportedGroups.begin(),
1024  supportedGroups.end(),
1025  keyShare->selected_group) == supportedGroups.end()) {
1026  throw FizzException(
1027  "server choose unsupported group in hrr",
1029  }
1030  negotiated.group = keyShare->selected_group;
1031  }
1032 
1033  return negotiated;
1034 }
1035 
1036 static std::map<NamedGroup, std::unique_ptr<KeyExchange>> getHrrKeyExchangers(
1037  const Factory& factory,
1038  std::map<NamedGroup, std::unique_ptr<KeyExchange>> previous,
1039  Optional<NamedGroup> negotiatedGroup) {
1040  if (negotiatedGroup) {
1041  if (previous.find(*negotiatedGroup) != previous.end()) {
1042  throw FizzException(
1043  "hrr selected already-sent group",
1045  }
1046  return getKeyExchangers(factory, {*negotiatedGroup});
1047  } else {
1048  return previous;
1049  }
1050 }
1051 
1053  ClientTypes,
1055  Event::HelloRetryRequest>::handle(const State& state, Param param) {
1056  auto hrr = std::move(boost::get<HelloRetryRequest>(param));
1057 
1059 
1060  if (state.keyExchangeType().hasValue()) {
1062  }
1063 
1064  auto negotiatedParams = negotiateParameters(
1065  hrr,
1066  state.context()->getSupportedVersions(),
1067  state.context()->getSupportedCiphers(),
1068  state.context()->getSupportedGroups());
1069 
1070  ProtocolVersion version = negotiatedParams.version;
1071  CipherSuite cipher = negotiatedParams.cipher;
1072  Optional<NamedGroup> group = negotiatedParams.group;
1073 
1074  auto cookie = getExtension<Cookie>(hrr.extensions);
1075 
1076  auto attemptedPsk = state.attemptedPsk();
1077  if (attemptedPsk &&
1078  getHashFunction(attemptedPsk->cipher) != getHashFunction(cipher)) {
1079  attemptedPsk = folly::none;
1080  }
1081 
1082  // We move the current key exchangers in so getHrrKeyExchangers can either
1083  // return the current set with ownership or create a new one.
1084  auto keyExchangers = getHrrKeyExchangers(
1085  *state.context()->getFactory(), std::move(*state.keyExchangers()), group);
1086 
1087  auto chlo = getClientHello(
1088  *state.context()->getFactory(),
1089  state.clientRandom(),
1090  state.context()->getSupportedCiphers(),
1091  state.context()->getSupportedVersions(),
1092  state.context()->getSupportedGroups(),
1093  keyExchangers,
1094  state.context()->getSupportedSigSchemes(),
1095  state.context()->getSupportedPskModes(),
1096  state.sni(),
1097  state.context()->getSupportedAlpns(),
1099  folly::none,
1100  state.legacySessionId(),
1101  state.extensions(),
1102  cookie ? std::move(cookie->cookie) : nullptr);
1103 
1104  auto firstHandshakeContext =
1105  state.context()->getFactory()->makeHandshakeContext(cipher);
1106  firstHandshakeContext->appendToTranscript(state.encodedClientHello());
1107 
1108  message_hash chloHash;
1109  chloHash.hash = firstHandshakeContext->getHandshakeContext();
1110 
1111  auto handshakeContext =
1112  state.context()->getFactory()->makeHandshakeContext(cipher);
1113  handshakeContext->appendToTranscript(encodeHandshake(std::move(chloHash)));
1114  handshakeContext->appendToTranscript(*hrr.originalEncoding);
1115 
1116  std::vector<ExtensionType> requestedExtensions;
1117  for (const auto& extension : chlo.extensions) {
1118  requestedExtensions.push_back(extension.extension_type);
1119  }
1120 
1121  Buf encodedClientHello;
1122  if (attemptedPsk) {
1123  requestedExtensions.push_back(ExtensionType::pre_shared_key);
1124  auto keyScheduler = state.context()->getFactory()->makeKeyScheduler(cipher);
1125 
1126  encodedClientHello = encodeAndAddBinders(
1127  std::move(chlo), *attemptedPsk, *keyScheduler, *handshakeContext);
1128  } else {
1129  encodedClientHello = encodeHandshake(std::move(chlo));
1130  handshakeContext->appendToTranscript(encodedClientHello);
1131  }
1132 
1133  auto earlyDataType = state.earlyDataType() == EarlyDataType::Attempted
1135  : state.earlyDataType();
1136 
1137  WriteToSocket clientFlight;
1138  auto chloWrite =
1139  state.writeRecordLayer()->writeHandshake(encodedClientHello->clone());
1140 
1141  bool sentCCS = state.sentCCS();
1143  if (state.context()->getCompatibilityMode() && !sentCCS) {
1144  TLSContent writeCCS;
1148  clientFlight.contents.emplace_back(std::move(writeCCS));
1149  sentCCS = true;
1150  }
1151  clientFlight.contents.emplace_back(std::move(chloWrite));
1152 
1153  return actions(
1154  [version,
1155  cipher,
1156  earlyDataType,
1157  encodedClientHello = std::move(encodedClientHello),
1158  keyExchangers = std::move(keyExchangers),
1159  handshakeContext = std::move(handshakeContext),
1160  attemptedPsk = std::move(attemptedPsk),
1161  requestedExtensions = std::move(requestedExtensions),
1162  sentCCS](State& newState) mutable {
1163  newState.version() = version;
1164  newState.cipher() = cipher;
1165  newState.earlyDataType() = earlyDataType;
1166  newState.earlyWriteRecordLayer() = nullptr;
1167  newState.encodedClientHello() = std::move(encodedClientHello);
1168  newState.keyExchangers() = std::move(keyExchangers);
1169  newState.handshakeContext() = std::move(handshakeContext);
1171  newState.attemptedPsk() = std::move(attemptedPsk);
1172  newState.requestedExtensions() = std::move(requestedExtensions);
1173  newState.sentCCS() = sentCCS;
1174  },
1175  std::move(clientFlight),
1176  &Transition<StateEnum::ExpectingServerHello>);
1177 }
1178 
1180  const State& state,
1181  const Optional<std::string>& alpn) {
1182  const auto& params = state.earlyDataParams();
1183 
1184  if (!state.attemptedPsk() || state.pskType() == PskType::Rejected ||
1185  !params) {
1186  throw FizzException(
1187  "early accepted without psk", AlertDescription::illegal_parameter);
1188  }
1189 
1190  if (params->cipher != state.cipher()) {
1191  throw FizzException(
1192  "early accepted with different cipher",
1194  }
1195 
1196  if (params->alpn != alpn) {
1197  throw FizzException(
1198  "early accepted with different alpn",
1200  }
1201 
1202  if (!state.earlyWriteRecordLayer()) {
1203  throw FizzException(
1204  "no early record layer", AlertDescription::illegal_parameter);
1205  }
1206 }
1207 
1209  ClientTypes,
1211  Event::EncryptedExtensions>::handle(const State& state, Param param) {
1212  auto ee = std::move(boost::get<EncryptedExtensions>(param));
1213 
1215 
1216  state.handshakeContext()->appendToTranscript(*ee.originalEncoding);
1217 
1218  Optional<std::string> appProto;
1219  auto alpn = getExtension<ProtocolNameList>(ee.extensions);
1220  if (alpn) {
1221  if (alpn->protocol_name_list.size() != 1) {
1222  throw FizzException(
1223  "alpn list does not contain exactly one protocol",
1225  }
1226  appProto =
1227  alpn->protocol_name_list.front().name->moveToFbString().toStdString();
1228  if (std::find(
1229  state.context()->getSupportedAlpns().begin(),
1230  state.context()->getSupportedAlpns().end(),
1231  *appProto) == state.context()->getSupportedAlpns().end()) {
1232  throw FizzException(
1233  folly::to<std::string>("alpn mismatch: server choose ", *appProto),
1235  }
1236  }
1237 
1238  auto serverEarly = getExtension<ServerEarlyData>(ee.extensions);
1239  auto earlyDataType = state.earlyDataType();
1240  if (state.earlyDataType() == EarlyDataType::Attempted) {
1241  if (serverEarly) {
1242  validateAcceptedEarly(state, appProto);
1243  earlyDataType = EarlyDataType::Accepted;
1244  } else {
1245  earlyDataType = EarlyDataType::Rejected;
1246  }
1247  } else {
1248  if (serverEarly) {
1249  throw FizzException(
1250  "unexpected accepted early data",
1252  }
1253  }
1254 
1255  if (state.extensions()) {
1256  state.extensions()->onEncryptedExtensions(ee.extensions);
1257  }
1258 
1259  auto mutateState = [appProto = std::move(appProto),
1260  earlyDataType](State& newState) mutable {
1261  newState.alpn() = std::move(appProto);
1262  newState.requestedExtensions() = folly::none;
1263  newState.earlyDataType() = earlyDataType;
1264  };
1265 
1266  if (state.serverCert() != nullptr) {
1267  return actions(
1268  std::move(mutateState), &Transition<StateEnum::ExpectingFinished>);
1269  } else {
1270  return actions(
1271  std::move(mutateState), &Transition<StateEnum::ExpectingCertificate>);
1272  }
1273 }
1274 
1275 static std::tuple<
1277  std::shared_ptr<const SelfCert>>
1278 getClientCert(const State& state, const std::vector<SignatureScheme>& schemes) {
1279  folly::Optional<SignatureScheme> selectedScheme;
1280  auto clientCert = state.context()->getClientCertificate();
1281  const auto& supportedSchemes = state.context()->getSupportedSigSchemes();
1282 
1283  if (clientCert) {
1284  const auto certSchemes = clientCert->getSigSchemes();
1285  for (const auto& scheme : supportedSchemes) {
1286  if (std::find(certSchemes.begin(), certSchemes.end(), scheme) !=
1287  certSchemes.end() &&
1288  std::find(schemes.begin(), schemes.end(), scheme) != schemes.end()) {
1289  selectedScheme = scheme;
1290  break;
1291  }
1292  }
1293 
1294  if (!selectedScheme) {
1295  VLOG(1) << "client cert/context doesn't support any signature algorithms "
1296  << "specified by the server";
1297  }
1298  }
1299 
1300  if (!selectedScheme) {
1301  clientCert = nullptr;
1302  }
1303 
1304  return std::make_tuple(std::move(selectedScheme), std::move(clientCert));
1305 }
1306 
1308  ClientTypes,
1310  Event::CertificateRequest>::handle(const State& state, Param param) {
1311  if (state.clientAuthRequested()) {
1312  throw FizzException(
1313  "duplicate certificate request message",
1315  }
1316 
1317  auto certRequest = std::move(boost::get<CertificateRequest>(param));
1318  state.handshakeContext()->appendToTranscript(*certRequest.originalEncoding);
1319 
1320  if (!certRequest.certificate_request_context->empty()) {
1321  throw FizzException(
1322  "certificate request context must be empty",
1324  }
1325 
1326  auto sigAlgsExtension =
1327  getExtension<SignatureAlgorithms>(certRequest.extensions);
1328  if (!sigAlgsExtension) {
1329  throw FizzException(
1330  "certificate request without signature algorithms",
1332  }
1333 
1334  folly::Optional<SignatureScheme> scheme;
1335  std::shared_ptr<const SelfCert> cert;
1336  std::tie(scheme, cert) =
1337  getClientCert(state, sigAlgsExtension->supported_signature_algorithms);
1338  ClientAuthType authType =
1340 
1341  auto mutateState = [scheme = std::move(scheme),
1342  cert = std::move(cert),
1343  authType](State& newState) mutable {
1344  newState.clientAuthRequested() = authType;
1345  newState.selectedClientCert() = std::move(cert);
1346  newState.clientAuthSigScheme() = std::move(scheme);
1347  };
1348 
1349  return actions(
1350  std::move(mutateState), &Transition<StateEnum::ExpectingCertificate>);
1351 }
1352 
1354  const State& state,
1355  CertificateMsg certMsg,
1357  if (!certMsg.certificate_request_context->empty()) {
1358  throw FizzException(
1359  "certificate request context must be empty",
1361  }
1362 
1363  std::vector<std::shared_ptr<const PeerCert>> serverCerts;
1364  for (auto& certEntry : certMsg.certificate_list) {
1365  // We don't request any certificate-related extensions
1366  if (!certEntry.extensions.empty()) {
1367  throw FizzException(
1368  "certificate extensions must be empty",
1370  }
1371 
1372  serverCerts.emplace_back(state.context()->getFactory()->makePeerCert(
1373  std::move(certEntry.cert_data)));
1374  }
1375 
1376  if (serverCerts.empty()) {
1377  throw FizzException(
1378  "no certificates received", AlertDescription::illegal_parameter);
1379  }
1380 
1381  ClientAuthType authType =
1383 
1384  return [unverifiedCertChain = std::move(serverCerts),
1385  authType,
1386  compAlgo = std::move(algo)](State& newState) mutable {
1387  newState.unverifiedCertChain() = std::move(unverifiedCertChain);
1388  newState.clientAuthRequested() = authType;
1389  newState.serverCertCompAlgo() = std::move(compAlgo);
1390  };
1391 }
1392 
1394  ClientTypes,
1396  Event::CompressedCertificate>::handle(const State& state, Param param) {
1397  if (state.context()->getSupportedCertDecompressionAlgorithms().empty()) {
1398  throw FizzException(
1399  "compressed certificate received unexpectedly",
1401  }
1402 
1403  auto compCert = std::move(boost::get<CompressedCertificate>(param));
1404  state.handshakeContext()->appendToTranscript(*compCert.originalEncoding);
1405 
1406  auto algos = state.context()->getSupportedCertDecompressionAlgorithms();
1407  if (std::find(algos.begin(),
1408  algos.end(),
1409  compCert.algorithm) == algos.end()) {
1410  throw FizzException(
1411  "certificate compressed with unsupported algorithm: " +
1412  toString(compCert.algorithm),
1414  }
1415 
1416  auto decompressor =
1417  state.context()->getCertDecompressorForAlgorithm(compCert.algorithm);
1418  DCHECK(decompressor);
1419 
1420  CertificateMsg msg;
1421  try {
1422  msg = decompressor->decompress(compCert);
1423  } catch (const std::exception& e) {
1424  throw FizzException(
1425  folly::to<std::string>("certificate decompression failed: ", e.what()),
1427  }
1428 
1429  return actions(
1430  handleCertMsg(state, std::move(msg), compCert.algorithm),
1431  &Transition<StateEnum::ExpectingCertificateVerify>);
1432 }
1433 
1434 Actions
1436  handle(const State& state, Param param) {
1437  auto certMsg = std::move(boost::get<CertificateMsg>(param));
1438 
1439  state.handshakeContext()->appendToTranscript(*certMsg.originalEncoding);
1440 
1441  return actions(
1442  handleCertMsg(state, std::move(certMsg), folly::none),
1443  &Transition<StateEnum::ExpectingCertificateVerify>);
1444 }
1445 
1447  ClientTypes,
1449  Event::CertificateVerify>::handle(const State& state, Param param) {
1450  auto certVerify = std::move(boost::get<CertificateVerify>(param));
1451 
1452  if (std::find(
1453  state.context()->getSupportedSigSchemes().begin(),
1454  state.context()->getSupportedSigSchemes().end(),
1455  certVerify.algorithm) ==
1456  state.context()->getSupportedSigSchemes().end()) {
1457  throw FizzException(
1458  folly::to<std::string>(
1459  "server choose unsupported sig scheme: ",
1460  toString(certVerify.algorithm)),
1462  }
1463 
1464  CHECK(!state.unverifiedCertChain().empty());
1465  auto leaf = state.unverifiedCertChain().front();
1466 
1467  leaf->verify(
1468  certVerify.algorithm,
1470  state.handshakeContext()->getHandshakeContext()->coalesce(),
1471  certVerify.signature->coalesce());
1472 
1473  if (state.verifier()) {
1474  try {
1475  state.verifier()->verify(state.unverifiedCertChain());
1476  } catch (const FizzException&) {
1477  std::rethrow_exception(std::current_exception());
1478  } catch (const std::exception& e) {
1480  folly::to<std::string>("verifier failure: ", e.what()),
1482  }
1483  }
1484 
1485  state.handshakeContext()->appendToTranscript(*certVerify.originalEncoding);
1486 
1487  return actions(
1488  [sigScheme = certVerify.algorithm,
1489  serverCert = std::move(leaf)](State& newState) mutable {
1490  newState.sigScheme() = sigScheme;
1491  newState.serverCert() = std::move(serverCert);
1492  newState.unverifiedCertChain() = folly::none;
1493  },
1494  &Transition<StateEnum::ExpectingFinished>);
1495 }
1496 
1497 Actions
1499  handle(const State& state, Param param) {
1500  auto finished = std::move(boost::get<Finished>(param));
1501 
1502  if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1503  throw FizzException(
1504  "data after finished", AlertDescription::unexpected_message);
1505  }
1506 
1507  auto expectedFinished = state.handshakeContext()->getFinishedData(
1508  state.serverHandshakeSecret()->coalesce());
1509  if (!CryptoUtils::equal(
1510  expectedFinished->coalesce(), finished.verify_data->coalesce())) {
1511  throw FizzException(
1512  "server finished verify failure", AlertDescription::bad_record_mac);
1513  }
1514 
1515  state.handshakeContext()->appendToTranscript(*finished.originalEncoding);
1516  auto clientFinishedContext = state.handshakeContext()->getHandshakeContext();
1517  state.keyScheduler()->deriveMasterSecret();
1518 
1519  folly::Optional<TLSContent> eoedWrite;
1520  if (state.earlyDataType() == EarlyDataType::Accepted) {
1521  auto encodedEndOfEarly = encodeHandshake(EndOfEarlyData());
1522  state.handshakeContext()->appendToTranscript(encodedEndOfEarly);
1523  DCHECK(state.earlyWriteRecordLayer());
1524  eoedWrite = state.earlyWriteRecordLayer()->writeHandshake(
1525  std::move(encodedEndOfEarly));
1526  }
1527 
1528  folly::Optional<Buf> encodedCertMessage;
1530  auto auth = *state.clientAuthRequested();
1531  std::shared_ptr<const Cert> clientCert;
1532  switch (auth) {
1534  clientCert = state.clientCert();
1535  break;
1537  encodedCertMessage = encodeHandshake(CertificateMsg());
1538  state.handshakeContext()->appendToTranscript(*encodedCertMessage);
1539  break;
1540  case ClientAuthType::Sent: {
1541  auto selectedCert = state.selectedClientCert();
1542  encodedCertMessage = encodeHandshake(selectedCert->getCertMessage());
1543  state.handshakeContext()->appendToTranscript(*encodedCertMessage);
1544 
1545  auto sigScheme = *state.clientAuthSigScheme();
1546  auto toSign = state.handshakeContext()->getHandshakeContext();
1547  auto signature = selectedCert->sign(
1548  sigScheme, CertificateVerifyContext::Client, toSign->coalesce());
1549 
1551  verify.algorithm = sigScheme;
1552  verify.signature = std::move(signature);
1553  encodedCertVerify = encodeHandshake(std::move(verify));
1554  state.handshakeContext()->appendToTranscript(*encodedCertVerify);
1555 
1556  clientCert = selectedCert;
1557  break;
1558  }
1560  break;
1561  }
1562 
1563  auto exporterMasterVector = state.keyScheduler()->getSecret(
1564  MasterSecrets::ExporterMaster, clientFinishedContext->coalesce());
1565  auto exporterMaster =
1566  folly::IOBuf::copyBuffer(folly::range(exporterMasterVector));
1567 
1568  auto encodedFinished = Protocol::getFinished(
1569  state.clientHandshakeSecret()->coalesce(), *state.handshakeContext());
1570  auto resumptionSecret =
1573  state.handshakeContext()->getHandshakeContext()->coalesce())));
1574 
1575  WriteToSocket clientFlight;
1576 
1577  bool sentCCS = state.sentCCS();
1578  if (state.context()->getCompatibilityMode() && !sentCCS) {
1579  TLSContent writeCCS;
1583  clientFlight.contents.emplace_back(std::move(writeCCS));
1584  sentCCS = true;
1585  }
1586 
1587  if (eoedWrite) {
1588  clientFlight.contents.emplace_back(std::move(*eoedWrite));
1589  }
1590 
1591  if (auth == ClientAuthType::RequestedNoMatch) {
1592  clientFlight.contents.emplace_back(state.writeRecordLayer()->writeHandshake(
1593  std::move(*encodedCertMessage), std::move(encodedFinished)));
1594  } else if (auth == ClientAuthType::Sent) {
1595  clientFlight.contents.emplace_back(state.writeRecordLayer()->writeHandshake(
1596  std::move(*encodedCertMessage),
1597  std::move(*encodedCertVerify),
1598  std::move(encodedFinished)));
1599  } else {
1600  clientFlight.contents.emplace_back(
1601  state.writeRecordLayer()->writeHandshake(std::move(encodedFinished)));
1602  }
1603 
1605  clientFinishedContext->coalesce());
1606  state.keyScheduler()->clearMasterSecret();
1607 
1608  auto writeRecordLayer =
1611  writeRecordLayer->setProtocolVersion(*state.version());
1612  auto writeSecret =
1615  *writeRecordLayer,
1616  *state.cipher(),
1617  folly::range(writeSecret),
1618  *state.context()->getFactory(),
1619  *state.keyScheduler());
1620 
1621  auto readRecordLayer =
1624  readRecordLayer->setProtocolVersion(*state.version());
1625  auto readSecret =
1628  *readRecordLayer,
1629  *state.cipher(),
1630  folly::range(readSecret),
1631  *state.context()->getFactory(),
1632  *state.keyScheduler());
1633 
1634  ReportHandshakeSuccess reportSuccess;
1635  reportSuccess.earlyDataAccepted =
1637 
1638  return actions(
1639  [readRecordLayer = std::move(readRecordLayer),
1640  writeRecordLayer = std::move(writeRecordLayer),
1641  resumptionSecret = std::move(resumptionSecret),
1642  exporterMaster = std::move(exporterMaster),
1643  clientCert = std::move(clientCert),
1644  sentCCS](State& newState) mutable {
1645  newState.readRecordLayer() = std::move(readRecordLayer);
1646  newState.writeRecordLayer() = std::move(writeRecordLayer);
1647  newState.earlyWriteRecordLayer() = nullptr;
1648  newState.clientHandshakeSecret() = folly::none;
1649  newState.serverHandshakeSecret() = folly::none;
1650  newState.resumptionSecret() = std::move(resumptionSecret);
1651  newState.exporterMasterSecret() = std::move(exporterMaster);
1652  newState.selectedClientCert() = nullptr;
1653  newState.clientCert() = std::move(clientCert);
1654  newState.sentCCS() = sentCCS;
1655  },
1656  &Transition<StateEnum::Established>,
1657  std::move(clientFlight),
1658  std::move(reportSuccess));
1659 }
1660 
1662  auto earlyData = getExtension<TicketEarlyData>(nst.extensions);
1663  if (earlyData) {
1664  return earlyData->max_early_data_size;
1665  } else {
1666  return 0;
1667  }
1668 }
1669 
1670 Actions
1672  handle(const State& state, Param param) {
1673  auto nst = std::move(boost::get<NewSessionTicket>(param));
1674 
1675  auto derivedResumptionSecret = state.keyScheduler()->getResumptionSecret(
1676  state.resumptionSecret()->coalesce(), nst.ticket_nonce->coalesce());
1677 
1678  auto pskRange = nst.ticket->coalesce();
1679  auto secretRange = derivedResumptionSecret->coalesce();
1680 
1681  NewCachedPsk newCachedPsk;
1682  newCachedPsk.psk.psk = std::string(pskRange.begin(), pskRange.end());
1683  newCachedPsk.psk.secret = std::string(secretRange.begin(), secretRange.end());
1684  newCachedPsk.psk.type = PskType::Resumption;
1685  newCachedPsk.psk.version = *state.version();
1686  newCachedPsk.psk.cipher = *state.cipher();
1687  newCachedPsk.psk.group = state.group();
1688  newCachedPsk.psk.serverCert = state.serverCert();
1689  newCachedPsk.psk.clientCert = state.clientCert();
1690  newCachedPsk.psk.alpn = state.alpn();
1691  newCachedPsk.psk.ticketAgeAdd = nst.ticket_age_add;
1694  std::chrono::seconds(nst.ticket_lifetime);
1695  newCachedPsk.psk.maxEarlyDataSize = getMaxEarlyDataSize(nst);
1696 
1697  return actions(std::move(newCachedPsk));
1698 }
1699 
1700 Actions
1702  const State&,
1703  Param param) {
1704  auto& appData = boost::get<AppData>(param);
1705 
1706  return actions(DeliverAppData{std::move(appData.data)});
1707 }
1708 
1709 Actions
1711  const State& state,
1712  Param param) {
1713  auto& appWrite = boost::get<AppWrite>(param);
1714 
1716  write.callback = appWrite.callback;
1717  write.contents.emplace_back(
1719  write.flags = appWrite.flags;
1720 
1721  return actions(std::move(write));
1722 }
1723 
1724 Actions
1726  const State& state,
1727  Param param) {
1728  auto& keyUpdate = boost::get<KeyUpdate>(param);
1729 
1730  if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1731  throw FizzException(
1732  "data after key_update", AlertDescription::unexpected_message);
1733  }
1734  state.keyScheduler()->serverKeyUpdate();
1735  auto readRecordLayer =
1738  readRecordLayer->setProtocolVersion(*state.version());
1739  auto readSecret =
1742  *readRecordLayer,
1743  *state.cipher(),
1744  folly::range(readSecret),
1745  *state.context()->getFactory(),
1746  *state.keyScheduler());
1747 
1748  if (keyUpdate.request_update == KeyUpdateRequest::update_not_requested) {
1749  return actions(
1750  [rRecordLayer = std::move(readRecordLayer)](State& newState) mutable {
1751  newState.readRecordLayer() = std::move(rRecordLayer);
1752  });
1753  }
1754 
1755  auto encodedKeyUpdated =
1758  write.contents.emplace_back(
1759  state.writeRecordLayer()->writeHandshake(std::move(encodedKeyUpdated)));
1760 
1761  state.keyScheduler()->clientKeyUpdate();
1762 
1763  auto writeRecordLayer =
1766  writeRecordLayer->setProtocolVersion(*state.version());
1767  auto writeSecret =
1770  *writeRecordLayer,
1771  *state.cipher(),
1772  folly::range(writeSecret),
1773  *state.context()->getFactory(),
1774  *state.keyScheduler());
1775 
1776  return actions(
1777  [rRecordLayer = std::move(readRecordLayer),
1778  wRecordLayer = std::move(writeRecordLayer)](State& newState) mutable {
1779  newState.readRecordLayer() = std::move(rRecordLayer);
1780  newState.writeRecordLayer() = std::move(wRecordLayer);
1781  },
1782  std::move(write));
1783 }
1784 
1785 // If we get an early data write after early data has been rejected we won't
1786 // bother writing the data out but we can't just throw away the data without
1787 // invoking a method on the write callback. Since the proper write callback
1788 // action to invoke depends on how the higher layer will react to rejected
1789 // early data, we give the write back in a special action for the higher layer
1790 // to handle.
1792  if (*state.earlyDataType() != EarlyDataType::Rejected) {
1793  throw FizzException("ignoring valid early write", folly::none);
1794  }
1795 
1796  ReportEarlyWriteFailed failedWrite;
1797  failedWrite.write = std::move(write);
1798  return actions(std::move(failedWrite));
1799 }
1800 
1802  switch (*state.earlyDataType()) {
1804  throw FizzException("invalid early write", folly::none);
1806  return ignoreEarlyAppWrite(state, std::move(appWrite));
1808  case EarlyDataType::Accepted: {
1810  write.callback = appWrite.callback;
1811  write.flags = appWrite.flags;
1812  auto appData =
1813  state.earlyWriteRecordLayer()->writeAppData(std::move(appWrite.data));
1814 
1815  if (!state.sentCCS() && state.context()->getCompatibilityMode()) {
1816  TLSContent writeCCS;
1820  write.contents.emplace_back(std::move(writeCCS));
1821  write.contents.emplace_back(std::move(appData));
1822  return actions(
1823  [](State& newState) { newState.sentCCS() = true; },
1824  std::move(write));
1825  } else {
1826  write.contents.emplace_back(std::move(appData));
1827  return actions(std::move(write));
1828  }
1829  }
1830  }
1831  LOG(FATAL) << "Bad EarlyDataType";
1832 }
1833 
1835  ClientTypes,
1837  Event::EarlyAppWrite>::handle(const State& state, Param param) {
1838  return handleEarlyAppWrite(
1839  state, std::move(boost::get<EarlyAppWrite>(param)));
1840 }
1841 
1843  ClientTypes,
1845  Event::EarlyAppWrite>::handle(const State& state, Param param) {
1846  return handleEarlyAppWrite(
1847  state, std::move(boost::get<EarlyAppWrite>(param)));
1848 }
1849 
1851  ClientTypes,
1853  Event::EarlyAppWrite>::handle(const State& state, Param param) {
1854  return ignoreEarlyAppWrite(
1855  state, std::move(boost::get<EarlyAppWrite>(param)));
1856 }
1857 
1859  ClientTypes,
1861  Event::EarlyAppWrite>::handle(const State& state, Param param) {
1862  return ignoreEarlyAppWrite(
1863  state, std::move(boost::get<EarlyAppWrite>(param)));
1864 }
1865 
1866 Actions
1868  handle(const State& state, Param param) {
1869  return handleEarlyAppWrite(
1870  state, std::move(boost::get<EarlyAppWrite>(param)));
1871 }
1872 
1873 Actions
1875  const State& state,
1876  Param param) {
1877  auto appWrite = std::move(boost::get<EarlyAppWrite>(param));
1878  if (*state.earlyDataType() == EarlyDataType::Accepted) {
1879  // It's possible that we had queued early writes before full handshake
1880  // success. It's fine to write them on the normal record layer as long as
1881  // the early data was accepted, otherwise we need to ignore them to preserve
1882  // the all-or-nothing property of early data.
1884  write.callback = appWrite.callback;
1885  write.contents.emplace_back(
1887  write.flags = appWrite.flags;
1888  return actions(std::move(write));
1889  } else {
1890  return ignoreEarlyAppWrite(state, std::move(appWrite));
1891  }
1892 }
1893 } // namespace sm
1894 } // namespace fizz
ClientAuthType
Definition: State.h:42
std::vector< Extension > extensions
Definition: Types.h:218
std::shared_ptr< const Cert > serverCert
Definition: State.h:52
std::unique_ptr< folly::IOBuf > split(size_t n)
Definition: IOBufQueue.h:420
const Buf & encodedClientHello() const
Definition: State.h:263
const auto & getSupportedGroups() const
std::unique_ptr< folly::IOBuf > data
Definition: Params.h:48
std::shared_ptr< const client::FizzClientContext > context
Definition: Params.h:39
TLSContent writeHandshake(Buf &&encodedHandshakeMsg, Args &&...args) const
Definition: RecordLayer.h:74
static std::pair< ProtocolVersion, CipherSuite > getAndValidateVersionAndCipher(const ServerMessage &msg, const std::vector< ProtocolVersion > &supportedVersions, const std::vector< CipherSuite > &supportedCiphers)
static void setAead(Type &recordLayer, CipherSuite cipher, folly::ByteRange secret, const Factory &factory, const KeyScheduler &scheduler)
Definition: Protocol.h:20
uint32_t obfuscated_ticket_age
Definition: Extensions.h:56
Buf encodeHandshake(T &&handshakeMsg)
Definition: Types-inl.h:515
std::shared_ptr< const CertificateVerifier > verifier
Definition: Params.h:40
auto & handshakeContext() const
Definition: State.h:376
folly::WriteFlags flags
Definition: Actions.h:43
Integral2 random(Integral1 low, Integral2 up)
folly::Optional< client::CachedPsk > cachedPsk
Definition: Params.h:42
folly::StringPiece toString(StateEnum state)
Definition: State.cpp:16
virtual bool hasUnparsedHandshakeData() const
std::vector< PskBinder > binders
Definition: Extensions.h:65
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
static Optional< EarlyDataParams > getEarlyDataParams(const FizzClientContext &context, const Optional< CachedPsk > &psk)
size_t getBinderLength(const ClientHello &chlo)
std::shared_ptr< const Cert > clientCert
Definition: PskCache.h:29
static Actions ignoreEarlyAppWrite(const State &state, EarlyAppWrite write)
void verify(int extras)
size_t chainLength() const
Definition: IOBufQueue.h:492
std::chrono::system_clock::time_point ticketIssueTime
Definition: PskCache.h:35
const Buf & clientHandshakeSecret() const
Definition: State.h:283
#define FIZZ_DECLARE_EVENT_HANDLER(sm, statename, eventname,...)
virtual void deriveEarlySecret(folly::ByteRange psk)
void write(const T &in, folly::io::Appender &appender)
Definition: Types-inl.h:112
int connect(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:94
TLSContent writeAlert(Alert &&alert) const
Definition: RecordLayer.h:65
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
const auto & getSupportedAlpns() const
folly::Optional< EarlyDataType > earlyDataType() const
Definition: State.h:156
static const std::string chlo
folly::Optional< std::string > alpn
Definition: PskCache.h:32
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
const auto & getSupportedVersions() const
size_t getHashSize(HashFunction hash)
Definition: Types.cpp:25
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
virtual std::vector< uint8_t > getSecret(EarlySecrets s, folly::ByteRange transcript) const
Actions handleError(const State &state, ReportError error, Optional< AlertDescription > alertDesc)
StringPiece cookie
std::shared_ptr< ClientExtensions > extensions
Definition: Params.h:43
static bool equal(folly::ByteRange a, folly::ByteRange b)
Definition: Utils.cpp:31
virtual void appendToTranscript(const Buf &transcript)=0
std::shared_ptr< const SelfCert > selectedClientCert() const
Definition: State.h:320
PskType type
virtual Buf getFinishedData(folly::ByteRange baseKey) const =0
context
Definition: CMakeCache.txt:563
std::unique_ptr< folly::IOBuf > hash
Definition: Types.h:82
NamedGroup
Definition: Types.h:302
std::chrono::steady_clock::time_point now()
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static uint32_t getMaxEarlyDataSize(const NewSessionTicket &nst)
folly::small_vector< TLSContent, 4 > contents
Definition: Actions.h:41
folly::Optional< NamedGroup > group() const
Definition: State.h:120
CipherSuite
Definition: Types.h:153
StringPiece alpn
std::shared_ptr< CertificateDecompressor > getCertDecompressorForAlgorithm(CertificateCompressionAlgorithm algo) const
virtual std::unique_ptr< KeyScheduler > makeKeyScheduler(CipherSuite cipher) const
Definition: Factory.h:56
std::vector< PskKeyExchangeMode > modes
Definition: Extensions.h:105
virtual void onEncryptedExtensions(const std::vector< Extension > &extensions)=0
const Buf & legacySessionId() const
Definition: State.h:208
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
StateEnum state() const
Definition: State.h:63
std::vector< NamedGroup > named_group_list
Definition: Extensions.h:23
Actions handleAppClose(const State &state)
ReadRecordLayer * readRecordLayer() const
Definition: State.h:235
static AppWrite appWrite(const std::string &str)
ProtocolVersion legacy_version
Definition: Types.h:188
virtual std::unique_ptr< KeyExchange > makeKeyExchange(NamedGroup group) const
Definition: Factory.h:90
std::shared_ptr< const Cert > clientCert
Definition: State.h:53
const Buf & serverHandshakeSecret() const
Definition: State.h:292
constexpr folly::StringPiece FakeChangeCipherSpec
Definition: Types.h:59
folly::Optional< ProtocolVersion > version() const
Definition: State.h:106
static const std::string encodedCertVerify
std::shared_ptr< folly::FunctionScheduler > scheduler
Definition: FilePoller.cpp:50
std::vector< Extension > extensions
Definition: Types.h:289
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
Buf certificate_request_context
Definition: Types.h:238
tuple make_tuple()
Definition: gtest-tuple.h:675
virtual Actions processEarlyAppWrite(const State &, EarlyAppWrite)
std::vector< KeyShareEntry > client_shares
Definition: Extensions.h:34
const Factory * getFactory() const
virtual folly::ByteRange getBlankContext() const =0
const std::vector< std::shared_ptr< const PeerCert > > & unverifiedCertChain() const
Definition: State.h:310
static ClientHello getClientHello(const Factory &, const Random &random, const std::vector< CipherSuite > &supportedCiphers, const std::vector< ProtocolVersion > &supportedVersions, const std::vector< NamedGroup > &supportedGroups, const std::map< NamedGroup, std::unique_ptr< KeyExchange >> &shares, const std::vector< SignatureScheme > &supportedSigSchemes, const std::vector< PskKeyExchangeMode > &supportedPskModes, const folly::Optional< std::string > &hostname, const std::vector< std::string > &supportedAlpns, const std::vector< CertificateCompressionAlgorithm > &compressionAlgos, const Optional< EarlyDataParams > &earlyDataParams, const Buf &legacySessionId, ClientExtensions *extensions, Buf cookie=nullptr)
static std::map< NamedGroup, std::unique_ptr< KeyExchange > > getKeyExchangers(const Factory &factory, const std::vector< NamedGroup > &groups)
CipherSuite cipher
ProtocolVersion version
Definition: PskCache.h:25
const auto & getSupportedCiphers() const
const Buf & resumptionSecret() const
Definition: State.h:301
virtual Actions processConnect(const State &, std::shared_ptr< const FizzClientContext > context, std::shared_ptr< const CertificateVerifier > verifier, folly::Optional< std::string > sni, folly::Optional< CachedPsk > cachedPsk, const std::shared_ptr< ClientExtensions > &extensions)
folly::Optional< CipherSuite > cipher() const
Definition: State.h:113
Random random
Definition: Types.h:189
NamedGroup group
Definition: Extensions.h:29
folly::Optional< PskKeyExchangeMode > mode
const folly::Optional< std::string > & alpn() const
Definition: State.h:170
virtual Actions processAppClose(const State &)
virtual std::shared_ptr< PeerCert > makePeerCert(Buf certData) const
Definition: Factory.h:128
ProtocolVersion
Definition: Types.h:24
const Random & clientRandom() const
Definition: State.h:200
HashFunction getHashFunction(CipherSuite cipher)
Definition: Types.cpp:13
virtual std::unique_ptr< EncryptedReadRecordLayer > makeEncryptedReadRecordLayer(EncryptionLevel encryptionLevel) const
Definition: Factory.h:47
ProtocolVersion version
std::vector< CertificateEntry > certificate_list
Definition: Types.h:239
std::shared_ptr< const Cert > clientCert() const
Definition: State.h:84
Buf legacy_session_id
Definition: Types.h:190
auto & keyExchangers() const
Definition: State.h:464
folly::Optional< NamedGroup > group
Definition: PskCache.h:27
static NegotiatedPsk negotiatePsk(const std::vector< PskKeyExchangeMode > &supportedPskModes, const folly::Optional< CachedPsk > &attemptedPsk, const ServerHello &shlo, ProtocolVersion version, CipherSuite cipher, bool hasExchange)
constexpr Params params[]
virtual uint32_t serverKeyUpdate()
static MutateState handleCertMsg(const State &state, CertificateMsg certMsg, folly::Optional< CertificateCompressionAlgorithm > algo)
static Options cacheChainLength()
Definition: IOBufQueue.h:83
virtual Actions processAppWrite(const State &, AppWrite)
folly::Optional< KeyExchangeType > keyExchangeType() const
Definition: State.h:149
folly::Optional< AlertDescription > getAlert() const
Definition: Types.h:324
std::string secret
Definition: PskCache.h:22
std::vector< Action > Actions
Definition: Actions.h:81
const folly::Optional< std::string > & sni() const
Definition: State.h:177
virtual folly::Optional< Param > readEvent(folly::IOBufQueue &socketBuf)
Definition: RecordLayer.cpp:18
static Buf encodeAndAddBinders(ClientHello chlo, const CachedPsk &psk, KeyScheduler &scheduler, HandshakeContext &handshakeContext)
const folly::Optional< EarlyDataParams > & earlyDataParams() const
Definition: State.h:163
folly::WriteFlags flags
Definition: Params.h:49
ClientExtensions * extensions() const
Definition: State.h:344
folly::Optional< PskType > pskType() const
Definition: State.h:135
const WriteRecordLayer * writeRecordLayer() const
Definition: State.h:245
static HrrParams negotiateParameters(const HelloRetryRequest &hrr, const std::vector< ProtocolVersion > &supportedVersions, const std::vector< CipherSuite > &supportedCiphers, const std::vector< NamedGroup > &supportedGroups)
static EventHandlerFun getHandler(typename SM::StateEnum state, typename SM::Event event)
virtual Buf getResumptionSecret(folly::ByteRange resumptionMasterSecret, folly::ByteRange ticketNonce) const
static std::tuple< folly::Optional< SignatureScheme >, std::shared_ptr< const SelfCert > > getClientCert(const State &state, const std::vector< SignatureScheme > &schemes)
static Map map(mapCap)
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
Definition: Optional.h:300
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
std::vector< SignatureScheme > supported_signature_algorithms
Definition: Extensions.h:17
EncryptionLevel encryptionLevel
Definition: RecordLayer.h:21
Definition: Actions.h:16
virtual std::unique_ptr< HandshakeContext > makeHandshakeContext(CipherSuite cipher) const
Definition: Factory.h:76
KeyScheduler * keyScheduler() const
Definition: State.h:225
virtual Actions processWriteNewSessionTicket(const State &, WriteNewSessionTicket)
std::vector< Extension > extensions
Definition: Types.h:193
virtual Actions processSocketData(const State &, folly::IOBufQueue &)
std::shared_ptr< const Cert > serverCert
std::vector< ProtocolVersion > versions
Definition: Extensions.h:93
std::array< uint8_t, 32 > Random
Definition: Types.h:184
std::vector< CipherSuite > cipher_suites
Definition: Types.h:191
folly::AsyncTransportWrapper::WriteCallback * callback
Definition: Actions.h:37
std::shared_ptr< const Cert > serverCert
Definition: PskCache.h:28
static ClientPresharedKey getPskExtension(const CachedPsk &psk)
static folly::Optional< CachedPsk > validatePsk(const FizzClientContext &context, folly::Optional< CachedPsk > psk)
FOLLY_CPP14_CONSTEXPR Value value_or(U &&dflt) const &
Definition: Optional.h:330
virtual void deriveAppTrafficSecrets(folly::ByteRange transcript)
Actions actions(Args &&...act)
Definition: Actions.h:86
const auto & getSupportedSigSchemes() const
int * count
static void checkAllowedExtensions(const EncryptedExtensions &ee, const std::vector< ExtensionType > &requestedExtensions)
Definition: Protocol.h:50
Optional< NamedGroup > group
PskType
Definition: Types.h:18
SignatureScheme algorithm
Definition: Types.h:273
virtual std::unique_ptr< EncryptedWriteRecordLayer > makeEncryptedWriteRecordLayer(EncryptionLevel encryptionLevel) const
Definition: Factory.h:52
bool sentCCS() const
Definition: State.h:215
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
folly::Optional< SignatureScheme > clientAuthSigScheme() const
Definition: State.h:99
std::vector< Extension > extensions
Definition: Types.h:205
Event
Definition: Events.h:15
std::vector< CertificateCompressionAlgorithm > getSupportedCertDecompressionAlgorithms() const
const auto & getSupportedPskModes() const
StringPiece sni
static const std::string nst
const folly::Optional< std::vector< ExtensionType > > & requestedExtensions() const
Definition: State.h:273
virtual std::vector< Extension > getClientHelloExtensions() const =0
const char * string
Definition: Conv.cpp:212
virtual void clearMasterSecret()
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
virtual void verify(const std::vector< std::shared_ptr< const PeerCert >> &certs) const =0
std::shared_ptr< const Cert > serverCert() const
Definition: State.h:77
Optional< PskKeyExchangeMode > pskMode
virtual void deriveMasterSecret()
const FizzClientContext * context() const
Definition: State.h:70
const CertificateVerifier * verifier() const
Definition: State.h:193
std::shared_ptr< const Cert > clientCert
std::vector< ProtocolName > protocol_name_list
Definition: Extensions.h:115
folly::Optional< std::string > alpn
Definition: State.h:54
static Buf getKeyUpdated(KeyUpdateRequest request_update)
Definition: Protocol.h:44
std::vector< PskIdentity > identities
Definition: Extensions.h:64
std::vector< uint8_t > legacy_compression_methods
Definition: Types.h:192
const auto & getClientCertificate() const
CipherSuite cipher
Definition: PskCache.h:26
virtual std::unique_ptr< folly::IOBuf > generateSharedSecret(folly::ByteRange keyShare) const =0
TLSContent writeAppData(std::unique_ptr< folly::IOBuf > &&appData) const
Definition: RecordLayer.h:69
Extension encodeExtension(const TokenBindingParameters &params)
Definition: Types.cpp:113
uint32_t maxEarlyDataSize
Definition: PskCache.h:31
static void validateAcceptedEarly(const State &state, const Optional< std::string > &alpn)
folly::Optional< ClientAuthType > clientAuthRequested() const
Definition: State.h:92
Actions handleInvalidEvent(const State &state, Event event, Param param)
folly::Optional< std::string > sni
Definition: Params.h:41
const WriteRecordLayer * earlyWriteRecordLayer() const
Definition: State.h:254
Actions processEvent(const State &state, Param param)
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
const folly::Optional< Buf > & exporterMasterSecret() const
Definition: State.h:327
static void validateNegotiationConsistency(const State &state, ProtocolVersion version, CipherSuite cipher)
PskKeyExchangeMode
Definition: Types.h:163
ProtocolVersion version
Definition: State.h:50
static std::map< NamedGroup, std::unique_ptr< KeyExchange > > getHrrKeyExchangers(const Factory &factory, std::map< NamedGroup, std::unique_ptr< KeyExchange >> previous, Optional< NamedGroup > negotiatedGroup)
std::unique_ptr< folly::IOBuf > data
Definition: Params.h:54
static Actions handleEarlyAppWrite(const State &state, EarlyAppWrite appWrite)
std::chrono::system_clock::time_point ticketExpirationTime
Definition: PskCache.h:36
folly::AsyncTransportWrapper::WriteCallback * callback
Definition: Params.h:47
state
Definition: http_parser.c:272
std::vector< CertificateCompressionAlgorithm > algorithms
Definition: Extensions.h:143
constexpr None none
Definition: Optional.h:87
const folly::Optional< CachedPsk > & attemptedPsk() const
Definition: State.h:336
folly::WriteFlags flags
Definition: Params.h:55
folly::AsyncTransportWrapper::WriteCallback * callback
Definition: Params.h:53
std::vector< ServerName > server_name_list
Definition: Extensions.h:128
virtual uint32_t clientKeyUpdate()