| #ifndef QUICHE_OBLIVIOUS_HTTP_BUFFERS_OBLIVIOUS_HTTP_REQUEST_H_ | |
| #define QUICHE_OBLIVIOUS_HTTP_BUFFERS_OBLIVIOUS_HTTP_REQUEST_H_ | |
| #include <optional> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| #include "openssl/hpke.h" | |
| #include "quiche/common/platform/api/quiche_export.h" | |
| #include "quiche/common/quiche_data_reader.h" | |
| #include "quiche/oblivious_http/common/oblivious_http_header_key_config.h" | |
| namespace quiche { | |
| // 1. Handles client side encryption of the payload that will subsequently be | |
| // added to HTTP POST body and passed on to Relay. | |
| // 2. Handles server side decryption of the payload received in HTTP POST body | |
| // from Relay. | |
| // https://www.rfc-editor.org/rfc/rfc9458.html#section-4.3 | |
| class QUICHE_EXPORT ObliviousHttpRequest { | |
| public: | |
| // Holds the HPKE related data received from request. This context is created | |
| // during request processing, and subsequently passed into response handling | |
| // in `ObliviousHttpResponse`. | |
| class QUICHE_EXPORT Context { | |
| public: | |
| ~Context() = default; | |
| // Movable | |
| Context(Context&& other) = default; | |
| Context& operator=(Context&& other) = default; | |
| std::string GetEncapsulatedKey() const { return encapsulated_key_; } | |
| private: | |
| explicit Context(bssl::UniquePtr<EVP_HPKE_CTX> hpke_context, | |
| std::string encapsulated_key); | |
| // All accessors must be friends to read `Context`. | |
| friend class ObliviousHttpRequest; | |
| friend class ObliviousHttpResponse; | |
| // Tests which need access. | |
| friend class | |
| ObliviousHttpRequest_TestDecapsulateWithSpecAppendixAExample_Test; | |
| friend class ObliviousHttpRequest_TestEncapsulatedRequestStructure_Test; | |
| friend class | |
| ObliviousHttpRequest_TestEncapsulatedOhttpEncryptedPayload_Test; | |
| friend class ObliviousHttpRequest_TestDeterministicSeededOhttpRequest_Test; | |
| friend class ObliviousHttpResponse_EndToEndTestForResponse_Test; | |
| friend class ObliviousHttpResponse_TestEncapsulateWithQuicheRandom_Test; | |
| bssl::UniquePtr<EVP_HPKE_CTX> hpke_context_; | |
| std::string encapsulated_key_; | |
| }; | |
| // Parse the OHTTP request from the given `encrypted_data`. | |
| // On success, returns obj that callers will use to `GetPlaintextData`. | |
| // Generic Usecase : server-side calls this method in the context of Request. | |
| static absl::StatusOr<ObliviousHttpRequest> CreateServerObliviousRequest( | |
| absl::string_view encrypted_data, const EVP_HPKE_KEY& gateway_key, | |
| const ObliviousHttpHeaderKeyConfig& ohttp_key_config, | |
| absl::string_view request_label = | |
| ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel); | |
| // Constructs an OHTTP request for the given `plaintext_payload`. | |
| // On success, returns obj that callers will use to `EncapsulateAndSerialize` | |
| // OHttp request. | |
| static absl::StatusOr<ObliviousHttpRequest> CreateClientObliviousRequest( | |
| std::string plaintext_payload, absl::string_view hpke_public_key, | |
| const ObliviousHttpHeaderKeyConfig& ohttp_key_config, | |
| absl::string_view request_label = | |
| ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel); | |
| // Same as above but accepts a random number seed for testing. | |
| static absl::StatusOr<ObliviousHttpRequest> CreateClientWithSeedForTesting( | |
| std::string plaintext_payload, absl::string_view hpke_public_key, | |
| const ObliviousHttpHeaderKeyConfig& ohttp_key_config, | |
| absl::string_view seed, | |
| absl::string_view request_label = | |
| ObliviousHttpHeaderKeyConfig::kOhttpRequestLabel); | |
| // Movable. | |
| ObliviousHttpRequest(ObliviousHttpRequest&& other) = default; | |
| ObliviousHttpRequest& operator=(ObliviousHttpRequest&& other) = default; | |
| ~ObliviousHttpRequest() = default; | |
| // Returns serialized OHTTP request bytestring. | |
| // @note: This method MUST NOT be called after `ReleaseContext()` has been | |
| // called. | |
| std::string EncapsulateAndSerialize() const; | |
| // Generic Usecase : server-side calls this method after Decapsulation using | |
| // `CreateServerObliviousRequest`. | |
| absl::string_view GetPlaintextData() const; | |
| // Oblivious HTTP request context is created after successful creation of | |
| // `this` object, and subsequently passed into the `ObliviousHttpResponse` for | |
| // followup response handling. | |
| // @returns: This rvalue reference qualified member function transfers the | |
| // ownership of `Context` to the caller, and further invokes | |
| // ClangTidy:misc-use-after-move warning if callers try to extract `Context` | |
| // twice after the fact that the ownership has already been transferred. | |
| // @note: Callers shouldn't extract the `Context` until you're done with this | |
| // Request and its data. | |
| Context ReleaseContext() && { | |
| return std::move(oblivious_http_request_context_.value()); | |
| } | |
| // Reads the OHTTP request header from the given `reader`. | |
| // On success, attempts to setup and return the Gateway Context. | |
| static absl::StatusOr<Context> DecodeEncapsulatedRequestHeader( | |
| QuicheDataReader& reader, const EVP_HPKE_KEY& gateway_key, | |
| const ObliviousHttpHeaderKeyConfig& ohttp_key_config, | |
| absl::string_view request_label); | |
| // Creates the client's HPKE sender context. | |
| static absl::StatusOr<Context> CreateHpkeSenderContext( | |
| absl::string_view hpke_public_key, | |
| const ObliviousHttpHeaderKeyConfig& ohttp_key_config, | |
| absl::string_view seed, absl::string_view request_label); | |
| // Encrypts a chunk of plaintext. If `is_final_chunk` is true, the chunk will | |
| // be encrypted with a final AAD. | |
| static absl::StatusOr<std::string> EncryptChunk( | |
| absl::string_view plaintext_payload, const Context& context, | |
| bool is_final_chunk); | |
| // Decrypts an encrypted chunk. If `is_final_chunk` is true, the chunk will | |
| // be decrypted with a final AAD. | |
| static absl::StatusOr<std::string> DecryptChunk( | |
| Context& context, absl::string_view encrypted_chunk, bool is_final_chunk); | |
| private: | |
| explicit ObliviousHttpRequest( | |
| bssl::UniquePtr<EVP_HPKE_CTX> hpke_context, std::string encapsulated_key, | |
| const ObliviousHttpHeaderKeyConfig& ohttp_key_config, | |
| std::string req_ciphertext, std::string req_plaintext); | |
| static absl::StatusOr<ObliviousHttpRequest> EncapsulateWithSeed( | |
| std::string plaintext_payload, absl::string_view hpke_public_key, | |
| const ObliviousHttpHeaderKeyConfig& ohttp_key_config, | |
| absl::string_view seed, absl::string_view request_label); | |
| // This field will be empty after calling `ReleaseContext()`. | |
| std::optional<Context> oblivious_http_request_context_; | |
| ObliviousHttpHeaderKeyConfig key_config_; | |
| std::string request_ciphertext_; | |
| std::string request_plaintext_; | |
| }; | |
| } // namespace quiche | |
| #endif // QUICHE_OBLIVIOUS_HTTP_BUFFERS_OBLIVIOUS_HTTP_REQUEST_H_ |