Allow masque_server to check signature auth on GET requests This CL refactors requests handling such that it is now possible to route GET requests through the MASQUE handling to check signature auth for them. This CL also fixes one more bug in HTTP signature auth. Since "\x00" is technically a const char*, absl::StrCat treats it like a NULL-terminated C-string, causing it to treat it like the empty string. Using std::string(1, 0x00) will instead correctly tell absl::StrCat that this is a one-byte long string of NULL-byte. With this fix, we successfully achieved interop between masque_client and the http-signature-auth-go server implementation! PiperOrigin-RevId: 600137791
diff --git a/quiche/quic/masque/masque_server_backend.cc b/quiche/quic/masque/masque_server_backend.cc index 1586a77..9b75bcd 100644 --- a/quiche/quic/masque/masque_server_backend.cc +++ b/quiche/quic/masque/masque_server_backend.cc
@@ -59,7 +59,9 @@ protocol_pair->second != "connect-ip" && protocol_pair->second != "connect-ethernet")) { // This is not a MASQUE request. - return false; + if (!signature_auth_on_all_requests_) { + return false; + } } if (!server_authority_.empty()) {
diff --git a/quiche/quic/masque/masque_server_backend.h b/quiche/quic/masque/masque_server_backend.h index 2285291..7a938fe 100644 --- a/quiche/quic/masque/masque_server_backend.h +++ b/quiche/quic/masque/masque_server_backend.h
@@ -83,6 +83,16 @@ absl::string_view key_id, uint8_t out_public_key[ED25519_PUBLIC_KEY_LEN]) const; + // Enable signature auth on all requests (e.g., GET) instead of just MASQUE. + void SetSignatureAuthOnAllRequests(bool signature_auth_on_all_requests) { + signature_auth_on_all_requests_ = signature_auth_on_all_requests; + } + + // Whether signature auth is enabled on all requests (e.g., GET). + bool IsSignatureAuthOnAllRequests() const { + return signature_auth_on_all_requests_; + } + private: // Handle MASQUE request. bool MaybeHandleMasqueRequest( @@ -105,6 +115,7 @@ uint8_t public_key[ED25519_PUBLIC_KEY_LEN]; }; std::list<SignatureAuthCredential> signature_auth_credentials_; + bool signature_auth_on_all_requests_ = false; }; } // namespace quic
diff --git a/quiche/quic/masque/masque_server_bin.cc b/quiche/quic/masque/masque_server_bin.cc index ee5e1ea..51f5b40 100644 --- a/quiche/quic/masque/masque_server_bin.cc +++ b/quiche/quic/masque/masque_server_bin.cc
@@ -46,6 +46,11 @@ "Separated with colons and semicolons. " "For example: \"kid1:0123...f;kid2:0123...f\"."); +DEFINE_QUICHE_COMMAND_LINE_FLAG( + bool, signature_auth_on_all_requests, false, + "If set to true, enable signature auth on all requests (such as GET) " + "instead of just MASQUE."); + int main(int argc, char* argv[]) { const char* usage = "Usage: masque_server [options]"; std::vector<std::string> non_option_args = @@ -69,6 +74,8 @@ backend->SetSignatureAuth( quiche::GetQuicheCommandLineFlag(FLAGS_signature_auth)); + backend->SetSignatureAuthOnAllRequests( + quiche::GetQuicheCommandLineFlag(FLAGS_signature_auth_on_all_requests)); auto server = std::make_unique<quic::MasqueServer>(masque_mode, backend.get());
diff --git a/quiche/quic/masque/masque_server_session.cc b/quiche/quic/masque/masque_server_session.cc index 8bca482..6a88ae3 100644 --- a/quiche/quic/masque/masque_server_session.cc +++ b/quiche/quic/masque/masque_server_session.cc
@@ -389,59 +389,76 @@ std::unique_ptr<QuicBackendResponse> MasqueServerSession::HandleMasqueRequest( const spdy::Http2HeaderBlock& request_headers, QuicSimpleServerBackend::RequestHandler* request_handler) { - auto path_pair = request_headers.find(":path"); - auto scheme_pair = request_headers.find(":scheme"); - auto method_pair = request_headers.find(":method"); - auto protocol_pair = request_headers.find(":protocol"); + // Authority. auto authority_pair = request_headers.find(":authority"); - if (path_pair == request_headers.end()) { - QUIC_DLOG(ERROR) << "MASQUE request is missing :path"; - return CreateBackendErrorResponse("400", "Missing :path"); - } - if (scheme_pair == request_headers.end()) { - QUIC_DLOG(ERROR) << "MASQUE request is missing :scheme"; - return CreateBackendErrorResponse("400", "Missing :scheme"); - } - if (method_pair == request_headers.end()) { - QUIC_DLOG(ERROR) << "MASQUE request is missing :method"; - return CreateBackendErrorResponse("400", "Missing :method"); - } - if (protocol_pair == request_headers.end()) { - QUIC_DLOG(ERROR) << "MASQUE request is missing :protocol"; - return CreateBackendErrorResponse("400", "Missing :protocol"); - } if (authority_pair == request_headers.end()) { QUIC_DLOG(ERROR) << "MASQUE request is missing :authority"; return CreateBackendErrorResponse("400", "Missing :authority"); } - absl::string_view path = path_pair->second; - absl::string_view scheme = scheme_pair->second; - absl::string_view method = method_pair->second; - absl::string_view protocol = protocol_pair->second; absl::string_view authority = authority_pair->second; - if (path.empty()) { - QUIC_DLOG(ERROR) << "MASQUE request with empty path"; - return CreateBackendErrorResponse("400", "Empty path"); + // Scheme. + auto scheme_pair = request_headers.find(":scheme"); + if (scheme_pair == request_headers.end()) { + QUIC_DLOG(ERROR) << "MASQUE request is missing :scheme"; + return CreateBackendErrorResponse("400", "Missing :scheme"); } + absl::string_view scheme = scheme_pair->second; if (scheme.empty()) { return CreateBackendErrorResponse("400", "Empty scheme"); } - if (method != "CONNECT") { - QUIC_DLOG(ERROR) << "MASQUE request with bad method \"" << method << "\""; - return CreateBackendErrorResponse("400", "Bad method"); - } - if (protocol != "connect-udp" && protocol != "connect-ip" && - protocol != "connect-ethernet") { - QUIC_DLOG(ERROR) << "MASQUE request with bad protocol \"" << protocol - << "\""; - return CreateBackendErrorResponse("400", "Bad protocol"); - } - + // Signature authentication. auto signature_auth_reply = MaybeCheckSignatureAuth( request_headers, authority, scheme, request_handler); if (signature_auth_reply) { return signature_auth_reply; } + // Path. + auto path_pair = request_headers.find(":path"); + if (path_pair == request_headers.end()) { + QUIC_DLOG(ERROR) << "MASQUE request is missing :path"; + return CreateBackendErrorResponse("400", "Missing :path"); + } + absl::string_view path = path_pair->second; + if (path.empty()) { + QUIC_DLOG(ERROR) << "MASQUE request with empty path"; + return CreateBackendErrorResponse("400", "Empty path"); + } + // Method. + auto method_pair = request_headers.find(":method"); + if (method_pair == request_headers.end()) { + QUIC_DLOG(ERROR) << "MASQUE request is missing :method"; + return CreateBackendErrorResponse("400", "Missing :method"); + } + absl::string_view method = method_pair->second; + if (method != "CONNECT") { + QUIC_DLOG(ERROR) << "MASQUE request with bad method \"" << method << "\""; + if (masque_server_backend_->IsSignatureAuthOnAllRequests()) { + return nullptr; + } else { + return CreateBackendErrorResponse("400", "Bad method"); + } + } + // Protocol. + auto protocol_pair = request_headers.find(":protocol"); + if (protocol_pair == request_headers.end()) { + QUIC_DLOG(ERROR) << "MASQUE request is missing :protocol"; + if (masque_server_backend_->IsSignatureAuthOnAllRequests()) { + return nullptr; + } else { + return CreateBackendErrorResponse("400", "Missing :protocol"); + } + } + absl::string_view protocol = protocol_pair->second; + if (protocol != "connect-udp" && protocol != "connect-ip" && + protocol != "connect-ethernet") { + QUIC_DLOG(ERROR) << "MASQUE request with bad protocol \"" << protocol + << "\""; + if (masque_server_backend_->IsSignatureAuthOnAllRequests()) { + return nullptr; + } else { + return CreateBackendErrorResponse("400", "Bad protocol"); + } + } if (protocol == "connect-ip") { QuicSpdyStream* stream = static_cast<QuicSpdyStream*>(
diff --git a/quiche/quic/masque/masque_utils.cc b/quiche/quic/masque/masque_utils.cc index 6cffb3a..b4ecdd4 100644 --- a/quiche/quic/masque/masque_utils.cc +++ b/quiche/quic/masque/masque_utils.cc
@@ -254,7 +254,7 @@ std::string SignatureAuthDataCoveredBySignature( absl::string_view signature_input) { return absl::StrCat(std::string(64, 0x20), "HTTP Signature Authentication", - "\0", signature_input); + std::string(1, 0x00), signature_input); } } // namespace quic