1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/renderer_host/pepper/device_id_fetcher.h"
7 #include "base/file_util.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/common/pref_names.h"
12 #if defined(OS_CHROMEOS)
13 #include "chromeos/cryptohome/system_salt_getter.h"
15 #include "components/user_prefs/pref_registry_syncable.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_ppapi_host.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "crypto/encryptor.h"
21 #include "crypto/random.h"
22 #include "crypto/sha2.h"
23 #include "ppapi/c/pp_errors.h"
24 #if defined(ENABLE_RLZ)
25 #include "rlz/lib/machine_id.h"
28 using content::BrowserPpapiHost
;
29 using content::BrowserThread
;
30 using content::RenderProcessHost
;
36 const char kDRMIdentifierFile
[] = "Pepper DRM ID.0";
38 const uint32_t kSaltLength
= 32;
40 void GetMachineIDAsync(
41 const base::Callback
<void(const std::string
&)>& callback
) {
42 #if defined(OS_WIN) && defined(ENABLE_RLZ)
44 rlz_lib::GetMachineId(&result
);
46 #elif defined(OS_CHROMEOS)
47 chromeos::SystemSaltGetter::Get()->GetSystemSalt(callback
);
49 // Not implemented for other platforms.
51 callback
.Run(std::string());
57 DeviceIDFetcher::DeviceIDFetcher(int render_process_id
)
58 : in_progress_(false),
59 render_process_id_(render_process_id
) {
60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
63 DeviceIDFetcher::~DeviceIDFetcher() {
66 bool DeviceIDFetcher::Start(const IDCallback
& callback
) {
67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
75 BrowserThread::PostTask(
76 BrowserThread::UI
, FROM_HERE
,
77 base::Bind(&DeviceIDFetcher::CheckPrefsOnUIThread
, this));
82 void DeviceIDFetcher::RegisterProfilePrefs(
83 user_prefs::PrefRegistrySyncable
* prefs
) {
84 prefs
->RegisterBooleanPref(prefs::kEnableDRM
,
86 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
87 prefs
->RegisterStringPref(
90 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
94 base::FilePath
DeviceIDFetcher::GetLegacyDeviceIDPath(
95 const base::FilePath
& profile_path
) {
96 return profile_path
.AppendASCII(kDRMIdentifierFile
);
99 void DeviceIDFetcher::CheckPrefsOnUIThread() {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
102 Profile
* profile
= NULL
;
103 RenderProcessHost
* render_process_host
=
104 RenderProcessHost::FromID(render_process_id_
);
105 if (render_process_host
&& render_process_host
->GetBrowserContext()) {
106 profile
= Profile::FromBrowserContext(
107 render_process_host
->GetBrowserContext());
111 profile
->IsOffTheRecord() ||
112 !profile
->GetPrefs()->GetBoolean(prefs::kEnableDRM
)) {
113 RunCallbackOnIOThread(std::string(), PP_ERROR_NOACCESS
);
117 // Check if the salt pref is set. If it isn't, set it.
118 std::string salt
= profile
->GetPrefs()->GetString(prefs::kDRMSalt
);
120 uint8_t salt_bytes
[kSaltLength
];
121 crypto::RandBytes(salt_bytes
, arraysize(salt_bytes
));
122 // Since it will be stored in a string pref, convert it to hex.
123 salt
= base::HexEncode(salt_bytes
, arraysize(salt_bytes
));
124 profile
->GetPrefs()->SetString(prefs::kDRMSalt
, salt
);
127 #if defined(OS_CHROMEOS)
128 // Try the legacy path first for ChromeOS. We pass the new salt in as well
129 // in case the legacy id doesn't exist.
130 BrowserThread::PostBlockingPoolTask(
132 base::Bind(&DeviceIDFetcher::LegacyComputeOnBlockingPool
,
134 profile
->GetPath(), salt
));
136 // Get the machine ID and call ComputeOnUIThread with salt + machine_id.
137 GetMachineIDAsync(base::Bind(&DeviceIDFetcher::ComputeOnUIThread
,
142 void DeviceIDFetcher::ComputeOnUIThread(const std::string
& salt
,
143 const std::string
& machine_id
) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
146 if (machine_id
.empty()) {
147 LOG(ERROR
) << "Empty machine id";
148 RunCallbackOnIOThread(std::string(), PP_ERROR_FAILED
);
152 // Build the identifier as follows:
153 // SHA256(machine-id||service||SHA256(machine-id||service||salt))
154 std::vector
<uint8
> salt_bytes
;
155 if (!base::HexStringToBytes(salt
, &salt_bytes
))
157 if (salt_bytes
.size() != kSaltLength
) {
158 LOG(ERROR
) << "Unexpected salt bytes length: " << salt_bytes
.size();
159 RunCallbackOnIOThread(std::string(), PP_ERROR_FAILED
);
163 char id_buf
[256 / 8]; // 256-bits for SHA256
164 std::string input
= machine_id
;
165 input
.append(kDRMIdentifierFile
);
166 input
.append(salt_bytes
.begin(), salt_bytes
.end());
167 crypto::SHA256HashString(input
, &id_buf
, sizeof(id_buf
));
168 std::string id
= StringToLowerASCII(
169 base::HexEncode(reinterpret_cast<const void*>(id_buf
), sizeof(id_buf
)));
171 input
.append(kDRMIdentifierFile
);
173 crypto::SHA256HashString(input
, &id_buf
, sizeof(id_buf
));
174 id
= StringToLowerASCII(base::HexEncode(
175 reinterpret_cast<const void*>(id_buf
),
178 RunCallbackOnIOThread(id
, PP_OK
);
181 // TODO(raymes): This is temporary code to migrate ChromeOS devices to the new
182 // scheme for generating device IDs. Delete this once we are sure most ChromeOS
183 // devices have been migrated.
184 void DeviceIDFetcher::LegacyComputeOnBlockingPool(
185 const base::FilePath
& profile_path
,
186 const std::string
& salt
) {
188 // First check if the legacy device ID file exists on ChromeOS. If it does, we
189 // should just return that.
190 base::FilePath id_path
= GetLegacyDeviceIDPath(profile_path
);
191 if (base::PathExists(id_path
)) {
192 if (base::ReadFileToString(id_path
, &id
) && !id
.empty()) {
193 RunCallbackOnIOThread(id
, PP_OK
);
197 // If we didn't find an ID, get the machine ID and call the new code path to
199 BrowserThread::PostTask(
200 BrowserThread::UI
, FROM_HERE
,
201 base::Bind(&GetMachineIDAsync
,
202 base::Bind(&DeviceIDFetcher::ComputeOnUIThread
,
206 void DeviceIDFetcher::RunCallbackOnIOThread(const std::string
& id
,
208 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
209 BrowserThread::PostTask(
210 BrowserThread::IO
, FROM_HERE
,
211 base::Bind(&DeviceIDFetcher::RunCallbackOnIOThread
, this, id
, result
));
214 in_progress_
= false;
215 callback_
.Run(id
, result
);
218 } // namespace chrome