Skip to content

Commit

Permalink
Implement Storage Id for encrypted media
Browse files Browse the repository at this point in the history
Adds code to compute Storage Id for encrypted media. It uses a new profile
setting ("media.storage_id_salt"). On Chromium this is not supported, so the
empty string is returned. Chrome implementation pending.

BUG=478960
TEST=StorageId browser_tests pass

Change-Id: I566e1cfbd1d44a2be809dd51c8418b922126cccc
Reviewed-on: https://chromium-review.googlesource.com/587828
Reviewed-by: Brett Wilson <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Bill Budge <[email protected]>
Reviewed-by: Thomas Guilbert <[email protected]>
Reviewed-by: Bernhard Bauer <[email protected]>
Commit-Queue: John Rummell <[email protected]>
Cr-Commit-Position: refs/heads/master@{#498600}
  • Loading branch information
jrummell-chromium authored and Commit Bot committed Aug 30, 2017
1 parent 6b47b44 commit 36e5b80
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 26 deletions.
4 changes: 4 additions & 0 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,8 @@ split_static_library("browser") {
"media/cast_remoting_connector.h",
"media/cast_remoting_sender.cc",
"media/cast_remoting_sender.h",
"media/cdm_storage_id.cc",
"media/cdm_storage_id.h",
"media/media_access_handler.cc",
"media/media_access_handler.h",
"media/media_device_id_salt.cc",
Expand All @@ -602,6 +604,8 @@ split_static_library("browser") {
"media/media_engagement_service.h",
"media/media_engagement_service_factory.cc",
"media/media_engagement_service_factory.h",
"media/media_storage_id_salt.cc",
"media/media_storage_id_salt.h",
"media/media_url_constants.cc",
"media/media_url_constants.h",
"media/midi_permission_context.cc",
Expand Down
18 changes: 18 additions & 0 deletions chrome/browser/media/cdm_storage_id.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2017 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 "chrome/browser/media/cdm_storage_id.h"

#include "base/callback.h"

namespace cdm_storage_id {

void ComputeStorageId(const std::vector<uint8_t>& salt,
const url::Origin& origin,
CdmStorageIdCallback callback) {
// Not implemented by default.
std::move(callback).Run(std::vector<uint8_t>());
}

} // namespace cdm_storage_id
31 changes: 31 additions & 0 deletions chrome/browser/media/cdm_storage_id.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2017 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 CHROME_BROWSER_MEDIA_CDM_STORAGE_ID_H_
#define CHROME_BROWSER_MEDIA_CDM_STORAGE_ID_H_

#include <stdint.h>

#include <vector>

#include "base/callback_forward.h"
#include "url/origin.h"

// This handles computing the Storage Id for platform verification.
namespace cdm_storage_id {

using CdmStorageIdCallback =
base::OnceCallback<void(const std::vector<uint8_t>& storage_id)>;

// Compute the Storage Id based on |salt| and |origin|. This may be
// asynchronous, so call |callback| with the result. If Storage Id is not
// supported on the current platform, an empty string will be passed to
// |callback|.
void ComputeStorageId(const std::vector<uint8_t>& salt,
const url::Origin& origin,
CdmStorageIdCallback callback);

} // namespace cdm_storage_id

#endif // CHROME_BROWSER_MEDIA_CDM_STORAGE_ID_H_
46 changes: 46 additions & 0 deletions chrome/browser/media/media_storage_id_salt.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2017 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 "chrome/browser/media/media_storage_id_salt.h"

#include <string>

#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "crypto/random.h"

namespace {

const char kMediaStorageIdSalt[] = "media.storage_id_salt";

} // namespace

std::vector<uint8_t> MediaStorageIdSalt::GetSalt(PrefService* pref_service) {
// Salt is stored as hex-encoded string.
std::string encoded_salt = pref_service->GetString(kMediaStorageIdSalt);
std::vector<uint8_t> salt;
if (encoded_salt.length() != kSaltLength * 2 ||
!base::HexStringToBytes(encoded_salt, &salt)) {
// If the salt is not the proper format log an error.
if (encoded_salt.length() > 0) {
DLOG(ERROR) << "Saved value for " << kMediaStorageIdSalt
<< " is not valid: " << encoded_salt;
// Continue on to generate a new one.
}

// If the salt doesn't exist, generate a new one.
salt.resize(kSaltLength);
crypto::RandBytes(salt.data(), salt.size());
encoded_salt = base::HexEncode(salt.data(), salt.size());
pref_service->SetString(kMediaStorageIdSalt, encoded_salt);
}

return salt;
}

void MediaStorageIdSalt::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(kMediaStorageIdSalt, std::string());
}
32 changes: 32 additions & 0 deletions chrome/browser/media/media_storage_id_salt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2017 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 CHROME_BROWSER_MEDIA_MEDIA_STORAGE_ID_SALT_H_
#define CHROME_BROWSER_MEDIA_MEDIA_STORAGE_ID_SALT_H_

#include <stdint.h>

#include <vector>

#include "base/macros.h"

class PrefRegistrySimple;
class PrefService;

// MediaStorageIDSalt is responsible for creating and retrieving a salt string
// that is used when creating Storage IDs.
class MediaStorageIdSalt {
public:
enum { kSaltLength = 32 };

// Retrieves the current salt. If one does not currently exist it is created.
static std::vector<uint8_t> GetSalt(PrefService* pref_service);

static void RegisterProfilePrefs(PrefRegistrySimple* registry);

private:
DISALLOW_IMPLICIT_CONSTRUCTORS(MediaStorageIdSalt);
};

#endif // CHROME_BROWSER_MEDIA_MEDIA_STORAGE_ID_SALT_H_
53 changes: 53 additions & 0 deletions chrome/browser/media/media_storage_id_salt_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2017 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 "chrome/browser/media/media_storage_id_salt.h"

#include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

const char kPrefsName[] = "media.storage_id_salt";

TEST(MediaStorageIdSalt, Register) {
TestingPrefServiceSimple prefs;

MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
}

TEST(MediaStorageIdSalt, Create) {
TestingPrefServiceSimple prefs;

MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
std::vector<uint8_t> salt = MediaStorageIdSalt::GetSalt(&prefs);
EXPECT_EQ(MediaStorageIdSalt::kSaltLength, salt.size());
}

TEST(MediaStorageIdSalt, Recreate) {
TestingPrefServiceSimple prefs;

MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
std::vector<uint8_t> original_salt = MediaStorageIdSalt::GetSalt(&prefs);
EXPECT_EQ(MediaStorageIdSalt::kSaltLength, original_salt.size());

// Now that the salt is created, mess it up and then try fetching it again
// (should generate a new salt and log an error).
prefs.SetString(kPrefsName, "123");
std::vector<uint8_t> new_salt = MediaStorageIdSalt::GetSalt(&prefs);
EXPECT_EQ(MediaStorageIdSalt::kSaltLength, new_salt.size());
EXPECT_NE(original_salt, new_salt);
}

TEST(MediaStorageIdSalt, FetchTwice) {
TestingPrefServiceSimple prefs;

MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
std::vector<uint8_t> salt1 = MediaStorageIdSalt::GetSalt(&prefs);
EXPECT_EQ(MediaStorageIdSalt::kSaltLength, salt1.size());

// Fetch the salt again. Should be the same value.
std::vector<uint8_t> salt2 = MediaStorageIdSalt::GetSalt(&prefs);
EXPECT_EQ(MediaStorageIdSalt::kSaltLength, salt2.size());
EXPECT_EQ(salt1, salt2);
}
2 changes: 2 additions & 0 deletions chrome/browser/prefs/browser_prefs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "chrome/browser/intranet_redirect_detector.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/media/media_device_id_salt.h"
#include "chrome/browser/media/media_storage_id_salt.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/media/webrtc/media_stream_devices_controller.h"
#include "chrome/browser/metrics/chrome_metrics_service_client.h"
Expand Down Expand Up @@ -488,6 +489,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
language::UrlLanguageHistogram::RegisterProfilePrefs(registry);
MediaCaptureDevicesDispatcher::RegisterProfilePrefs(registry);
MediaDeviceIDSalt::RegisterProfilePrefs(registry);
MediaStorageIdSalt::RegisterProfilePrefs(registry);
MediaStreamDevicesController::RegisterProfilePrefs(registry);
NavigationCorrectionTabObserver::RegisterProfilePrefs(registry);
NotifierStateTracker::RegisterProfilePrefs(registry);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
#include "chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h"

#include "base/bind_helpers.h"
#include "chrome/browser/media/cdm_storage_id.h"
#include "chrome/browser/media/media_storage_id_salt.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
Expand All @@ -17,6 +21,17 @@

namespace chrome {

namespace {

std::vector<uint8_t> GetSalt(content::RenderFrameHost* rfh) {
DCHECK(rfh);
Profile* profile =
Profile::FromBrowserContext(rfh->GetProcess()->GetBrowserContext());
return MediaStorageIdSalt::GetSalt(profile->GetPrefs());
}

} // namespace

PepperPlatformVerificationMessageFilter::
PepperPlatformVerificationMessageFilter(content::BrowserPpapiHost* host,
PP_Instance instance)
Expand Down Expand Up @@ -115,14 +130,31 @@ void PepperPlatformVerificationMessageFilter::ChallengePlatformCallback(

int32_t PepperPlatformVerificationMessageFilter::OnGetStorageId(
ppapi::host::HostMessageContext* context) {
// TODO(jrummell): Implement Storage ID. For now simply returns empty string.
// http://crbug.com/478960.
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
if (!rfh) {
// Won't be able to get the salt, so return empty buffer.
GetStorageIdCallback(context->MakeReplyMessageContext(),
std::vector<uint8_t>());
return PP_OK_COMPLETIONPENDING;
}

std::vector<uint8_t> salt = GetSalt(rfh);
DCHECK(salt.size());
cdm_storage_id::ComputeStorageId(
salt, rfh->GetLastCommittedOrigin(),
base::BindOnce(
&PepperPlatformVerificationMessageFilter::GetStorageIdCallback, this,
context->MakeReplyMessageContext()));
return PP_OK_COMPLETIONPENDING;
}

void PepperPlatformVerificationMessageFilter::GetStorageIdCallback(
ppapi::host::ReplyMessageContext reply_context,
const std::vector<uint8_t>& storage_id) {
reply_context.params.set_result(PP_OK);
SendReply(reply_context,
PpapiHostMsg_PlatformVerification_GetStorageIdReply(std::string()));
return PP_OK_COMPLETIONPENDING;
PpapiHostMsg_PlatformVerification_GetStorageIdReply(storage_id));
}

} // namespace chrome
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

#include <stdint.h>

#include <string>
#include <vector>

#include "base/macros.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/host/resource_message_filter.h"
Expand Down Expand Up @@ -58,6 +61,8 @@ class PepperPlatformVerificationMessageFilter
#endif

int32_t OnGetStorageId(ppapi::host::HostMessageContext* context);
void GetStorageIdCallback(ppapi::host::ReplyMessageContext reply_context,
const std::vector<uint8_t>& storage_id);

// Used to lookup the WebContents associated with this PP_Instance.
int render_process_id_;
Expand Down
1 change: 1 addition & 0 deletions chrome/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3172,6 +3172,7 @@ test("unit_tests") {
"../browser/media/media_engagement_contents_observer_unittest.cc",
"../browser/media/media_engagement_score_unittest.cc",
"../browser/media/media_engagement_service_unittest.cc",
"../browser/media/media_storage_id_salt_unittest.cc",
"../browser/media/midi_permission_context_unittest.cc",
"../browser/media/midi_sysex_permission_context_unittest.cc",
"../browser/media/router/browser_presentation_connection_proxy_unittest.cc",
Expand Down
22 changes: 12 additions & 10 deletions media/cdm/ppapi/ppapi_cdm_adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1204,8 +1204,6 @@ void PpapiCdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
}

void PpapiCdmAdapter::RequestStorageId() {
CDM_DLOG() << __func__;

// If persistent storage is not allowed, no need to get the Storage ID.
if (allow_persistent_state_) {
linked_ptr<pp::Var> response(new pp::Var());
Expand Down Expand Up @@ -1339,16 +1337,20 @@ void PpapiCdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
void PpapiCdmAdapter::RequestStorageIdDone(
int32_t result,
const linked_ptr<pp::Var>& response) {
std::string storage_id;

if (result == PP_OK)
storage_id = response->AsString();
uint8_t* storage_id_ptr;
uint32_t storage_id_size;

CDM_DLOG() << __func__ << ": result = " << result
<< ", storage_id = " << storage_id;
if (result == PP_OK && response->is_array_buffer()) {
pp::VarArrayBuffer storage_id(*response);
storage_id_ptr = static_cast<uint8_t*>(storage_id.Map());
storage_id_size = storage_id.ByteLength();
} else {
CDM_DLOG() << __func__ << " failed, result = " << result;
storage_id_ptr = nullptr;
storage_id_size = 0;
}

cdm_->OnStorageId(reinterpret_cast<const uint8_t*>(storage_id.data()),
static_cast<uint32_t>(storage_id.length()));
cdm_->OnStorageId(storage_id_ptr, storage_id_size);
}

PpapiCdmAdapter::SessionError::SessionError(
Expand Down
7 changes: 4 additions & 3 deletions media/test/data/eme_player_js/player_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,11 @@ PlayerUtils.registerEMEEventListeners = function(player) {
}

// The File IO test requires persistent state support.
if (player.testConfig.keySystem ==
'org.chromium.externalclearkey.fileiotest') {
if (player.testConfig.keySystem == FILE_IO_TEST_KEYSYSTEM) {
config.persistentState = 'required';
} else if (player.testConfig.sessionToLoad) {
} else if (
player.testConfig.sessionToLoad ||
player.testConfig.keySystem == STORAGE_ID_TEST_KEYSYSTEM) {
config.persistentState = 'required';
config.sessionTypes = ['temporary', 'persistent-license'];
}
Expand Down
2 changes: 1 addition & 1 deletion ppapi/api/private/ppb_platform_verification_private.idl
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ interface PPB_PlatformVerification_Private {
* Requests the device's storage ID.
*
* @param[out] storage_id A <code>PP_Var</code> of type
* <code>PP_VARTYPE_STRING</code> that contains the storage ID.
* <code>PP_VARTYPE_ARRAY_BUFFER</code> that contains the storage ID.
*
* @param[in] callback A <code>PP_CompletionCallback</code> to be called after
* the storage ID has been obtained. This callback will only run if
Expand Down
4 changes: 2 additions & 2 deletions ppapi/c/private/ppb_platform_verification_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

/* From private/ppb_platform_verification_private.idl,
* modified Tue Jun 13 15:47:24 2017.
* modified Fri Aug 11 11:47:35 2017.
*/

#ifndef PPAPI_C_PRIVATE_PPB_PLATFORM_VERIFICATION_PRIVATE_H_
Expand Down Expand Up @@ -102,7 +102,7 @@ struct PPB_PlatformVerification_Private_0_3 {
* Requests the device's storage ID.
*
* @param[out] storage_id A <code>PP_Var</code> of type
* <code>PP_VARTYPE_STRING</code> that contains the storage ID.
* <code>PP_VARTYPE_ARRAY_BUFFER</code> that contains the storage ID.
*
* @param[in] callback A <code>PP_CompletionCallback</code> to be called after
* the storage ID has been obtained. This callback will only run if
Expand Down
Loading

0 comments on commit 36e5b80

Please sign in to comment.