device_id_fetcher.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/browser/renderer_host/pepper/pepper_flash_device_id_host.h" 12#include "chrome/common/pref_names.h" 13#if defined(OS_CHROMEOS) 14#include "chromeos/cryptohome/cryptohome_library.h" 15#endif 16#include "components/user_prefs/pref_registry_syncable.h" 17#include "content/public/browser/browser_context.h" 18#include "content/public/browser/browser_ppapi_host.h" 19#include "content/public/browser/browser_thread.h" 20#include "content/public/browser/render_process_host.h" 21#include "crypto/encryptor.h" 22#include "crypto/random.h" 23#include "crypto/sha2.h" 24#if defined(ENABLE_RLZ) 25#include "rlz/lib/machine_id.h" 26#endif 27 28using content::BrowserPpapiHost; 29using content::BrowserThread; 30using content::RenderProcessHost; 31 32namespace chrome { 33 34namespace { 35 36const char kDRMIdentifierFile[] = "Pepper DRM ID.0"; 37 38const uint32_t kSaltLength = 32; 39 40} // namespace 41 42DeviceIDFetcher::DeviceIDFetcher(const IDCallback& callback, 43 PP_Instance instance) 44 : callback_(callback), 45 instance_(instance) { 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 47} 48 49DeviceIDFetcher::~DeviceIDFetcher() { 50} 51 52void DeviceIDFetcher::Start(BrowserPpapiHost* browser_host) { 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 54 55 int process_id = 0; 56 int unused = 0; 57 browser_host->GetRenderViewIDsForInstance(instance_, 58 &process_id, 59 &unused); 60 BrowserThread::PostTask( 61 BrowserThread::UI, FROM_HERE, 62 base::Bind(&DeviceIDFetcher::CheckPrefsOnUIThread, this, process_id)); 63} 64 65// static 66void DeviceIDFetcher::RegisterUserPrefs( 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(int process_id) { 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 89 90 Profile* profile = NULL; 91 RenderProcessHost* render_process_host = 92 RenderProcessHost::FromID(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 (file_util::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 callback_.Run(id); 191} 192 193std::string DeviceIDFetcher::GetMachineID() { 194#if defined(OS_WIN) && defined(ENABLE_RLZ) 195 std::string result; 196 rlz_lib::GetMachineId(&result); 197 return result; 198#elif defined(OS_CHROMEOS) 199 chromeos::CryptohomeLibrary* c_home = chromeos::CryptohomeLibrary::Get(); 200 return c_home->GetSystemSalt(); 201#else 202 // Not implemented for other platforms. 203 NOTREACHED(); 204 return ""; 205#endif 206} 207 208} // namespace chrome 209