device_id_fetcher.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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 // TODO(wad): Once UI is connected, a final default can be set. At that point 69 // change this pref from UNSYNCABLE to SYNCABLE. 70 prefs->RegisterBooleanPref(prefs::kEnableDRM, 71 true, 72 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 73 prefs->RegisterStringPref( 74 prefs::kDRMSalt, 75 "", 76 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 77} 78 79// static 80base::FilePath DeviceIDFetcher::GetLegacyDeviceIDPath( 81 const base::FilePath& profile_path) { 82 return profile_path.AppendASCII(kDRMIdentifierFile); 83} 84 85// TODO(raymes): Change this to just return the device id salt and call it with 86// PostTaskAndReply once the legacy ChromeOS codepath is removed. 87void DeviceIDFetcher::CheckPrefsOnUIThread() { 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 89 90 Profile* profile = NULL; 91 RenderProcessHost* render_process_host = 92 RenderProcessHost::FromID(render_process_id_); 93 if (render_process_host && render_process_host->GetBrowserContext()) { 94 profile = Profile::FromBrowserContext( 95 render_process_host->GetBrowserContext()); 96 } 97 98 if (!profile || 99 profile->IsOffTheRecord() || 100 !profile->GetPrefs()->GetBoolean(prefs::kEnableDRM)) { 101 RunCallbackOnIOThread(std::string()); 102 return; 103 } 104 105 // Check if the salt pref is set. If it isn't, set it. 106 std::string salt = profile->GetPrefs()->GetString(prefs::kDRMSalt); 107 if (salt.empty()) { 108 uint8_t salt_bytes[kSaltLength]; 109 crypto::RandBytes(salt_bytes, arraysize(salt_bytes)); 110 // Since it will be stored in a string pref, convert it to hex. 111 salt = base::HexEncode(salt_bytes, arraysize(salt_bytes)); 112 profile->GetPrefs()->SetString(prefs::kDRMSalt, salt); 113 } 114 115#if defined(OS_CHROMEOS) 116 // Try the legacy path first for ChromeOS. We pass the new salt in as well 117 // in case the legacy id doesn't exist. 118 BrowserThread::PostBlockingPoolTask(FROM_HERE, 119 base::Bind(&DeviceIDFetcher::ComputeOnBlockingPool, this, 120 profile->GetPath(), salt)); 121#else 122 BrowserThread::PostTask( 123 BrowserThread::IO, FROM_HERE, 124 base::Bind(&DeviceIDFetcher::ComputeOnIOThread, this, salt)); 125#endif 126} 127 128 129void DeviceIDFetcher::ComputeOnIOThread(const std::string& salt) { 130 std::vector<uint8> salt_bytes; 131 if (!base::HexStringToBytes(salt, &salt_bytes)) 132 salt_bytes.clear(); 133 134 // Build the identifier as follows: 135 // SHA256(machine-id||service||SHA256(machine-id||service||salt)) 136 std::string machine_id = GetMachineID(); 137 if (machine_id.empty() || salt_bytes.size() != kSaltLength) { 138 NOTREACHED(); 139 RunCallbackOnIOThread(std::string()); 140 return; 141 } 142 143 char id_buf[256 / 8]; // 256-bits for SHA256 144 std::string input = machine_id; 145 input.append(kDRMIdentifierFile); 146 input.append(salt_bytes.begin(), salt_bytes.end()); 147 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); 148 std::string id = StringToLowerASCII( 149 base::HexEncode(reinterpret_cast<const void*>(id_buf), sizeof(id_buf))); 150 input = machine_id; 151 input.append(kDRMIdentifierFile); 152 input.append(id); 153 crypto::SHA256HashString(input, &id_buf, sizeof(id_buf)); 154 id = StringToLowerASCII(base::HexEncode( 155 reinterpret_cast<const void*>(id_buf), 156 sizeof(id_buf))); 157 158 RunCallbackOnIOThread(id); 159} 160 161// TODO(raymes): This is temporary code to migrate ChromeOS devices to the new 162// scheme for generating device IDs. Delete this once we are sure most ChromeOS 163// devices have been migrated. 164void DeviceIDFetcher::ComputeOnBlockingPool(const base::FilePath& profile_path, 165 const std::string& salt) { 166 std::string id; 167 // First check if the legacy device ID file exists on ChromeOS. If it does, we 168 // should just return that. 169 base::FilePath id_path = GetLegacyDeviceIDPath(profile_path); 170 if (base::PathExists(id_path)) { 171 if (file_util::ReadFileToString(id_path, &id) && !id.empty()) { 172 RunCallbackOnIOThread(id); 173 return; 174 } 175 } 176 // If we didn't find an ID, go back to the new code path to generate an ID. 177 BrowserThread::PostTask( 178 BrowserThread::IO, FROM_HERE, 179 base::Bind(&DeviceIDFetcher::ComputeOnIOThread, this, salt)); 180} 181 182 183void DeviceIDFetcher::RunCallbackOnIOThread(const std::string& id) { 184 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 185 BrowserThread::PostTask( 186 BrowserThread::IO, FROM_HERE, 187 base::Bind(&DeviceIDFetcher::RunCallbackOnIOThread, this, id)); 188 return; 189 } 190 in_progress_ = false; 191 callback_.Run(id); 192} 193 194std::string DeviceIDFetcher::GetMachineID() { 195#if defined(OS_WIN) && defined(ENABLE_RLZ) 196 std::string result; 197 rlz_lib::GetMachineId(&result); 198 return result; 199#elif defined(OS_CHROMEOS) 200 chromeos::CryptohomeLibrary* c_home = chromeos::CryptohomeLibrary::Get(); 201 return c_home->GetSystemSalt(); 202#else 203 // Not implemented for other platforms. 204 NOTREACHED(); 205 return ""; 206#endif 207} 208 209} // namespace chrome 210