1 // Copyright (c) 2022 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_CONFIG_H_ 6 #define QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_CONFIG_H_ 7 8 #include <cstdint> 9 #include <optional> 10 11 #include "absl/base/attributes.h" 12 #include "absl/strings/string_view.h" 13 #include "absl/types/span.h" 14 #include "openssl/aes.h" 15 #include "quiche/quic/core/quic_connection_id.h" 16 #include "quiche/quic/load_balancer/load_balancer_server_id.h" 17 #include "quiche/quic/platform/api/quic_export.h" 18 19 namespace quic { 20 21 namespace test { 22 class LoadBalancerConfigPeer; 23 } // namespace test 24 25 // The number of bits in the first byte used for the config ID 26 inline constexpr uint8_t kConfigIdBits = 3; 27 // The number of bits in the first byte used for the connection ID length, if 28 // the encoder uses this option. Otherwise, by spec it's random bits. 29 inline constexpr uint8_t kConnectionIdLengthBits = 8 - kConfigIdBits; 30 // One codepoint is reserved for unroutable connection IDs, so subtract one to 31 // find the maximum number of configs. 32 inline constexpr uint8_t kNumLoadBalancerConfigs = (1 << kConfigIdBits) - 1; 33 inline constexpr uint8_t kLoadBalancerKeyLen = 16; 34 // The spec says nonces can be 18 bytes, but 16 lets it be a uint128. 35 inline constexpr uint8_t kLoadBalancerMaxNonceLen = 16; 36 inline constexpr uint8_t kLoadBalancerMinNonceLen = 4; 37 inline constexpr uint8_t kNumLoadBalancerCryptoPasses = 4; 38 39 // This the base class for QUIC-LB configuration. It contains configuration 40 // elements usable by both encoders (servers) and decoders (load balancers). 41 // Confusingly, it is called "LoadBalancerConfig" because it pertains to objects 42 // that both servers and load balancers use to interact with each other. 43 class QUIC_EXPORT_PRIVATE LoadBalancerConfig { 44 public: 45 // This factory function initializes an encrypted LoadBalancerConfig and 46 // returns it in std::optional, which is empty if the config is invalid. 47 // config_id: The first two bits of the Connection Id. Must be no larger than 48 // 2. 49 // server_id_len: Expected length of the server ids associated with this 50 // config. Must be greater than 0 and less than 16. 51 // nonce_len: Length of the nonce. Must be at least 4 and no larger than 16. 52 // Further the server_id_len + nonce_len must be no larger than 19. 53 // key: The encryption key must be 16B long. 54 static std::optional<LoadBalancerConfig> Create(uint8_t config_id, 55 uint8_t server_id_len, 56 uint8_t nonce_len, 57 absl::string_view key); 58 59 // Creates an unencrypted config. 60 static std::optional<LoadBalancerConfig> CreateUnencrypted( 61 uint8_t config_id, uint8_t server_id_len, uint8_t nonce_len); 62 63 // Returns an invalid Server ID if ciphertext is too small, or needed keys are 64 // missing. |ciphertext| contains the full connection ID minus the first byte. 65 // 66 // IMPORTANT: The decoder data path is likely the most performance-sensitive 67 // part of the load balancer design, and this code has been carefully 68 // optimized for performance. Please do not make changes without running the 69 // benchmark tests to ensure there is no regression. 70 bool FourPassDecrypt(absl::Span<const uint8_t> ciphertext, 71 LoadBalancerServerId& server_id) const; 72 // Returns an empty connection ID if the plaintext is too small, or needed 73 // keys are missing. |plaintext| contains the full unencrypted connection ID, 74 // including the first byte. 75 QuicConnectionId FourPassEncrypt(absl::Span<uint8_t> plaintext) const; 76 77 // Use the key to do a block encryption, which is used both in all cases of 78 // encrypted configs. Returns false if there's no key. Type char is 79 // convenient because that's what QuicConnectionId uses. 80 ABSL_MUST_USE_RESULT bool BlockEncrypt( 81 const uint8_t plaintext[kLoadBalancerBlockSize], 82 uint8_t ciphertext[kLoadBalancerBlockSize]) const; 83 // Returns false if the config does not require block decryption. 84 ABSL_MUST_USE_RESULT bool BlockDecrypt( 85 const uint8_t ciphertext[kLoadBalancerBlockSize], 86 uint8_t plaintext[kLoadBalancerBlockSize]) const; 87 config_id()88 uint8_t config_id() const { return config_id_; } server_id_len()89 uint8_t server_id_len() const { return server_id_len_; } nonce_len()90 uint8_t nonce_len() const { return nonce_len_; } 91 // Returns length of all but the first octet. plaintext_len()92 uint8_t plaintext_len() const { return server_id_len_ + nonce_len_; } 93 // Returns length of the entire connection ID. total_len()94 uint8_t total_len() const { return server_id_len_ + nonce_len_ + 1; } IsEncrypted()95 bool IsEncrypted() const { return key_.has_value(); } 96 97 private: 98 friend class test::LoadBalancerConfigPeer; 99 100 // Constructor is private because it doesn't validate input. 101 LoadBalancerConfig(uint8_t config_id, uint8_t server_id_len, 102 uint8_t nonce_len, absl::string_view key); 103 104 // Initialize state for 4-pass encryption passes, using the connection ID 105 // provided in |input|. Returns true if the plaintext is an odd number of 106 // bytes. |half_len| is half the length of the plaintext, rounded up. 107 bool InitializeFourPass(const uint8_t* input, uint8_t* left, uint8_t* right, 108 uint8_t* half_len) const; 109 // Handles one pass of 4-pass encryption for both encrypt and decrypt. 110 void EncryptionPass(uint8_t index, uint8_t half_len, bool is_length_odd, 111 uint8_t* left, uint8_t* right) const; 112 113 uint8_t config_id_; 114 uint8_t server_id_len_; 115 uint8_t nonce_len_; 116 // All Connection ID encryption and decryption uses the AES_encrypt function 117 // at root, so there is a single key for all of it. This is empty if the 118 // config is not encrypted. 119 std::optional<AES_KEY> key_; 120 // The one exception is that when total_len == 16, connection ID decryption 121 // uses AES_decrypt. The bytes that comprise the key are the same, but 122 // AES_decrypt requires an AES_KEY that is initialized differently. In all 123 // other cases, block_decrypt_key_ is empty. 124 std::optional<AES_KEY> block_decrypt_key_; 125 }; 126 127 } // namespace quic 128 129 #endif // QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_CONFIG_H_ 130