Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_host / pepper / device_id_fetcher.cc
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.
4
5 #include "chrome/browser/renderer_host/pepper/device_id_fetcher.h"
6
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
27
28 using content::BrowserPpapiHost;
29 using content::BrowserThread;
30 using content::RenderProcessHost;
31
32 namespace chrome {
33
34 namespace {
35
36 const char kDRMIdentifierFile[] = "Pepper DRM ID.0";
37
38 const uint32_t kSaltLength = 32;
39
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
53 }
54
55 }  // namespace
56
57 DeviceIDFetcher::DeviceIDFetcher(int render_process_id)
58     : in_progress_(false), render_process_id_(render_process_id) {
59   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
60 }
61
62 DeviceIDFetcher::~DeviceIDFetcher() {}
63
64 bool DeviceIDFetcher::Start(const IDCallback& callback) {
65   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
66
67   if (in_progress_)
68     return false;
69
70   in_progress_ = true;
71   callback_ = callback;
72
73   BrowserThread::PostTask(
74       BrowserThread::UI,
75       FROM_HERE,
76       base::Bind(&DeviceIDFetcher::CheckPrefsOnUIThread, this));
77   return true;
78 }
79
80 // static
81 void DeviceIDFetcher::RegisterProfilePrefs(
82     user_prefs::PrefRegistrySyncable* prefs) {
83   prefs->RegisterBooleanPref(prefs::kEnableDRM,
84                              true,
85                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
86   prefs->RegisterStringPref(
87       prefs::kDRMSalt, "", user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
88 }
89
90 // static
91 base::FilePath DeviceIDFetcher::GetLegacyDeviceIDPath(
92     const base::FilePath& profile_path) {
93   return profile_path.AppendASCII(kDRMIdentifierFile);
94 }
95
96 void DeviceIDFetcher::CheckPrefsOnUIThread() {
97   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98
99   Profile* profile = NULL;
100   RenderProcessHost* render_process_host =
101       RenderProcessHost::FromID(render_process_id_);
102   if (render_process_host && render_process_host->GetBrowserContext()) {
103     profile =
104         Profile::FromBrowserContext(render_process_host->GetBrowserContext());
105   }
106
107   if (!profile || profile->IsOffTheRecord() ||
108       !profile->GetPrefs()->GetBoolean(prefs::kEnableDRM)) {
109     RunCallbackOnIOThread(std::string(), PP_ERROR_NOACCESS);
110     return;
111   }
112
113   // Check if the salt pref is set. If it isn't, set it.
114   std::string salt = profile->GetPrefs()->GetString(prefs::kDRMSalt);
115   if (salt.empty()) {
116     uint8_t salt_bytes[kSaltLength];
117     crypto::RandBytes(salt_bytes, arraysize(salt_bytes));
118     // Since it will be stored in a string pref, convert it to hex.
119     salt = base::HexEncode(salt_bytes, arraysize(salt_bytes));
120     profile->GetPrefs()->SetString(prefs::kDRMSalt, salt);
121   }
122
123 #if defined(OS_CHROMEOS)
124   // Try the legacy path first for ChromeOS. We pass the new salt in as well
125   // in case the legacy id doesn't exist.
126   BrowserThread::PostBlockingPoolTask(
127       FROM_HERE,
128       base::Bind(&DeviceIDFetcher::LegacyComputeOnBlockingPool,
129                  this,
130                  profile->GetPath(),
131                  salt));
132 #else
133   // Get the machine ID and call ComputeOnUIThread with salt + machine_id.
134   GetMachineIDAsync(
135       base::Bind(&DeviceIDFetcher::ComputeOnUIThread, this, salt));
136 #endif
137 }
138
139 void DeviceIDFetcher::ComputeOnUIThread(const std::string& salt,
140                                         const std::string& machine_id) {
141   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
142
143   if (machine_id.empty()) {
144     LOG(ERROR) << "Empty machine id";
145     RunCallbackOnIOThread(std::string(), PP_ERROR_FAILED);
146     return;
147   }
148
149   // Build the identifier as follows:
150   // SHA256(machine-id||service||SHA256(machine-id||service||salt))
151   std::vector<uint8> salt_bytes;
152   if (!base::HexStringToBytes(salt, &salt_bytes))
153     salt_bytes.clear();
154   if (salt_bytes.size() != kSaltLength) {
155     LOG(ERROR) << "Unexpected salt bytes length: " << salt_bytes.size();
156     RunCallbackOnIOThread(std::string(), PP_ERROR_FAILED);
157     return;
158   }
159
160   char id_buf[256 / 8];  // 256-bits for SHA256
161   std::string input = machine_id;
162   input.append(kDRMIdentifierFile);
163   input.append(salt_bytes.begin(), salt_bytes.end());
164   crypto::SHA256HashString(input, &id_buf, sizeof(id_buf));
165   std::string id = base::StringToLowerASCII(
166       base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf)));
167   input = machine_id;
168   input.append(kDRMIdentifierFile);
169   input.append(id);
170   crypto::SHA256HashString(input, &id_buf, sizeof(id_buf));
171   id = base::StringToLowerASCII(
172       base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf)));
173
174   RunCallbackOnIOThread(id, PP_OK);
175 }
176
177 // TODO(raymes): This is temporary code to migrate ChromeOS devices to the new
178 // scheme for generating device IDs. Delete this once we are sure most ChromeOS
179 // devices have been migrated.
180 void DeviceIDFetcher::LegacyComputeOnBlockingPool(
181     const base::FilePath& profile_path,
182     const std::string& salt) {
183   std::string id;
184   // First check if the legacy device ID file exists on ChromeOS. If it does, we
185   // should just return that.
186   base::FilePath id_path = GetLegacyDeviceIDPath(profile_path);
187   if (base::PathExists(id_path)) {
188     if (base::ReadFileToString(id_path, &id) && !id.empty()) {
189       RunCallbackOnIOThread(id, PP_OK);
190       return;
191     }
192   }
193   // If we didn't find an ID, get the machine ID and call the new code path to
194   // generate an ID.
195   BrowserThread::PostTask(
196       BrowserThread::UI,
197       FROM_HERE,
198       base::Bind(&GetMachineIDAsync,
199                  base::Bind(&DeviceIDFetcher::ComputeOnUIThread, this, salt)));
200 }
201
202 void DeviceIDFetcher::RunCallbackOnIOThread(const std::string& id,
203                                             int32_t result) {
204   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
205     BrowserThread::PostTask(
206         BrowserThread::IO,
207         FROM_HERE,
208         base::Bind(&DeviceIDFetcher::RunCallbackOnIOThread, this, id, result));
209     return;
210   }
211   in_progress_ = false;
212   callback_.Run(id, result);
213 }
214
215 }  // namespace chrome