summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos/system/drm_settings.cc
blob: 6206a45106ac982862e0e6776818ef1318b7d1ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/system/drm_settings.h"

#include "base/bind.h"
#include "base/chromeos/chromeos_version.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chromeos/chromeos_switches.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/encryptor.h"
#include "crypto/sha2.h"

using content::BrowserThread;

namespace {

// This constant is mirrored in
//   content/browser/renderer_host/pepper_message_filter.cc
// for OnGetDeviceID.
//
// This ID file is solely for use via the private pepper API.
//
// NOTE! Changing this value will also change the generated value
//       do not do so without accounting for the change.
const char kDRMIdentifierFile[] = "Pepper DRM ID.0";

void ManageDrmIdentifierOnFileThread(bool enable, const std::string& email) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  // Drop the file under <data>/<profile>/<drm id file>.
  // TODO(wad) get the profile directory in a more succinct fashion.
  base::FilePath drm_id_file;
  PathService::Get(chrome::DIR_USER_DATA, &drm_id_file);
  const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
  base::FilePath profile = cmd_line.GetSwitchValuePath(
      chromeos::switches::kLoginProfile);
  if (profile.empty()) {
    LOG(ERROR) << "called with no login-profile!";
    return;
  }
  drm_id_file = drm_id_file.AppendASCII(profile.value());
  drm_id_file = drm_id_file.AppendASCII(kDRMIdentifierFile);

  // The file will be regenerated or deleted at toggle-time.
  file_util::Delete(drm_id_file, false);

  // If DRM support is disabled, then do nothing else.
  if (!enable)
    return;

  // Build the identifier as follows:
  // SHA256(system-salt||service||SHA256(system-salt||service||email))
  chromeos::CryptohomeLibrary* c_home =
    chromeos::CrosLibrary::Get()->GetCryptohomeLibrary();
  std::string salt = c_home->GetSystemSalt();
  char id_buf[256 / 8];  // 256-bits for SHA256
  std::string input = salt;
  input.append(kDRMIdentifierFile);
  input.append(email);
  crypto::SHA256HashString(input, &id_buf, sizeof(id_buf));
  std::string id = StringToLowerASCII(base::HexEncode(
        reinterpret_cast<const void*>(id_buf),
        sizeof(id_buf)));
  input = salt;
  input.append(kDRMIdentifierFile);
  input.append(id);
  crypto::SHA256HashString(input, &id_buf, sizeof(id_buf));
  id = StringToLowerASCII(base::HexEncode(
        reinterpret_cast<const void*>(id_buf),
        sizeof(id_buf)));

  if (file_util::WriteFile(drm_id_file, id.c_str(), id.length()) !=
      static_cast<int>(id.length())) {
    LOG(ERROR) << "Failed to write " << drm_id_file.value();
    return;
  }
}

}  // namespace

namespace chromeos {
namespace system {

void ToggleDrm(bool enable) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  UserManager* user_manager = UserManager::Get();
  if (!user_manager)
    return;

  // This preference is only meant to be called when a user
  // is logged in.
  if (!user_manager->IsUserLoggedIn()) {
    LOG(WARNING) << "Called without a logged in user!";
    return;
  }

  // Don't generate files as a guest or demo user.
  if (user_manager->IsLoggedInAsGuest() ||
      user_manager->IsLoggedInAsDemoUser())
    return;

  // The user email address is included in the hash to keep the identifier
  // from being the same across users.
  std::string email = user_manager->GetLoggedInUser()->email();
  // If there is no real user then there's nothing to do here.
  if (email.empty()) {
    LOG(WARNING) << "Unexpected empty user email.";
    return;
  }

  // Generate a DRM identifier on the FILE thread.
  // The DRM identifier is a per-user, per-OS-install identifier that is used
  // by privileged pepper plugins specifically for deriving
  // per-content-provider identifiers.  The user must be able to clear it,
  // reset it, and deny its use.
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&ManageDrmIdentifierOnFileThread, enable, email));
}

}  // namespace system
}  // namespace chromeos