OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/renderer_host/pepper/device_id_fetcher.h" | 5 #include "chrome/browser/renderer_host/pepper/device_id_fetcher.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/prefs/pref_service.h" | 8 #include "base/prefs/pref_service.h" |
9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
10 #include "chrome/browser/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
(...skipping 18 matching lines...) Expand all Loading... | |
29 using content::RenderProcessHost; | 29 using content::RenderProcessHost; |
30 | 30 |
31 namespace chrome { | 31 namespace chrome { |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 const char kDRMIdentifierFile[] = "Pepper DRM ID.0"; | 35 const char kDRMIdentifierFile[] = "Pepper DRM ID.0"; |
36 | 36 |
37 const uint32_t kSaltLength = 32; | 37 const uint32_t kSaltLength = 32; |
38 | 38 |
39 void GetMachineIdAsync(const DeviceIDFetcher::IDCallback& callback) { | |
40 std::string result; | |
41 #if defined(OS_WIN) && defined(ENABLE_RLZ) | |
42 rlz_lib::GetMachineId(&result); | |
43 #elif defined(OS_CHROMEOS) | |
44 result = chromeos::CryptohomeLibrary::Get()->GetSystemSalt(); | |
45 if (result.empty()) { | |
46 // cryptohome must not be running; re-request after a delay. | |
47 const int64 kRequestStstemSaltDelayMs = 500; | |
raymes
2013/09/16 22:13:38
-Ststem -> System
-Seems ok to retry but how did y
stevenjb
2013/09/16 22:32:48
The delay is designed to be long enough not to spa
| |
48 base::MessageLoop::current()->PostDelayedTask( | |
49 FROM_HERE, | |
50 base::Bind(&GetMachineIdAsync, callback), | |
51 base::TimeDelta::FromMilliseconds(kRequestStstemSaltDelayMs)); | |
52 return; | |
53 } | |
54 #else | |
55 // Not implemented for other platforms. | |
56 NOTREACHED(); | |
57 #endif | |
58 callback.Run(result); | |
59 } | |
60 | |
39 } // namespace | 61 } // namespace |
40 | 62 |
41 DeviceIDFetcher::DeviceIDFetcher(int render_process_id) | 63 DeviceIDFetcher::DeviceIDFetcher(int render_process_id) |
42 : in_progress_(false), | 64 : in_progress_(false), |
43 render_process_id_(render_process_id) { | 65 render_process_id_(render_process_id), |
66 weak_ptr_factory_(this) { | |
44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
45 } | 68 } |
46 | 69 |
47 DeviceIDFetcher::~DeviceIDFetcher() { | 70 DeviceIDFetcher::~DeviceIDFetcher() { |
48 } | 71 } |
49 | 72 |
50 bool DeviceIDFetcher::Start(const IDCallback& callback) { | 73 bool DeviceIDFetcher::Start(const IDCallback& callback) { |
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
52 | 75 |
53 if (in_progress_) | 76 if (in_progress_) |
(...skipping 13 matching lines...) Expand all Loading... | |
67 user_prefs::PrefRegistrySyncable* prefs) { | 90 user_prefs::PrefRegistrySyncable* prefs) { |
68 prefs->RegisterBooleanPref(prefs::kEnableDRM, | 91 prefs->RegisterBooleanPref(prefs::kEnableDRM, |
69 true, | 92 true, |
70 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 93 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
71 prefs->RegisterStringPref( | 94 prefs->RegisterStringPref( |
72 prefs::kDRMSalt, | 95 prefs::kDRMSalt, |
73 "", | 96 "", |
74 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 97 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
75 } | 98 } |
76 | 99 |
77 // static | |
78 base::FilePath DeviceIDFetcher::GetLegacyDeviceIDPath( | |
79 const base::FilePath& profile_path) { | |
80 return profile_path.AppendASCII(kDRMIdentifierFile); | |
81 } | |
82 | |
83 // TODO(raymes): Change this to just return the device id salt and call it with | |
84 // PostTaskAndReply once the legacy ChromeOS codepath is removed. | |
85 void DeviceIDFetcher::CheckPrefsOnUIThread() { | 100 void DeviceIDFetcher::CheckPrefsOnUIThread() { |
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
87 | 102 |
88 Profile* profile = NULL; | 103 Profile* profile = NULL; |
89 RenderProcessHost* render_process_host = | 104 RenderProcessHost* render_process_host = |
90 RenderProcessHost::FromID(render_process_id_); | 105 RenderProcessHost::FromID(render_process_id_); |
91 if (render_process_host && render_process_host->GetBrowserContext()) { | 106 if (render_process_host && render_process_host->GetBrowserContext()) { |
92 profile = Profile::FromBrowserContext( | 107 profile = Profile::FromBrowserContext( |
93 render_process_host->GetBrowserContext()); | 108 render_process_host->GetBrowserContext()); |
94 } | 109 } |
95 | 110 |
96 if (!profile || | 111 if (!profile || |
97 profile->IsOffTheRecord() || | 112 profile->IsOffTheRecord() || |
98 !profile->GetPrefs()->GetBoolean(prefs::kEnableDRM)) { | 113 !profile->GetPrefs()->GetBoolean(prefs::kEnableDRM)) { |
99 RunCallbackOnIOThread(std::string()); | 114 RunCallbackOnIOThread(std::string()); |
100 return; | 115 return; |
101 } | 116 } |
102 | 117 |
103 // Check if the salt pref is set. If it isn't, set it. | 118 // Check if the salt pref is set. If it isn't, set it. |
104 std::string salt = profile->GetPrefs()->GetString(prefs::kDRMSalt); | 119 std::string salt = profile->GetPrefs()->GetString(prefs::kDRMSalt); |
105 if (salt.empty()) { | 120 if (salt.empty()) { |
106 uint8_t salt_bytes[kSaltLength]; | 121 uint8_t salt_bytes[kSaltLength]; |
107 crypto::RandBytes(salt_bytes, arraysize(salt_bytes)); | 122 crypto::RandBytes(salt_bytes, arraysize(salt_bytes)); |
108 // Since it will be stored in a string pref, convert it to hex. | 123 // Since it will be stored in a string pref, convert it to hex. |
109 salt = base::HexEncode(salt_bytes, arraysize(salt_bytes)); | 124 salt = base::HexEncode(salt_bytes, arraysize(salt_bytes)); |
110 profile->GetPrefs()->SetString(prefs::kDRMSalt, salt); | 125 profile->GetPrefs()->SetString(prefs::kDRMSalt, salt); |
111 } | 126 } |
112 | 127 |
113 #if defined(OS_CHROMEOS) | |
114 // Try the legacy path first for ChromeOS. We pass the new salt in as well | |
115 // in case the legacy id doesn't exist. | |
stevenjb
2013/09/16 21:54:12
Since Chrome and ChromeOS are synced, I believe th
raymes
2013/09/16 22:13:38
Unfortunately I think we have to keep this. If som
stevenjb
2013/09/16 22:32:48
Ugh, you man this isn't something we can automatic
raymes
2013/09/18 23:21:20
Not easily. There's a bug filed at https://code.go
| |
116 BrowserThread::PostBlockingPoolTask(FROM_HERE, | |
117 base::Bind(&DeviceIDFetcher::ComputeOnBlockingPool, this, | |
118 profile->GetPath(), salt)); | |
119 #else | |
120 BrowserThread::PostTask( | |
121 BrowserThread::IO, FROM_HERE, | |
122 base::Bind(&DeviceIDFetcher::ComputeOnIOThread, this, salt)); | |
123 #endif | |
124 } | |
125 | |
126 | |
127 void DeviceIDFetcher::ComputeOnIOThread(const std::string& salt) { | |
128 std::vector<uint8> salt_bytes; | 128 std::vector<uint8> salt_bytes; |
129 if (!base::HexStringToBytes(salt, &salt_bytes)) | 129 if (!base::HexStringToBytes(salt, &salt_bytes)) |
130 salt_bytes.clear(); | 130 salt_bytes.clear(); |
131 | 131 if (salt_bytes.size() != kSaltLength) { |
132 // Build the identifier as follows: | 132 LOG(ERROR) << "Unexpected salt bytes length: " << salt_bytes.size(); |
133 // SHA256(machine-id||service||SHA256(machine-id||service||salt)) | |
134 std::string machine_id = GetMachineID(); | |
stevenjb
2013/09/16 21:54:12
Calling this on the IO thread was actually incorre
raymes
2013/09/16 22:13:38
Thanks for catching this. That makes sense :)
| |
135 if (machine_id.empty() || salt_bytes.size() != kSaltLength) { | |
136 NOTREACHED(); | |
137 RunCallbackOnIOThread(std::string()); | 133 RunCallbackOnIOThread(std::string()); |
138 return; | 134 return; |
139 } | 135 } |
140 | 136 |
137 GetMachineIdAsync( | |
138 base::Bind(&DeviceIDFetcher::ComputeOnUIThread, | |
139 weak_ptr_factory_.GetWeakPtr(), | |
140 salt_bytes)); | |
141 } | |
142 | |
143 void DeviceIDFetcher::ComputeOnUIThread(const std::vector<uint8>& salt_bytes, | |
144 const std::string& machine_id) { | |
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
146 | |
147 if (machine_id.empty()) { | |
148 LOG(ERROR) << "Empty machine id"; | |
149 RunCallbackOnIOThread(std::string()); | |
150 return; | |
151 } | |
152 | |
153 // Build the identifier as follows: | |
154 // SHA256(machine-id||service||SHA256(machine-id||service||salt)) | |
141 char id_buf[256 / 8]; // 256-bits for SHA256 | 155 char id_buf[256 / 8]; // 256-bits for SHA256 |
142 std::string input = machine_id; | 156 std::string input = machine_id; |
143 input.append(kDRMIdentifierFile); | 157 input.append(kDRMIdentifierFile); |
144 input.append(salt_bytes.begin(), salt_bytes.end()); | 158 input.append(salt_bytes.begin(), salt_bytes.end()); |
145 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); | 159 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); |
146 std::string id = StringToLowerASCII( | 160 std::string id = StringToLowerASCII( |
147 base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf))); | 161 base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf))); |
148 input = machine_id; | 162 input = machine_id; |
149 input.append(kDRMIdentifierFile); | 163 input.append(kDRMIdentifierFile); |
150 input.append(id); | 164 input.append(id); |
151 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); | 165 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); |
152 id = StringToLowerASCII(base::HexEncode( | 166 id = StringToLowerASCII(base::HexEncode( |
153 reinterpret_cast<const void*>(id_buf), | 167 reinterpret_cast<const void*>(id_buf), |
154 sizeof(id_buf))); | 168 sizeof(id_buf))); |
155 | 169 |
156 RunCallbackOnIOThread(id); | 170 RunCallbackOnIOThread(id); |
157 } | 171 } |
158 | 172 |
159 // TODO(raymes): This is temporary code to migrate ChromeOS devices to the new | |
160 // scheme for generating device IDs. Delete this once we are sure most ChromeOS | |
161 // devices have been migrated. | |
162 void DeviceIDFetcher::ComputeOnBlockingPool(const base::FilePath& profile_path, | |
163 const std::string& salt) { | |
164 std::string id; | |
165 // First check if the legacy device ID file exists on ChromeOS. If it does, we | |
166 // should just return that. | |
167 base::FilePath id_path = GetLegacyDeviceIDPath(profile_path); | |
168 if (base::PathExists(id_path)) { | |
169 if (base::ReadFileToString(id_path, &id) && !id.empty()) { | |
170 RunCallbackOnIOThread(id); | |
171 return; | |
172 } | |
173 } | |
174 // If we didn't find an ID, go back to the new code path to generate an ID. | |
175 BrowserThread::PostTask( | |
176 BrowserThread::IO, FROM_HERE, | |
177 base::Bind(&DeviceIDFetcher::ComputeOnIOThread, this, salt)); | |
178 } | |
179 | |
180 | |
181 void DeviceIDFetcher::RunCallbackOnIOThread(const std::string& id) { | 173 void DeviceIDFetcher::RunCallbackOnIOThread(const std::string& id) { |
182 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 174 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
183 BrowserThread::PostTask( | 175 BrowserThread::PostTask( |
184 BrowserThread::IO, FROM_HERE, | 176 BrowserThread::IO, FROM_HERE, |
185 base::Bind(&DeviceIDFetcher::RunCallbackOnIOThread, this, id)); | 177 base::Bind(&DeviceIDFetcher::RunCallbackOnIOThread, this, id)); |
186 return; | 178 return; |
187 } | 179 } |
188 in_progress_ = false; | 180 in_progress_ = false; |
189 callback_.Run(id); | 181 callback_.Run(id); |
190 } | 182 } |
191 | 183 |
192 std::string DeviceIDFetcher::GetMachineID() { | |
193 #if defined(OS_WIN) && defined(ENABLE_RLZ) | |
194 std::string result; | |
195 rlz_lib::GetMachineId(&result); | |
196 return result; | |
197 #elif defined(OS_CHROMEOS) | |
198 chromeos::CryptohomeLibrary* c_home = chromeos::CryptohomeLibrary::Get(); | |
199 return c_home->GetSystemSalt(); | |
200 #else | |
201 // Not implemented for other platforms. | |
202 NOTREACHED(); | |
203 return ""; | |
204 #endif | |
205 } | |
206 | |
207 } // namespace chrome | 184 } // namespace chrome |
OLD | NEW |