device_id_fetcher.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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/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/cryptohome_library.h" 14#endif 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#if defined(ENABLE_RLZ) 24#include "rlz/lib/machine_id.h" 25#endif 26 27using content::BrowserPpapiHost; 28using content::BrowserThread; 29using content::RenderProcessHost; 30 31namespace chrome { 32 33namespace { 34 35const char kDRMIdentifierFile[] = "Pepper DRM ID.0"; 36 37const uint32_t kSaltLength = 32; 38 39} // namespace 40 41DeviceIDFetcher::DeviceIDFetcher(int render_process_id) 42 : in_progress_(false), 43 render_process_id_(render_process_id) { 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 45} 46 47DeviceIDFetcher::~DeviceIDFetcher() { 48} 49 50bool DeviceIDFetcher::Start(const IDCallback& callback) { 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 52 53 if (in_progress_) 54 return false; 55 56 in_progress_ = true; 57 callback_ = callback; 58 59 BrowserThread::PostTask( 60 BrowserThread::UI, FROM_HERE, 61 base::Bind(&DeviceIDFetcher::CheckPrefsOnUIThread, this)); 62 return true; 63} 64 65// static 66void DeviceIDFetcher::RegisterProfilePrefs( 67 user_prefs::PrefRegistrySyncable* prefs) { 68 prefs->RegisterBooleanPref(prefs::kEnableDRM, 69 true, 70 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 71 prefs->RegisterStringPref( 72 prefs::kDRMSalt, 73 "", 74 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 75} 76 77// static 78base::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. 85void DeviceIDFetcher::CheckPrefsOnUIThread() { 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 87 88 Profile* profile = NULL; 89 RenderProcessHost* render_process_host = 90 RenderProcessHost::FromID(render_process_id_); 91 if (render_process_host && render_process_host->GetBrowserContext()) { 92 profile = Profile::FromBrowserContext( 93 render_process_host->GetBrowserContext()); 94 } 95 96 if (!profile || 97 profile->IsOffTheRecord() || 98 !profile->GetPrefs()->GetBoolean(prefs::kEnableDRM)) { 99 RunCallbackOnIOThread(std::string()); 100 return; 101 } 102 103 // Check if the salt pref is set. If it isn't, set it. 104 std::string salt = profile->GetPrefs()->GetString(prefs::kDRMSalt); 105 if (salt.empty()) { 106 uint8_t salt_bytes[kSaltLength]; 107 crypto::RandBytes(salt_bytes, arraysize(salt_bytes)); 108 // Since it will be stored in a string pref, convert it to hex. 109 salt = base::HexEncode(salt_bytes, arraysize(salt_bytes)); 110 profile->GetPrefs()->SetString(prefs::kDRMSalt, salt); 111 } 112 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. 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 127void DeviceIDFetcher::ComputeOnIOThread(const std::string& salt) { 128 std::vector<uint8> salt_bytes; 129 if (!base::HexStringToBytes(salt, &salt_bytes)) 130 salt_bytes.clear(); 131 132 // Build the identifier as follows: 133 // SHA256(machine-id||service||SHA256(machine-id||service||salt)) 134 std::string machine_id = GetMachineID(); 135 if (machine_id.empty() || salt_bytes.size() != kSaltLength) { 136 NOTREACHED(); 137 RunCallbackOnIOThread(std::string()); 138 return; 139 } 140 141 char id_buf[256 / 8]; // 256-bits for SHA256 142 std::string input = machine_id; 143 input.append(kDRMIdentifierFile); 144 input.append(salt_bytes.begin(), salt_bytes.end()); 145 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); 146 std::string id = StringToLowerASCII( 147 base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf))); 148 input = machine_id; 149 input.append(kDRMIdentifierFile); 150 input.append(id); 151 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); 152 id = StringToLowerASCII(base::HexEncode( 153 reinterpret_cast<const void*>(id_buf), 154 sizeof(id_buf))); 155 156 RunCallbackOnIOThread(id); 157} 158 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. 162void 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 181void DeviceIDFetcher::RunCallbackOnIOThread(const std::string& id) { 182 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 183 BrowserThread::PostTask( 184 BrowserThread::IO, FROM_HERE, 185 base::Bind(&DeviceIDFetcher::RunCallbackOnIOThread, this, id)); 186 return; 187 } 188 in_progress_ = false; 189 callback_.Run(id); 190} 191 192std::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 208