1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 * 7 */ 8 9 #include <quic/server/handshake/RetryTokenGenerator.h> 10 11 #include <folly/Range.h> 12 #include <quic/codec/Decode.h> 13 14 namespace { 15 16 const std::vector<std::string> kCipherContexts = {"RetryToken"}; 17 18 } // namespace 19 20 namespace quic { 21 RetryTokenGenerator(RetryTokenSecret secret)22RetryTokenGenerator::RetryTokenGenerator(RetryTokenSecret secret) 23 : cipher_(kCipherContexts) { 24 std::vector<folly::ByteRange> secrets; 25 secrets.emplace_back(folly::range(secret)); 26 cipher_.setSecrets(secrets); 27 } 28 encryptToken(const ConnectionId & connId,const folly::IPAddress & clientIp,uint16_t clientPort)29folly::Optional<Buf> RetryTokenGenerator::encryptToken( 30 const ConnectionId& connId, 31 const folly::IPAddress& clientIp, 32 uint16_t clientPort) { 33 // Generate the retry token in plaintext 34 uint64_t timestampInMs = 35 std::chrono::duration_cast<std::chrono::milliseconds>( 36 std::chrono::system_clock::now().time_since_epoch()) 37 .count(); 38 RetryToken token(connId, clientIp, clientPort, timestampInMs); 39 auto plaintextToken = token.getPlaintextToken(); 40 41 // Try to encrypt it 42 auto maybeEncryptedToken = cipher_.encrypt(std::move(plaintextToken)); 43 if (!maybeEncryptedToken) { 44 LOG(ERROR) << "Failed to encypt retry token with IP " << clientIp.str() 45 << " and port " << clientPort; 46 } 47 48 // If the encryption failed, this will be empty optional 49 return maybeEncryptedToken; 50 } 51 decryptToken(Buf encryptedToken)52folly::Optional<RetryToken> RetryTokenGenerator::decryptToken( 53 Buf encryptedToken) { 54 auto maybeDecryptedToken = cipher_.decrypt(std::move(encryptedToken)); 55 if (!maybeDecryptedToken) { 56 LOG(ERROR) << "Failed to decrypt token."; 57 return folly::none; 58 } 59 60 // Try to parse the decrypted token 61 auto decryptedToken = (*maybeDecryptedToken).get(); 62 folly::io::Cursor cursor(decryptedToken); 63 auto parseResult = parsePlaintextRetryToken(cursor); 64 65 if (parseResult.hasError()) { 66 LOG(ERROR) << "Failed to parse decrypted retry token"; 67 return folly::none; 68 } 69 return parseResult.value(); 70 } 71 72 } // namespace quic 73