nss_util_chromeos.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. // Copyright (c) 2012 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. #include "crypto/nss_util.h"
  5. #include <nss.h>
  6. #include <pk11pub.h>
  7. #include <plarena.h>
  8. #include <prerror.h>
  9. #include <prinit.h>
  10. #include <prtime.h>
  11. #include <secmod.h>
  12. #include <map>
  13. #include <memory>
  14. #include <utility>
  15. #include "base/bind.h"
  16. #include "base/callback_list.h"
  17. #include "base/debug/stack_trace.h"
  18. #include "base/files/file_enumerator.h"
  19. #include "base/files/file_path.h"
  20. #include "base/files/file_util.h"
  21. #include "base/lazy_instance.h"
  22. #include "base/location.h"
  23. #include "base/logging.h"
  24. #include "base/no_destructor.h"
  25. #include "base/path_service.h"
  26. #include "base/strings/string_piece.h"
  27. #include "base/strings/stringprintf.h"
  28. #include "base/task/thread_pool.h"
  29. #include "base/threading/scoped_blocking_call.h"
  30. #include "base/threading/thread_checker.h"
  31. #include "base/threading/thread_restrictions.h"
  32. #include "base/threading/thread_task_runner_handle.h"
  33. #include "build/build_config.h"
  34. #include "crypto/chaps_support.h"
  35. #include "crypto/nss_util_internal.h"
  36. namespace crypto {
  37. namespace {
  38. const char kUserNSSDatabaseName[] = "UserNSSDB";
  39. class ChromeOSUserData {
  40. public:
  41. using SlotReadyCallback = base::OnceCallback<void(ScopedPK11Slot)>;
  42. explicit ChromeOSUserData(ScopedPK11Slot public_slot)
  43. : public_slot_(std::move(public_slot)) {}
  44. ~ChromeOSUserData() {
  45. if (public_slot_) {
  46. SECStatus status = CloseSoftwareNSSDB(public_slot_.get());
  47. if (status != SECSuccess)
  48. PLOG(ERROR) << "CloseSoftwareNSSDB failed: " << PORT_GetError();
  49. }
  50. }
  51. ScopedPK11Slot GetPublicSlot() {
  52. return ScopedPK11Slot(public_slot_ ? PK11_ReferenceSlot(public_slot_.get())
  53. : nullptr);
  54. }
  55. ScopedPK11Slot GetPrivateSlot(SlotReadyCallback callback) {
  56. if (private_slot_)
  57. return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
  58. if (!callback.is_null()) {
  59. // Callback lists cannot hold callbacks that take move-only args, since
  60. // Notify()ing such a list would move the arg into the first callback,
  61. // leaving it null or unspecified for remaining callbacks. Instead, adapt
  62. // the provided callbacks to accept a raw pointer, which can be copied,
  63. // and then wrap in a separate scoping object for each callback.
  64. tpm_ready_callback_list_.AddUnsafe(base::BindOnce(
  65. [](SlotReadyCallback callback, PK11SlotInfo* info) {
  66. std::move(callback).Run(ScopedPK11Slot(PK11_ReferenceSlot(info)));
  67. },
  68. std::move(callback)));
  69. }
  70. return ScopedPK11Slot();
  71. }
  72. void SetPrivateSlot(ScopedPK11Slot private_slot) {
  73. DCHECK(!private_slot_);
  74. private_slot_ = std::move(private_slot);
  75. tpm_ready_callback_list_.Notify(private_slot_.get());
  76. }
  77. bool private_slot_initialization_started() const {
  78. return private_slot_initialization_started_;
  79. }
  80. void set_private_slot_initialization_started() {
  81. private_slot_initialization_started_ = true;
  82. }
  83. private:
  84. using SlotReadyCallbackList = base::OnceCallbackList<void(PK11SlotInfo*)>;
  85. ScopedPK11Slot public_slot_;
  86. ScopedPK11Slot private_slot_;
  87. bool private_slot_initialization_started_ = false;
  88. SlotReadyCallbackList tpm_ready_callback_list_;
  89. };
  90. // Contains state used for the ChromeOSTokenManager. Unlike the
  91. // ChromeOSTokenManager, which is thread-checked, this object may live
  92. // and be accessed on multiple threads. While this is normally dangerous,
  93. // this is done to support callers initializing early in process startup,
  94. // where the threads using the objects may not be created yet, and the
  95. // thread startup may depend on these objects.
  96. // Put differently: They may be written to from any thread, if, and only
  97. // if, the thread they will be read from has not yet been created;
  98. // otherwise, this should be treated as thread-affine/thread-hostile.
  99. struct ChromeOSTokenManagerDataForTesting {
  100. static ChromeOSTokenManagerDataForTesting& GetInstance() {
  101. static base::NoDestructor<ChromeOSTokenManagerDataForTesting> instance;
  102. return *instance;
  103. }
  104. // System slot that will be used for the system slot initialization.
  105. ScopedPK11Slot test_system_slot;
  106. };
  107. class ChromeOSTokenManager {
  108. public:
  109. enum class State {
  110. // Initial state.
  111. kInitializationNotStarted,
  112. // Initialization of the TPM token was started.
  113. kInitializationStarted,
  114. // TPM token was successfully initialized, but not available to the class'
  115. // users yet.
  116. kTpmTokenInitialized,
  117. // TPM token was successfully enabled. It is a final state.
  118. kTpmTokenEnabled,
  119. // TPM token will never be enabled. It is a final state.
  120. kTpmTokenDisabled,
  121. };
  122. // Used with PostTaskAndReply to pass handles to worker thread and back.
  123. struct TPMModuleAndSlot {
  124. explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
  125. : chaps_module(init_chaps_module) {}
  126. SECMODModule* chaps_module;
  127. ScopedPK11Slot tpm_slot;
  128. };
  129. ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name,
  130. const base::FilePath& path) {
  131. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  132. // NSS is allowed to do IO on the current thread since dispatching
  133. // to a dedicated thread would still have the affect of blocking
  134. // the current thread, due to NSS's internal locking requirements
  135. base::ThreadRestrictions::ScopedAllowIO allow_io;
  136. base::FilePath nssdb_path = GetSoftwareNSSDBPath(path);
  137. if (!base::CreateDirectory(nssdb_path)) {
  138. LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
  139. return ScopedPK11Slot();
  140. }
  141. return OpenSoftwareNSSDB(nssdb_path, db_name);
  142. }
  143. void InitializeTPMTokenAndSystemSlot(
  144. int system_slot_id,
  145. base::OnceCallback<void(bool)> callback) {
  146. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  147. DCHECK_EQ(state_, State::kInitializationNotStarted);
  148. state_ = State::kInitializationStarted;
  149. // Note that a reference is not taken to chaps_module_. This is safe since
  150. // ChromeOSTokenManager is Leaky, so the reference it holds is never
  151. // released.
  152. std::unique_ptr<TPMModuleAndSlot> tpm_args(
  153. new TPMModuleAndSlot(chaps_module_));
  154. TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
  155. base::ThreadPool::PostTaskAndReply(
  156. FROM_HERE,
  157. {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
  158. base::BindOnce(&ChromeOSTokenManager::InitializeTPMTokenInThreadPool,
  159. system_slot_id, tpm_args_ptr),
  160. base::BindOnce(
  161. &ChromeOSTokenManager::OnInitializedTPMTokenAndSystemSlot,
  162. base::Unretained(this), // ChromeOSTokenManager is leaky
  163. std::move(callback), std::move(tpm_args)));
  164. }
  165. void FinishInitializingTPMTokenAndSystemSlot() {
  166. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  167. DCHECK(!IsInitializationFinished());
  168. // If `OnInitializedTPMTokenAndSystemSlot` was not called, but a test system
  169. // slot is prepared, start using it now. Can happen in tests that don't fake
  170. // enable TPM.
  171. if (!system_slot_ &&
  172. ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot) {
  173. system_slot_ = ScopedPK11Slot(
  174. PK11_ReferenceSlot(ChromeOSTokenManagerDataForTesting::GetInstance()
  175. .test_system_slot.get()));
  176. }
  177. state_ = (state_ == State::kTpmTokenInitialized) ? State::kTpmTokenEnabled
  178. : State::kTpmTokenDisabled;
  179. tpm_ready_callback_list_->Notify();
  180. }
  181. static void InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id,
  182. TPMModuleAndSlot* tpm_args) {
  183. // NSS functions may reenter //net via extension hooks. If the reentered
  184. // code needs to synchronously wait for a task to run but the thread pool in
  185. // which that task must run doesn't have enough threads to schedule it, a
  186. // deadlock occurs. To prevent that, the base::ScopedBlockingCall below
  187. // increments the thread pool capacity for the duration of the TPM
  188. // initialization.
  189. base::ScopedBlockingCall scoped_blocking_call(
  190. FROM_HERE, base::BlockingType::WILL_BLOCK);
  191. if (!tpm_args->chaps_module) {
  192. tpm_args->chaps_module = LoadChaps();
  193. }
  194. if (tpm_args->chaps_module) {
  195. tpm_args->tpm_slot = GetChapsSlot(tpm_args->chaps_module, token_slot_id);
  196. }
  197. }
  198. void OnInitializedTPMTokenAndSystemSlot(
  199. base::OnceCallback<void(bool)> callback,
  200. std::unique_ptr<TPMModuleAndSlot> tpm_args) {
  201. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  202. DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
  203. << ", got tpm slot: " << !!tpm_args->tpm_slot;
  204. chaps_module_ = tpm_args->chaps_module;
  205. if (ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot) {
  206. // chromeos_unittests try to test the TPM initialization process. If we
  207. // have a test DB open, pretend that it is the system slot.
  208. system_slot_ = ScopedPK11Slot(
  209. PK11_ReferenceSlot(ChromeOSTokenManagerDataForTesting::GetInstance()
  210. .test_system_slot.get()));
  211. } else {
  212. system_slot_ = std::move(tpm_args->tpm_slot);
  213. }
  214. if (system_slot_) {
  215. state_ = State::kTpmTokenInitialized;
  216. }
  217. std::move(callback).Run(!!system_slot_);
  218. }
  219. void IsTPMTokenEnabled(base::OnceCallback<void(bool)> callback) {
  220. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  221. DCHECK(!callback.is_null());
  222. if (!IsInitializationFinished()) {
  223. // Call back to this method when initialization is finished.
  224. tpm_ready_callback_list_->AddUnsafe(
  225. base::BindOnce(&ChromeOSTokenManager::IsTPMTokenEnabled,
  226. base::Unretained(this) /* singleton is leaky */,
  227. std::move(callback)));
  228. return;
  229. }
  230. DCHECK(base::SequencedTaskRunnerHandle::IsSet());
  231. base::SequencedTaskRunnerHandle::Get()->PostTask(
  232. FROM_HERE,
  233. base::BindOnce(std::move(callback),
  234. /*is_tpm_enabled=*/(state_ == State::kTpmTokenEnabled)));
  235. }
  236. bool InitializeNSSForChromeOSUser(const std::string& username_hash,
  237. const base::FilePath& path) {
  238. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  239. if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
  240. // This user already exists in our mapping.
  241. DVLOG(2) << username_hash << " already initialized.";
  242. return false;
  243. }
  244. DVLOG(2) << "Opening NSS DB " << path.value();
  245. std::string db_name = base::StringPrintf("%s %s", kUserNSSDatabaseName,
  246. username_hash.c_str());
  247. ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
  248. chromeos_user_map_[username_hash] =
  249. std::make_unique<ChromeOSUserData>(std::move(public_slot));
  250. return true;
  251. }
  252. bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
  253. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  254. DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
  255. return !chromeos_user_map_[username_hash]
  256. ->private_slot_initialization_started();
  257. }
  258. void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
  259. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  260. DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
  261. chromeos_user_map_[username_hash]
  262. ->set_private_slot_initialization_started();
  263. }
  264. void InitializeTPMForChromeOSUser(const std::string& username_hash,
  265. CK_SLOT_ID slot_id) {
  266. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  267. DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
  268. DCHECK(chromeos_user_map_[username_hash]
  269. ->private_slot_initialization_started());
  270. if (!chaps_module_)
  271. return;
  272. // Note that a reference is not taken to chaps_module_. This is safe since
  273. // ChromeOSTokenManager is Leaky, so the reference it holds is never
  274. // released.
  275. std::unique_ptr<TPMModuleAndSlot> tpm_args(
  276. new TPMModuleAndSlot(chaps_module_));
  277. TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
  278. base::ThreadPool::PostTaskAndReply(
  279. FROM_HERE,
  280. {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
  281. base::BindOnce(&ChromeOSTokenManager::InitializeTPMTokenInThreadPool,
  282. slot_id, tpm_args_ptr),
  283. base::BindOnce(&ChromeOSTokenManager::OnInitializedTPMForChromeOSUser,
  284. base::Unretained(this), // ChromeOSTokenManager is leaky
  285. username_hash, std::move(tpm_args)));
  286. }
  287. void OnInitializedTPMForChromeOSUser(
  288. const std::string& username_hash,
  289. std::unique_ptr<TPMModuleAndSlot> tpm_args) {
  290. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  291. DVLOG(2) << "Got tpm slot for " << username_hash << " "
  292. << !!tpm_args->tpm_slot;
  293. chromeos_user_map_[username_hash]->SetPrivateSlot(
  294. std::move(tpm_args->tpm_slot));
  295. }
  296. void InitializePrivateSoftwareSlotForChromeOSUser(
  297. const std::string& username_hash) {
  298. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  299. VLOG(1) << "using software private slot for " << username_hash;
  300. DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
  301. DCHECK(chromeos_user_map_[username_hash]
  302. ->private_slot_initialization_started());
  303. if (prepared_test_private_slot_) {
  304. chromeos_user_map_[username_hash]->SetPrivateSlot(
  305. std::move(prepared_test_private_slot_));
  306. return;
  307. }
  308. chromeos_user_map_[username_hash]->SetPrivateSlot(
  309. chromeos_user_map_[username_hash]->GetPublicSlot());
  310. }
  311. ScopedPK11Slot GetPublicSlotForChromeOSUser(
  312. const std::string& username_hash) {
  313. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  314. if (username_hash.empty()) {
  315. DVLOG(2) << "empty username_hash";
  316. return ScopedPK11Slot();
  317. }
  318. if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
  319. LOG(ERROR) << username_hash << " not initialized.";
  320. return ScopedPK11Slot();
  321. }
  322. return chromeos_user_map_[username_hash]->GetPublicSlot();
  323. }
  324. ScopedPK11Slot GetPrivateSlotForChromeOSUser(
  325. const std::string& username_hash,
  326. base::OnceCallback<void(ScopedPK11Slot)> callback) {
  327. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  328. if (username_hash.empty()) {
  329. DVLOG(2) << "empty username_hash";
  330. if (!callback.is_null()) {
  331. base::ThreadTaskRunnerHandle::Get()->PostTask(
  332. FROM_HERE, base::BindOnce(std::move(callback), ScopedPK11Slot()));
  333. }
  334. return ScopedPK11Slot();
  335. }
  336. DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
  337. return chromeos_user_map_[username_hash]->GetPrivateSlot(
  338. std::move(callback));
  339. }
  340. void CloseChromeOSUserForTesting(const std::string& username_hash) {
  341. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  342. auto i = chromeos_user_map_.find(username_hash);
  343. DCHECK(i != chromeos_user_map_.end());
  344. chromeos_user_map_.erase(i);
  345. }
  346. void GetSystemNSSKeySlot(base::OnceCallback<void(ScopedPK11Slot)> callback) {
  347. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  348. if (!IsInitializationFinished()) {
  349. // Call back to this method when initialization is finished.
  350. tpm_ready_callback_list_->AddUnsafe(
  351. base::BindOnce(&ChromeOSTokenManager::GetSystemNSSKeySlot,
  352. base::Unretained(this) /* singleton is leaky */,
  353. std::move(callback)));
  354. return;
  355. }
  356. base::SequencedTaskRunnerHandle::Get()->PostTask(
  357. FROM_HERE,
  358. base::BindOnce(std::move(callback),
  359. /*system_slot=*/ScopedPK11Slot(
  360. system_slot_ ? PK11_ReferenceSlot(system_slot_.get())
  361. : nullptr)));
  362. }
  363. void ResetSystemSlotForTesting() { system_slot_.reset(); }
  364. void ResetTokenManagerForTesting() {
  365. // Prevent test failures when two tests in the same process use the same
  366. // ChromeOSTokenManager from different threads.
  367. DETACH_FROM_THREAD(thread_checker_);
  368. state_ = State::kInitializationNotStarted;
  369. // Configuring chaps_module_ here is not supported yet.
  370. CHECK(!chaps_module_);
  371. // Make sure there are no outstanding callbacks between tests.
  372. // OnceClosureList doesn't provide a way to clear the callback list.
  373. tpm_ready_callback_list_ = std::make_unique<base::OnceClosureList>();
  374. chromeos_user_map_.clear();
  375. ResetSystemSlotForTesting(); // IN-TEST
  376. prepared_test_private_slot_.reset();
  377. }
  378. void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
  379. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  380. // Ensure that a previous value of prepared_test_private_slot_ is not
  381. // overwritten. Unsetting, i.e. setting a nullptr, however is allowed.
  382. DCHECK(!slot || !prepared_test_private_slot_);
  383. prepared_test_private_slot_ = std::move(slot);
  384. }
  385. bool IsInitializationStarted() {
  386. return (state_ != State::kInitializationNotStarted);
  387. }
  388. private:
  389. friend struct base::LazyInstanceTraitsBase<ChromeOSTokenManager>;
  390. ChromeOSTokenManager() { EnsureNSSInit(); }
  391. // NOTE(willchan): We don't actually cleanup on destruction since we leak NSS
  392. // to prevent non-joinable threads from using NSS after it's already been
  393. // shut down.
  394. ~ChromeOSTokenManager() = delete;
  395. bool IsInitializationFinished() {
  396. switch (state_) {
  397. case State::kTpmTokenEnabled:
  398. case State::kTpmTokenDisabled:
  399. return true;
  400. case State::kInitializationNotStarted:
  401. case State::kInitializationStarted:
  402. case State::kTpmTokenInitialized:
  403. return false;
  404. }
  405. }
  406. State state_ = State::kInitializationNotStarted;
  407. std::unique_ptr<base::OnceClosureList> tpm_ready_callback_list_ =
  408. std::make_unique<base::OnceClosureList>();
  409. SECMODModule* chaps_module_ = nullptr;
  410. ScopedPK11Slot system_slot_;
  411. std::map<std::string, std::unique_ptr<ChromeOSUserData>> chromeos_user_map_;
  412. ScopedPK11Slot prepared_test_private_slot_;
  413. THREAD_CHECKER(thread_checker_);
  414. };
  415. base::LazyInstance<ChromeOSTokenManager>::Leaky g_token_manager =
  416. LAZY_INSTANCE_INITIALIZER;
  417. } // namespace
  418. base::FilePath GetSoftwareNSSDBPath(
  419. const base::FilePath& profile_directory_path) {
  420. return profile_directory_path.AppendASCII(".pki").AppendASCII("nssdb");
  421. }
  422. void GetSystemNSSKeySlot(base::OnceCallback<void(ScopedPK11Slot)> callback) {
  423. g_token_manager.Get().GetSystemNSSKeySlot(std::move(callback));
  424. }
  425. void PrepareSystemSlotForTesting(ScopedPK11Slot slot) {
  426. DCHECK(!ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot);
  427. DCHECK(!g_token_manager.IsCreated() ||
  428. !g_token_manager.Get().IsInitializationStarted())
  429. << "PrepareSystemSlotForTesting is called after initialization started";
  430. ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot =
  431. std::move(slot);
  432. }
  433. void ResetSystemSlotForTesting() {
  434. if (g_token_manager.IsCreated()) {
  435. g_token_manager.Get().ResetSystemSlotForTesting(); // IN-TEST
  436. }
  437. ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot.reset();
  438. }
  439. void ResetTokenManagerForTesting() {
  440. if (g_token_manager.IsCreated()) {
  441. g_token_manager.Get().ResetTokenManagerForTesting(); // IN-TEST
  442. }
  443. ResetSystemSlotForTesting(); // IN-TEST
  444. }
  445. void IsTPMTokenEnabled(base::OnceCallback<void(bool)> callback) {
  446. g_token_manager.Get().IsTPMTokenEnabled(std::move(callback));
  447. }
  448. void InitializeTPMTokenAndSystemSlot(int token_slot_id,
  449. base::OnceCallback<void(bool)> callback) {
  450. g_token_manager.Get().InitializeTPMTokenAndSystemSlot(token_slot_id,
  451. std::move(callback));
  452. }
  453. void FinishInitializingTPMTokenAndSystemSlot() {
  454. g_token_manager.Get().FinishInitializingTPMTokenAndSystemSlot();
  455. }
  456. bool InitializeNSSForChromeOSUser(const std::string& username_hash,
  457. const base::FilePath& path) {
  458. return g_token_manager.Get().InitializeNSSForChromeOSUser(username_hash,
  459. path);
  460. }
  461. bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
  462. return g_token_manager.Get().ShouldInitializeTPMForChromeOSUser(
  463. username_hash);
  464. }
  465. void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
  466. g_token_manager.Get().WillInitializeTPMForChromeOSUser(username_hash);
  467. }
  468. void InitializeTPMForChromeOSUser(const std::string& username_hash,
  469. CK_SLOT_ID slot_id) {
  470. g_token_manager.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
  471. }
  472. void InitializePrivateSoftwareSlotForChromeOSUser(
  473. const std::string& username_hash) {
  474. g_token_manager.Get().InitializePrivateSoftwareSlotForChromeOSUser(
  475. username_hash);
  476. }
  477. ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
  478. return g_token_manager.Get().GetPublicSlotForChromeOSUser(username_hash);
  479. }
  480. ScopedPK11Slot GetPrivateSlotForChromeOSUser(
  481. const std::string& username_hash,
  482. base::OnceCallback<void(ScopedPK11Slot)> callback) {
  483. return g_token_manager.Get().GetPrivateSlotForChromeOSUser(
  484. username_hash, std::move(callback));
  485. }
  486. void CloseChromeOSUserForTesting(const std::string& username_hash) {
  487. g_token_manager.Get().CloseChromeOSUserForTesting(username_hash);
  488. }
  489. void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
  490. g_token_manager.Get().SetPrivateSoftwareSlotForChromeOSUserForTesting(
  491. std::move(slot));
  492. }
  493. namespace {
  494. void PrintDirectoryInfo(std::stringstream& ss, const base::FilePath& path) {
  495. base::stat_wrapper_t file_stat;
  496. base::File::Error error_code = base::File::Error::FILE_OK;
  497. if (base::File::Stat(path.value().c_str(), &file_stat) == -1) {
  498. error_code = base::File::OSErrorToFileError(errno);
  499. }
  500. ss << path << ", ";
  501. ss << std::oct << file_stat.st_mode << std::dec << ", ";
  502. ss << "uid " << file_stat.st_uid << ", ";
  503. ss << "gid " << file_stat.st_gid << std::endl;
  504. ss << "Enumerate error code: " << error_code << std::endl;
  505. }
  506. } // namespace
  507. // TODO(crbug.com/1163303): Remove when the bug is fixed.
  508. void DiagnosePublicSlotAndCrash(const base::FilePath& nss_path) {
  509. std::stringstream ss;
  510. ss << "Public slot is invalid." << std::endl;
  511. // Should be something like /home/chronos/u-<hash>/.pki/nssdb .
  512. ss << "NSS path: " << nss_path << std::endl;
  513. {
  514. // NSS files like pkcs11.txt, cert9.db, key4.db .
  515. base::FileEnumerator files(
  516. nss_path, /*recursive=*/false,
  517. /*file_type=*/base::FileEnumerator::FILES,
  518. /*pattern=*/base::FilePath::StringType(),
  519. base::FileEnumerator::FolderSearchPolicy::MATCH_ONLY,
  520. base::FileEnumerator::ErrorPolicy::STOP_ENUMERATION);
  521. ss << "Public slot database files:" << std::endl;
  522. for (base::FilePath path = files.Next(); !path.empty();
  523. path = files.Next()) {
  524. base::FileEnumerator::FileInfo file_info = files.GetInfo();
  525. ss << file_info.GetName() << ", ";
  526. ss << std::oct << file_info.stat().st_mode << std::dec << ", ";
  527. ss << "uid " << file_info.stat().st_uid << ", ";
  528. ss << "gid " << file_info.stat().st_gid << ", ";
  529. ss << file_info.stat().st_size << " bytes, ";
  530. char buf[16];
  531. int read_result = base::ReadFile(path, buf, sizeof(buf) - 1);
  532. ss << ((read_result > 0) ? "readable" : "not readable");
  533. ss << std::endl;
  534. }
  535. ss << "Enumerate error code: " << files.GetError() << std::endl;
  536. }
  537. // NSS directory might not be created yet, also check parent directories.
  538. // Use u-hash directory as a comparison point for user and group ids and
  539. // access permissions.
  540. base::FilePath nssdb_path = nss_path.Append(base::FilePath::kParentDirectory);
  541. PrintDirectoryInfo(ss, nssdb_path);
  542. base::FilePath pki_path = nssdb_path.Append(base::FilePath::kParentDirectory);
  543. PrintDirectoryInfo(ss, pki_path);
  544. base::FilePath u_hash_path =
  545. pki_path.Append(base::FilePath::kParentDirectory);
  546. PrintDirectoryInfo(ss, u_hash_path);
  547. {
  548. // Check whether the NSS path exists, and if not, check whether it's
  549. // possible to create it.
  550. if (base::DirectoryExists(nss_path)) {
  551. ss << "NSS path exists." << std::endl;
  552. } else {
  553. base::File::Error error = base::File::Error::FILE_OK;
  554. if (base::CreateDirectoryAndGetError(nss_path, &error)) {
  555. ss << "NSS path didn't exist. Created successfully." << std::endl;
  556. } else {
  557. ss << "NSS path didn't exist. Failed to create, error: " << error
  558. << std::endl;
  559. }
  560. }
  561. }
  562. CHECK(false) << ss.str();
  563. }
  564. } // namespace crypto