0

[SRI Message Signatures] Support the @target-uri derived component.

This CL adds support for the `@target-uri` derived component, as defined
in https://www.rfc-editor.org/rfc/rfc9421.html#name-target-uri.

Bug: 383409584
Change-Id: Ic37d62540aaef9abc2679163cf1fa3a8d3ba6054
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6578249
Commit-Queue: Mike West <mkwst@chromium.org>
Reviewed-by: Joe DeBlasio <jdeblasio@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1464565}
This commit is contained in:
Mike West
2025-05-22 22:26:58 -07:00
committed by Chromium LUCI CQ
parent 22dd0af342
commit 4693684f8f
2 changed files with 56 additions and 3 deletions

@ -29,12 +29,12 @@ const size_t kEd25519SigLength = 64;
constexpr std::string_view kAcceptSignature = "accept-signature";
constexpr std::array<std::string_view, 9u> kDerivedComponents = {
"@authority", "@query-param", "@query", "@method",
"@path", "@scheme", "@status"
"@authority", "@query-param", "@query", "@method",
"@path", "@scheme", "@status", "@target-uri",
// TODO(383409584): We should support the remaining derived components from
// https://www.rfc-editor.org/rfc/rfc9421.html#name-derived-components:
//
// "@request-target", "@target-uri",
// "@request-target"
};
ParameterType ParamNameToType(std::string_view name) {
@ -315,6 +315,14 @@ std::string SerializeDerivedComponent(
} else if (component->name == "@status") {
// https://www.rfc-editor.org/rfc/rfc9421.html#content-status-code
return base::NumberToString(response_status_code);
} else if (component->name == "@target-uri") {
// While we certainly need to clear any fragment component present in the
// requested URL, it's unclear whether `@target-uri` is intended to include
// the `userinfo` portion of a requested URL. For the moment, we'll strip
// those components as well, just as we do for referrers.
//
// https://datatracker.ietf.org/doc/html/rfc9421#content-target-uri
return url_request.url().GetAsReferrer().spec();
}
// TODO(383409584): Support additional derived components.

@ -1122,6 +1122,51 @@ TEST_F(SRIMessageSignatureBaseTest, PathComponent) {
}
}
TEST_F(SRIMessageSignatureBaseTest, TargetUriComponent) {
struct {
std::string_view url;
std::string_view target;
} cases[] = {
{"https://url.test/", "https://url.test/"},
{"https://url.test:8080/", "https://url.test:8080/"},
{"https://user:pass@url.test/", "https://url.test/"},
{"https://url.test/?a=b", "https://url.test/?a=b"},
{"https://url.test/#anchor", "https://url.test/"},
{"https://url.test/path", "https://url.test/path"},
{"https://url.test/path/", "https://url.test/path/"},
{"https://url.test/pAtH", "https://url.test/pAtH"},
{"https://url.test/%0Apath", "https://url.test/%0Apath"},
{"https://url.test/%0apath", "https://url.test/%0apath"},
{"https://url.test/path/../", "https://url.test/"},
{"https://url.test/ü", "https://url.test/%C3%BC"},
};
for (const auto& test : cases) {
SCOPED_TRACE(test.url);
std::string input_header = base::StrCat(
{"signature=(\"unencoded-digest\";sf \"@target-uri\";req);", "keyid=\"",
kPublicKey, "\";tag=\"ed25519-integrity\""});
std::stringstream expected_base;
expected_base << "\"unencoded-digest\";sf: " << kValidDigestHeader << '\n'
<< "\"@target-uri\";req: " << test.target << '\n'
<< "\"@signature-params\": (\"unencoded-digest\";sf "
"\"@target-uri\";req);"
<< "keyid=\"" << kPublicKey << "\";tag=\"ed25519-integrity\"";
auto headers = ValidHeadersPlusInput(input_header.c_str());
auto parsed = ParseSRIMessageSignaturesFromHeaders(*headers);
ASSERT_EQ(1u, parsed->signatures.size());
EXPECT_EQ(0u, parsed->issues.size());
request_ = CreateRequest(*context_, test.url);
std::optional<std::string> result =
ConstructSignatureBase(parsed->signatures[0], request(), *headers);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(expected_base.str(), result.value());
}
}
TEST_F(SRIMessageSignatureBaseTest, SchemeComponent) {
struct {
std::string_view url;