blob: 6447bab6c2b5b1780080d472271a099106ae4025 [file] [log] [blame]
#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_PRIVATE ObliviousHttpHeaderKeyConfig {
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) =
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).
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_]
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;
// 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.
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
// for details of the "Key Configuration" spec.
// ObliviousHttpKeyConfigs objects are immutable after construction.
class QUICHE_EXPORT_PRIVATE ObliviousHttpKeyConfigs {
// Parses the "application/ohttp-keys" media type, which is a byte string
// formatted according to the spec:
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.
using PublicKeyMap = absl::flat_hash_map<uint8_t, std::string>;
using ConfigMap =
absl::btree_map<uint8_t, std::vector<ObliviousHttpHeaderKeyConfig>,
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