Commit eee8c331 authored by Kunihiko Sakamoto's avatar Kunihiko Sakamoto Committed by Commit Bot

Signed Exchange: Update to draft-thomson-http-mice-03

This patch updates the followings:

- Use the Digest header instead of the MI header
- Update the identifier from mi-sha256-draft2 to mi-sha256-03
- The top-proof is now encoded in standard base64, not base64url

Http-mice-03 also changes the behavior on 0-length payloads. That will
be addressed in a followup CL.

Bug: 875721
Change-Id: I4c53a5ed6c25a62685d523c7a9d4583875a940c2
Reviewed-on: https://chromium-review.googlesource.com/1180955
Commit-Queue: Kunihiko Sakamoto <ksakamoto@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarDavid Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585311}
parent 9c4449ba
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include <string.h> #include <string.h>
#include "base/base64url.h" #include "base/base64.h"
#include "base/big_endian.h" #include "base/big_endian.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
...@@ -19,7 +19,7 @@ namespace { ...@@ -19,7 +19,7 @@ namespace {
// maximum record size in TLS and the default maximum frame size in HTTP/2. // maximum record size in TLS and the default maximum frame size in HTTP/2.
constexpr uint64_t kMaxRecordSize = 16 * 1024; constexpr uint64_t kMaxRecordSize = 16 * 1024;
constexpr char kMiSha256Header[] = "mi-sha256-draft2="; constexpr char kMiSha256Header[] = "mi-sha256-03=";
constexpr size_t kMiSha256HeaderLength = sizeof(kMiSha256Header) - 1; constexpr size_t kMiSha256HeaderLength = sizeof(kMiSha256Header) - 1;
// Copies as many bytes from |input| as will fit in |output| and advances both. // Copies as many bytes from |input| as will fit in |output| and advances both.
...@@ -34,15 +34,13 @@ size_t CopyClamped(base::span<const char>* input, base::span<char>* output) { ...@@ -34,15 +34,13 @@ size_t CopyClamped(base::span<const char>* input, base::span<char>* output) {
} // namespace } // namespace
MerkleIntegritySourceStream::MerkleIntegritySourceStream( MerkleIntegritySourceStream::MerkleIntegritySourceStream(
base::StringPiece mi_header_value, base::StringPiece digest_header_value,
std::unique_ptr<SourceStream> upstream) std::unique_ptr<SourceStream> upstream)
// TODO(ksakamoto): Use appropriate SourceType. // TODO(ksakamoto): Use appropriate SourceType.
: net::FilterSourceStream(SourceStream::TYPE_NONE, std::move(upstream)) { : net::FilterSourceStream(SourceStream::TYPE_NONE, std::move(upstream)) {
// TODO(ksakamoto): Support quoted parameter value.
std::string next_proof; std::string next_proof;
if (!mi_header_value.starts_with(kMiSha256Header) || if (!digest_header_value.starts_with(kMiSha256Header) ||
!base::Base64UrlDecode(mi_header_value.substr(kMiSha256HeaderLength), !base::Base64Decode(digest_header_value.substr(kMiSha256HeaderLength),
base::Base64UrlDecodePolicy::DISALLOW_PADDING,
&next_proof) || &next_proof) ||
next_proof.size() != SHA256_DIGEST_LENGTH) { next_proof.size() != SHA256_DIGEST_LENGTH) {
failed_ = true; failed_ = true;
......
...@@ -19,12 +19,12 @@ namespace content { ...@@ -19,12 +19,12 @@ namespace content {
// MerkleIntegritySourceStream decodes and validates content encoded with the // MerkleIntegritySourceStream decodes and validates content encoded with the
// "mi-sha256" content encoding // "mi-sha256" content encoding
// (https://tools.ietf.org/html/draft-thomson-http-mice-02). // (https://tools.ietf.org/html/draft-thomson-http-mice-03).
// TODO(ksakamoto): This class should eventually live in src/net/filter/. // TODO(ksakamoto): This class should eventually live in src/net/filter/.
class CONTENT_EXPORT MerkleIntegritySourceStream class CONTENT_EXPORT MerkleIntegritySourceStream
: public net::FilterSourceStream { : public net::FilterSourceStream {
public: public:
MerkleIntegritySourceStream(base::StringPiece mi_header_value, MerkleIntegritySourceStream(base::StringPiece digest_header_value,
std::unique_ptr<SourceStream> upstream); std::unique_ptr<SourceStream> upstream);
~MerkleIntegritySourceStream() override; ~MerkleIntegritySourceStream() override;
......
...@@ -92,7 +92,7 @@ TEST(SignedExchangeEnvelopeTest, ParseGoldenFile) { ...@@ -92,7 +92,7 @@ TEST(SignedExchangeEnvelopeTest, ParseGoldenFile) {
EXPECT_EQ(envelope->response_code(), static_cast<net::HttpStatusCode>(200u)); EXPECT_EQ(envelope->response_code(), static_cast<net::HttpStatusCode>(200u));
EXPECT_EQ(envelope->response_headers().size(), 3u); EXPECT_EQ(envelope->response_headers().size(), 3u);
EXPECT_EQ(envelope->response_headers().find("content-encoding")->second, EXPECT_EQ(envelope->response_headers().find("content-encoding")->second,
"mi-sha256-draft2"); "mi-sha256-03");
} }
TEST(SignedExchangeEnvelopeTest, ValidHeader) { TEST(SignedExchangeEnvelopeTest, ValidHeader) {
......
...@@ -47,7 +47,7 @@ namespace content { ...@@ -47,7 +47,7 @@ namespace content {
namespace { namespace {
constexpr char kMiHeader[] = "MI-Draft2"; constexpr char kDigestHeader[] = "Digest";
net::CertVerifier* g_cert_verifier_for_testing = nullptr; net::CertVerifier* g_cert_verifier_for_testing = nullptr;
...@@ -520,16 +520,16 @@ void SignedExchangeHandler::OnCertVerifyComplete(int result) { ...@@ -520,16 +520,16 @@ void SignedExchangeHandler::OnCertVerifyComplete(int result) {
response_head.load_timing.send_end = now; response_head.load_timing.send_end = now;
response_head.load_timing.receive_headers_end = now; response_head.load_timing.receive_headers_end = now;
std::string mi_header_value; std::string digest_header_value;
if (!response_head.headers->EnumerateHeader(nullptr, kMiHeader, if (!response_head.headers->EnumerateHeader(nullptr, kDigestHeader,
&mi_header_value)) { &digest_header_value)) {
signed_exchange_utils::ReportErrorAndTraceEvent( signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy_.get(), "Signed exchange has no MI-Draft2: header"); devtools_proxy_.get(), "Signed exchange has no Digest: header");
RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE); RunErrorCallback(net::ERR_INVALID_SIGNED_EXCHANGE);
return; return;
} }
auto mi_stream = std::make_unique<MerkleIntegritySourceStream>( auto mi_stream = std::make_unique<MerkleIntegritySourceStream>(
mi_header_value, std::move(source_)); digest_header_value, std::move(source_));
net::SSLInfo ssl_info; net::SSLInfo ssl_info;
ssl_info.cert = cert_verify_result_.verified_cert; ssl_info.cert = cert_verify_result_.verified_cert;
......
...@@ -347,10 +347,11 @@ SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify( ...@@ -347,10 +347,11 @@ SignedExchangeSignatureVerifier::Result SignedExchangeSignatureVerifier::Verify(
} }
if (!base::EqualsCaseInsensitiveASCII(envelope.signature().integrity, if (!base::EqualsCaseInsensitiveASCII(envelope.signature().integrity,
"mi-draft2")) { "digest/mi-sha256-03")) {
signed_exchange_utils::ReportErrorAndTraceEvent( signed_exchange_utils::ReportErrorAndTraceEvent(
devtools_proxy, devtools_proxy,
"The current implemention only supports \"mi\" integrity scheme."); "The current implemention only supports \"digest/mi-sha256-03\" "
"integrity scheme.");
return Result::kErrInvalidSignatureIntegrity; return Result::kErrInvalidSignatureIntegrity;
} }
return Result::kSuccess; return Result::kSuccess;
......
...@@ -20,7 +20,7 @@ TEST(SignedExchangeSignatureVerifier, EncodeCanonicalExchangeHeaders) { ...@@ -20,7 +20,7 @@ TEST(SignedExchangeSignatureVerifier, EncodeCanonicalExchangeHeaders) {
envelope.set_request_url(GURL("https://example.com/index.html")); envelope.set_request_url(GURL("https://example.com/index.html"));
envelope.set_response_code(net::HTTP_OK); envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8"); envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2"); envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
base::Optional<std::vector<uint8_t>> encoded = base::Optional<std::vector<uint8_t>> encoded =
SignedExchangeSignatureVerifier::EncodeCanonicalExchangeHeaders(envelope); SignedExchangeSignatureVerifier::EncodeCanonicalExchangeHeaders(envelope);
...@@ -51,9 +51,9 @@ TEST(SignedExchangeSignatureVerifier, EncodeCanonicalExchangeHeaders) { ...@@ -51,9 +51,9 @@ TEST(SignedExchangeSignatureVerifier, EncodeCanonicalExchangeHeaders) {
0x50, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x50, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e,
0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, // bytes "content-encoding" 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, // bytes "content-encoding"
0x50, 0x6d, 0x69, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2d, 0x4c, 0x6d, 0x69, 0x2d, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x2d,
0x64, 0x72, 0x61, 0x66, 0x74, 0x32 0x30, 0x33
// bytes "mi-sha256-draft2" // bytes "mi-sha256-03"
// clang-format on // clang-format on
}; };
EXPECT_THAT(*encoded, EXPECT_THAT(*encoded,
...@@ -65,9 +65,9 @@ const uint64_t kSignatureHeaderExpires = 1517895941; ...@@ -65,9 +65,9 @@ const uint64_t kSignatureHeaderExpires = 1517895941;
// See content/testdata/sxg/README on how to generate these data. // See content/testdata/sxg/README on how to generate these data.
// clang-format off // clang-format off
constexpr char kSignatureHeaderRSA[] = R"(label; sig=*yYFb09i7VXuqsGBxc3RuJzGL4XMD9bZ20kXWSv1JObEf7KIG0MznSE1nu1fE+7DrgWQxH7FQfSWjyseOAvxsBOfkptmCCi/Ffklz3N1UU8LfwfaLWj80oBqDeofiIYwevSSpsaRKBYie7KjiVOjslFLOGe82MmHyF2utFRKY/i6UAHgMrg2FGfbwBaJsxEgtpPcN8/QnFKgt1la+JjwvYbMHpJhHTedDqx9GCxJOzbJjKRL1E2tIBvhDfK2m3eJv/nqvgWkK3MOd/Xp4FkndciS3eNyZZjwvJ6IL/3x4e0AZ36KvglpS092ZftiE4lKQWnHmVeDRmEHW6qOyv1Q3+w==*; validity-url="https://example.com/resource.validity.msg"; integrity="mi-draft2"; cert-url="https://example.com/cert.msg"; cert-sha256=*tJGJP8ej7KCEW8VnVK3bKwpBza/oLrtWA75z5ZPptuc=*; date=1517892341; expires=1517895941)"; constexpr char kSignatureHeaderRSA[] = R"(label; sig=*HrNLDfn6oHUmfx3YvP7dTseyZdmnQQB7jR8yea0FezZmy7IwJVtcZ/tGpXJ6fe8druTsGeFArdCeeLBapmPLq8BP6k6Uk2ClKUWNbM3is/HHaWWsfpLBF2fETKEBXvvUI9G8nJqDLJ9RS3AAZMEG+OrCybR1kEFDhc+Cp34isj8aUn7OG1ugq8ADt1DkP8xwSLn4MA2E6tHdG1dNNs+GpWE5pUbqe49DdQaQp/DcvOpixeDi3iID2VHDeASfyCVQvxNfEPRLKQ5fOELlGerTVY5XTXeegUfUuzTRHDsOBTPQ4iihCK2+/8vRwx92sExXnMH163ZL/YIM55FoU2KuRQ==*; validity-url="https://example.com/resource.validity.msg"; integrity="digest/mi-sha256-03"; cert-url="https://example.com/cert.msg"; cert-sha256=*tJGJP8ej7KCEW8VnVK3bKwpBza/oLrtWA75z5ZPptuc=*; date=1517892341; expires=1517895941)";
constexpr char kSignatureHeaderECDSAP256[] = R"(label; sig=*MEQCIA0w6auOuWGT6//MO/h43/xkXBchJUOp53GU5dmA8U+/AiAe0FggCblVxzosT2Ow9rrC2Q8zO0DZPLSNbcu29xYP6g==*; validity-url="https://example.com/resource.validity.msg"; integrity="mi-draft2"; cert-url="https://example.com/cert.msg"; cert-sha256=*KX+BYLSMgDOON8Ju65RoId39Qvajxa12HO+WnD4HpS0=*; date=1517892341; expires=1517895941)"; constexpr char kSignatureHeaderECDSAP256[] = R"(label; sig=*MEYCIQD0rF/pJqqYa9WEE6eZcGzrVKv8yx+78tLAATxfLlyoWgIhAPJoiWcYAC+vDrZ1m5qE++y1TLdYUenwV84vpAaV3wTG*; validity-url="https://example.com/resource.validity.msg"; integrity="digest/mi-sha256-03"; cert-url="https://example.com/cert.msg"; cert-sha256=*KX+BYLSMgDOON8Ju65RoId39Qvajxa12HO+WnD4HpS0=*; date=1517892341; expires=1517895941)";
constexpr char kSignatureHeaderECDSAP384[] = R"(label; sig=*MGYCMQC/P8m0ZnPrIMlI3I412MixcK9cQSirIECUNR7pOIlTiLaH95L72KXqq2aL+lxxKIICMQDU3s/BhoWtR61eKG9SqgGHd0ZtUJVY24xaJ2yHiYWxZU/QhOr5ZArSj3x1khivpRg=*; validity-url="https://example.com/resource.validity.msg"; integrity="mi-draft2"; cert-url="https://example.com/cert.msg"; cert-sha256=*8X8y8nj8vDJHSSa0cxn+TCu+8zGpIJfbdzAnd5cW+jA=*; date=1517892341; expires=1517895941)"; constexpr char kSignatureHeaderECDSAP384[] = R"(label; sig=*MGUCMDkTn0MhRiG0OfbAbnyXRgM8XSV8vjm5w0olX5qoL94LEiJ7zS4ZmdxvSNHp5luK5QIxAPlQRvcIBq8vvKgkzQCjsbZ/jEAKh1Gx2JKSyj4HRfLWRar4KbGbMm+GbyU7N/SZYQ==*; validity-url="https://example.com/resource.validity.msg"; integrity="digest/mi-sha256-03"; cert-url="https://example.com/cert.msg"; cert-sha256=*8X8y8nj8vDJHSSa0cxn+TCu+8zGpIJfbdzAnd5cW+jA=*; date=1517892341; expires=1517895941)";
// clang-format on // clang-format on
// |expires| (1518497142) is more than 7 days (604800 seconds) after |date| // |expires| (1518497142) is more than 7 days (604800 seconds) after |date|
...@@ -255,10 +255,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyRSA) { ...@@ -255,10 +255,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyRSA) {
envelope.set_request_url(GURL("https://test.example.org/test/")); envelope.set_request_url(GURL("https://test.example.org/test/"));
envelope.set_response_code(net::HTTP_OK); envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8"); envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2"); envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
envelope.AddResponseHeader( envelope.AddResponseHeader(
"mi-draft2", "digest", "mi-sha256-03=wmp4dRMYgxP3tSMCwV/I0CWOCiHZpAihKZk19bsN9RI=");
"mi-sha256-draft2=wmp4dRMYgxP3tSMCwV_I0CWOCiHZpAihKZk19bsN9RI");
envelope.SetSignatureForTesting((*signature)[0]); envelope.SetSignatureForTesting((*signature)[0]);
EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrUnsupportedCertType, EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrUnsupportedCertType,
...@@ -284,10 +283,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP256) { ...@@ -284,10 +283,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP256) {
envelope.set_request_url(GURL("https://test.example.org/test/")); envelope.set_request_url(GURL("https://test.example.org/test/"));
envelope.set_response_code(net::HTTP_OK); envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8"); envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2"); envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
envelope.AddResponseHeader( envelope.AddResponseHeader(
"mi-draft2", "digest", "mi-sha256-03=wmp4dRMYgxP3tSMCwV/I0CWOCiHZpAihKZk19bsN9RI=");
"mi-sha256-draft2=wmp4dRMYgxP3tSMCwV_I0CWOCiHZpAihKZk19bsN9RI");
envelope.SetSignatureForTesting((*signature)[0]); envelope.SetSignatureForTesting((*signature)[0]);
...@@ -311,10 +309,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP384) { ...@@ -311,10 +309,9 @@ TEST_F(SignedExchangeSignatureVerifierTest, VerifyECDSAP384) {
envelope.set_request_url(GURL("https://test.example.org/test/")); envelope.set_request_url(GURL("https://test.example.org/test/"));
envelope.set_response_code(net::HTTP_OK); envelope.set_response_code(net::HTTP_OK);
envelope.AddResponseHeader("content-type", "text/html; charset=utf-8"); envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
envelope.AddResponseHeader("content-encoding", "mi-sha256-draft2"); envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
envelope.AddResponseHeader( envelope.AddResponseHeader(
"mi-draft2", "digest", "mi-sha256-03=wmp4dRMYgxP3tSMCwV/I0CWOCiHZpAihKZk19bsN9RIG=");
"mi-sha256-draft2=wmp4dRMYgxP3tSMCwV_I0CWOCiHZpAihKZk19bsN9RIG");
envelope.SetSignatureForTesting((*signature)[0]); envelope.SetSignatureForTesting((*signature)[0]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment