xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/load_balancer/load_balancer_config.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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