| #ifndef QUICHE_OBLIVIOUS_HTTP_COMMON_OBLIVIOUS_HTTP_HEADER_KEY_CONFIG_H_ | |
| #define QUICHE_OBLIVIOUS_HTTP_COMMON_OBLIVIOUS_HTTP_HEADER_KEY_CONFIG_H_ | |
| #include <stdint.h> | |
| #include "absl/container/btree_map.h" | |
| #include "absl/container/flat_hash_map.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| #include "openssl/base.h" | |
| #include "quiche/common/platform/api/quiche_export.h" | |
| #include "quiche/common/quiche_data_reader.h" | |
| namespace quiche { | |
| class QUICHE_EXPORT ObliviousHttpHeaderKeyConfig { | |
| public: | |
| // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#section-4.1-4.2 | |
| static constexpr absl::string_view kOhttpRequestLabel = | |
| "message/bhttp request"; | |
| static constexpr absl::string_view kOhttpResponseLabel = | |
| "message/bhttp response"; | |
| // Length of the Oblivious HTTP header. | |
| static constexpr uint32_t kHeaderLength = | |
| sizeof(uint8_t) + (3 * sizeof(uint16_t)); | |
| static constexpr absl::string_view kKeyHkdfInfo = "key"; | |
| static constexpr absl::string_view kNonceHkdfInfo = "nonce"; | |
| static absl::StatusOr<ObliviousHttpHeaderKeyConfig> Create(uint8_t key_id, | |
| uint16_t kem_id, | |
| uint16_t kdf_id, | |
| uint16_t aead_id); | |
| // Copyable to support stack allocated pass-by-value for trivial data members. | |
| ObliviousHttpHeaderKeyConfig(const ObliviousHttpHeaderKeyConfig& other) = | |
| default; | |
| ObliviousHttpHeaderKeyConfig& operator=( | |
| const ObliviousHttpHeaderKeyConfig& other) = default; | |
| // Movable. | |
| ObliviousHttpHeaderKeyConfig(ObliviousHttpHeaderKeyConfig&& other) = default; | |
| ObliviousHttpHeaderKeyConfig& operator=( | |
| ObliviousHttpHeaderKeyConfig&& other) = default; | |
| ~ObliviousHttpHeaderKeyConfig() = default; | |
| const EVP_HPKE_KEM* GetHpkeKem() const; | |
| const EVP_HPKE_KDF* GetHpkeKdf() const; | |
| const EVP_HPKE_AEAD* GetHpkeAead() const; | |
| uint8_t GetKeyId() const { return key_id_; } | |
| uint16_t GetHpkeKemId() const { return kem_id_; } | |
| uint16_t GetHpkeKdfId() const { return kdf_id_; } | |
| uint16_t GetHpkeAeadId() const { return aead_id_; } | |
| // Build HPKE context info ["message/bhttp request", 0x00, keyID(1 byte), | |
| // kemID(2 bytes), kdfID(2 bytes), aeadID(2 bytes)] in network byte order and | |
| // return a sequence of bytes(bytestring). | |
| // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#section-4.1-10 | |
| std::string SerializeRecipientContextInfo() const; | |
| // Parses the below Header | |
| // [keyID(1 byte), kemID(2 bytes), kdfID(2 bytes), aeadID(2 bytes)] | |
| // from the payload received in Ohttp Request, and verifies that these values | |
| // match with the info stored in `this` namely [key_id_, kem_id_, kdf_id_, | |
| // aead_id_] | |
| // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#section-4.1-7 | |
| absl::Status ParseOhttpPayloadHeader(absl::string_view payload_bytes) const; | |
| // Parses the Oblivious HTTP header [keyID(1 byte), kemID(2 bytes), kdfID(2 | |
| // bytes), aeadID(2 bytes)] from the buffer initialized within | |
| // `QuicheDataReader`, and verifies these values against instantiated class | |
| // data namely [key_id_, kem_id_, kdf_id_, aead_id_] for a match. On | |
| // success(i.e., if matched successfully), leaves `reader` pointing at the | |
| // first byte after the header. | |
| absl::Status ParseOhttpPayloadHeader(QuicheDataReader& reader) const; | |
| // Extracts Key ID from the OHTTP Request payload. | |
| static absl::StatusOr<uint8_t> ParseKeyIdFromObliviousHttpRequestPayload( | |
| absl::string_view payload_bytes); | |
| // Build Request header according to network byte order and return string. | |
| std::string SerializeOhttpPayloadHeader() const; | |
| private: | |
| // Constructor | |
| explicit ObliviousHttpHeaderKeyConfig(uint8_t key_id, uint16_t kem_id, | |
| uint16_t kdf_id, uint16_t aead_id); | |
| // Helps validate Key configuration for supported schemes. | |
| absl::Status ValidateKeyConfig() const; | |
| // Public Key configuration hosted by Gateway to facilitate Oblivious HTTP | |
| // HPKE encryption. | |
| // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-03.html#name-key-configuration-encoding | |
| uint8_t key_id_; | |
| uint16_t kem_id_; | |
| uint16_t kdf_id_; | |
| uint16_t aead_id_; | |
| }; | |
| // Contains multiple ObliviousHttpHeaderKeyConfig objects and associated private | |
| // keys. An ObliviousHttpHeaderKeyConfigs object can be constructed from the | |
| // "Key Configuration" defined in the Oblivious HTTP spec. Multiple key | |
| // configurations maybe be supported by the server. | |
| // | |
| // See https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-04.html#section-3 | |
| // for details of the "Key Configuration" spec. | |
| // | |
| // ObliviousHttpKeyConfigs objects are immutable after construction. | |
| class QUICHE_EXPORT ObliviousHttpKeyConfigs { | |
| public: | |
| // Parses the "application/ohttp-keys" media type, which is a byte string | |
| // formatted according to the spec: | |
| // https://www.ietf.org/archive/id/draft-ietf-ohai-ohttp-04.html#section-3 | |
| static absl::StatusOr<ObliviousHttpKeyConfigs> ParseConcatenatedKeys( | |
| absl::string_view key_configs); | |
| int NumKeys() const { return public_keys_.size(); } | |
| // Returns a preferred config to use. The preferred key is the key with | |
| // the highest key_id. If more than one configuration exists for the | |
| // preferred key any configuration may be returned. | |
| // | |
| // These methods are useful in the (common) case where only one key | |
| // configuration is supported by the server. | |
| ObliviousHttpHeaderKeyConfig PreferredConfig() const; | |
| absl::StatusOr<absl::string_view> GetPublicKeyForId(uint8_t key_id) const; | |
| // TODO(kmg): Add methods to somehow access other non-preferred key | |
| // configurations. | |
| private: | |
| using PublicKeyMap = absl::flat_hash_map<uint8_t, std::string>; | |
| using ConfigMap = | |
| absl::btree_map<uint8_t, std::vector<ObliviousHttpHeaderKeyConfig>, | |
| std::greater<uint8_t>>; | |
| ObliviousHttpKeyConfigs(ConfigMap cm, PublicKeyMap km) | |
| : configs_(std::move(cm)), public_keys_(std::move(km)) {} | |
| static absl::Status ReadSingleKeyConfig(QuicheDataReader& reader, | |
| ConfigMap& configs, | |
| PublicKeyMap& keys); | |
| // A mapping from key_id to ObliviousHttpHeaderKeyConfig objects for that key. | |
| const ConfigMap configs_; | |
| // A mapping from key_id to the public key for that key_id. | |
| const PublicKeyMap public_keys_; | |
| }; | |
| } // namespace quiche | |
| #endif // QUICHE_OBLIVIOUS_HTTP_COMMON_OBLIVIOUS_HTTP_HEADER_KEY_CONFIG_H_ |