Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / renderer_host / pepper / device_id_fetcher.cc
blob3ec57772c70b8bd1843904cb09b5c0d6190e0df6
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/files/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"
14 #endif
15 #include "components/pref_registry/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"
26 #endif
28 using content::BrowserPpapiHost;
29 using content::BrowserThread;
30 using content::RenderProcessHost;
32 namespace chrome {
34 namespace {
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)
43 std::string result;
44 rlz_lib::GetMachineId(&result);
45 callback.Run(result);
46 #elif defined(OS_CHROMEOS)
47 chromeos::SystemSaltGetter::Get()->GetSystemSalt(callback);
48 #else
49 // Not implemented for other platforms.
50 NOTREACHED();
51 callback.Run(std::string());
52 #endif
55 } // namespace
57 DeviceIDFetcher::DeviceIDFetcher(int render_process_id)
58 : in_progress_(false), render_process_id_(render_process_id) {
59 DCHECK_CURRENTLY_ON(BrowserThread::IO);
62 DeviceIDFetcher::~DeviceIDFetcher() {}
64 bool DeviceIDFetcher::Start(const IDCallback& callback) {
65 DCHECK_CURRENTLY_ON(BrowserThread::IO);
67 if (in_progress_)
68 return false;
70 in_progress_ = true;
71 callback_ = callback;
73 BrowserThread::PostTask(
74 BrowserThread::UI,
75 FROM_HERE,
76 base::Bind(&DeviceIDFetcher::CheckPrefsOnUIThread, this));
77 return true;
80 // static
81 void DeviceIDFetcher::RegisterProfilePrefs(
82 user_prefs::PrefRegistrySyncable* prefs) {
83 prefs->RegisterBooleanPref(prefs::kEnableDRM, true);
84 prefs->RegisterStringPref(prefs::kDRMSalt, "");
87 // static
88 base::FilePath DeviceIDFetcher::GetLegacyDeviceIDPath(
89 const base::FilePath& profile_path) {
90 return profile_path.AppendASCII(kDRMIdentifierFile);
93 void DeviceIDFetcher::CheckPrefsOnUIThread() {
94 DCHECK_CURRENTLY_ON(BrowserThread::UI);
96 Profile* profile = NULL;
97 RenderProcessHost* render_process_host =
98 RenderProcessHost::FromID(render_process_id_);
99 if (render_process_host && render_process_host->GetBrowserContext()) {
100 profile =
101 Profile::FromBrowserContext(render_process_host->GetBrowserContext());
104 if (!profile || profile->IsOffTheRecord() ||
105 !profile->GetPrefs()->GetBoolean(prefs::kEnableDRM)) {
106 RunCallbackOnIOThread(std::string(), PP_ERROR_NOACCESS);
107 return;
110 // Check if the salt pref is set. If it isn't, set it.
111 std::string salt = profile->GetPrefs()->GetString(prefs::kDRMSalt);
112 if (salt.empty()) {
113 uint8_t salt_bytes[kSaltLength];
114 crypto::RandBytes(salt_bytes, arraysize(salt_bytes));
115 // Since it will be stored in a string pref, convert it to hex.
116 salt = base::HexEncode(salt_bytes, arraysize(salt_bytes));
117 profile->GetPrefs()->SetString(prefs::kDRMSalt, salt);
120 #if defined(OS_CHROMEOS)
121 // Try the legacy path first for ChromeOS. We pass the new salt in as well
122 // in case the legacy id doesn't exist.
123 BrowserThread::PostBlockingPoolTask(
124 FROM_HERE,
125 base::Bind(&DeviceIDFetcher::LegacyComputeOnBlockingPool,
126 this,
127 profile->GetPath(),
128 salt));
129 #else
130 // Get the machine ID and call ComputeOnUIThread with salt + machine_id.
131 GetMachineIDAsync(
132 base::Bind(&DeviceIDFetcher::ComputeOnUIThread, this, salt));
133 #endif
136 void DeviceIDFetcher::ComputeOnUIThread(const std::string& salt,
137 const std::string& machine_id) {
138 DCHECK_CURRENTLY_ON(BrowserThread::UI);
140 if (machine_id.empty()) {
141 LOG(ERROR) << "Empty machine id";
142 RunCallbackOnIOThread(std::string(), PP_ERROR_FAILED);
143 return;
146 // Build the identifier as follows:
147 // SHA256(machine-id||service||SHA256(machine-id||service||salt))
148 std::vector<uint8> salt_bytes;
149 if (!base::HexStringToBytes(salt, &salt_bytes))
150 salt_bytes.clear();
151 if (salt_bytes.size() != kSaltLength) {
152 LOG(ERROR) << "Unexpected salt bytes length: " << salt_bytes.size();
153 RunCallbackOnIOThread(std::string(), PP_ERROR_FAILED);
154 return;
157 char id_buf[256 / 8]; // 256-bits for SHA256
158 std::string input = machine_id;
159 input.append(kDRMIdentifierFile);
160 input.append(salt_bytes.begin(), salt_bytes.end());
161 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf));
162 std::string id = base::ToLowerASCII(
163 base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf)));
164 input = machine_id;
165 input.append(kDRMIdentifierFile);
166 input.append(id);
167 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf));
168 id = base::ToLowerASCII(
169 base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf)));
171 RunCallbackOnIOThread(id, PP_OK);
174 // TODO(raymes): This is temporary code to migrate ChromeOS devices to the new
175 // scheme for generating device IDs. Delete this once we are sure most ChromeOS
176 // devices have been migrated.
177 void DeviceIDFetcher::LegacyComputeOnBlockingPool(
178 const base::FilePath& profile_path,
179 const std::string& salt) {
180 std::string id;
181 // First check if the legacy device ID file exists on ChromeOS. If it does, we
182 // should just return that.
183 base::FilePath id_path = GetLegacyDeviceIDPath(profile_path);
184 if (base::PathExists(id_path)) {
185 if (base::ReadFileToString(id_path, &id) && !id.empty()) {
186 RunCallbackOnIOThread(id, PP_OK);
187 return;
190 // If we didn't find an ID, get the machine ID and call the new code path to
191 // generate an ID.
192 BrowserThread::PostTask(
193 BrowserThread::UI,
194 FROM_HERE,
195 base::Bind(&GetMachineIDAsync,
196 base::Bind(&DeviceIDFetcher::ComputeOnUIThread, this, salt)));
199 void DeviceIDFetcher::RunCallbackOnIOThread(const std::string& id,
200 int32_t result) {
201 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
202 BrowserThread::PostTask(
203 BrowserThread::IO,
204 FROM_HERE,
205 base::Bind(&DeviceIDFetcher::RunCallbackOnIOThread, this, id, result));
206 return;
208 in_progress_ = false;
209 callback_.Run(id, result);
212 } // namespace chrome