summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Kelly <wanderview@chromium.org>2021-02-02 15:45:09 +0000
committerMichael BrĂ¼ning <michael.bruning@qt.io>2021-04-20 12:57:09 +0000
commit8783292e8cb9179403dd425476a35f3b6fbae7cd (patch)
tree6ad4f01bc2cd50bb33f5a8551f0581e108bccb0b
parent4e34cdf60a697a3831bea711e0f55af76e043fab (diff)
[Backport] CVE-2021-21209: Inappropriate implementation in storage (3/5)
Manual backport of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/2590076: CacheStorage: Refactor opaque padding. This CL refactors how we generate and store opaque response padding: * Padding values are now generated immediately in fetch(). * Padding values are associated with the Response and follow it. * Network loaded responses get a purely random pad. * Http cache loaded responses get a hashed padding value. * CacheStorage now stores padding values in each entry. * CacheStorage entries with side data for code cache have a separate, additional padding value added. * Many additional tests. Bug: 1143526 Change-Id: I40b094097b64be7bab8899acad8b9baffe304d33 Reviewed-by: Yutaka Hirano <yhirano@chromium.org> Reviewed-by: Marijn Kruisselbrink <mek@chromium.org> Reviewed-by: Kinuko Yasuda <kinuko@chromium.org> Commit-Queue: Ben Kelly <wanderview@chromium.org> Cr-Commit-Position: refs/heads/master@{#849608} Change-Id: I56d667a2f0ad266a3cd978c842e78e501eb79c60 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--chromium/content/browser/appcache/appcache_backfillers.cc6
-rw-r--r--chromium/content/browser/appcache/appcache_database.cc1
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.cc7
-rw-r--r--chromium/content/browser/cache_storage/cache_storage.proto2
-rw-r--r--chromium/content/browser/cache_storage/cache_storage_histogram_utils.h3
-rw-r--r--chromium/content/browser/cache_storage/legacy/legacy_cache_storage.cc2
-rw-r--r--chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc287
-rw-r--r--chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h23
-rw-r--r--chromium/content/common/background_fetch/background_fetch_types.cc4
-rw-r--r--chromium/content/common/service_worker/service_worker_loader_helpers.cc1
-rw-r--r--chromium/content/renderer/loader/web_url_loader_impl.cc1
-rw-r--r--chromium/services/network/public/mojom/url_response_head.mojom6
-rw-r--r--chromium/storage/browser/BUILD.gn2
-rw-r--r--chromium/storage/browser/quota/padding_key.cc87
-rw-r--r--chromium/storage/browser/quota/padding_key.h70
-rw-r--r--chromium/storage/common/BUILD.gn2
-rw-r--r--chromium/storage/common/quota/padding_key.cc168
-rw-r--r--chromium/storage/common/quota/padding_key.h86
-rw-r--r--chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom4
-rw-r--r--chromium/third_party/blink/public/platform/web_url_response.h6
-rw-r--r--chromium/third_party/blink/renderer/core/BUILD.gn1
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/DEPS1
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h5
-rw-r--r--chromium/third_party/blink/renderer/core/fetch/response.cc1
-rw-r--r--chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc10
-rw-r--r--chromium/third_party/blink/renderer/platform/exported/web_url_response.cc7
-rw-r--r--chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h8
-rwxr-xr-xchromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py9
-rw-r--r--chromium/tools/metrics/histograms/enums.xml2
31 files changed, 562 insertions, 289 deletions
diff --git a/chromium/content/browser/appcache/appcache_backfillers.cc b/chromium/content/browser/appcache/appcache_backfillers.cc
index f3509a30e05..fbe0b5de0a3 100644
--- a/chromium/content/browser/appcache/appcache_backfillers.cc
+++ b/chromium/content/browser/appcache/appcache_backfillers.cc
@@ -7,7 +7,7 @@
#include "content/browser/appcache/appcache_update_job.h"
#include "net/http/http_request_headers.h"
#include "sql/statement.h"
-#include "storage/browser/quota/padding_key.h"
+#include "storage/common/quota/padding_key.h"
#include "url/gurl.h"
namespace content {
@@ -18,9 +18,7 @@ int64_t ComputeEntryPaddingSize(std::string response_url,
std::string manifest_url) {
if (GURL(response_url).GetOrigin() == GURL(manifest_url).GetOrigin())
return 0;
- return storage::ComputeResponsePadding(
- response_url, storage::GetDefaultPaddingKey(), /*has_metadata=*/false,
- /*loaded_with_credentials=*/false, net::HttpRequestHeaders::kGetMethod);
+ return storage::ComputeRandomResponsePadding();
}
// Iterates over each Cache record; execute |callable| on each iteration.
diff --git a/chromium/content/browser/appcache/appcache_database.cc b/chromium/content/browser/appcache/appcache_database.cc
index e2148da8719..a8e52341824 100644
--- a/chromium/content/browser/appcache/appcache_database.cc
+++ b/chromium/content/browser/appcache/appcache_database.cc
@@ -19,7 +19,6 @@
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
-#include "storage/browser/quota/padding_key.h"
#include "third_party/blink/public/common/features.h"
namespace content {
diff --git a/chromium/content/browser/appcache/appcache_update_job.cc b/chromium/content/browser/appcache/appcache_update_job.cc
index c12a5b3adb7..61dbf4f0238 100644
--- a/chromium/content/browser/appcache/appcache_update_job.cc
+++ b/chromium/content/browser/appcache/appcache_update_job.cc
@@ -26,7 +26,7 @@
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/http/http_request_headers.h"
-#include "storage/browser/quota/padding_key.h"
+#include "storage/common/quota/padding_key.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
@@ -207,10 +207,7 @@ int64_t ComputeAppCacheResponsePadding(const GURL& response_url,
if (response_url.GetOrigin() == manifest_url.GetOrigin())
return 0;
- return storage::ComputeResponsePadding(
- response_url.spec(), storage::GetDefaultPaddingKey(),
- /*has_metadata=*/false, /*loaded_with_credentials=*/false,
- net::HttpRequestHeaders::kGetMethod);
+ return storage::ComputeRandomResponsePadding();
}
} // namespace
diff --git a/chromium/content/browser/cache_storage/cache_storage.proto b/chromium/content/browser/cache_storage/cache_storage.proto
index 14ad0f0e34f..245cc2bde73 100644
--- a/chromium/content/browser/cache_storage/cache_storage.proto
+++ b/chromium/content/browser/cache_storage/cache_storage.proto
@@ -56,6 +56,8 @@ message CacheResponse {
optional bool was_fetched_via_spdy = 12;
optional string mime_type = 13;
optional string request_method = 14;
+ optional int64 padding = 15;
+ optional int64 side_data_padding = 16;
}
message CacheMetadata {
diff --git a/chromium/content/browser/cache_storage/cache_storage_histogram_utils.h b/chromium/content/browser/cache_storage/cache_storage_histogram_utils.h
index 031ddacc804..3fd75d694b8 100644
--- a/chromium/content/browser/cache_storage/cache_storage_histogram_utils.h
+++ b/chromium/content/browser/cache_storage/cache_storage_histogram_utils.h
@@ -37,7 +37,8 @@ enum class ErrorStorageType {
kCreateBackendDidCreateFailed = 22,
kStorageGetAllMatchedEntriesBackendClosed = 23,
kStorageHandleNull = 24,
- kMaxValue = kStorageHandleNull,
+ kWriteSideDataDidWriteMetadataWrongBytes = 25,
+ kMaxValue = kWriteSideDataDidWriteMetadataWrongBytes,
};
blink::mojom::CacheStorageError MakeErrorStorage(ErrorStorageType type);
diff --git a/chromium/content/browser/cache_storage/legacy/legacy_cache_storage.cc b/chromium/content/browser/cache_storage/legacy/legacy_cache_storage.cc
index 28a928b65f6..48acfdb7a51 100644
--- a/chromium/content/browser/cache_storage/legacy/legacy_cache_storage.cc
+++ b/chromium/content/browser/cache_storage/legacy/legacy_cache_storage.cc
@@ -46,8 +46,8 @@
#include "net/base/directory_lister.h"
#include "net/base/net_errors.h"
#include "storage/browser/blob/blob_storage_context.h"
-#include "storage/browser/quota/padding_key.h"
#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/quota/padding_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
using blink::mojom::CacheStorageError;
diff --git a/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
index c662b8af907..5613029b80c 100644
--- a/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
+++ b/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -53,8 +53,8 @@
#include "net/http/http_status_code.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "storage/browser/blob/blob_storage_context.h"
-#include "storage/browser/quota/padding_key.h"
#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/quota/padding_key.h"
#include "third_party/blink/public/common/cache_storage/cache_storage_utils.h"
#include "third_party/blink/public/common/fetch/fetch_api_request_headers_map.h"
#include "third_party/blink/public/mojom/loader/referrer.mojom.h"
@@ -79,7 +79,8 @@ const size_t kMaxQueryCacheResultBytes =
//
// 1: Uniform random 400K.
// 2: Uniform random 14,431K.
-const int32_t kCachePaddingAlgorithmVersion = 2;
+// 3: FetchAPIResponse.padding and separate side data padding.
+const int32_t kCachePaddingAlgorithmVersion = 3;
// Maximum number of recursive QueryCacheOpenNextEntry() calls we permit
// before forcing an asynchronous task.
@@ -374,6 +375,14 @@ void ReadMetadataDidReadMetadata(disk_cache::Entry* entry,
std::move(callback).Run(std::move(metadata));
}
+bool ShouldPadResourceSize(const content::proto::CacheResponse* response) {
+ return storage::ShouldPadResponseType(
+ ProtoResponseTypeToFetchResponseType(response->response_type()));
+}
+bool ShouldPadResourceSize(const blink::mojom::FetchAPIResponse& response) {
+ return storage::ShouldPadResponseType(response.response_type);
+}
+
blink::mojom::FetchAPIRequestPtr CreateRequest(
const proto::CacheMetadata& metadata,
const GURL& request_url) {
@@ -394,6 +403,7 @@ blink::mojom::FetchAPIRequestPtr CreateRequest(
}
blink::mojom::FetchAPIResponsePtr CreateResponse(
+ const url::Origin& origin,
const proto::CacheMetadata& metadata,
const std::string& cache_name) {
// We no longer support Responses with only a single URL entry. This field
@@ -427,6 +437,15 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
if (metadata.response().has_request_method())
request_method = metadata.response().request_method();
+ auto response_time =
+ base::Time::FromInternalValue(metadata.response().response_time());
+ int64_t padding = 0;
+ if (metadata.response().has_padding()) {
+ padding = metadata.response().padding();
+ } else if (ShouldPadResourceSize(&metadata.response())) {
+ padding = storage::ComputeRandomResponsePadding();
+ }
+
// Note that |has_range_requested| can be safely set to false since it only
// affects HTTP 206 (Partial) responses, which are blocked from cache storage.
// See https://fetch.spec.whatwg.org/#main-fetch for usage of
@@ -435,10 +454,9 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
url_list, metadata.response().status_code(),
metadata.response().status_text(),
ProtoResponseTypeToFetchResponseType(metadata.response().response_type()),
- network::mojom::FetchResponseSource::kCacheStorage, headers, mime_type,
- request_method, nullptr /* blob */,
- blink::mojom::ServiceWorkerResponseError::kUnknown,
- base::Time::FromInternalValue(metadata.response().response_time()),
+ padding, network::mojom::FetchResponseSource::kCacheStorage, headers,
+ mime_type, request_method, /*blob=*/nullptr,
+ blink::mojom::ServiceWorkerResponseError::kUnknown, response_time,
cache_name,
std::vector<std::string>(
metadata.response().cors_exposed_header_names().begin(),
@@ -450,53 +468,27 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
metadata.response().connection_info()),
alpn_negotiated_protocol, metadata.response().loaded_with_credentials(),
metadata.response().was_fetched_via_spdy(),
- /* has_range_requested */ false);
+ /*has_range_requested=*/false);
}
-
-// The size of opaque (non-cors) resource responses are padded in order
-// to obfuscate their actual size.
-bool ShouldPadResponseType(network::mojom::FetchResponseType response_type,
- bool has_urls) {
- switch (response_type) {
- case network::mojom::FetchResponseType::kBasic:
- case network::mojom::FetchResponseType::kCors:
- case network::mojom::FetchResponseType::kDefault:
- case network::mojom::FetchResponseType::kError:
- return false;
- case network::mojom::FetchResponseType::kOpaque:
- case network::mojom::FetchResponseType::kOpaqueRedirect:
- return has_urls;
- }
- NOTREACHED();
- return false;
-}
-
-bool ShouldPadResourceSize(const content::proto::CacheResponse* response) {
- return ShouldPadResponseType(
- ProtoResponseTypeToFetchResponseType(response->response_type()),
- response->url_list_size());
-}
-
-bool ShouldPadResourceSize(const blink::mojom::FetchAPIResponse& response) {
- return ShouldPadResponseType(response.response_type,
- !response.url_list.empty());
-}
-
-int64_t CalculateResponsePaddingInternal(
+int64_t CalculateSideDataPadding(
+ const url::Origin& origin,
const ::content::proto::CacheResponse* response,
- const crypto::SymmetricKey* padding_key,
int side_data_size) {
DCHECK(ShouldPadResourceSize(response));
DCHECK_GE(side_data_size, 0);
+
+ if (!side_data_size)
+ return 0;
+ // Fallback to random padding if this is for an older entry without
+ // a url list or request method.
+ if (response->url_list_size() == 0 || !response->has_request_method())
+ return storage::ComputeRandomResponsePadding();
+
const std::string& url = response->url_list(response->url_list_size() - 1);
- bool loaded_with_credentials = response->has_loaded_with_credentials() &&
- response->loaded_with_credentials();
- const std::string& request_method = response->has_request_method()
- ? response->request_method()
- : net::HttpRequestHeaders::kGetMethod;
- return storage::ComputeResponsePadding(url, padding_key, side_data_size > 0,
- loaded_with_credentials,
- request_method);
+ const base::Time response_time =
+ base::Time::FromInternalValue(response->response_time());
+ return storage::ComputeStableResponsePadding(
+ origin, url, response_time, response->request_method(), side_data_size);
}
net::RequestPriority GetDiskCachePriority(
@@ -508,12 +500,19 @@ net::RequestPriority GetDiskCachePriority(
} // namespace
struct LegacyCacheStorageCache::QueryCacheResult {
- explicit QueryCacheResult(base::Time entry_time) : entry_time(entry_time) {}
+ QueryCacheResult(base::Time entry_time,
+ int64_t padding,
+ int64_t side_data_padding)
+ : entry_time(entry_time),
+ padding(padding),
+ side_data_padding(side_data_padding) {}
blink::mojom::FetchAPIRequestPtr request;
blink::mojom::FetchAPIResponsePtr response;
disk_cache::ScopedEntryPtr entry;
base::Time entry_time;
+ int64_t padding = 0;
+ int64_t side_data_padding = 0;
};
struct LegacyCacheStorageCache::QueryCacheContext {
@@ -1248,17 +1247,40 @@ void LegacyCacheStorageCache::QueryCacheDidReadMetadata(
return;
}
+ // Check for older cache entries that need to be padded, but don't
+ // have any padding stored in the entry. Upgrade these entries
+ // as we encounter them. This method will be re-entered once the
+ // new paddings are written back to disk.
+ if (ShouldPadResourceSize(&metadata->response()) &&
+ !metadata->response().has_padding()) {
+ QueryCacheUpgradePadding(std::move(query_cache_context), std::move(entry),
+ std::move(metadata));
+ return;
+ }
+
// If the entry was created before we started adding entry times, then
// default to using the Response object's time for sorting purposes.
int64_t entry_time = metadata->has_entry_time()
? metadata->entry_time()
: metadata->response().response_time();
- query_cache_context->matches->push_back(
- QueryCacheResult(base::Time::FromInternalValue(entry_time)));
+ // Note, older entries that don't require padding may still not have
+ // a padding value since we don't pay the cost to upgrade these entries.
+ // Treat these as a zero padding.
+ int64_t padding =
+ metadata->response().has_padding() ? metadata->response().padding() : 0;
+ int64_t side_data_padding = metadata->response().has_side_data_padding()
+ ? metadata->response().side_data_padding()
+ : 0;
+
+ DCHECK(!ShouldPadResourceSize(&metadata->response()) ||
+ (padding + side_data_padding));
+
+ query_cache_context->matches->push_back(QueryCacheResult(
+ base::Time::FromInternalValue(entry_time), padding, side_data_padding));
QueryCacheResult* match = &query_cache_context->matches->back();
match->request = CreateRequest(*metadata, GURL(entry->GetKey()));
- match->response = CreateResponse(*metadata, cache_name_);
+ match->response = CreateResponse(origin_, *metadata, cache_name_);
if (!match->response) {
entry->Doom();
@@ -1320,6 +1342,49 @@ void LegacyCacheStorageCache::QueryCacheDidReadMetadata(
QueryCacheOpenNextEntry(std::move(query_cache_context));
}
+void LegacyCacheStorageCache::QueryCacheUpgradePadding(
+ std::unique_ptr<QueryCacheContext> query_cache_context,
+ disk_cache::ScopedEntryPtr entry,
+ std::unique_ptr<proto::CacheMetadata> metadata) {
+ DCHECK(ShouldPadResourceSize(&metadata->response()));
+ // This should only be called while initializing because the padding
+ // version change should trigger an immediate query of all resources
+ // to recompute padding.
+ DCHECK(initializing_);
+ auto* response = metadata->mutable_response();
+ response->set_padding(storage::ComputeRandomResponsePadding());
+ response->set_side_data_padding(CalculateSideDataPadding(
+ origin_, response, entry->GetDataSize(INDEX_SIDE_DATA)));
+ // Get a temporary copy of the entry and metadata pointers before moving them
+ // into base::BindOnce.
+ disk_cache::Entry* temp_entry_ptr = entry.get();
+ auto* temp_metadata_ptr = metadata.get();
+ WriteMetadata(
+ temp_entry_ptr, *temp_metadata_ptr,
+ base::BindOnce(
+ [](base::WeakPtr<LegacyCacheStorageCache> self,
+ std::unique_ptr<QueryCacheContext> query_cache_context,
+ disk_cache::ScopedEntryPtr entry,
+ std::unique_ptr<proto::CacheMetadata> metadata, int expected_bytes,
+ int rv) {
+ if (!self)
+ return;
+ if (expected_bytes != rv) {
+ entry->Doom();
+ self->QueryCacheOpenNextEntry(std::move(query_cache_context));
+ return;
+ }
+ // We must have a padding here in order to avoid infinite
+ // recursion.
+ DCHECK(metadata->response().has_padding());
+ self->QueryCacheDidReadMetadata(std::move(query_cache_context),
+ std::move(entry),
+ std::move(metadata));
+ },
+ weak_ptr_factory_.GetWeakPtr(), std::move(query_cache_context),
+ std::move(entry), std::move(metadata)));
+}
+
// static
bool LegacyCacheStorageCache::QueryCacheResultCompare(
const QueryCacheResult& lhs,
@@ -1346,26 +1411,6 @@ size_t LegacyCacheStorageCache::EstimatedResponseSizeWithoutBlob(
}
// static
-int64_t LegacyCacheStorageCache::CalculateResponsePadding(
- const blink::mojom::FetchAPIResponse& response,
- const crypto::SymmetricKey* padding_key,
- int side_data_size) {
- DCHECK_GE(side_data_size, 0);
- if (!ShouldPadResourceSize(response))
- return 0;
- // Going forward we should always have a request method here since its
- // impossible to create a no-cors Response via the constructor. We must
- // handle a missing method, however, since we may get a Response loaded
- // from an old cache_storage instance without the data.
- std::string request_method = response.request_method.has_value()
- ? response.request_method.value()
- : net::HttpRequestHeaders::kGetMethod;
- return storage::ComputeResponsePadding(
- response.url_list.back().spec(), padding_key, side_data_size > 0,
- response.loaded_with_credentials, request_method);
-}
-
-// static
int32_t LegacyCacheStorageCache::GetResponsePaddingVersion() {
return kCachePaddingAlgorithmVersion;
}
@@ -1608,19 +1653,13 @@ void LegacyCacheStorageCache::WriteSideDataDidReadMetaData(
if (!headers || headers->response().response_time() !=
expected_response_time.ToInternalValue()) {
WriteSideDataComplete(std::move(callback), std::move(entry),
+ /*padding=*/0, /*side_data_padding=*/0,
CacheStorageError::kErrorNotFound);
return;
}
// Get a temporary copy of the entry pointer before passing it in base::Bind.
disk_cache::Entry* temp_entry_ptr = entry.get();
- std::unique_ptr<content::proto::CacheResponse> response(
- headers->release_response());
-
- int side_data_size_before_write = 0;
- if (ShouldPadResourceSize(response.get()))
- side_data_size_before_write = entry->GetDataSize(INDEX_SIDE_DATA);
-
// Create a callback that is copyable, even though it can only be called once.
// BindRepeating() cannot be used directly because |callback|, |entry| and
// |response| are not copyable.
@@ -1628,7 +1667,7 @@ void LegacyCacheStorageCache::WriteSideDataDidReadMetaData(
base::AdaptCallbackForRepeating(base::BindOnce(
&LegacyCacheStorageCache::WriteSideDataDidWrite,
weak_ptr_factory_.GetWeakPtr(), std::move(callback), std::move(entry),
- buf_len, std::move(response), side_data_size_before_write, trace_id));
+ buf_len, std::move(headers), trace_id));
DCHECK(scheduler_->IsRunningExclusiveOperation());
int rv = temp_entry_ptr->WriteData(
@@ -1643,8 +1682,7 @@ void LegacyCacheStorageCache::WriteSideDataDidWrite(
ErrorCallback callback,
ScopedWritableEntry entry,
int expected_bytes,
- std::unique_ptr<::content::proto::CacheResponse> response,
- int side_data_size_before_write,
+ std::unique_ptr<::content::proto::CacheMetadata> metadata,
int64_t trace_id,
int rv) {
TRACE_EVENT_WITH_FLOW0("CacheStorage",
@@ -1652,31 +1690,67 @@ void LegacyCacheStorageCache::WriteSideDataDidWrite(
TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_IN);
if (rv != expected_bytes) {
WriteSideDataComplete(std::move(callback), std::move(entry),
+ /*padding=*/0, /*side_data_padding=*/0,
CacheStorageError::kErrorStorage);
return;
}
- if (ShouldPadResourceSize(response.get())) {
- cache_padding_ -= CalculateResponsePaddingInternal(
- response.get(), cache_padding_key_.get(), side_data_size_before_write);
+ auto* response = metadata->mutable_response();
+
+ if (ShouldPadResourceSize(response)) {
+ cache_padding_ -= response->side_data_padding();
+
+ response->set_side_data_padding(
+ CalculateSideDataPadding(origin_, response, rv));
+ cache_padding_ += response->side_data_padding();
+
+ // Get a temporary copy of the entry pointer before passing it in
+ // base::Bind.
+ disk_cache::Entry* temp_entry_ptr = entry.get();
- cache_padding_ += CalculateResponsePaddingInternal(
- response.get(), cache_padding_key_.get(), rv);
+ WriteMetadata(
+ temp_entry_ptr, *metadata,
+ base::BindOnce(&LegacyCacheStorageCache::WriteSideDataDidWriteMetadata,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+ std::move(entry), response->padding(),
+ response->side_data_padding()));
+ return;
}
WriteSideDataComplete(std::move(callback), std::move(entry),
+ response->padding(), response->side_data_padding(),
CacheStorageError::kSuccess);
}
+void LegacyCacheStorageCache::WriteSideDataDidWriteMetadata(
+ ErrorCallback callback,
+ ScopedWritableEntry entry,
+ int64_t padding,
+ int64_t side_data_padding,
+ int expected_bytes,
+ int rv) {
+ auto result = blink::mojom::CacheStorageError::kSuccess;
+ if (rv != expected_bytes) {
+ result = MakeErrorStorage(
+ ErrorStorageType::kWriteSideDataDidWriteMetadataWrongBytes);
+ }
+ WriteSideDataComplete(std::move(callback), std::move(entry), padding,
+ side_data_padding, result);
+}
+
void LegacyCacheStorageCache::WriteSideDataComplete(
ErrorCallback callback,
ScopedWritableEntry entry,
+ int64_t padding,
+ int64_t side_data_padding,
blink::mojom::CacheStorageError error) {
if (error != CacheStorageError::kSuccess) {
// If we found the entry, then we possibly wrote something and now we're
// dooming the entry, causing a change in size, so update the size before
// returning.
if (error != CacheStorageError::kErrorNotFound) {
+ entry.reset();
+ cache_padding_ -= (padding + side_data_padding);
UpdateCacheSize(base::BindOnce(std::move(callback), error));
return;
}
@@ -1870,17 +1944,33 @@ void LegacyCacheStorageCache::PutDidCreateEntry(
for (const auto& header : put_context->response->cors_exposed_header_names)
response_metadata->add_cors_exposed_header_names(header);
+ DCHECK(!ShouldPadResourceSize(*put_context->response) ||
+ put_context->response->padding);
+ response_metadata->set_padding(put_context->response->padding);
+
+ int64_t side_data_padding = 0;
+ if (ShouldPadResourceSize(*put_context->response) &&
+ put_context->side_data_blob) {
+ side_data_padding = CalculateSideDataPadding(
+ origin_, response_metadata, put_context->side_data_blob_size);
+ }
+ response_metadata->set_side_data_padding(side_data_padding);
+
// Get a temporary copy of the entry pointer before passing it in base::Bind.
disk_cache::Entry* temp_entry_ptr = put_context->cache_entry.get();
WriteMetadata(
temp_entry_ptr, metadata,
base::BindOnce(&LegacyCacheStorageCache::PutDidWriteHeaders,
- weak_ptr_factory_.GetWeakPtr(), std::move(put_context)));
+ weak_ptr_factory_.GetWeakPtr(), std::move(put_context),
+ response_metadata->padding(),
+ response_metadata->side_data_padding()));
}
void LegacyCacheStorageCache::PutDidWriteHeaders(
std::unique_ptr<PutContext> put_context,
+ int64_t padding,
+ int64_t side_data_padding,
int expected_bytes,
int rv) {
TRACE_EVENT_WITH_FLOW0("CacheStorage",
@@ -1896,11 +1986,9 @@ void LegacyCacheStorageCache::PutDidWriteHeaders(
return;
}
- if (ShouldPadResourceSize(*put_context->response)) {
- cache_padding_ += CalculateResponsePadding(*put_context->response,
- cache_padding_key_.get(),
- 0 /* side_data_size */);
- }
+ DCHECK(!ShouldPadResourceSize(*put_context->response) ||
+ (padding + side_data_padding));
+ cache_padding_ += padding + side_data_padding;
PutWriteBlobToCache(std::move(put_context), INDEX_RESPONSE_BODY);
}
@@ -2084,12 +2172,9 @@ void LegacyCacheStorageCache::PaddingDidQueryCache(
int64_t cache_padding = 0;
if (error == CacheStorageError::kSuccess) {
for (const auto& result : *query_cache_results) {
- if (ShouldPadResourceSize(*result.response)) {
- int32_t side_data_size =
- result.entry ? result.entry->GetDataSize(INDEX_SIDE_DATA) : 0;
- cache_padding += CalculateResponsePadding(
- *result.response, cache_padding_key_.get(), side_data_size);
- }
+ DCHECK(!ShouldPadResourceSize(*result.response) ||
+ (result.padding + result.side_data_padding));
+ cache_padding += result.padding + result.side_data_padding;
}
}
@@ -2290,9 +2375,9 @@ void LegacyCacheStorageCache::DeleteDidQueryCache(
for (auto& result : *query_cache_results) {
disk_cache::ScopedEntryPtr entry = std::move(result.entry);
if (ShouldPadResourceSize(*result.response)) {
- cache_padding_ -=
- CalculateResponsePadding(*result.response, cache_padding_key_.get(),
- entry->GetDataSize(INDEX_SIDE_DATA));
+ DCHECK(!ShouldPadResourceSize(*result.response) ||
+ (result.padding + result.side_data_padding));
+ cache_padding_ -= (result.padding + result.side_data_padding);
}
entry->Doom();
}
diff --git a/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h b/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h
index 099b9c49e36..bf173d95546 100644
--- a/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h
+++ b/chromium/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h
@@ -47,7 +47,6 @@ struct PutContext;
namespace proto {
class CacheMetadata;
-class CacheResponse;
} // namespace proto
namespace cache_storage_cache_unittest {
@@ -83,10 +82,6 @@ class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache {
int64_t cache_size,
int64_t cache_padding,
std::unique_ptr<crypto::SymmetricKey> cache_padding_key);
- static int64_t CalculateResponsePadding(
- const blink::mojom::FetchAPIResponse& response,
- const crypto::SymmetricKey* padding_key,
- int side_data_size);
static int32_t GetResponsePaddingVersion();
void Match(blink::mojom::FetchAPIRequestPtr request,
@@ -282,6 +277,10 @@ class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache {
std::unique_ptr<QueryCacheContext> query_cache_context,
disk_cache::ScopedEntryPtr entry,
std::unique_ptr<proto::CacheMetadata> metadata);
+ void QueryCacheUpgradePadding(
+ std::unique_ptr<QueryCacheContext> query_cache_context,
+ disk_cache::ScopedEntryPtr entry,
+ std::unique_ptr<proto::CacheMetadata> metadata);
static bool QueryCacheResultCompare(const QueryCacheResult& lhs,
const QueryCacheResult& rhs);
static size_t EstimatedResponseSizeWithoutBlob(
@@ -362,12 +361,19 @@ class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache {
ErrorCallback callback,
ScopedWritableEntry entry,
int expected_bytes,
- std::unique_ptr<content::proto::CacheResponse> response,
- int side_data_size_before_write,
+ std::unique_ptr<content::proto::CacheMetadata> metadata,
int64_t trace_id,
int rv);
+ void WriteSideDataDidWriteMetadata(ErrorCallback callback,
+ ScopedWritableEntry entry,
+ int64_t padding,
+ int64_t side_data_padding,
+ int expected_bytes,
+ int rv);
void WriteSideDataComplete(ErrorCallback callback,
ScopedWritableEntry entry,
+ int64_t padding,
+ int64_t side_data_padding,
blink::mojom::CacheStorageError error);
// Puts the request and response object in the cache. The response body (if
@@ -386,6 +392,8 @@ class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache {
void PutDidCreateEntry(std::unique_ptr<PutContext> put_context,
disk_cache::EntryResult result);
void PutDidWriteHeaders(std::unique_ptr<PutContext> put_context,
+ int64_t padding,
+ int64_t side_data_padding,
int expected_bytes,
int rv);
void PutWriteBlobToCache(std::unique_ptr<PutContext> put_context,
@@ -540,6 +548,7 @@ class CONTENT_EXPORT LegacyCacheStorageCache : public CacheStorageCache {
// The actual cache size (not including padding).
int64_t cache_size_;
int64_t cache_padding_ = 0;
+ // TODO(wanderview): remove padding key management
std::unique_ptr<crypto::SymmetricKey> cache_padding_key_;
int64_t last_reported_size_ = 0;
size_t max_query_size_bytes_;
diff --git a/chromium/content/common/background_fetch/background_fetch_types.cc b/chromium/content/common/background_fetch/background_fetch_types.cc
index a37fe7d14c1..08f8fb83c5c 100644
--- a/chromium/content/common/background_fetch/background_fetch_types.cc
+++ b/chromium/content/common/background_fetch/background_fetch_types.cc
@@ -31,8 +31,8 @@ blink::mojom::FetchAPIResponsePtr BackgroundFetchSettledFetch::CloneResponse(
return nullptr;
return blink::mojom::FetchAPIResponse::New(
response->url_list, response->status_code, response->status_text,
- response->response_type, response->response_source, response->headers,
- response->mime_type, response->request_method,
+ response->response_type, response->padding, response->response_source,
+ response->headers, response->mime_type, response->request_method,
CloneSerializedBlob(response->blob), response->error,
response->response_time, response->cache_storage_cache_name,
response->cors_exposed_header_names,
diff --git a/chromium/content/common/service_worker/service_worker_loader_helpers.cc b/chromium/content/common/service_worker/service_worker_loader_helpers.cc
index 0a8f32b009c..c9bd10b8b14 100644
--- a/chromium/content/common/service_worker/service_worker_loader_helpers.cc
+++ b/chromium/content/common/service_worker/service_worker_loader_helpers.cc
@@ -97,6 +97,7 @@ void ServiceWorkerLoaderHelpers::SaveResponseInfo(
out_head->was_fallback_required_by_service_worker = false;
out_head->url_list_via_service_worker = response.url_list;
out_head->response_type = response.response_type;
+ out_head->padding = response.padding;
if (response.mime_type.has_value()) {
std::string charset;
bool had_charset = false;
diff --git a/chromium/content/renderer/loader/web_url_loader_impl.cc b/chromium/content/renderer/loader/web_url_loader_impl.cc
index 1f45b65c172..56c8518504e 100644
--- a/chromium/content/renderer/loader/web_url_loader_impl.cc
+++ b/chromium/content/renderer/loader/web_url_loader_impl.cc
@@ -929,6 +929,7 @@ void WebURLLoaderImpl::PopulateURLResponse(
response->SetWasFallbackRequiredByServiceWorker(
head.was_fallback_required_by_service_worker);
response->SetType(head.response_type);
+ response->SetPadding(head.padding);
response->SetUrlListViaServiceWorker(head.url_list_via_service_worker);
response->SetCacheStorageCacheName(
head.service_worker_response_source ==
diff --git a/chromium/services/network/public/mojom/url_response_head.mojom b/chromium/services/network/public/mojom/url_response_head.mojom
index fa737edd89d..d24f063b8eb 100644
--- a/chromium/services/network/public/mojom/url_response_head.mojom
+++ b/chromium/services/network/public/mojom/url_response_head.mojom
@@ -134,6 +134,12 @@ struct URLResponseHead {
// https://fetch.spec.whatwg.org/#concept-response-type
FetchResponseType response_type = FetchResponseType.kDefault;
+ // Pre-computed padding. This should only be non-zero when |response_type|
+ // is set to kOpaque. Note, this is not set by network service, but will be
+ // populated if the response was provided by a service worker FetchEvent
+ // handler.
+ int64 padding = 0;
+
// The cache name of the CacheStorage from where the response is served via
// the ServiceWorker. Empty if the response isn't from the CacheStorage.
string cache_storage_cache_name;
diff --git a/chromium/storage/browser/BUILD.gn b/chromium/storage/browser/BUILD.gn
index 99e3c71c1dd..389b129e9ee 100644
--- a/chromium/storage/browser/BUILD.gn
+++ b/chromium/storage/browser/BUILD.gn
@@ -183,8 +183,6 @@ jumbo_component("browser") {
"file_system/watcher_manager.h",
"quota/client_usage_tracker.cc",
"quota/client_usage_tracker.h",
- "quota/padding_key.cc",
- "quota/padding_key.h",
"quota/quota_callbacks.h",
"quota/quota_client.h",
"quota/quota_client_type.cc",
diff --git a/chromium/storage/browser/quota/padding_key.cc b/chromium/storage/browser/quota/padding_key.cc
deleted file mode 100644
index 788f6f4634c..00000000000
--- a/chromium/storage/browser/quota/padding_key.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "storage/browser/quota/padding_key.h"
-
-#include <cstdint>
-#include <vector>
-
-#include "base/no_destructor.h"
-#include "crypto/hmac.h"
-#include "net/http/http_request_headers.h"
-
-using crypto::SymmetricKey;
-
-namespace storage {
-
-namespace {
-
-const SymmetricKey::Algorithm kPaddingKeyAlgorithm = SymmetricKey::AES;
-
-// The range of the padding added to response sizes for opaque resources.
-// Increment the CacheStorage padding version if changed.
-constexpr uint64_t kPaddingRange = 14431 * 1024;
-
-std::unique_ptr<SymmetricKey>* GetPaddingKeyInternal() {
- static base::NoDestructor<std::unique_ptr<SymmetricKey>> s_padding_key([] {
- return SymmetricKey::GenerateRandomKey(kPaddingKeyAlgorithm, 128);
- }());
- return s_padding_key.get();
-}
-
-} // namespace
-
-const SymmetricKey* GetDefaultPaddingKey() {
- return GetPaddingKeyInternal()->get();
-}
-
-std::unique_ptr<SymmetricKey> CopyDefaultPaddingKey() {
- return SymmetricKey::Import(kPaddingKeyAlgorithm,
- (*GetPaddingKeyInternal())->key());
-}
-
-std::unique_ptr<SymmetricKey> DeserializePaddingKey(
- const std::string& raw_key) {
- return SymmetricKey::Import(kPaddingKeyAlgorithm, raw_key);
-}
-
-std::string SerializeDefaultPaddingKey() {
- return (*GetPaddingKeyInternal())->key();
-}
-
-void ResetPaddingKeyForTesting() {
- *GetPaddingKeyInternal() =
- SymmetricKey::GenerateRandomKey(kPaddingKeyAlgorithm, 128);
-}
-
-int64_t ComputeResponsePadding(const std::string& response_url,
- const crypto::SymmetricKey* padding_key,
- bool has_metadata,
- bool loaded_with_credentials,
- const std::string& request_method) {
- DCHECK(!response_url.empty());
-
- crypto::HMAC hmac(crypto::HMAC::SHA256);
- CHECK(hmac.Init(padding_key));
-
- std::string key = response_url;
- if (has_metadata)
- key += "METADATA";
- if (loaded_with_credentials)
- key += "CREDENTIALED";
-
- // It should only be possible to have a CORS safelisted method here since
- // the spec does not permit other methods for no-cors requests.
- DCHECK(request_method == net::HttpRequestHeaders::kGetMethod ||
- request_method == net::HttpRequestHeaders::kHeadMethod ||
- request_method == net::HttpRequestHeaders::kPostMethod);
- key += request_method;
-
- uint64_t digest_start;
- CHECK(hmac.Sign(key, reinterpret_cast<uint8_t*>(&digest_start),
- sizeof(digest_start)));
- return digest_start % kPaddingRange;
-}
-
-} // namespace storage
diff --git a/chromium/storage/browser/quota/padding_key.h b/chromium/storage/browser/quota/padding_key.h
deleted file mode 100644
index 4b5978a82e7..00000000000
--- a/chromium/storage/browser/quota/padding_key.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef STORAGE_BROWSER_QUOTA_PADDING_KEY_H_
-#define STORAGE_BROWSER_QUOTA_PADDING_KEY_H_
-
-#include <memory>
-#include <string>
-
-#include "base/component_export.h"
-#include "crypto/symmetric_key.h"
-#include "url/gurl.h"
-
-namespace storage {
-
-COMPONENT_EXPORT(STORAGE_BROWSER)
-const crypto::SymmetricKey* GetDefaultPaddingKey();
-
-// Returns a copy of the default key used to calculate padding sizes.
-//
-// The default padding key is a singleton object whose value is randomly
-// generated the first time it is requested on every browser startup. In
-// CacheStorage, when a cache does not have a padding key, it is assigned the
-// current default key.
-COMPONENT_EXPORT(STORAGE_BROWSER)
-std::unique_ptr<crypto::SymmetricKey> CopyDefaultPaddingKey();
-
-// Builds a key whose value is the given string.
-//
-// May return null if deserializing fails (e.g. if the raw key is the wrong
-// size).
-COMPONENT_EXPORT(STORAGE_BROWSER)
-std::unique_ptr<crypto::SymmetricKey> DeserializePaddingKey(
- const std::string& raw_key);
-
-// Gets the raw value of the default padding key.
-//
-// Each cache stores the raw value of the key that should be used when
-// calculating its padding size.
-COMPONENT_EXPORT(STORAGE_BROWSER)
-std::string SerializeDefaultPaddingKey();
-
-// Resets the default key to a random value.
-//
-// Simulating a key change across a browser restart lets us test that padding
-// calculations are using the appropriate key.
-COMPONENT_EXPORT(STORAGE_BROWSER)
-void ResetPaddingKeyForTesting();
-
-// Computes the padding size for a resource.
-//
-// For AppCache, which does not support storing metadata for a resource,
-// |has_metadata| will always be false.
-//
-// For CacheStorage, the padding size of an entry depends on whether it contains
-// metadata (a.k.a. "side data") and if the response was loaded with
-// credentials. If metadata is added to the entry, the entry must be assigned a
-// new padding size. Otherwise, the growth in the entry's size would leak the
-// exact size of the added metadata.
-COMPONENT_EXPORT(STORAGE_BROWSER)
-int64_t ComputeResponsePadding(const std::string& response_url,
- const crypto::SymmetricKey* padding_key,
- bool has_metadata,
- bool loaded_with_credentials,
- const std::string& request_method);
-
-} // namespace storage
-
-#endif // STORAGE_BROWSER_QUOTA_PADDING_KEY_H_
diff --git a/chromium/storage/common/BUILD.gn b/chromium/storage/common/BUILD.gn
index 5e76c440e76..8fdf0dc0951 100644
--- a/chromium/storage/common/BUILD.gn
+++ b/chromium/storage/common/BUILD.gn
@@ -17,6 +17,8 @@ component("common") {
"file_system/file_system_types.h",
"file_system/file_system_util.cc",
"file_system/file_system_util.h",
+ "quota/padding_key.cc",
+ "quota/padding_key.h",
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
diff --git a/chromium/storage/common/quota/padding_key.cc b/chromium/storage/common/quota/padding_key.cc
new file mode 100644
index 00000000000..24cd429e3fe
--- /dev/null
+++ b/chromium/storage/common/quota/padding_key.cc
@@ -0,0 +1,168 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "storage/common/quota/padding_key.h"
+
+#include <inttypes.h>
+#include <cstdint>
+#include <vector>
+#include "base/no_destructor.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "crypto/hmac.h"
+#include "crypto/random.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/base/url_util.h"
+#include "net/http/http_request_headers.h"
+#include "services/network/public/mojom/url_response_head.mojom-shared.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "url/url_canon.h"
+#include "url/url_constants.h"
+#include "url/url_util.h"
+
+using crypto::SymmetricKey;
+
+namespace storage {
+
+namespace {
+
+const SymmetricKey::Algorithm kPaddingKeyAlgorithm = SymmetricKey::AES;
+
+// The range of the padding added to response sizes for opaque resources.
+// Increment the CacheStorage padding version if changed.
+constexpr uint64_t kPaddingRange = 14431 * 1024;
+
+std::unique_ptr<SymmetricKey>* GetPaddingKeyInternal() {
+ static base::NoDestructor<std::unique_ptr<SymmetricKey>> s_padding_key([] {
+ return SymmetricKey::GenerateRandomKey(kPaddingKeyAlgorithm, 128);
+ }());
+ return s_padding_key.get();
+}
+
+static bool IsStandardSchemeWithNetworkHost(base::StringPiece scheme) {
+ // file scheme is special. Windows file share origins can have network hosts.
+ if (scheme == url::kFileScheme)
+ return true;
+
+ url::SchemeType scheme_type;
+ if (!url::GetStandardSchemeType(
+ scheme.data(), url::Component(0, scheme.length()), &scheme_type)) {
+ return false;
+ }
+ return scheme_type == url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION ||
+ scheme_type == url::SCHEME_WITH_HOST_AND_PORT;
+}
+
+
+static url::Origin SchemefuleSiteReplacement(
+ const url::Origin& origin) {
+ // 1. If origin is an opaque origin, then return origin.
+ if (origin.opaque())
+ return origin;
+
+ std::string registerable_domain;
+
+ // Non-normative step.
+ // We only lookup the registerable domain for schemes with network hosts, this
+ // is non-normative. Other schemes for non-opaque origins do not
+ // meaningfully have a registerable domain for their host, so they are
+ // skipped.
+ if (IsStandardSchemeWithNetworkHost(origin.scheme())) {
+ registerable_domain = GetDomainAndRegistry(
+ origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+ }
+
+ // If origin's host's registrable domain is null, then return (origin's
+ // scheme, origin's host).
+ //
+ // `GetDomainAndRegistry()` returns an empty string for IP literals and
+ // effective TLDs.
+ //
+ // Note that `registerable_domain` could still end up empty, since the
+ // `origin` might have a scheme that permits empty hostnames, such as "file".
+ bool used_registerable_domain = !registerable_domain.empty();
+ if (!used_registerable_domain)
+ registerable_domain = origin.host();
+
+ int port = url::DefaultPortForScheme(origin.scheme().c_str(),
+ origin.scheme().length());
+
+ // Provide a default port of 0 for non-standard schemes.
+ if (port == url::PORT_UNSPECIFIED)
+ port = 0;
+
+ return url::Origin::CreateFromNormalizedTuple(origin.scheme(),
+ registerable_domain, port);
+}
+
+} // namespace
+
+const SymmetricKey* GetDefaultPaddingKey() {
+ return GetPaddingKeyInternal()->get();
+}
+
+std::unique_ptr<SymmetricKey> CopyDefaultPaddingKey() {
+ return SymmetricKey::Import(kPaddingKeyAlgorithm,
+ (*GetPaddingKeyInternal())->key());
+}
+
+std::unique_ptr<SymmetricKey> DeserializePaddingKey(
+ const std::string& raw_key) {
+ return SymmetricKey::Import(kPaddingKeyAlgorithm, raw_key);
+}
+
+std::string SerializeDefaultPaddingKey() {
+ return (*GetPaddingKeyInternal())->key();
+}
+
+void ResetPaddingKeyForTesting() {
+ *GetPaddingKeyInternal() =
+ SymmetricKey::GenerateRandomKey(kPaddingKeyAlgorithm, 128);
+}
+
+bool ShouldPadResponseType(network::mojom::FetchResponseType type) {
+ return type == network::mojom::FetchResponseType::kOpaque ||
+ type == network::mojom::FetchResponseType::kOpaqueRedirect;
+}
+
+int64_t ComputeRandomResponsePadding() {
+ uint64_t raw_random = 0;
+ crypto::RandBytes(&raw_random, sizeof(uint64_t));
+ return raw_random % kPaddingRange;
+}
+
+int64_t ComputeStableResponsePadding(const url::Origin& origin,
+ const std::string& response_url,
+ const base::Time& response_time,
+ const std::string& request_method,
+ int64_t side_data_size) {
+ DCHECK(!response_url.empty());
+
+ url::Origin site = SchemefuleSiteReplacement(origin);
+
+ DCHECK_GT(response_time, base::Time::UnixEpoch());
+ int64_t microseconds =
+ (response_time - base::Time::UnixEpoch()).InMicroseconds();
+
+ // It should only be possible to have a CORS safelisted method here since
+ // the spec does not permit other methods for no-cors requests.
+ DCHECK(request_method == net::HttpRequestHeaders::kGetMethod ||
+ request_method == net::HttpRequestHeaders::kHeadMethod ||
+ request_method == net::HttpRequestHeaders::kPostMethod);
+
+ std::string key = base::StringPrintf(
+ "%s-%" PRId64 "-%s-%s-%" PRId64, response_url.c_str(), microseconds,
+ site.Serialize().c_str(), request_method.c_str(), side_data_size);
+
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ CHECK(hmac.Init(GetDefaultPaddingKey()));
+
+ uint64_t digest_start = 0;
+ CHECK(hmac.Sign(key, reinterpret_cast<uint8_t*>(&digest_start),
+ sizeof(digest_start)));
+ return digest_start % kPaddingRange;
+}
+
+} // namespace storage
diff --git a/chromium/storage/common/quota/padding_key.h b/chromium/storage/common/quota/padding_key.h
new file mode 100644
index 00000000000..ad463cb1e49
--- /dev/null
+++ b/chromium/storage/common/quota/padding_key.h
@@ -0,0 +1,86 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef STORAGE_COMMON_QUOTA_PADDING_KEY_H_
+#define STORAGE_COMMON_QUOTA_PADDING_KEY_H_
+
+#include <memory>
+#include <string>
+
+#include "base/component_export.h"
+#include "crypto/symmetric_key.h"
+#include "services/network/public/mojom/url_response_head.mojom-shared.h"
+#include "url/gurl.h"
+
+namespace base {
+class Time;
+} // namespace base
+
+namespace url {
+class Origin;
+} // namespace url
+
+namespace storage {
+
+COMPONENT_EXPORT(STORAGE_COMMON)
+const crypto::SymmetricKey* GetDefaultPaddingKey();
+
+// Returns a copy of the default key used to calculate padding sizes.
+//
+// The default padding key is a singleton object whose value is randomly
+// generated the first time it is requested on every browser startup. In
+// CacheStorage, when a cache does not have a padding key, it is assigned the
+// current default key.
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::unique_ptr<crypto::SymmetricKey> CopyDefaultPaddingKey();
+
+// Builds a key whose value is the given string.
+//
+// May return null if deserializing fails (e.g. if the raw key is the wrong
+// size).
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::unique_ptr<crypto::SymmetricKey> DeserializePaddingKey(
+ const std::string& raw_key);
+
+// Gets the raw value of the default padding key.
+//
+// Each cache stores the raw value of the key that should be used when
+// calculating its padding size.
+COMPONENT_EXPORT(STORAGE_COMMON)
+std::string SerializeDefaultPaddingKey();
+
+// Resets the default key to a random value.
+//
+// Simulating a key change across a browser restart lets us test that padding
+// calculations are using the appropriate key.
+COMPONENT_EXPORT(STORAGE_COMMON)
+void ResetPaddingKeyForTesting();
+
+// Utility method to determine if a given type of response should be padded.
+COMPONENT_EXPORT(STORAGE_COMMON)
+bool ShouldPadResponseType(network::mojom::FetchResponseType type);
+
+// Compute a purely random padding size for a resource. A random padding is
+// preferred except in cases where a site could rapidly trigger a large number
+// of padded values for the same resource; e.g. from http cache.
+COMPONENT_EXPORT(STORAGE_COMMON)
+int64_t ComputeRandomResponsePadding();
+
+// Compute a stable padding value for a resource. This should be used for
+// cases where a site could trigger a large number of padding values to be
+// generated for the same resource; e.g. http cache. The |origin| is the
+// origin of the context that loaded the resource. Note, its important that the
+// |response_time| be the time stored in the cache and not just the current
+// time. The |side_data_size| should only be passed if padding is being
+// computed for a side data blob.
+COMPONENT_EXPORT(STORAGE_COMMON)
+int64_t ComputeStableResponsePadding(const url::Origin& origin,
+ const std::string& response_url,
+ const base::Time& response_time,
+ const std::string& request_method,
+ int64_t side_data_size = 0);
+
+} // namespace storage
+
+#endif // STORAGE_COMMON_QUOTA_PADDING_KEY_H_
diff --git a/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom b/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
index 678de941eb3..de5ab4ea2fd 100644
--- a/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
+++ b/chromium/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
@@ -36,6 +36,10 @@ struct FetchAPIResponse {
network.mojom.FetchResponseType response_type =
network.mojom.FetchResponseType.kDefault;
+ // Pre-computed padding for this response. This should only be non-zero
+ // for when |response_type| is kOpaque.
+ int64 padding = 0;
+
// The source of this response, e.g. network, CacheStorage.
network.mojom.FetchResponseSource response_source =
network.mojom.FetchResponseSource.kUnspecified;
diff --git a/chromium/third_party/blink/public/platform/web_url_response.h b/chromium/third_party/blink/public/platform/web_url_response.h
index 412624130e2..5d4aa60d001 100644
--- a/chromium/third_party/blink/public/platform/web_url_response.h
+++ b/chromium/third_party/blink/public/platform/web_url_response.h
@@ -264,6 +264,12 @@ class WebURLResponse {
BLINK_PLATFORM_EXPORT void SetType(network::mojom::FetchResponseType);
BLINK_PLATFORM_EXPORT network::mojom::FetchResponseType GetType() const;
+ // Pre-computed padding. This should only be non-zero if the type is
+ // kOpaque. In addition, it is only set for responses provided by a
+ // service worker FetchEvent handler.
+ BLINK_PLATFORM_EXPORT void SetPadding(int64_t);
+ BLINK_PLATFORM_EXPORT int64_t GetPadding() const;
+
// The URL list of the Response object the ServiceWorker passed to
// respondWith(). See
// network::ResourceResponseInfo::url_list_via_service_worker for details.
diff --git a/chromium/third_party/blink/renderer/core/BUILD.gn b/chromium/third_party/blink/renderer/core/BUILD.gn
index 1b10ab1a079..5dc17a42531 100644
--- a/chromium/third_party/blink/renderer/core/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/BUILD.gn
@@ -199,6 +199,7 @@ component("core") {
]
deps = [
"//components/paint_preview/common",
+ "//storage/common",
"//third_party/blink/public/common",
"//third_party/blink/renderer/platform",
"//third_party/blink/renderer/platform/wtf",
diff --git a/chromium/third_party/blink/renderer/core/fetch/DEPS b/chromium/third_party/blink/renderer/core/fetch/DEPS
index 26583be0e15..5a78494f81c 100644
--- a/chromium/third_party/blink/renderer/core/fetch/DEPS
+++ b/chromium/third_party/blink/renderer/core/fetch/DEPS
@@ -9,6 +9,7 @@ include_rules = [
"+net/http/http_response_info.h",
"+services/network/public/cpp",
"+services/network/public/mojom",
+ "+storage/common/quota/padding_key.h",
"+url/gurl.h",
]
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
index fc3052584fc..df680aa38a4 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -423,16 +423,21 @@ void FetchManager::Loader::DidReceiveResponse(
FetchResponseData* response_data = FetchResponseData::CreateWithBuffer(
BodyStreamBuffer::Create(script_state, place_holder_body_, signal_));
- response_data->InitFromResourceResponse(
- url_list_, fetch_request_data_->Method(),
- fetch_request_data_->Credentials(), tainting, response);
-
- FetchResponseData* tainted_response = nullptr;
-
DCHECK(!(network_utils::IsRedirectResponseCode(response_http_status_code_) &&
HasNonEmptyLocationHeader(response_data->HeaderList()) &&
fetch_request_data_->Redirect() != RedirectMode::kManual));
+ auto response_type = response.GetType();
+ if (network_utils::IsRedirectResponseCode(response_http_status_code_) &&
+ fetch_request_data_->Redirect() == RedirectMode::kManual)
+ response_type = network::mojom::FetchResponseType::kOpaqueRedirect;
+
+ response_data->InitFromResourceResponse(
+ execution_context_, response_type, url_list_,
+ fetch_request_data_->Method(), fetch_request_data_->Credentials(),
+ tainting, response);
+
+ FetchResponseData* tainted_response = nullptr;
if (network_utils::IsRedirectResponseCode(response_http_status_code_) &&
fetch_request_data_->Redirect() == RedirectMode::kManual) {
tainted_response = response_data->CreateOpaqueRedirectFilteredResponse();
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index 00870a35078..8188a1ebb20 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/fetch/fetch_response_data.h"
+#include "storage/common/quota/padding_key.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom-blink.h"
#include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
@@ -188,6 +189,7 @@ FetchResponseData* FetchResponseData::Clone(ScriptState* script_state,
ExceptionState& exception_state) {
FetchResponseData* new_response = Create();
new_response->type_ = type_;
+ new_response->padding_ = padding_;
new_response->response_source_ = response_source_;
if (termination_reason_) {
new_response->termination_reason_ = std::make_unique<TerminationReason>();
@@ -269,6 +271,7 @@ mojom::blink::FetchAPIResponsePtr FetchResponseData::PopulateFetchAPIResponse(
response->status_code = status_;
response->status_text = status_message_;
response->response_type = type_;
+ response->padding = padding_;
response->response_source = response_source_;
response->mime_type = mime_type_;
response->request_method = request_method_;
@@ -289,6 +292,8 @@ mojom::blink::FetchAPIResponsePtr FetchResponseData::PopulateFetchAPIResponse(
}
void FetchResponseData::InitFromResourceResponse(
+ ExecutionContext* context,
+ network::mojom::FetchResponseType response_type,
const Vector<KURL>& request_url_list,
const AtomicString& request_method,
network::mojom::CredentialsMode request_credentials,
@@ -347,6 +352,22 @@ void FetchResponseData::InitFromResourceResponse(
tainting == FetchRequestData::kBasicTainting));
SetHasRangeRequested(response.HasRangeRequested());
+
+ // Use the explicit padding in the response provided by a service worker
+ // or compute a new padding if necessary.
+ if (response.GetPadding()) {
+ SetPadding(response.GetPadding());
+ } else {
+ if (storage::ShouldPadResponseType(response_type)) {
+ int64_t padding = response.WasCached()
+ ? storage::ComputeStableResponsePadding(
+ context->GetSecurityOrigin()->ToUrlOrigin(),
+ Url()->GetString().Utf8(), ResponseTime(),
+ request_method.Utf8())
+ : storage::ComputeRandomResponsePadding();
+ SetPadding(padding);
+ }
+ }
}
FetchResponseData::FetchResponseData(Type type,
@@ -354,6 +375,7 @@ FetchResponseData::FetchResponseData(Type type,
uint16_t status,
AtomicString status_message)
: type_(type),
+ padding_(0),
response_source_(source),
status_(status),
status_message_(status_message),
diff --git a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
index 33657bb877c..31bc68df135 100644
--- a/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
+++ b/chromium/third_party/blink/renderer/core/fetch/fetch_response_data.h
@@ -85,6 +85,8 @@ class CORE_EXPORT FetchResponseData final
}
bool HasRangeRequested() const { return has_range_requested_; }
+ int64_t GetPadding() const { return padding_; }
+ void SetPadding(int64_t padding) { padding_ = padding; }
void SetResponseSource(network::mojom::FetchResponseSource response_source) {
response_source_ = response_source;
}
@@ -138,6 +140,8 @@ class CORE_EXPORT FetchResponseData final
// Initialize non-body data from the given |response|.
void InitFromResourceResponse(
+ ExecutionContext* context,
+ network::mojom::FetchResponseType response_type,
const Vector<KURL>& request_url_list,
const AtomicString& request_method,
network::mojom::CredentialsMode request_credentials,
@@ -148,6 +152,7 @@ class CORE_EXPORT FetchResponseData final
private:
network::mojom::FetchResponseType type_;
+ int64_t padding_;
network::mojom::FetchResponseSource response_source_;
std::unique_ptr<TerminationReason> termination_reason_;
Vector<KURL> url_list_;
diff --git a/chromium/third_party/blink/renderer/core/fetch/response.cc b/chromium/third_party/blink/renderer/core/fetch/response.cc
index c6cc155d70d..73905e17b1e 100644
--- a/chromium/third_party/blink/renderer/core/fetch/response.cc
+++ b/chromium/third_party/blink/renderer/core/fetch/response.cc
@@ -374,6 +374,7 @@ FetchResponseData* Response::CreateUnfilteredFetchResponseDataWithoutBody(
else
response = FetchResponseData::CreateNetworkErrorResponse();
+ response->SetPadding(fetch_api_response.padding);
response->SetResponseSource(fetch_api_response.response_source);
response->SetURLList(fetch_api_response.url_list);
response->SetStatus(fetch_api_response.status_code);
diff --git a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
index 28d7ddd6787..7d4e830eae6 100644
--- a/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
+++ b/chromium/third_party/blink/renderer/modules/service_worker/fetch_event.cc
@@ -158,13 +158,19 @@ void FetchEvent::OnNavigationPreloadResponse(
Vector<KURL> url_list(1);
url_list[0] = preload_response_->CurrentRequestUrl();
+ auto response_type =
+ network_utils::IsRedirectResponseCode(preload_response_->HttpStatusCode())
+ ? network::mojom::FetchResponseType::kOpaqueRedirect
+ : network::mojom::FetchResponseType::kBasic;
+
response_data->InitFromResourceResponse(
- url_list, http_names::kGET, network::mojom::CredentialsMode::kInclude,
+ ExecutionContext::From(script_state), response_type, url_list,
+ http_names::kGET, network::mojom::CredentialsMode::kInclude,
FetchRequestData::kBasicTainting,
preload_response_->ToResourceResponse());
FetchResponseData* tainted_response =
- network_utils::IsRedirectResponseCode(preload_response_->HttpStatusCode())
+ response_type == network::mojom::FetchResponseType::kOpaqueRedirect
? response_data->CreateOpaqueRedirectFilteredResponse()
: response_data->CreateBasicFilteredResponse();
preload_response_property_->Resolve(
diff --git a/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc b/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
index 3f3efff75b0..cf5836a0bbc 100644
--- a/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
+++ b/chromium/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -374,6 +374,13 @@ network::mojom::FetchResponseType WebURLResponse::GetType() const {
return resource_response_->GetType();
}
+void WebURLResponse::SetPadding(int64_t padding) {
+ resource_response_->SetPadding(padding);
+}
+int64_t WebURLResponse::GetPadding() const {
+ return resource_response_->GetPadding();
+}
+
void WebURLResponse::SetUrlListViaServiceWorker(
const WebVector<WebURL>& url_list_via_service_worker) {
Vector<KURL> url_list(url_list_via_service_worker.size());
diff --git a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index 5fadb1c34d9..5201e70e02a 100644
--- a/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/chromium/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -358,6 +358,9 @@ class PLATFORM_EXPORT ResourceResponse final {
// https://html.spec.whatwg.org/C/#cors-cross-origin
bool IsCorsCrossOrigin() const;
+ int64_t GetPadding() const { return padding_; }
+ void SetPadding(int64_t padding) { padding_ = padding; }
+
// See network::ResourceResponseInfo::url_list_via_service_worker.
const Vector<KURL>& UrlListViaServiceWorker() const {
return url_list_via_service_worker_;
@@ -597,6 +600,11 @@ class PLATFORM_EXPORT ResourceResponse final {
network::mojom::FetchResponseType response_type_ =
network::mojom::FetchResponseType::kDefault;
+ // Pre-computed padding. This should only be non-zero if |response_type| is
+ // set to kOpaque. In addition, it is only set if the response was provided
+ // by a service worker FetchEvent handler.
+ int64_t padding_ = 0;
+
// HTTP version used in the response, if known.
HTTPVersion http_version_ = kHTTPVersionUnknown;
diff --git a/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index d063e8f2508..fe8b5e5d618 100755
--- a/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/chromium/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1172,6 +1172,15 @@ _CONFIG = [
'allowed': ['net::RequestPriority'],
},
{
+ 'paths':
+ ['third_party/blink/renderer/core/fetch/fetch_response_data.cc'],
+ 'allowed': [
+ 'storage::ComputeRandomResponsePadding',
+ 'storage::ComputeStableResponsePadding',
+ 'storage::ShouldPadResponseType'
+ ],
+ },
+ {
'paths': ['third_party/blink/renderer/core/frame/local_frame_view.cc'],
'allowed':
['cc::frame_viewer_instrumentation::IsTracingLayerTreeSnapshots'],
diff --git a/chromium/tools/metrics/histograms/enums.xml b/chromium/tools/metrics/histograms/enums.xml
index 798b69c07a3..f524d6df7fe 100644
--- a/chromium/tools/metrics/histograms/enums.xml
+++ b/chromium/tools/metrics/histograms/enums.xml
@@ -8777,6 +8777,8 @@ Called by update_bad_message_reasons.py.-->
<int value="21" label="kKeysImplBackendClosed"/>
<int value="22" label="kCreateBackendDidCreateFailed"/>
<int value="23" label="kStorageGetAllMatchedEntriesBackendClosed"/>
+ <int value="24" label="kStorageHandleNull"/>
+ <int value="25" label="kWriteSideDataDidWriteMetadataWrongBytes"/>
</enum>
<enum name="CacheStorageErrorType">