1 /*
2 * Copyright (c) 2018-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <fizz/server/ServerProtocol.h>
10
11 #include <fizz/crypto/Utils.h>
12 #include <fizz/protocol/CertificateVerifier.h>
13 #include <fizz/protocol/Protocol.h>
14 #include <fizz/protocol/StateMachine.h>
15 #include <fizz/protocol/ech/Decrypter.h>
16 #include <fizz/record/Extensions.h>
17 #include <fizz/record/PlaintextRecordLayer.h>
18 #include <fizz/server/AsyncSelfCert.h>
19 #include <fizz/server/Negotiator.h>
20 #include <fizz/server/ReplayCache.h>
21 #include <fizz/util/Workarounds.h>
22 #include <folly/Overload.h>
23 #include <algorithm>
24
25 using folly::Future;
26 using folly::Optional;
27
28 using namespace fizz::server;
29 using namespace fizz::server::detail;
30
31 // We only ever use the first PSK sent.
32 static constexpr uint16_t kPskIndex = 0;
33
34 namespace fizz {
35 namespace sm {
36
37 FIZZ_DECLARE_EVENT_HANDLER(
38 ServerTypes,
39 StateEnum::Uninitialized,
40 Event::Accept,
41 StateEnum::ExpectingClientHello);
42
43 FIZZ_DECLARE_EVENT_HANDLER(
44 ServerTypes,
45 StateEnum::ExpectingClientHello,
46 Event::ClientHello,
47 StateEnum::ExpectingClientHello,
48 StateEnum::ExpectingCertificate,
49 StateEnum::ExpectingFinished,
50 StateEnum::AcceptingEarlyData,
51 StateEnum::Error);
52
53 FIZZ_DECLARE_EVENT_HANDLER(
54 ServerTypes,
55 StateEnum::AcceptingEarlyData,
56 Event::AppData,
57 StateEnum::Error);
58
59 FIZZ_DECLARE_EVENT_HANDLER(
60 ServerTypes,
61 StateEnum::AcceptingEarlyData,
62 Event::AppWrite,
63 StateEnum::Error);
64
65 FIZZ_DECLARE_EVENT_HANDLER(
66 ServerTypes,
67 StateEnum::AcceptingEarlyData,
68 Event::EndOfEarlyData,
69 StateEnum::ExpectingFinished);
70
71 FIZZ_DECLARE_EVENT_HANDLER(
72 ServerTypes,
73 StateEnum::ExpectingCertificate,
74 Event::Certificate,
75 StateEnum::ExpectingCertificateVerify,
76 StateEnum::ExpectingFinished)
77
78 FIZZ_DECLARE_EVENT_HANDLER(
79 ServerTypes,
80 StateEnum::ExpectingCertificateVerify,
81 Event::CertificateVerify,
82 StateEnum::ExpectingFinished);
83
84 FIZZ_DECLARE_EVENT_HANDLER(
85 ServerTypes,
86 StateEnum::ExpectingFinished,
87 Event::AppWrite,
88 StateEnum::Error);
89
90 FIZZ_DECLARE_EVENT_HANDLER(
91 ServerTypes,
92 StateEnum::ExpectingFinished,
93 Event::Finished,
94 StateEnum::AcceptingData);
95
96 FIZZ_DECLARE_EVENT_HANDLER(
97 ServerTypes,
98 StateEnum::AcceptingData,
99 Event::WriteNewSessionTicket,
100 StateEnum::Error);
101
102 FIZZ_DECLARE_EVENT_HANDLER(
103 ServerTypes,
104 StateEnum::AcceptingData,
105 Event::AppData,
106 StateEnum::Error);
107
108 FIZZ_DECLARE_EVENT_HANDLER(
109 ServerTypes,
110 StateEnum::AcceptingData,
111 Event::AppWrite,
112 StateEnum::Error);
113
114 FIZZ_DECLARE_EVENT_HANDLER(
115 ServerTypes,
116 StateEnum::AcceptingData,
117 Event::KeyUpdate,
118 StateEnum::AcceptingData);
119
120 FIZZ_DECLARE_EVENT_HANDLER(
121 ServerTypes,
122 StateEnum::AcceptingData,
123 Event::CloseNotify,
124 StateEnum::Closed);
125
126 FIZZ_DECLARE_EVENT_HANDLER(
127 ServerTypes,
128 StateEnum::ExpectingCloseNotify,
129 Event::CloseNotify,
130 StateEnum::Closed);
131 } // namespace sm
132
133 namespace server {
134
processAccept(const State & state,folly::Executor * executor,std::shared_ptr<const FizzServerContext> context,const std::shared_ptr<ServerExtensions> & extensions)135 AsyncActions ServerStateMachine::processAccept(
136 const State& state,
137 folly::Executor* executor,
138 std::shared_ptr<const FizzServerContext> context,
139 const std::shared_ptr<ServerExtensions>& extensions) {
140 Accept accept;
141 accept.executor = executor;
142 accept.context = std::move(context);
143 accept.extensions = extensions;
144 return detail::processEvent(state, std::move(accept));
145 }
146
processSocketData(const State & state,folly::IOBufQueue & buf,Aead::AeadOptions options)147 AsyncActions ServerStateMachine::processSocketData(
148 const State& state,
149 folly::IOBufQueue& buf,
150 Aead::AeadOptions options) {
151 try {
152 if (!state.readRecordLayer()) {
153 return detail::handleError(
154 state,
155 ReportError("attempting to process data without record layer"),
156 folly::none);
157 }
158 auto param = state.readRecordLayer()->readEvent(buf, std::move(options));
159 if (!param.has_value()) {
160 return actions(WaitForData{param.sizeHint});
161 }
162 return detail::processEvent(state, std::move(*param));
163 } catch (const FizzException& e) {
164 return detail::handleError(
165 state,
166 ReportError(folly::exception_wrapper(std::current_exception(), e)),
167 e.getAlert());
168 } catch (const std::exception& e) {
169 return detail::handleError(
170 state,
171 ReportError(folly::make_exception_wrapper<FizzException>(
172 folly::to<std::string>(
173 "error decoding record in state ",
174 toString(state.state()),
175 ": ",
176 e.what()),
177 AlertDescription::decode_error)),
178 AlertDescription::decode_error);
179 }
180 }
181
processWriteNewSessionTicket(const State & state,WriteNewSessionTicket write)182 AsyncActions ServerStateMachine::processWriteNewSessionTicket(
183 const State& state,
184 WriteNewSessionTicket write) {
185 return detail::processEvent(state, std::move(write));
186 }
187
processAppWrite(const State & state,AppWrite write)188 AsyncActions ServerStateMachine::processAppWrite(
189 const State& state,
190 AppWrite write) {
191 return detail::processEvent(state, std::move(write));
192 }
193
processEarlyAppWrite(const State & state,EarlyAppWrite write)194 AsyncActions ServerStateMachine::processEarlyAppWrite(
195 const State& state,
196 EarlyAppWrite write) {
197 return detail::processEvent(state, std::move(write));
198 }
199
processAppClose(const State & state)200 Actions ServerStateMachine::processAppClose(const State& state) {
201 return detail::handleAppClose(state);
202 }
203
processAppCloseImmediate(const State & state)204 Actions ServerStateMachine::processAppCloseImmediate(const State& state) {
205 return detail::handleAppCloseImmediate(state);
206 }
207
208 namespace detail {
209
processEvent(const State & state,Param param)210 AsyncActions processEvent(const State& state, Param param) {
211 auto event = EventVisitor()(param);
212 // We can have an exception directly in the handler or in a future so we need
213 // to handle both types.
214 try {
215 auto actions = sm::StateMachine<ServerTypes>::getHandler(
216 state.state(), event)(state, std::move(param));
217
218 return folly::variant_match(
219 actions,
220 ::fizz::detail::result_type<AsyncActions>(),
221 [&state](folly::Future<Actions>& futureActions) -> AsyncActions {
222 return std::move(futureActions)
223 .thenError([&state](folly::exception_wrapper ew) {
224 auto ex = ew.get_exception<FizzException>();
225 if (ex) {
226 return detail::handleError(
227 state, ReportError(std::move(ew)), ex->getAlert());
228 }
229 return detail::handleError(
230 state,
231 ReportError(std::move(ew)),
232 AlertDescription::unexpected_message);
233 });
234 },
235 [](Actions& immediateActions) -> AsyncActions {
236 return std::move(immediateActions);
237 });
238 } catch (const FizzException& e) {
239 return detail::handleError(
240 state,
241 ReportError(folly::exception_wrapper(std::current_exception(), e)),
242 e.getAlert());
243 } catch (const std::exception& e) {
244 return detail::handleError(
245 state,
246 ReportError(folly::exception_wrapper(std::current_exception(), e)),
247 AlertDescription::unexpected_message);
248 }
249 }
250
handleError(const State & state,ReportError error,Optional<AlertDescription> alertDesc)251 Actions handleError(
252 const State& state,
253 ReportError error,
254 Optional<AlertDescription> alertDesc) {
255 if (state.state() == StateEnum::Error) {
256 return Actions();
257 }
258 MutateState transition([](State& newState) {
259 newState.state() = StateEnum::Error;
260 newState.writeRecordLayer() = nullptr;
261 newState.readRecordLayer() = nullptr;
262 });
263 if (alertDesc && state.writeRecordLayer()) {
264 Alert alert(*alertDesc);
265 WriteToSocket write;
266 write.contents.emplace_back(
267 state.writeRecordLayer()->writeAlert(std::move(alert)));
268 return actions(std::move(transition), std::move(write), std::move(error));
269 } else {
270 return actions(std::move(transition), std::move(error));
271 }
272 }
273
handleAppCloseImmediate(const State & state)274 Actions handleAppCloseImmediate(const State& state) {
275 MutateState transition([](State& newState) {
276 newState.state() = StateEnum::Closed;
277 newState.readRecordLayer() = nullptr;
278 newState.writeRecordLayer() = nullptr;
279 });
280
281 if (state.writeRecordLayer()) {
282 Alert alert(AlertDescription::close_notify);
283 WriteToSocket write;
284 write.contents.emplace_back(
285 state.writeRecordLayer()->writeAlert(std::move(alert)));
286 return actions(std::move(transition), std::move(write));
287 } else {
288 return actions(std::move(transition));
289 }
290 }
291
handleAppClose(const State & state)292 Actions handleAppClose(const State& state) {
293 if (state.writeRecordLayer()) {
294 MutateState transition([](State& newState) {
295 newState.state() = StateEnum::ExpectingCloseNotify;
296 newState.writeRecordLayer() = nullptr;
297 });
298
299 Alert alert(AlertDescription::close_notify);
300 WriteToSocket write;
301 write.contents.emplace_back(
302 state.writeRecordLayer()->writeAlert(std::move(alert)));
303 return actions(std::move(transition), std::move(write));
304 } else {
305 MutateState transition([](State& newState) {
306 newState.state() = StateEnum::Closed;
307 newState.writeRecordLayer() = nullptr;
308 newState.readRecordLayer() = nullptr;
309 });
310 return actions(std::move(transition));
311 }
312 }
313
handleInvalidEvent(const State & state,Event event,Param param)314 Actions handleInvalidEvent(const State& state, Event event, Param param) {
315 if (event == Event::Alert) {
316 auto& alert = *param.asAlert();
317 throw FizzException(
318 folly::to<std::string>(
319 "received alert: ",
320 toString(alert.description),
321 ", in state ",
322 toString(state.state())),
323 folly::none);
324 } else {
325 throw FizzException(
326 folly::to<std::string>(
327 "invalid event: ",
328 toString(event),
329 ", in state ",
330 toString(state.state())),
331 AlertDescription::unexpected_message);
332 }
333 }
334
335 template <typename T, typename F>
336 folly::Future<
337 typename folly::futures::detail::valueCallableResult<T, F>::value_type>
runOnCallerIfComplete(folly::Executor * executor,folly::Future<T> future,F && func)338 runOnCallerIfComplete(
339 folly::Executor* executor,
340 folly::Future<T> future,
341 F&& func) {
342 if (future.isReady()) {
343 return func(std::move(future).get());
344 } else {
345 return future.via(executor).thenValue(std::forward<F>(func));
346 }
347 }
348
349 } // namespace detail
350 } // namespace server
351
352 namespace sm {
353
ensureNoUnparsedHandshakeData(const State & state,Event event)354 static void ensureNoUnparsedHandshakeData(const State& state, Event event) {
355 if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
356 throw FizzException(
357 folly::to<std::string>(
358 "unprocessed handshake data while handling event ",
359 toString(event),
360 " in state ",
361 toString(state.state())),
362 AlertDescription::unexpected_message);
363 }
364 }
365
366 AsyncActions
handle(const State &,Param param)367 EventHandler<ServerTypes, StateEnum::Uninitialized, Event::Accept>::handle(
368 const State& /*state*/,
369 Param param) {
370 auto& accept = *param.asAccept();
371 auto factory = accept.context->getFactory();
372 auto readRecordLayer = factory->makePlaintextReadRecordLayer();
373 auto writeRecordLayer = factory->makePlaintextWriteRecordLayer();
374 auto handshakeLogging = std::make_unique<HandshakeLogging>();
375 return actions(
376 MutateState([executor = accept.executor,
377 rrl = std::move(readRecordLayer),
378 wrl = std::move(writeRecordLayer),
379 context = std::move(accept.context),
380 handshakeLogging = std::move(handshakeLogging),
381 extensions = accept.extensions](State& newState) mutable {
382 newState.executor() = executor;
383 newState.context() = std::move(context);
384 newState.readRecordLayer() = std::move(rrl);
385 newState.writeRecordLayer() = std::move(wrl);
386 newState.handshakeLogging() = std::move(handshakeLogging);
387 newState.extensions() = std::move(extensions);
388 }),
389 MutateState(&Transition<StateEnum::ExpectingClientHello>));
390 }
391
addHandshakeLogging(const State & state,const ClientHello & chlo)392 static void addHandshakeLogging(const State& state, const ClientHello& chlo) {
393 auto logging = state.handshakeLogging();
394 if (!logging) {
395 return;
396 }
397 logging->populateFromClientHello(chlo);
398 auto plaintextReadRecord =
399 dynamic_cast<PlaintextReadRecordLayer*>(state.readRecordLayer());
400 if (plaintextReadRecord) {
401 logging->clientRecordVersion =
402 plaintextReadRecord->getReceivedRecordVersion();
403 }
404 }
405
validateClientHello(const ClientHello & chlo)406 static void validateClientHello(const ClientHello& chlo) {
407 if (chlo.legacy_compression_methods.size() != 1 ||
408 chlo.legacy_compression_methods.front() != 0x00) {
409 throw FizzException(
410 "client compression methods not exactly NULL",
411 AlertDescription::illegal_parameter);
412 }
413 Protocol::checkDuplicateExtensions(chlo.extensions);
414 }
415
negotiateVersion(const ClientHello & chlo,const std::vector<ProtocolVersion> & versions)416 static Optional<ProtocolVersion> negotiateVersion(
417 const ClientHello& chlo,
418 const std::vector<ProtocolVersion>& versions) {
419 const auto& clientVersions = getExtension<SupportedVersions>(chlo.extensions);
420 if (!clientVersions) {
421 return folly::none;
422 }
423 auto version = negotiate(versions, clientVersions->versions);
424 if (!version) {
425 return folly::none;
426 }
427 return version;
428 }
429
getCookieState(const ClientHello & chlo,ProtocolVersion version,CipherSuite cipher,const CookieCipher * cookieCipher)430 static Optional<CookieState> getCookieState(
431 const ClientHello& chlo,
432 ProtocolVersion version,
433 CipherSuite cipher,
434 const CookieCipher* cookieCipher) {
435 auto cookieExt = getExtension<Cookie>(chlo.extensions);
436 if (!cookieExt) {
437 return folly::none;
438 }
439
440 // If the client sent a cookie we can't use we have to consider it a fatal
441 // error since we can't reconstruct the handshake transcript.
442 if (!cookieCipher) {
443 throw FizzException(
444 "no cookie cipher", AlertDescription::unsupported_extension);
445 }
446
447 auto cookieState = cookieCipher->decrypt(std::move(cookieExt->cookie));
448
449 if (!cookieState) {
450 throw FizzException(
451 "could not decrypt cookie", AlertDescription::decrypt_error);
452 }
453
454 if (cookieState->version != version) {
455 throw FizzException(
456 "version mismatch with cookie", AlertDescription::protocol_version);
457 }
458
459 if (cookieState->cipher != cipher) {
460 throw FizzException(
461 "cipher mismatch with cookie", AlertDescription::handshake_failure);
462 }
463
464 return cookieState;
465 }
466
467 namespace {
468 struct ResumptionStateResult {
ResumptionStateResultfizz::sm::__anonfebae84f0911::ResumptionStateResult469 explicit ResumptionStateResult(
470 Future<std::pair<PskType, Optional<ResumptionState>>> futureResStateArg,
471 Optional<PskKeyExchangeMode> pskModeArg = folly::none,
472 Optional<uint32_t> obfuscatedAgeArg = folly::none)
473 : futureResState(std::move(futureResStateArg)),
474 pskMode(std::move(pskModeArg)),
475 obfuscatedAge(std::move(obfuscatedAgeArg)) {}
476
477 Future<std::pair<PskType, Optional<ResumptionState>>> futureResState;
478 Optional<PskKeyExchangeMode> pskMode;
479 Optional<uint32_t> obfuscatedAge;
480 };
481 } // namespace
482
getResumptionState(const ClientHello & chlo,const TicketCipher * ticketCipher,const std::vector<PskKeyExchangeMode> & supportedModes)483 static ResumptionStateResult getResumptionState(
484 const ClientHello& chlo,
485 const TicketCipher* ticketCipher,
486 const std::vector<PskKeyExchangeMode>& supportedModes) {
487 auto psks = getExtension<ClientPresharedKey>(chlo.extensions);
488 auto clientModes = getExtension<PskKeyExchangeModes>(chlo.extensions);
489 if (psks && !clientModes) {
490 throw FizzException("no psk modes", AlertDescription::missing_extension);
491 }
492
493 Optional<PskKeyExchangeMode> pskMode;
494 if (clientModes) {
495 pskMode = negotiate(supportedModes, clientModes->modes);
496 }
497 if (!psks && !pskMode) {
498 return ResumptionStateResult(
499 std::make_pair(PskType::NotSupported, folly::none));
500 } else if (!psks || psks->identities.size() <= kPskIndex) {
501 return ResumptionStateResult(
502 std::make_pair(PskType::NotAttempted, folly::none));
503 } else if (!ticketCipher) {
504 VLOG(8) << "No ticket cipher, rejecting PSK.";
505 return ResumptionStateResult(
506 std::make_pair(PskType::Rejected, folly::none));
507 } else if (!pskMode) {
508 VLOG(8) << "No psk mode match, rejecting PSK.";
509 return ResumptionStateResult(
510 std::make_pair(PskType::Rejected, folly::none));
511 } else {
512 const auto& ident = psks->identities[kPskIndex].psk_identity;
513 return ResumptionStateResult(
514 ticketCipher->decrypt(ident->clone()),
515 pskMode,
516 psks->identities[kPskIndex].obfuscated_ticket_age);
517 }
518 }
519
getReplayCacheResult(const ClientHello & chlo,bool zeroRttEnabled,ReplayCache * replayCache)520 static Future<ReplayCacheResult> getReplayCacheResult(
521 const ClientHello& chlo,
522 bool zeroRttEnabled,
523 ReplayCache* replayCache) {
524 if (!zeroRttEnabled || !replayCache ||
525 !getExtension<ClientEarlyData>(chlo.extensions)) {
526 return ReplayCacheResult::NotChecked;
527 }
528
529 return replayCache->check(folly::range(chlo.random));
530 }
531
validateResumptionState(const ResumptionState & resState,PskKeyExchangeMode,ProtocolVersion version,CipherSuite cipher)532 static bool validateResumptionState(
533 const ResumptionState& resState,
534 PskKeyExchangeMode /* mode */,
535 ProtocolVersion version,
536 CipherSuite cipher) {
537 if (resState.version != version) {
538 VLOG(8) << "Protocol version mismatch, rejecting PSK.";
539 return false;
540 }
541
542 if (getHashFunction(resState.cipher) != getHashFunction(cipher)) {
543 VLOG(8) << "Hash mismatch, rejecting PSK.";
544 return false;
545 }
546
547 return true;
548 }
549
negotiateCipher(const ClientHello & chlo,const std::vector<std::vector<CipherSuite>> & supportedCiphers)550 static CipherSuite negotiateCipher(
551 const ClientHello& chlo,
552 const std::vector<std::vector<CipherSuite>>& supportedCiphers) {
553 auto cipher = negotiate(supportedCiphers, chlo.cipher_suites);
554 if (!cipher) {
555 throw FizzException("no cipher match", AlertDescription::handshake_failure);
556 }
557 return *cipher;
558 }
559
560 /*
561 * Sets up a KeyScheduler and HandshakeContext for the connection. The
562 * KeyScheduler will have the early secret derived if applicable, and the
563 * ClientHello will be added to the HandshakeContext. This also verifies the
564 * PSK binder if applicable.
565 *
566 * If the passed in handshakeContext is non-null it is used instead of a new
567 * context. This is used after a HelloRetryRequest when there is already a
568 * handshake transcript before the current ClientHello.
569 */
570 static std::
571 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)572 setupSchedulerAndContext(
573 const Factory& factory,
574 CipherSuite cipher,
575 const ClientHello& chlo,
576 const Optional<ResumptionState>& resState,
577 const Optional<CookieState>& cookieState,
578 PskType pskType,
579 std::unique_ptr<HandshakeContext> handshakeContext,
580 ProtocolVersion /*version*/) {
581 auto scheduler = factory.makeKeyScheduler(cipher);
582
583 if (cookieState) {
584 if (handshakeContext) {
585 throw FizzException(
586 "cookie after statefull hrr", AlertDescription::illegal_parameter);
587 }
588
589 handshakeContext = factory.makeHandshakeContext(cipher);
590
591 message_hash chloHash;
592 chloHash.hash = cookieState->chloHash->clone();
593 handshakeContext->appendToTranscript(encodeHandshake(std::move(chloHash)));
594
595 auto cookie = getExtension<Cookie>(chlo.extensions);
596 handshakeContext->appendToTranscript(getStatelessHelloRetryRequest(
597 cookieState->version,
598 cookieState->cipher,
599 cookieState->group,
600 std::move(cookie->cookie)));
601 } else if (!handshakeContext) {
602 handshakeContext = factory.makeHandshakeContext(cipher);
603 }
604
605 if (resState) {
606 scheduler->deriveEarlySecret(resState->resumptionSecret->coalesce());
607
608 auto binderKey = scheduler
609 ->getSecret(
610 pskType == PskType::External
611 ? EarlySecrets::ExternalPskBinder
612 : EarlySecrets::ResumptionPskBinder,
613 handshakeContext->getBlankContext())
614 .secret;
615
616 folly::IOBufQueue chloQueue(folly::IOBufQueue::cacheChainLength());
617 chloQueue.append((*chlo.originalEncoding)->clone());
618 auto chloPrefix =
619 chloQueue.split(chloQueue.chainLength() - getBinderLength(chlo));
620 handshakeContext->appendToTranscript(chloPrefix);
621
622 const auto& psks = getExtension<ClientPresharedKey>(chlo.extensions);
623 if (!psks || psks->binders.size() <= kPskIndex) {
624 throw FizzException("no binders", AlertDescription::illegal_parameter);
625 }
626 auto expectedBinder =
627 handshakeContext->getFinishedData(folly::range(binderKey));
628 if (!CryptoUtils::equal(
629 expectedBinder->coalesce(),
630 psks->binders[kPskIndex].binder->coalesce())) {
631 throw FizzException(
632 "binder does not match", AlertDescription::bad_record_mac);
633 }
634
635 handshakeContext->appendToTranscript(chloQueue.move());
636 return std::make_pair(std::move(scheduler), std::move(handshakeContext));
637 } else {
638 handshakeContext->appendToTranscript(*chlo.originalEncoding);
639 return std::make_pair(std::move(scheduler), std::move(handshakeContext));
640 }
641 }
642
validateGroups(const std::vector<KeyShareEntry> & client_shares)643 static void validateGroups(const std::vector<KeyShareEntry>& client_shares) {
644 std::set<NamedGroup> setOfNamedGroups;
645
646 for (const auto& share : client_shares) {
647 if (setOfNamedGroups.find(share.group) != setOfNamedGroups.end()) {
648 throw FizzException(
649 "duplicate client key share", AlertDescription::illegal_parameter);
650 }
651
652 setOfNamedGroups.insert(share.group);
653 }
654 }
655
negotiateGroup(ProtocolVersion version,const ClientHello & chlo,const std::vector<NamedGroup> & supportedGroups)656 static std::tuple<NamedGroup, Optional<Buf>> negotiateGroup(
657 ProtocolVersion version,
658 const ClientHello& chlo,
659 const std::vector<NamedGroup>& supportedGroups) {
660 auto groups = getExtension<SupportedGroups>(chlo.extensions);
661 if (!groups) {
662 throw FizzException("no named groups", AlertDescription::missing_extension);
663 }
664 auto group = negotiate(supportedGroups, groups->named_group_list);
665 if (!group) {
666 throw FizzException("no group match", AlertDescription::handshake_failure);
667 }
668 auto clientShares = getExtension<ClientKeyShare>(chlo.extensions);
669 if (!clientShares) {
670 throw FizzException(
671 "no client shares", AlertDescription::missing_extension);
672 }
673
674 validateGroups(clientShares->client_shares);
675 for (const auto& share : clientShares->client_shares) {
676 if (share.group == *group) {
677 return std::make_tuple(*group, share.key_exchange->clone());
678 }
679 }
680 return std::make_tuple(*group, folly::none);
681 }
682
doKex(const Factory & factory,NamedGroup group,const Buf & clientShare,KeyScheduler & scheduler)683 static Buf doKex(
684 const Factory& factory,
685 NamedGroup group,
686 const Buf& clientShare,
687 KeyScheduler& scheduler) {
688 auto kex = factory.makeKeyExchange(group);
689 kex->generateKeyPair();
690 auto sharedSecret = kex->generateSharedSecret(clientShare->coalesce());
691 scheduler.deriveHandshakeSecret(sharedSecret->coalesce());
692 return kex->getKeyShare();
693 }
694
getHelloRetryRequest(ProtocolVersion version,CipherSuite cipher,NamedGroup group,Buf legacySessionId,HandshakeContext & handshakeContext)695 static Buf getHelloRetryRequest(
696 ProtocolVersion version,
697 CipherSuite cipher,
698 NamedGroup group,
699 Buf legacySessionId,
700 HandshakeContext& handshakeContext) {
701 HelloRetryRequest hrr;
702 hrr.legacy_version = ProtocolVersion::tls_1_2;
703 hrr.legacy_session_id_echo = std::move(legacySessionId);
704 hrr.cipher_suite = cipher;
705 ServerSupportedVersions versionExt;
706 versionExt.selected_version = version;
707 hrr.extensions.push_back(encodeExtension(std::move(versionExt)));
708 HelloRetryRequestKeyShare keyShare;
709 keyShare.selected_group = group;
710 hrr.extensions.push_back(encodeExtension(std::move(keyShare)));
711 auto encodedHelloRetryRequest = encodeHandshake(std::move(hrr));
712
713 handshakeContext.appendToTranscript(encodedHelloRetryRequest);
714 return encodedHelloRetryRequest;
715 }
716
getServerHello(ProtocolVersion version,Random random,CipherSuite cipher,bool psk,Optional<NamedGroup> group,Optional<Buf> serverShare,Buf legacySessionId,HandshakeContext & handshakeContext)717 static Buf getServerHello(
718 ProtocolVersion version,
719 Random random,
720 CipherSuite cipher,
721 bool psk,
722 Optional<NamedGroup> group,
723 Optional<Buf> serverShare,
724 Buf legacySessionId,
725 HandshakeContext& handshakeContext) {
726 ServerHello serverHello;
727
728 serverHello.legacy_version = ProtocolVersion::tls_1_2;
729 ServerSupportedVersions versionExt;
730 versionExt.selected_version = version;
731 serverHello.extensions.push_back(encodeExtension(std::move(versionExt)));
732 serverHello.legacy_session_id_echo = std::move(legacySessionId);
733
734 serverHello.random = std::move(random);
735 serverHello.cipher_suite = cipher;
736 if (group) {
737 ServerKeyShare serverKeyShare;
738 serverKeyShare.server_share.group = *group;
739 serverKeyShare.server_share.key_exchange = std::move(*serverShare);
740
741 serverHello.extensions.push_back(
742 encodeExtension(std::move(serverKeyShare)));
743 }
744 if (psk) {
745 ServerPresharedKey serverPsk;
746 serverPsk.selected_identity = kPskIndex;
747 serverHello.extensions.push_back(encodeExtension(std::move(serverPsk)));
748 }
749 auto encodedServerHello = encodeHandshake(std::move(serverHello));
750 handshakeContext.appendToTranscript(encodedServerHello);
751 return encodedServerHello;
752 }
753
negotiateAlpn(const ClientHello & chlo,folly::Optional<std::string> zeroRttAlpn,const FizzServerContext & context)754 static Optional<std::string> negotiateAlpn(
755 const ClientHello& chlo,
756 folly::Optional<std::string> zeroRttAlpn,
757 const FizzServerContext& context) {
758 auto ext = getExtension<ProtocolNameList>(chlo.extensions);
759 std::vector<std::string> clientProtocols;
760 // Check whether client supports ALPN
761 if (ext) {
762 for (auto& protocol : ext->protocol_name_list) {
763 clientProtocols.push_back(protocol.name->moveToFbString().toStdString());
764 }
765 } else {
766 VLOG(6) << "Client did not send ALPN extension";
767 if (context.getAlpnMode() == AlpnMode::Required) {
768 throw FizzException(
769 "ALPN is required", AlertDescription::no_application_protocol);
770 }
771 return folly::none;
772 }
773
774 // Since both support ALPN, check whether the protocols match.
775 // Server's support for ALPN is to be enforced at the configuration.
776 auto selected = context.negotiateAlpn(clientProtocols, zeroRttAlpn);
777 if (!selected) {
778 VLOG(6) << "ALPN mismatch";
779 if (context.getAlpnMode() != AlpnMode::AllowMismatch) {
780 auto msg = context.getAlpnMode() == AlpnMode::Optional
781 ? "Unable to negotiate ALPN, as required by policy. policy=AlpnMode::Optional"
782 : "Unable to negotiate ALPN, as required by policy. policy=AlpnMode::Required";
783 throw FizzException(msg, AlertDescription::no_application_protocol);
784 }
785 } else {
786 VLOG(6) << "ALPN: " << *selected;
787 }
788 return selected;
789 }
790
getClockSkew(const Optional<ResumptionState> & psk,Optional<uint32_t> obfuscatedAge,const std::chrono::system_clock::time_point & currentTime)791 static Optional<std::chrono::milliseconds> getClockSkew(
792 const Optional<ResumptionState>& psk,
793 Optional<uint32_t> obfuscatedAge,
794 const std::chrono::system_clock::time_point& currentTime) {
795 if (!psk || !obfuscatedAge) {
796 return folly::none;
797 }
798
799 auto age = std::chrono::milliseconds(
800 static_cast<uint32_t>(*obfuscatedAge - psk->ticketAgeAdd));
801
802 auto expected = std::chrono::duration_cast<std::chrono::milliseconds>(
803 currentTime - psk->ticketIssueTime);
804
805 return std::chrono::milliseconds(age - expected);
806 }
807
getAppToken(const Optional<ResumptionState> & psk)808 static Optional<Buf> getAppToken(const Optional<ResumptionState>& psk) {
809 if (!psk.has_value() || !psk->appToken) {
810 return folly::none;
811 }
812 return psk->appToken->clone();
813 }
814
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)815 static EarlyDataType negotiateEarlyDataType(
816 bool acceptEarlyData,
817 const ClientHello& chlo,
818 const Optional<ResumptionState>& psk,
819 CipherSuite cipher,
820 Optional<KeyExchangeType> keyExchangeType,
821 const Optional<CookieState>& cookieState,
822 Optional<std::string> alpn,
823 ReplayCacheResult replayCacheResult,
824 Optional<std::chrono::milliseconds> clockSkew,
825 ClockSkewTolerance clockSkewTolerance,
826 const AppTokenValidator* appTokenValidator) {
827 if (!getExtension<ClientEarlyData>(chlo.extensions)) {
828 return EarlyDataType::NotAttempted;
829 }
830
831 if (!acceptEarlyData) {
832 VLOG(5) << "Rejecting early data: disabled";
833 return EarlyDataType::Rejected;
834 }
835
836 if (!psk) {
837 VLOG(5) << "Rejected early data: psk rejected";
838 return EarlyDataType::Rejected;
839 }
840
841 if (psk->cipher != cipher) {
842 VLOG(5) << "Rejected early data: cipher mismatch";
843 return EarlyDataType::Rejected;
844 }
845
846 if (psk->alpn != alpn) {
847 VLOG(5) << "Rejecting early data: alpn mismatch";
848 return EarlyDataType::Rejected;
849 }
850
851 if (keyExchangeType &&
852 *keyExchangeType == KeyExchangeType::HelloRetryRequest) {
853 VLOG(5) << "Rejecting early data: HelloRetryRequest";
854 return EarlyDataType::Rejected;
855 }
856
857 if (cookieState) {
858 VLOG(5) << "Rejecting early data: Cookie";
859 return EarlyDataType::Rejected;
860 }
861
862 if (replayCacheResult != ReplayCacheResult::NotReplay) {
863 VLOG(5) << "Rejecting early data: replay";
864 return EarlyDataType::Rejected;
865 }
866
867 if (!clockSkew || *clockSkew < clockSkewTolerance.before ||
868 *clockSkew > clockSkewTolerance.after) {
869 VLOG(5) << "Rejecting early data: clock skew clockSkew="
870 << (clockSkew ? folly::to<std::string>(clockSkew->count())
871 : "(none)")
872 << " toleranceBefore=" << clockSkewTolerance.before.count()
873 << " toleranceAfter=" << clockSkewTolerance.after.count();
874 return EarlyDataType::Rejected;
875 }
876
877 if (appTokenValidator && !appTokenValidator->validate(*psk)) {
878 VLOG(5) << "Rejecting early data: invalid app token";
879 return EarlyDataType::Rejected;
880 }
881
882 return EarlyDataType::Accepted;
883 }
884
getEncryptedExt(HandshakeContext & handshakeContext,const folly::Optional<std::string> & selectedAlpn,EarlyDataType earlyData,std::vector<Extension> otherExtensions)885 static Buf getEncryptedExt(
886 HandshakeContext& handshakeContext,
887 const folly::Optional<std::string>& selectedAlpn,
888 EarlyDataType earlyData,
889 std::vector<Extension> otherExtensions) {
890 EncryptedExtensions encryptedExt;
891 if (selectedAlpn) {
892 ProtocolNameList alpn;
893 ProtocolName protocol;
894 protocol.name = folly::IOBuf::copyBuffer(*selectedAlpn);
895 alpn.protocol_name_list.push_back(std::move(protocol));
896 encryptedExt.extensions.push_back(encodeExtension(std::move(alpn)));
897 }
898
899 if (earlyData == EarlyDataType::Accepted) {
900 encryptedExt.extensions.push_back(encodeExtension(ServerEarlyData()));
901 }
902
903 for (auto& ext : otherExtensions) {
904 encryptedExt.extensions.push_back(std::move(ext));
905 }
906 auto encodedEncryptedExt =
907 encodeHandshake<EncryptedExtensions>(std::move(encryptedExt));
908 handshakeContext.appendToTranscript(encodedEncryptedExt);
909 return encodedEncryptedExt;
910 }
911
chooseCert(const FizzServerContext & context,const ClientHello & chlo)912 static std::pair<std::shared_ptr<SelfCert>, SignatureScheme> chooseCert(
913 const FizzServerContext& context,
914 const ClientHello& chlo) {
915 const auto& clientSigSchemes =
916 getExtension<SignatureAlgorithms>(chlo.extensions);
917 if (!clientSigSchemes) {
918 throw FizzException("no sig schemes", AlertDescription::missing_extension);
919 }
920 Optional<std::string> sni;
921 auto serverNameList = getExtension<ServerNameList>(chlo.extensions);
922 if (serverNameList && !serverNameList->server_name_list.empty()) {
923 sni = serverNameList->server_name_list.front()
924 .hostname->moveToFbString()
925 .toStdString();
926 }
927
928 auto certAndScheme = context.getCert(
929 sni, clientSigSchemes->supported_signature_algorithms, chlo.extensions);
930 if (!certAndScheme) {
931 throw FizzException(
932 "could not find suitable cert", AlertDescription::handshake_failure);
933 }
934 return *certAndScheme;
935 }
936
937 static std::tuple<Buf, folly::Optional<CertificateCompressionAlgorithm>>
getCertificate(const std::shared_ptr<const SelfCert> & serverCert,const FizzServerContext & context,const ClientHello & chlo,HandshakeContext & handshakeContext)938 getCertificate(
939 const std::shared_ptr<const SelfCert>& serverCert,
940 const FizzServerContext& context,
941 const ClientHello& chlo,
942 HandshakeContext& handshakeContext) {
943 // Check for compression support first, and if so, send compressed.
944 Buf encodedCertificate;
945 folly::Optional<CertificateCompressionAlgorithm> algo;
946 auto compAlgos =
947 getExtension<CertificateCompressionAlgorithms>(chlo.extensions);
948 if (compAlgos && !context.getSupportedCompressionAlgorithms().empty()) {
949 algo = negotiate(
950 context.getSupportedCompressionAlgorithms(), compAlgos->algorithms);
951 }
952
953 if (algo) {
954 encodedCertificate = encodeHandshake(serverCert->getCompressedCert(*algo));
955 } else {
956 encodedCertificate = encodeHandshake(serverCert->getCertMessage());
957 }
958 handshakeContext.appendToTranscript(encodedCertificate);
959 return std::make_tuple(std::move(encodedCertificate), std::move(algo));
960 }
961
getCertificateVerify(SignatureScheme sigScheme,Buf signature,HandshakeContext & handshakeContext)962 static Buf getCertificateVerify(
963 SignatureScheme sigScheme,
964 Buf signature,
965 HandshakeContext& handshakeContext) {
966 CertificateVerify verify;
967 verify.algorithm = sigScheme;
968 verify.signature = std::move(signature);
969 auto encodedCertificateVerify = encodeHandshake(std::move(verify));
970 handshakeContext.appendToTranscript(encodedCertificateVerify);
971 return encodedCertificateVerify;
972 }
973
getCertificateRequest(const std::vector<SignatureScheme> & acceptableSigSchemes,const CertificateVerifier * const verifier,HandshakeContext & handshakeContext)974 static Buf getCertificateRequest(
975 const std::vector<SignatureScheme>& acceptableSigSchemes,
976 const CertificateVerifier* const verifier,
977 HandshakeContext& handshakeContext) {
978 CertificateRequest request;
979 SignatureAlgorithms algos;
980 algos.supported_signature_algorithms = acceptableSigSchemes;
981 request.extensions.push_back(encodeExtension(std::move(algos)));
982 if (verifier) {
983 auto verifierExtensions = verifier->getCertificateRequestExtensions();
984 for (auto& ext : verifierExtensions) {
985 request.extensions.push_back(std::move(ext));
986 }
987 }
988 auto encodedCertificateRequest = encodeHandshake(std::move(request));
989 handshakeContext.appendToTranscript(encodedCertificateRequest);
990 return encodedCertificateRequest;
991 }
992
updateClientHelloIfECH(std::shared_ptr<ech::Decrypter> decrypter,ClientHello & chlo)993 static void updateClientHelloIfECH(
994 std::shared_ptr<ech::Decrypter> decrypter,
995 ClientHello& chlo) {
996 if (decrypter) {
997 auto gotChlo = decrypter->decryptClientHello(chlo);
998 if (gotChlo.has_value()) {
999 chlo = std::move(gotChlo.value());
1000 }
1001 }
1002 }
1003
1004 AsyncActions
1005 EventHandler<ServerTypes, StateEnum::ExpectingClientHello, Event::ClientHello>::
handle(const State & state,Param param)1006 handle(const State& state, Param param) {
1007 ClientHello chlo = std::move(*param.asClientHello());
1008
1009 // Update the client hello if we are using ECH
1010 updateClientHelloIfECH(state.context()->getECHDecrypter(), chlo);
1011
1012 addHandshakeLogging(state, chlo);
1013
1014 if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1015 throw FizzException(
1016 "data after client hello", AlertDescription::unexpected_message);
1017 }
1018
1019 auto version =
1020 negotiateVersion(chlo, state.context()->getSupportedVersions());
1021
1022 if (state.version().has_value() &&
1023 (!version || *version != *state.version())) {
1024 throw FizzException(
1025 "version mismatch with previous negotiation",
1026 AlertDescription::illegal_parameter);
1027 }
1028
1029 if (!version) {
1030 if (getExtension<ClientEarlyData>(chlo.extensions)) {
1031 throw FizzException(
1032 "supported version mismatch with early data",
1033 AlertDescription::protocol_version);
1034 }
1035 if (state.context()->getVersionFallbackEnabled()) {
1036 AttemptVersionFallback fallback;
1037 // Re-encode to put the record layer header back on. This won't
1038 // necessarily preserve it byte-for-byte, but it isn't authenticated so
1039 // should be ok.
1040 fallback.clientHello =
1041 PlaintextWriteRecordLayer()
1042 .writeInitialClientHello(std::move(*chlo.originalEncoding))
1043 .data;
1044 return actions(
1045 MutateState(&Transition<StateEnum::Error>), std::move(fallback));
1046 } else {
1047 throw FizzException(
1048 "supported version mismatch", AlertDescription::protocol_version);
1049 }
1050 }
1051
1052 state.writeRecordLayer()->setProtocolVersion(*version);
1053
1054 validateClientHello(chlo);
1055
1056 auto cipher = negotiateCipher(chlo, state.context()->getSupportedCiphers());
1057
1058 auto cookieState = getCookieState(
1059 chlo, *version, cipher, state.context()->getCookieCipher());
1060
1061 auto resStateResult = getResumptionState(
1062 chlo,
1063 state.context()->getTicketCipher(),
1064 state.context()->getSupportedPskModes());
1065
1066 auto replayCacheResultFuture = getReplayCacheResult(
1067 chlo,
1068 state.context()->getAcceptEarlyData(*version),
1069 state.context()->getReplayCache());
1070
1071 auto results =
1072 collectAllUnsafe(resStateResult.futureResState, replayCacheResultFuture);
1073
1074 using FutureResultType = std::tuple<
1075 folly::Try<std::pair<PskType, Optional<ResumptionState>>>,
1076 folly::Try<ReplayCacheResult>>;
1077 return runOnCallerIfComplete(
1078 state.executor(),
1079 std::move(results),
1080 [&state,
1081 chlo = std::move(chlo),
1082 cookieState = std::move(cookieState),
1083 version = *version,
1084 cipher,
1085 pskMode = resStateResult.pskMode,
1086 obfuscatedAge =
1087 resStateResult.obfuscatedAge](FutureResultType result) mutable {
1088 auto& resumption = *std::get<0>(result);
1089 auto pskType = resumption.first;
1090 auto resState = std::move(resumption.second);
1091 auto replayCacheResult = *std::get<1>(result);
1092
1093 if (resState) {
1094 if (!validateResumptionState(*resState, *pskMode, version, cipher)) {
1095 pskType = PskType::Rejected;
1096 pskMode = folly::none;
1097 resState = folly::none;
1098 }
1099 } else {
1100 pskMode = folly::none;
1101 }
1102
1103 auto legacySessionId = chlo.legacy_session_id->clone();
1104
1105 // If we successfully resumed, set the handshake time to the ticket's
1106 // handshake time to preserve it across ticket updates. If not, set it
1107 // to now.
1108 std::chrono::system_clock::time_point handshakeTime;
1109 if (resState) {
1110 handshakeTime = resState->handshakeTime;
1111 } else {
1112 handshakeTime = state.context()->getClock().getCurrentTime();
1113 }
1114
1115 std::unique_ptr<KeyScheduler> scheduler;
1116 std::unique_ptr<HandshakeContext> handshakeContext;
1117 std::tie(scheduler, handshakeContext) = setupSchedulerAndContext(
1118 *state.context()->getFactory(),
1119 cipher,
1120 chlo,
1121 resState,
1122 cookieState,
1123 pskType,
1124 std::move(state.handshakeContext()),
1125 version);
1126
1127 if (state.cipher().has_value() && cipher != *state.cipher()) {
1128 throw FizzException(
1129 "cipher mismatch with previous negotiation",
1130 AlertDescription::illegal_parameter);
1131 }
1132
1133 auto alpn = negotiateAlpn(chlo, folly::none, *state.context());
1134
1135 auto clockSkew = getClockSkew(
1136 resState,
1137 obfuscatedAge,
1138 state.context()->getClock().getCurrentTime());
1139
1140 auto appToken = getAppToken(resState);
1141
1142 auto earlyDataType = negotiateEarlyDataType(
1143 state.context()->getAcceptEarlyData(version),
1144 chlo,
1145 resState,
1146 cipher,
1147 state.keyExchangeType(),
1148 cookieState,
1149 alpn,
1150 replayCacheResult,
1151 clockSkew,
1152 state.context()->getClockSkewTolerance(),
1153 state.appTokenValidator());
1154
1155 std::unique_ptr<EncryptedReadRecordLayer> earlyReadRecordLayer;
1156 Buf earlyExporterMaster;
1157 folly::Optional<SecretAvailable> earlyReadSecretAvailable;
1158 if (earlyDataType == EarlyDataType::Accepted) {
1159 auto earlyContext = handshakeContext->getHandshakeContext();
1160 auto earlyReadSecret = scheduler->getSecret(
1161 EarlySecrets::ClientEarlyTraffic, earlyContext->coalesce());
1162 if (!state.context()->getOmitEarlyRecordLayer()) {
1163 earlyReadRecordLayer =
1164 state.context()->getFactory()->makeEncryptedReadRecordLayer(
1165 EncryptionLevel::EarlyData);
1166 earlyReadRecordLayer->setProtocolVersion(version);
1167
1168 Protocol::setAead(
1169 *earlyReadRecordLayer,
1170 cipher,
1171 folly::range(earlyReadSecret.secret),
1172 *state.context()->getFactory(),
1173 *scheduler);
1174 }
1175
1176 earlyReadSecretAvailable =
1177 SecretAvailable(std::move(earlyReadSecret));
1178 earlyExporterMaster = folly::IOBuf::copyBuffer(
1179 scheduler
1180 ->getSecret(
1181 EarlySecrets::EarlyExporter, earlyContext->coalesce())
1182 .secret);
1183 }
1184
1185 Optional<NamedGroup> group;
1186 Optional<Buf> serverShare;
1187 KeyExchangeType keyExchangeType;
1188 if (!pskMode || *pskMode != PskKeyExchangeMode::psk_ke) {
1189 Optional<Buf> clientShare;
1190 std::tie(group, clientShare) = negotiateGroup(
1191 version, chlo, state.context()->getSupportedGroups());
1192 if (!clientShare) {
1193 VLOG(8) << "Did not find key share for " << toString(*group);
1194 if (state.group().has_value() || cookieState) {
1195 throw FizzException(
1196 "key share not found for already negotiated group",
1197 AlertDescription::illegal_parameter);
1198 }
1199
1200 // If we were otherwise going to accept early data we now need to
1201 // reject it. It's a little ugly to change our previous early data
1202 // decision, but doing it this way allows us to move the key
1203 // schedule forward as we do the key exchange.
1204 if (earlyDataType == EarlyDataType::Accepted) {
1205 earlyDataType = EarlyDataType::Rejected;
1206 }
1207
1208 message_hash chloHash;
1209 chloHash.hash = handshakeContext->getHandshakeContext();
1210 handshakeContext =
1211 state.context()->getFactory()->makeHandshakeContext(cipher);
1212 handshakeContext->appendToTranscript(
1213 encodeHandshake(std::move(chloHash)));
1214
1215 auto encodedHelloRetryRequest = getHelloRetryRequest(
1216 version,
1217 cipher,
1218 *group,
1219 legacySessionId ? legacySessionId->clone() : nullptr,
1220 *handshakeContext);
1221
1222 WriteToSocket serverFlight;
1223 serverFlight.contents.emplace_back(
1224 state.writeRecordLayer()->writeHandshake(
1225 std::move(encodedHelloRetryRequest)));
1226
1227 if (legacySessionId && !legacySessionId->empty()) {
1228 TLSContent writeCCS;
1229 writeCCS.encryptionLevel = EncryptionLevel::Plaintext;
1230 writeCCS.contentType = ContentType::change_cipher_spec;
1231 writeCCS.data = folly::IOBuf::wrapBuffer(FakeChangeCipherSpec);
1232 serverFlight.contents.emplace_back(std::move(writeCCS));
1233 }
1234
1235 // Create a new record layer in case we need to skip early data.
1236 auto newReadRecordLayer =
1237 state.context()->getFactory()->makePlaintextReadRecordLayer();
1238 newReadRecordLayer->setSkipEncryptedRecords(
1239 earlyDataType == EarlyDataType::Rejected);
1240
1241 return Future<Actions>(actions(
1242 MutateState([handshakeContext = std::move(handshakeContext),
1243 version,
1244 cipher,
1245 group,
1246 earlyDataType,
1247 replayCacheResult,
1248 newReadRecordLayer = std::move(
1249 newReadRecordLayer)](State& newState) mutable {
1250 // Save some information about the current state to be
1251 // validated when we get the second client hello. We don't
1252 // validate that the second client hello matches the first
1253 // as strictly as we could according to the spec however.
1254 newState.handshakeContext() = std::move(handshakeContext);
1255 newState.version() = version;
1256 newState.cipher() = cipher;
1257 newState.group() = group;
1258 newState.keyExchangeType() =
1259 KeyExchangeType::HelloRetryRequest;
1260 newState.earlyDataType() = earlyDataType;
1261 newState.replayCacheResult() = replayCacheResult;
1262 newState.readRecordLayer() = std::move(newReadRecordLayer);
1263 }),
1264 std::move(serverFlight),
1265 MutateState(&Transition<StateEnum::ExpectingClientHello>)));
1266 }
1267
1268 if (state.keyExchangeType().has_value()) {
1269 keyExchangeType = *state.keyExchangeType();
1270 } else {
1271 keyExchangeType = KeyExchangeType::OneRtt;
1272 }
1273
1274 serverShare = doKex(
1275 *state.context()->getFactory(), *group, *clientShare, *scheduler);
1276 } else {
1277 keyExchangeType = KeyExchangeType::None;
1278 scheduler->deriveHandshakeSecret();
1279 }
1280
1281 std::vector<Extension> additionalExtensions;
1282 if (state.extensions()) {
1283 additionalExtensions = state.extensions()->getExtensions(chlo);
1284 }
1285
1286 if (state.group().has_value() && (!group || *group != *state.group())) {
1287 throw FizzException(
1288 "group mismatch with previous negotiation",
1289 AlertDescription::illegal_parameter);
1290 }
1291
1292 // Cookies are not required to have already negotiated the group but if
1293 // they did it must match (psk_ke is still allowed as we may not know if
1294 // we are accepting the psk when sending the cookie).
1295 if (cookieState && cookieState->group && group &&
1296 *group != *cookieState->group) {
1297 throw FizzException(
1298 "group mismatch with cookie",
1299 AlertDescription::illegal_parameter);
1300 }
1301
1302 auto encodedServerHello = getServerHello(
1303 version,
1304 state.context()->getFactory()->makeRandom(),
1305 cipher,
1306 resState.has_value(),
1307 group,
1308 std::move(serverShare),
1309 legacySessionId ? legacySessionId->clone() : nullptr,
1310 *handshakeContext);
1311
1312 // Derive handshake keys.
1313 auto handshakeWriteRecordLayer =
1314 state.context()->getFactory()->makeEncryptedWriteRecordLayer(
1315 EncryptionLevel::Handshake);
1316 handshakeWriteRecordLayer->setProtocolVersion(version);
1317 auto handshakeWriteSecret = scheduler->getSecret(
1318 HandshakeSecrets::ServerHandshakeTraffic,
1319 handshakeContext->getHandshakeContext()->coalesce());
1320 Protocol::setAead(
1321 *handshakeWriteRecordLayer,
1322 cipher,
1323 folly::range(handshakeWriteSecret.secret),
1324 *state.context()->getFactory(),
1325 *scheduler);
1326
1327 auto handshakeReadRecordLayer =
1328 state.context()->getFactory()->makeEncryptedReadRecordLayer(
1329 EncryptionLevel::Handshake);
1330 handshakeReadRecordLayer->setProtocolVersion(version);
1331 handshakeReadRecordLayer->setSkipFailedDecryption(
1332 earlyDataType == EarlyDataType::Rejected);
1333 auto handshakeReadSecret = scheduler->getSecret(
1334 HandshakeSecrets::ClientHandshakeTraffic,
1335 handshakeContext->getHandshakeContext()->coalesce());
1336 Protocol::setAead(
1337 *handshakeReadRecordLayer,
1338 cipher,
1339 folly::range(handshakeReadSecret.secret),
1340 *state.context()->getFactory(),
1341 *scheduler);
1342 auto clientHandshakeSecret =
1343 folly::IOBuf::copyBuffer(handshakeReadSecret.secret);
1344
1345 auto encodedEncryptedExt = getEncryptedExt(
1346 *handshakeContext,
1347 alpn,
1348 earlyDataType,
1349 std::move(additionalExtensions));
1350
1351 /*
1352 * Determine we are requesting client auth.
1353 * If yes, add CertificateRequest to handshake write and transcript.
1354 */
1355 bool requestClientAuth =
1356 state.context()->getClientAuthMode() != ClientAuthMode::None &&
1357 !resState;
1358 Optional<Buf> encodedCertRequest;
1359 if (requestClientAuth) {
1360 encodedCertRequest = getCertificateRequest(
1361 state.context()->getSupportedSigSchemes(),
1362 state.context()->getClientCertVerifier().get(),
1363 *handshakeContext);
1364 }
1365
1366 /*
1367 * Set the cert and signature scheme we are using.
1368 * If sending new cert, add Certificate to handshake write and
1369 * transcript.
1370 */
1371 Optional<Buf> encodedCertificate;
1372 Future<Optional<Buf>> signature = folly::none;
1373 Optional<SignatureScheme> sigScheme;
1374 Optional<std::shared_ptr<const Cert>> serverCert;
1375 std::shared_ptr<const Cert> clientCert;
1376 Optional<CertificateCompressionAlgorithm> certCompressionAlgo;
1377 if (!resState) { // TODO or reauth
1378 std::shared_ptr<const SelfCert> originalSelfCert;
1379 std::tie(originalSelfCert, sigScheme) =
1380 chooseCert(*state.context(), chlo);
1381
1382 std::tie(encodedCertificate, certCompressionAlgo) = getCertificate(
1383 originalSelfCert, *state.context(), chlo, *handshakeContext);
1384
1385 auto toBeSigned = handshakeContext->getHandshakeContext();
1386 auto asyncSelfCert =
1387 dynamic_cast<const AsyncSelfCert*>(originalSelfCert.get());
1388 if (asyncSelfCert) {
1389 signature = asyncSelfCert->signFuture(
1390 *sigScheme,
1391 CertificateVerifyContext::Server,
1392 toBeSigned->coalesce());
1393 } else {
1394 signature = originalSelfCert->sign(
1395 *sigScheme,
1396 CertificateVerifyContext::Server,
1397 toBeSigned->coalesce());
1398 }
1399 serverCert = std::move(originalSelfCert);
1400 } else {
1401 serverCert = std::move(resState->serverCert);
1402 clientCert = std::move(resState->clientCert);
1403 }
1404
1405 auto clientRandom = std::move(chlo.random);
1406 return runOnCallerIfComplete(
1407 state.executor(),
1408 std::move(signature),
1409 [&state,
1410 scheduler = std::move(scheduler),
1411 handshakeContext = std::move(handshakeContext),
1412 cipher,
1413 clientRandom = std::move(clientRandom),
1414 group,
1415 encodedServerHello = std::move(encodedServerHello),
1416 handshakeWriteRecordLayer = std::move(handshakeWriteRecordLayer),
1417 handshakeWriteSecret = std::move(handshakeWriteSecret),
1418 handshakeReadRecordLayer = std::move(handshakeReadRecordLayer),
1419 handshakeReadSecret = std::move(handshakeReadSecret),
1420 earlyReadRecordLayer = std::move(earlyReadRecordLayer),
1421 earlyReadSecretAvailable = std::move(earlyReadSecretAvailable),
1422 earlyExporterMaster = std::move(earlyExporterMaster),
1423 clientHandshakeSecret = std::move(clientHandshakeSecret),
1424 encodedEncryptedExt = std::move(encodedEncryptedExt),
1425 encodedCertificate = std::move(encodedCertificate),
1426 encodedCertRequest = std::move(encodedCertRequest),
1427 requestClientAuth,
1428 pskType,
1429 pskMode,
1430 sigScheme,
1431 version,
1432 keyExchangeType,
1433 earlyDataType,
1434 replayCacheResult,
1435 serverCert = std::move(serverCert),
1436 clientCert = std::move(clientCert),
1437 alpn = std::move(alpn),
1438 clockSkew,
1439 appToken = std::move(appToken),
1440 legacySessionId = std::move(legacySessionId),
1441 serverCertCompAlgo = certCompressionAlgo,
1442 handshakeTime](Optional<Buf> sig) mutable {
1443 Optional<Buf> encodedCertificateVerify;
1444 if (sig) {
1445 encodedCertificateVerify = getCertificateVerify(
1446 *sigScheme, std::move(*sig), *handshakeContext);
1447 }
1448
1449 auto encodedFinished = Protocol::getFinished(
1450 folly::range(handshakeWriteSecret.secret), *handshakeContext);
1451
1452 folly::IOBufQueue combined;
1453 if (encodedCertificate) {
1454 if (encodedCertRequest) {
1455 combined.append(std::move(encodedEncryptedExt));
1456 combined.append(std::move(*encodedCertRequest));
1457 combined.append(std::move(*encodedCertificate));
1458 combined.append(std::move(*encodedCertificateVerify));
1459 combined.append(std::move(encodedFinished));
1460 } else {
1461 combined.append(std::move(encodedEncryptedExt));
1462 combined.append(std::move(*encodedCertificate));
1463 combined.append(std::move(*encodedCertificateVerify));
1464 combined.append(std::move(encodedFinished));
1465 }
1466 } else {
1467 combined.append(std::move(encodedEncryptedExt));
1468 combined.append(std::move(encodedFinished));
1469 }
1470
1471 // Some middleboxes appear to break if the first encrypted record
1472 // is larger than ~1300 bytes (likely if it does not fit in the
1473 // first packet).
1474 auto serverEncrypted = handshakeWriteRecordLayer->writeHandshake(
1475 combined.splitAtMost(1000));
1476 if (!combined.empty()) {
1477 auto splitRecord =
1478 handshakeWriteRecordLayer->writeHandshake(combined.move());
1479 // Split record must have the same encryption level as the main
1480 // handshake.
1481 DCHECK(
1482 splitRecord.encryptionLevel ==
1483 serverEncrypted.encryptionLevel);
1484 serverEncrypted.data->prependChain(std::move(splitRecord.data));
1485 }
1486
1487 WriteToSocket serverFlight;
1488 serverFlight.contents.emplace_back(
1489 state.writeRecordLayer()->writeHandshake(
1490 std::move(encodedServerHello)));
1491 if (legacySessionId && !legacySessionId->empty()) {
1492 TLSContent ccsWrite;
1493 ccsWrite.encryptionLevel = EncryptionLevel::Plaintext;
1494 ccsWrite.contentType = ContentType::change_cipher_spec;
1495 ccsWrite.data = folly::IOBuf::wrapBuffer(FakeChangeCipherSpec);
1496 serverFlight.contents.emplace_back(std::move(ccsWrite));
1497 }
1498 serverFlight.contents.emplace_back(std::move(serverEncrypted));
1499
1500 scheduler->deriveMasterSecret();
1501 auto clientFinishedContext =
1502 handshakeContext->getHandshakeContext();
1503 auto exporterMasterVector = scheduler->getSecret(
1504 MasterSecrets::ExporterMaster,
1505 clientFinishedContext->coalesce());
1506 auto exporterMaster = folly::IOBuf::copyBuffer(
1507 folly::range(exporterMasterVector.secret));
1508
1509 scheduler->deriveAppTrafficSecrets(
1510 clientFinishedContext->coalesce());
1511 auto appTrafficWriteRecordLayer =
1512 state.context()->getFactory()->makeEncryptedWriteRecordLayer(
1513 EncryptionLevel::AppTraffic);
1514 appTrafficWriteRecordLayer->setProtocolVersion(version);
1515 auto writeSecret =
1516 scheduler->getSecret(AppTrafficSecrets::ServerAppTraffic);
1517 Protocol::setAead(
1518 *appTrafficWriteRecordLayer,
1519 cipher,
1520 folly::range(writeSecret.secret),
1521 *state.context()->getFactory(),
1522 *scheduler);
1523
1524 // If we have previously dealt with early data (before a
1525 // HelloRetryRequest), don't overwrite the previous result.
1526 auto earlyDataTypeSave = state.earlyDataType()
1527 ? *state.earlyDataType()
1528 : earlyDataType;
1529
1530 SecretAvailable handshakeReadSecretAvailable(
1531 std::move(handshakeReadSecret));
1532 SecretAvailable handshakeWriteSecretAvailable(
1533 std::move(handshakeWriteSecret));
1534 SecretAvailable appWriteSecretAvailable(std::move(writeSecret));
1535
1536 // Save all the necessary state except for the read record layer,
1537 // which is done separately as it varies if early data was
1538 // accepted.
1539 MutateState saveState(
1540 [appTrafficWriteRecordLayer =
1541 std::move(appTrafficWriteRecordLayer),
1542 handshakeContext = std::move(handshakeContext),
1543 scheduler = std::move(scheduler),
1544 exporterMaster = std::move(exporterMaster),
1545 serverCert = std::move(serverCert),
1546 clientCert = std::move(clientCert),
1547 cipher,
1548 group,
1549 sigScheme,
1550 clientHandshakeSecret = std::move(clientHandshakeSecret),
1551 pskType,
1552 pskMode,
1553 version,
1554 keyExchangeType,
1555 alpn = std::move(alpn),
1556 earlyDataTypeSave,
1557 replayCacheResult,
1558 clockSkew,
1559 appToken = std::move(appToken),
1560 serverCertCompAlgo,
1561 clientRandom = std::move(clientRandom),
1562 handshakeTime =
1563 std::move(handshakeTime)](State& newState) mutable {
1564 newState.writeRecordLayer() =
1565 std::move(appTrafficWriteRecordLayer);
1566 newState.handshakeContext() = std::move(handshakeContext);
1567 newState.keyScheduler() = std::move(scheduler);
1568 newState.exporterMasterSecret() = std::move(exporterMaster);
1569 newState.serverCert() = std::move(*serverCert);
1570 newState.clientCert() = std::move(clientCert);
1571 newState.version() = version;
1572 newState.cipher() = cipher;
1573 newState.group() = group;
1574 newState.sigScheme() = sigScheme;
1575 newState.clientHandshakeSecret() =
1576 std::move(clientHandshakeSecret);
1577 newState.pskType() = pskType;
1578 newState.pskMode() = pskMode;
1579 newState.keyExchangeType() = keyExchangeType;
1580 newState.earlyDataType() = earlyDataTypeSave;
1581 newState.replayCacheResult() = replayCacheResult;
1582 newState.alpn() = std::move(alpn);
1583 newState.clientClockSkew() = clockSkew;
1584 newState.appToken() = std::move(appToken);
1585 newState.serverCertCompAlgo() = serverCertCompAlgo;
1586 newState.handshakeTime() = std::move(handshakeTime);
1587 newState.clientRandom() = std::move(clientRandom);
1588 });
1589
1590 if (earlyDataType == EarlyDataType::Accepted) {
1591 if (state.context()->getOmitEarlyRecordLayer()) {
1592 return actions(
1593 MutateState([handshakeReadRecordLayer =
1594 std::move(handshakeReadRecordLayer),
1595 earlyExporterMaster =
1596 std::move(earlyExporterMaster)](
1597 State& newState) mutable {
1598 newState.readRecordLayer() =
1599 std::move(handshakeReadRecordLayer);
1600 newState.earlyExporterMasterSecret() =
1601 std::move(earlyExporterMaster);
1602 }),
1603 std::move(saveState),
1604 std::move(*earlyReadSecretAvailable),
1605 std::move(handshakeReadSecretAvailable),
1606 std::move(handshakeWriteSecretAvailable),
1607 std::move(appWriteSecretAvailable),
1608 std::move(serverFlight),
1609 MutateState(&Transition<StateEnum::ExpectingFinished>),
1610 ReportEarlyHandshakeSuccess());
1611
1612 } else {
1613 return actions(
1614 MutateState([handshakeReadRecordLayer =
1615 std::move(handshakeReadRecordLayer),
1616 earlyReadRecordLayer =
1617 std::move(earlyReadRecordLayer),
1618 earlyExporterMaster =
1619 std::move(earlyExporterMaster)](
1620 State& newState) mutable {
1621 newState.readRecordLayer() =
1622 std::move(earlyReadRecordLayer);
1623 newState.handshakeReadRecordLayer() =
1624 std::move(handshakeReadRecordLayer);
1625 newState.earlyExporterMasterSecret() =
1626 std::move(earlyExporterMaster);
1627 }),
1628 std::move(saveState),
1629 std::move(*earlyReadSecretAvailable),
1630 std::move(handshakeReadSecretAvailable),
1631 std::move(handshakeWriteSecretAvailable),
1632 std::move(appWriteSecretAvailable),
1633 std::move(serverFlight),
1634 MutateState(&Transition<StateEnum::AcceptingEarlyData>),
1635 ReportEarlyHandshakeSuccess());
1636 }
1637 } else {
1638 auto transition = requestClientAuth
1639 ? Transition<StateEnum::ExpectingCertificate>
1640 : Transition<StateEnum::ExpectingFinished>;
1641 return actions(
1642 MutateState([handshakeReadRecordLayer =
1643 std::move(handshakeReadRecordLayer)](
1644 State& newState) mutable {
1645 newState.readRecordLayer() =
1646 std::move(handshakeReadRecordLayer);
1647 }),
1648 std::move(saveState),
1649 std::move(handshakeReadSecretAvailable),
1650 std::move(handshakeWriteSecretAvailable),
1651 std::move(appWriteSecretAvailable),
1652 std::move(serverFlight),
1653 MutateState(transition));
1654 }
1655 });
1656 });
1657 }
1658
1659 AsyncActions
1660 EventHandler<ServerTypes, StateEnum::AcceptingEarlyData, Event::AppData>::
handle(const State &,Param param)1661 handle(const State&, Param param) {
1662 auto& appData = *param.asAppData();
1663
1664 return actions(DeliverAppData{std::move(appData.data)});
1665 }
1666
1667 AsyncActions
1668 EventHandler<ServerTypes, StateEnum::AcceptingEarlyData, Event::AppWrite>::
handle(const State & state,Param param)1669 handle(const State& state, Param param) {
1670 auto& appWrite = *param.asAppWrite();
1671
1672 WriteToSocket write;
1673 write.callback = appWrite.callback;
1674 write.contents.emplace_back(state.writeRecordLayer()->writeAppData(
1675 std::move(appWrite.data), appWrite.aeadOptions));
1676 write.flags = appWrite.flags;
1677
1678 return actions(std::move(write));
1679 }
1680
1681 AsyncActions EventHandler<
1682 ServerTypes,
1683 StateEnum::AcceptingEarlyData,
handle(const State & state,Param param)1684 Event::EndOfEarlyData>::handle(const State& state, Param param) {
1685 auto& eoed = *param.asEndOfEarlyData();
1686
1687 if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1688 throw FizzException(
1689 "data after eoed", AlertDescription::unexpected_message);
1690 }
1691
1692 state.handshakeContext()->appendToTranscript(*eoed.originalEncoding);
1693
1694 auto readRecordLayer = std::move(state.handshakeReadRecordLayer());
1695
1696 return actions(
1697 MutateState([readRecordLayer =
1698 std::move(readRecordLayer)](State& newState) mutable {
1699 newState.readRecordLayer() = std::move(readRecordLayer);
1700 }),
1701 MutateState(&Transition<StateEnum::ExpectingFinished>));
1702 }
1703
1704 AsyncActions
1705 EventHandler<ServerTypes, StateEnum::ExpectingFinished, Event::AppWrite>::
handle(const State & state,Param param)1706 handle(const State& state, Param param) {
1707 auto& appWrite = *param.asAppWrite();
1708
1709 WriteToSocket write;
1710 write.callback = appWrite.callback;
1711 write.contents.emplace_back(state.writeRecordLayer()->writeAppData(
1712 std::move(appWrite.data), appWrite.aeadOptions));
1713 write.flags = appWrite.flags;
1714
1715 return actions(std::move(write));
1716 }
1717
writeNewSessionTicket(const FizzServerContext & context,const WriteRecordLayer & recordLayer,std::chrono::seconds ticketLifetime,uint32_t ticketAgeAdd,Buf nonce,Buf ticket,ProtocolVersion version)1718 static WriteToSocket writeNewSessionTicket(
1719 const FizzServerContext& context,
1720 const WriteRecordLayer& recordLayer,
1721 std::chrono::seconds ticketLifetime,
1722 uint32_t ticketAgeAdd,
1723 Buf nonce,
1724 Buf ticket,
1725 ProtocolVersion version) {
1726 NewSessionTicket nst;
1727 nst.ticket_lifetime = ticketLifetime.count();
1728 nst.ticket_age_add = ticketAgeAdd;
1729 nst.ticket_nonce = std::move(nonce);
1730 nst.ticket = std::move(ticket);
1731
1732 if (context.getAcceptEarlyData(version)) {
1733 TicketEarlyData early;
1734 early.max_early_data_size = context.getMaxEarlyDataSize();
1735 nst.extensions.push_back(encodeExtension(std::move(early)));
1736 }
1737
1738 auto encodedNst = encodeHandshake(std::move(nst));
1739 WriteToSocket nstWrite;
1740 nstWrite.contents.emplace_back(
1741 recordLayer.writeHandshake(std::move(encodedNst)));
1742 return nstWrite;
1743 }
1744
generateTicket(const State & state,const std::vector<uint8_t> & resumptionMasterSecret,Buf appToken=nullptr)1745 static Future<Optional<WriteToSocket>> generateTicket(
1746 const State& state,
1747 const std::vector<uint8_t>& resumptionMasterSecret,
1748 Buf appToken = nullptr) {
1749 auto ticketCipher = state.context()->getTicketCipher();
1750
1751 if (!ticketCipher || *state.pskType() == PskType::NotSupported) {
1752 return folly::none;
1753 }
1754
1755 Buf resumptionSecret;
1756 auto ticketNonce = folly::IOBuf::create(0);
1757 resumptionSecret = state.keyScheduler()->getResumptionSecret(
1758 folly::range(resumptionMasterSecret), ticketNonce->coalesce());
1759
1760 ResumptionState resState;
1761 resState.version = *state.version();
1762 resState.cipher = *state.cipher();
1763 resState.resumptionSecret = std::move(resumptionSecret);
1764 resState.serverCert = state.serverCert();
1765 resState.clientCert = state.clientCert();
1766 resState.alpn = state.alpn();
1767 resState.ticketAgeAdd = state.context()->getFactory()->makeTicketAgeAdd();
1768 resState.ticketIssueTime = state.context()->getClock().getCurrentTime();
1769 resState.appToken = std::move(appToken);
1770 resState.handshakeTime = *state.handshakeTime();
1771
1772 auto ticketFuture = ticketCipher->encrypt(std::move(resState));
1773 return runOnCallerIfComplete(
1774 state.executor(),
1775 std::move(ticketFuture),
1776 [&state,
1777 ticketAgeAdd = resState.ticketAgeAdd,
1778 ticketNonce = std::move(ticketNonce)](
1779 Optional<std::pair<Buf, std::chrono::seconds>> ticket) mutable
1780 -> Optional<WriteToSocket> {
1781 if (!ticket) {
1782 return folly::none;
1783 }
1784 return writeNewSessionTicket(
1785 *state.context(),
1786 *state.writeRecordLayer(),
1787 ticket->second,
1788 ticketAgeAdd,
1789 std::move(ticketNonce),
1790 std::move(ticket->first),
1791 *state.version());
1792 });
1793 }
1794
1795 AsyncActions
1796 EventHandler<ServerTypes, StateEnum::ExpectingCertificate, Event::Certificate>::
handle(const State & state,Param param)1797 handle(const State& state, Param param) {
1798 auto certMsg = std::move(*param.asCertificateMsg());
1799
1800 state.handshakeContext()->appendToTranscript(*certMsg.originalEncoding);
1801
1802 if (!certMsg.certificate_request_context->empty()) {
1803 throw FizzException(
1804 "certificate request context must be empty",
1805 AlertDescription::illegal_parameter);
1806 }
1807
1808 std::vector<std::shared_ptr<const PeerCert>> clientCerts;
1809 bool leaf = true;
1810 for (auto& certEntry : certMsg.certificate_list) {
1811 // We don't request any extensions, so this ought to be empty
1812 if (!certEntry.extensions.empty()) {
1813 throw FizzException(
1814 "certificate extensions must be empty",
1815 AlertDescription::illegal_parameter);
1816 }
1817
1818 clientCerts.emplace_back(state.context()->getFactory()->makePeerCert(
1819 std::move(certEntry), leaf));
1820 leaf = false;
1821 }
1822
1823 if (clientCerts.empty()) {
1824 if (state.context()->getClientAuthMode() == ClientAuthMode::Optional) {
1825 VLOG(6) << "Client authentication not sent";
1826 return actions(
1827 MutateState([](State& newState) {
1828 newState.unverifiedCertChain() = folly::none;
1829 }),
1830 MutateState(&Transition<StateEnum::ExpectingFinished>));
1831 } else {
1832 throw FizzException(
1833 "certificate requested but none received",
1834 AlertDescription::certificate_required);
1835 }
1836 } else {
1837 return actions(
1838 MutateState([certs = std::move(clientCerts)](State& newState) mutable {
1839 newState.unverifiedCertChain() = std::move(certs);
1840 }),
1841 MutateState(&Transition<StateEnum::ExpectingCertificateVerify>));
1842 }
1843 }
1844
1845 AsyncActions EventHandler<
1846 ServerTypes,
1847 StateEnum::ExpectingCertificateVerify,
handle(const State & state,Param param)1848 Event::CertificateVerify>::handle(const State& state, Param param) {
1849 auto certVerify = std::move(*param.asCertificateVerify());
1850
1851 if (std::find(
1852 state.context()->getSupportedSigSchemes().begin(),
1853 state.context()->getSupportedSigSchemes().end(),
1854 certVerify.algorithm) ==
1855 state.context()->getSupportedSigSchemes().end()) {
1856 throw FizzException(
1857 folly::to<std::string>(
1858 "client chose unsupported sig scheme: ",
1859 toString(certVerify.algorithm)),
1860 AlertDescription::handshake_failure);
1861 }
1862
1863 const auto& certs = *state.unverifiedCertChain();
1864 auto leafCert = certs.front();
1865 leafCert->verify(
1866 certVerify.algorithm,
1867 CertificateVerifyContext::Client,
1868 state.handshakeContext()->getHandshakeContext()->coalesce(),
1869 certVerify.signature->coalesce());
1870
1871 try {
1872 const auto& verifier = state.context()->getClientCertVerifier();
1873 if (verifier) {
1874 verifier->verify(certs);
1875 }
1876 } catch (const FizzException&) {
1877 throw;
1878 } catch (const std::exception& e) {
1879 throw FizzVerificationException(
1880 folly::to<std::string>("client certificate failure: ", e.what()),
1881 AlertDescription::bad_certificate);
1882 }
1883
1884 state.handshakeContext()->appendToTranscript(*certVerify.originalEncoding);
1885
1886 return actions(
1887 MutateState([cert = std::move(leafCert)](State& newState) {
1888 newState.unverifiedCertChain() = folly::none;
1889 newState.clientCert() = std::move(cert);
1890 }),
1891 MutateState(&Transition<StateEnum::ExpectingFinished>));
1892 }
1893
1894 AsyncActions
1895 EventHandler<ServerTypes, StateEnum::ExpectingFinished, Event::Finished>::
handle(const State & state,Param param)1896 handle(const State& state, Param param) {
1897 auto& finished = *param.asFinished();
1898
1899 auto expectedFinished = state.handshakeContext()->getFinishedData(
1900 state.clientHandshakeSecret()->coalesce());
1901 if (!CryptoUtils::equal(
1902 expectedFinished->coalesce(), finished.verify_data->coalesce())) {
1903 throw FizzException("client finished verify failure", folly::none);
1904 }
1905
1906 if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
1907 throw FizzException("data after finished", folly::none);
1908 }
1909
1910 auto readRecordLayer =
1911 state.context()->getFactory()->makeEncryptedReadRecordLayer(
1912 EncryptionLevel::AppTraffic);
1913 readRecordLayer->setProtocolVersion(*state.version());
1914 auto readSecret =
1915 state.keyScheduler()->getSecret(AppTrafficSecrets::ClientAppTraffic);
1916 Protocol::setAead(
1917 *readRecordLayer,
1918 *state.cipher(),
1919 folly::range(readSecret.secret),
1920 *state.context()->getFactory(),
1921 *state.keyScheduler());
1922
1923 state.handshakeContext()->appendToTranscript(*finished.originalEncoding);
1924
1925 auto resumptionMasterSecret =
1926 state.keyScheduler()
1927 ->getSecret(
1928 MasterSecrets::ResumptionMaster,
1929 state.handshakeContext()->getHandshakeContext()->coalesce())
1930 .secret;
1931 state.keyScheduler()->clearMasterSecret();
1932
1933 MutateState saveState([readRecordLayer = std::move(readRecordLayer),
1934 resumptionMasterSecret](State& newState) mutable {
1935 newState.readRecordLayer() = std::move(readRecordLayer);
1936 newState.resumptionMasterSecret() = std::move(resumptionMasterSecret);
1937 });
1938
1939 SecretAvailable appReadTrafficSecretAvailable(std::move(readSecret));
1940
1941 if (!state.context()->getSendNewSessionTicket()) {
1942 return actions(
1943 std::move(saveState),
1944 std::move(appReadTrafficSecretAvailable),
1945 MutateState(&Transition<StateEnum::AcceptingData>),
1946 ReportHandshakeSuccess());
1947 } else {
1948 auto ticketFuture = generateTicket(state, resumptionMasterSecret);
1949 return runOnCallerIfComplete(
1950 state.executor(),
1951 std::move(ticketFuture),
1952 [saveState = std::move(saveState),
1953 appReadTrafficSecretAvailable =
1954 std::move(appReadTrafficSecretAvailable)](
1955 Optional<WriteToSocket> nstWrite) mutable {
1956 if (!nstWrite) {
1957 return actions(
1958 std::move(saveState),
1959 MutateState(&Transition<StateEnum::AcceptingData>),
1960 std::move(appReadTrafficSecretAvailable),
1961 ReportHandshakeSuccess());
1962 }
1963
1964 return actions(
1965 std::move(saveState),
1966 MutateState(&Transition<StateEnum::AcceptingData>),
1967 std::move(appReadTrafficSecretAvailable),
1968 std::move(*nstWrite),
1969 ReportHandshakeSuccess());
1970 });
1971 }
1972 }
1973
1974 AsyncActions EventHandler<
1975 ServerTypes,
1976 StateEnum::AcceptingData,
handle(const State & state,Param param)1977 Event::WriteNewSessionTicket>::handle(const State& state, Param param) {
1978 auto& writeNewSessionTicket = *param.asWriteNewSessionTicket();
1979 auto ticketFuture = generateTicket(
1980 state,
1981 state.resumptionMasterSecret(),
1982 std::move(writeNewSessionTicket.appToken));
1983 return runOnCallerIfComplete(
1984 state.executor(),
1985 std::move(ticketFuture),
1986 [](Optional<WriteToSocket> nstWrite) {
1987 if (!nstWrite) {
1988 return Actions();
1989 }
1990 return actions(std::move(*nstWrite));
1991 });
1992 }
1993
1994 AsyncActions
handle(const State &,Param param)1995 EventHandler<ServerTypes, StateEnum::AcceptingData, Event::AppData>::handle(
1996 const State& /*state*/,
1997 Param param) {
1998 auto& appData = *param.asAppData();
1999
2000 return actions(DeliverAppData{std::move(appData.data)});
2001 }
2002
2003 AsyncActions
handle(const State & state,Param param)2004 EventHandler<ServerTypes, StateEnum::AcceptingData, Event::AppWrite>::handle(
2005 const State& state,
2006 Param param) {
2007 auto& appWrite = *param.asAppWrite();
2008
2009 WriteToSocket write;
2010 write.callback = appWrite.callback;
2011 write.contents.emplace_back(state.writeRecordLayer()->writeAppData(
2012 std::move(appWrite.data), appWrite.aeadOptions));
2013 write.flags = appWrite.flags;
2014
2015 return actions(std::move(write));
2016 }
2017
2018 AsyncActions
handle(const State & state,Param param)2019 EventHandler<ServerTypes, StateEnum::AcceptingData, Event::KeyUpdate>::handle(
2020 const State& state,
2021 Param param) {
2022 auto& keyUpdate = *param.asKeyUpdate();
2023
2024 if (state.readRecordLayer()->hasUnparsedHandshakeData()) {
2025 throw FizzException("data after key_update", folly::none);
2026 }
2027 state.keyScheduler()->clientKeyUpdate();
2028 auto readRecordLayer =
2029 state.context()->getFactory()->makeEncryptedReadRecordLayer(
2030 EncryptionLevel::AppTraffic);
2031 readRecordLayer->setProtocolVersion(*state.version());
2032 auto readSecret =
2033 state.keyScheduler()->getSecret(AppTrafficSecrets::ClientAppTraffic);
2034 Protocol::setAead(
2035 *readRecordLayer,
2036 *state.cipher(),
2037 folly::range(readSecret.secret),
2038 *state.context()->getFactory(),
2039 *state.keyScheduler());
2040
2041 if (keyUpdate.request_update == KeyUpdateRequest::update_not_requested) {
2042 return actions(
2043 MutateState([rRecordLayer =
2044 std::move(readRecordLayer)](State& newState) mutable {
2045 newState.readRecordLayer() = std::move(rRecordLayer);
2046 }),
2047 SecretAvailable(std::move(readSecret)));
2048 }
2049
2050 auto encodedKeyUpdated =
2051 Protocol::getKeyUpdated(KeyUpdateRequest::update_not_requested);
2052 WriteToSocket write;
2053 write.contents.emplace_back(
2054 state.writeRecordLayer()->writeHandshake(std::move(encodedKeyUpdated)));
2055
2056 state.keyScheduler()->serverKeyUpdate();
2057
2058 auto writeRecordLayer =
2059 state.context()->getFactory()->makeEncryptedWriteRecordLayer(
2060 EncryptionLevel::AppTraffic);
2061 writeRecordLayer->setProtocolVersion(*state.version());
2062 auto writeSecret =
2063 state.keyScheduler()->getSecret(AppTrafficSecrets::ServerAppTraffic);
2064 Protocol::setAead(
2065 *writeRecordLayer,
2066 *state.cipher(),
2067 folly::range(writeSecret.secret),
2068 *state.context()->getFactory(),
2069 *state.keyScheduler());
2070
2071 return actions(
2072 MutateState([rRecordLayer = std::move(readRecordLayer),
2073 wRecordLayer =
2074 std::move(writeRecordLayer)](State& newState) mutable {
2075 newState.readRecordLayer() = std::move(rRecordLayer);
2076 newState.writeRecordLayer() = std::move(wRecordLayer);
2077 }),
2078 SecretAvailable(std::move(writeSecret)),
2079 SecretAvailable(std::move(readSecret)),
2080 std::move(write));
2081 }
2082
2083 AsyncActions
handle(const State & state,Param param)2084 EventHandler<ServerTypes, StateEnum::AcceptingData, Event::CloseNotify>::handle(
2085 const State& state,
2086 Param param) {
2087 ensureNoUnparsedHandshakeData(state, Event::CloseNotify);
2088 auto& closenotify = *param.asCloseNotify();
2089 auto eod = EndOfData(std::move(closenotify.ignoredPostCloseData));
2090
2091 MutateState clearRecordLayers([](State& newState) {
2092 newState.writeRecordLayer() = nullptr;
2093 newState.readRecordLayer() = nullptr;
2094 });
2095
2096 WriteToSocket write;
2097 write.contents.emplace_back(state.writeRecordLayer()->writeAlert(
2098 Alert(AlertDescription::close_notify)));
2099 return actions(
2100 std::move(write),
2101 std::move(clearRecordLayers),
2102 MutateState(&Transition<StateEnum::Closed>),
2103 std::move(eod));
2104 }
2105
2106 AsyncActions
2107 EventHandler<ServerTypes, StateEnum::ExpectingCloseNotify, Event::CloseNotify>::
handle(const State & state,Param param)2108 handle(const State& state, Param param) {
2109 ensureNoUnparsedHandshakeData(state, Event::CloseNotify);
2110 auto& closenotify = *param.asCloseNotify();
2111 auto eod = EndOfData(std::move(closenotify.ignoredPostCloseData));
2112
2113 MutateState clearRecordLayers([](State& newState) {
2114 newState.readRecordLayer() = nullptr;
2115 newState.writeRecordLayer() = nullptr;
2116 });
2117 return actions(
2118 std::move(clearRecordLayers),
2119 MutateState(&Transition<StateEnum::Closed>),
2120 std::move(eod));
2121 }
2122
2123 } // namespace sm
2124 } // namespace fizz
2125