gcm_key_store.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // Copyright 2015 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 "components/gcm_driver/crypto/gcm_key_store.h"
  5. #include <stddef.h>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/logging.h"
  11. #include "base/metrics/histogram_macros.h"
  12. #include "base/strings/string_util.h"
  13. #include "base/task/sequenced_task_runner.h"
  14. #include "components/gcm_driver/crypto/p256_key_util.h"
  15. #include "components/leveldb_proto/public/proto_database_provider.h"
  16. #include "components/leveldb_proto/public/shared_proto_database_client_list.h"
  17. #include "crypto/random.h"
  18. #include "third_party/leveldatabase/env_chromium.h"
  19. namespace gcm {
  20. namespace {
  21. using EntryVectorType =
  22. leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
  23. // Number of cryptographically secure random bytes to generate as a key pair's
  24. // authentication secret. Must be at least 16 bytes.
  25. const size_t kAuthSecretBytes = 16;
  26. // Size cap for the leveldb log file before compression.
  27. const size_t kDatabaseWriteBufferSizeBytes = 16 * 1024;
  28. std::string DatabaseKey(const std::string& app_id,
  29. const std::string& authorized_entity) {
  30. DCHECK_EQ(std::string::npos, app_id.find(','));
  31. DCHECK_EQ(std::string::npos, authorized_entity.find(','));
  32. DCHECK_NE("*", authorized_entity) << "Wildcards require special handling";
  33. return authorized_entity.empty()
  34. ? app_id // No comma, for compatibility with existing keys.
  35. : app_id + ',' + authorized_entity;
  36. }
  37. leveldb_env::Options CreateLevelDbOptions() {
  38. leveldb_env::Options options;
  39. options.create_if_missing = true;
  40. options.max_open_files = 0; // Use minimum.
  41. options.write_buffer_size = kDatabaseWriteBufferSizeBytes;
  42. return options;
  43. }
  44. } // namespace
  45. enum class GCMKeyStore::State {
  46. UNINITIALIZED,
  47. INITIALIZING,
  48. INITIALIZED,
  49. FAILED
  50. };
  51. GCMKeyStore::GCMKeyStore(
  52. const base::FilePath& key_store_path,
  53. const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
  54. : key_store_path_(key_store_path),
  55. blocking_task_runner_(blocking_task_runner),
  56. state_(State::UNINITIALIZED) {
  57. DCHECK(blocking_task_runner);
  58. }
  59. GCMKeyStore::~GCMKeyStore() {}
  60. void GCMKeyStore::GetKeys(const std::string& app_id,
  61. const std::string& authorized_entity,
  62. bool fallback_to_empty_authorized_entity,
  63. KeysCallback callback) {
  64. LazyInitialize(
  65. base::BindOnce(&GCMKeyStore::GetKeysAfterInitialize,
  66. weak_factory_.GetWeakPtr(), app_id, authorized_entity,
  67. fallback_to_empty_authorized_entity, std::move(callback)));
  68. }
  69. void GCMKeyStore::GetKeysAfterInitialize(
  70. const std::string& app_id,
  71. const std::string& authorized_entity,
  72. bool fallback_to_empty_authorized_entity,
  73. KeysCallback callback) {
  74. DCHECK(state_ == State::INITIALIZED || state_ == State::FAILED);
  75. bool success = false;
  76. if (state_ == State::INITIALIZED) {
  77. auto outer_iter = key_data_.find(app_id);
  78. if (outer_iter != key_data_.end()) {
  79. const auto& inner_map = outer_iter->second;
  80. auto inner_iter = inner_map.find(authorized_entity);
  81. if (fallback_to_empty_authorized_entity && inner_iter == inner_map.end())
  82. inner_iter = inner_map.find(std::string());
  83. if (inner_iter != inner_map.end()) {
  84. const auto& map_entry = inner_iter->second;
  85. std::move(callback).Run(map_entry.first->Copy(), map_entry.second);
  86. success = true;
  87. }
  88. }
  89. }
  90. UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.GetKeySuccessRate", success);
  91. if (!success)
  92. std::move(callback).Run(nullptr /* key */, std::string() /* auth_secret */);
  93. }
  94. void GCMKeyStore::CreateKeys(const std::string& app_id,
  95. const std::string& authorized_entity,
  96. KeysCallback callback) {
  97. LazyInitialize(base::BindOnce(&GCMKeyStore::CreateKeysAfterInitialize,
  98. weak_factory_.GetWeakPtr(), app_id,
  99. authorized_entity, std::move(callback)));
  100. }
  101. void GCMKeyStore::CreateKeysAfterInitialize(
  102. const std::string& app_id,
  103. const std::string& authorized_entity,
  104. KeysCallback callback) {
  105. DCHECK(state_ == State::INITIALIZED || state_ == State::FAILED);
  106. if (state_ != State::INITIALIZED) {
  107. std::move(callback).Run(nullptr /* key */, std::string() /* auth_secret */);
  108. return;
  109. }
  110. // Only allow creating new keys if no keys currently exist. Multiple Instance
  111. // ID tokens can share an app_id (with different authorized entities), but
  112. // InstanceID tokens can't share an app_id with a non-InstanceID registration.
  113. // This invariant is necessary for the fallback_to_empty_authorized_entity
  114. // mode of GetKey (needed by GCMEncryptionProvider::DecryptMessage, which
  115. // can't distinguish Instance ID tokens from non-InstanceID registrations).
  116. DCHECK(!key_data_.count(app_id) ||
  117. (!authorized_entity.empty() &&
  118. !key_data_[app_id].count(authorized_entity) &&
  119. !key_data_[app_id].count(std::string())))
  120. << "Instance ID tokens cannot share an app_id with a non-InstanceID GCM "
  121. "registration";
  122. std::unique_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create());
  123. if (!key) {
  124. NOTREACHED() << "Unable to initialize a P-256 key pair.";
  125. std::move(callback).Run(nullptr /* key */, std::string() /* auth_secret */);
  126. return;
  127. }
  128. std::string auth_secret;
  129. // Create the authentication secret, which has to be a cryptographically
  130. // secure random number of at least 128 bits (16 bytes).
  131. crypto::RandBytes(base::WriteInto(&auth_secret, kAuthSecretBytes + 1),
  132. kAuthSecretBytes);
  133. // Store the keys in a new EncryptionData object.
  134. EncryptionData encryption_data;
  135. encryption_data.set_app_id(app_id);
  136. if (!authorized_entity.empty())
  137. encryption_data.set_authorized_entity(authorized_entity);
  138. encryption_data.set_auth_secret(auth_secret);
  139. std::string private_key;
  140. bool success = GetRawPrivateKey(*key, &private_key);
  141. DCHECK(success);
  142. encryption_data.set_private_key(private_key);
  143. // Write them immediately to our cache, so subsequent calls to
  144. // {Get/Create/Remove}Keys can see them.
  145. key_data_[app_id][authorized_entity] = {key->Copy(), auth_secret};
  146. std::unique_ptr<EntryVectorType> entries_to_save(new EntryVectorType());
  147. std::unique_ptr<std::vector<std::string>> keys_to_remove(
  148. new std::vector<std::string>());
  149. entries_to_save->push_back(
  150. std::make_pair(DatabaseKey(app_id, authorized_entity), encryption_data));
  151. database_->UpdateEntries(
  152. std::move(entries_to_save), std::move(keys_to_remove),
  153. base::BindOnce(&GCMKeyStore::DidStoreKeys, weak_factory_.GetWeakPtr(),
  154. std::move(key), auth_secret, std::move(callback)));
  155. }
  156. void GCMKeyStore::DidStoreKeys(std::unique_ptr<crypto::ECPrivateKey> pair,
  157. const std::string& auth_secret,
  158. KeysCallback callback,
  159. bool success) {
  160. UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.CreateKeySuccessRate", success);
  161. if (!success) {
  162. DVLOG(1) << "Unable to store the created key in the GCM Key Store.";
  163. // Our cache is now inconsistent. Reject requests until restarted.
  164. state_ = State::FAILED;
  165. std::move(callback).Run(nullptr /* key */, std::string() /* auth_secret */);
  166. return;
  167. }
  168. std::move(callback).Run(std::move(pair), auth_secret);
  169. }
  170. void GCMKeyStore::RemoveKeys(const std::string& app_id,
  171. const std::string& authorized_entity,
  172. base::OnceClosure callback) {
  173. LazyInitialize(base::BindOnce(&GCMKeyStore::RemoveKeysAfterInitialize,
  174. weak_factory_.GetWeakPtr(), app_id,
  175. authorized_entity, std::move(callback)));
  176. }
  177. void GCMKeyStore::RemoveKeysAfterInitialize(
  178. const std::string& app_id,
  179. const std::string& authorized_entity,
  180. base::OnceClosure callback) {
  181. DCHECK(state_ == State::INITIALIZED || state_ == State::FAILED);
  182. const auto& outer_iter = key_data_.find(app_id);
  183. if (outer_iter == key_data_.end() || state_ != State::INITIALIZED) {
  184. std::move(callback).Run();
  185. return;
  186. }
  187. std::unique_ptr<EntryVectorType> entries_to_save(new EntryVectorType());
  188. std::unique_ptr<std::vector<std::string>> keys_to_remove(
  189. new std::vector<std::string>());
  190. bool had_keys = false;
  191. auto& inner_map = outer_iter->second;
  192. for (auto it = inner_map.begin(); it != inner_map.end();) {
  193. // Wildcard "*" matches all non-empty authorized entities (InstanceID only).
  194. if (authorized_entity == "*" ? !it->first.empty()
  195. : it->first == authorized_entity) {
  196. had_keys = true;
  197. keys_to_remove->push_back(DatabaseKey(app_id, it->first));
  198. // Clear keys immediately from our cache, so subsequent calls to
  199. // {Get/Create/Remove}Keys don't see them.
  200. it = inner_map.erase(it);
  201. } else {
  202. ++it;
  203. }
  204. }
  205. if (!had_keys) {
  206. std::move(callback).Run();
  207. return;
  208. }
  209. if (inner_map.empty())
  210. key_data_.erase(app_id);
  211. database_->UpdateEntries(
  212. std::move(entries_to_save), std::move(keys_to_remove),
  213. base::BindOnce(&GCMKeyStore::DidRemoveKeys, weak_factory_.GetWeakPtr(),
  214. std::move(callback)));
  215. }
  216. void GCMKeyStore::DidRemoveKeys(base::OnceClosure callback, bool success) {
  217. UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.RemoveKeySuccessRate", success);
  218. if (!success) {
  219. DVLOG(1) << "Unable to delete a key from the GCM Key Store.";
  220. // Our cache is now inconsistent. Reject requests until restarted.
  221. state_ = State::FAILED;
  222. }
  223. std::move(callback).Run();
  224. }
  225. void GCMKeyStore::DidUpgradeDatabase(bool success) {
  226. UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.GCMDatabaseUpgradeResult", success);
  227. if (!success) {
  228. DVLOG(1) << "Unable to upgrade the GCM Key Store database.";
  229. // Our cache is now inconsistent. Reject requests until restarted.
  230. state_ = State::FAILED;
  231. delayed_task_controller_.SetReady();
  232. return;
  233. }
  234. database_->LoadEntries(
  235. base::BindOnce(&GCMKeyStore::DidLoadKeys, weak_factory_.GetWeakPtr()));
  236. }
  237. void GCMKeyStore::LazyInitialize(base::OnceClosure done_closure) {
  238. if (delayed_task_controller_.CanRunTaskWithoutDelay()) {
  239. std::move(done_closure).Run();
  240. return;
  241. }
  242. delayed_task_controller_.AddTask(std::move(done_closure));
  243. if (state_ == State::INITIALIZING)
  244. return;
  245. state_ = State::INITIALIZING;
  246. database_ = leveldb_proto::ProtoDatabaseProvider::GetUniqueDB<EncryptionData>(
  247. leveldb_proto::ProtoDbType::GCM_KEY_STORE, key_store_path_,
  248. blocking_task_runner_);
  249. database_->Init(
  250. CreateLevelDbOptions(),
  251. base::BindOnce(&GCMKeyStore::DidInitialize, weak_factory_.GetWeakPtr()));
  252. }
  253. void GCMKeyStore::DidInitialize(leveldb_proto::Enums::InitStatus status) {
  254. bool success = status == leveldb_proto::Enums::kOK;
  255. UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.InitKeyStoreSuccessRate", success);
  256. if (!success) {
  257. DVLOG(1) << "Unable to initialize the GCM Key Store.";
  258. state_ = State::FAILED;
  259. delayed_task_controller_.SetReady();
  260. return;
  261. }
  262. database_->LoadEntries(
  263. base::BindOnce(&GCMKeyStore::DidLoadKeys, weak_factory_.GetWeakPtr()));
  264. }
  265. void GCMKeyStore::UpgradeDatabase(
  266. std::unique_ptr<std::vector<EncryptionData>> entries) {
  267. std::unique_ptr<EntryVectorType> entries_to_save =
  268. std::make_unique<EntryVectorType>();
  269. std::unique_ptr<std::vector<std::string>> keys_to_remove =
  270. std::make_unique<std::vector<std::string>>();
  271. // Loop over entries, create list of database entries to overwrite.
  272. for (EncryptionData& entry : *entries) {
  273. if (!entry.keys_size())
  274. continue;
  275. std::string decrypted_private_key;
  276. if (!DecryptPrivateKey(entry.keys(0).private_key(),
  277. &decrypted_private_key)) {
  278. DVLOG(1) << "Unable to decrypt private key: "
  279. << entry.keys(0).private_key();
  280. state_ = State::FAILED;
  281. delayed_task_controller_.SetReady();
  282. UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.GCMDatabaseUpgradeResult",
  283. false /* sucess */);
  284. return;
  285. }
  286. entry.set_private_key(decrypted_private_key);
  287. entry.clear_keys();
  288. entries_to_save->push_back(std::make_pair(
  289. DatabaseKey(entry.app_id(), entry.authorized_entity()), entry));
  290. }
  291. database_->UpdateEntries(std::move(entries_to_save),
  292. std::move(keys_to_remove),
  293. base::BindOnce(&GCMKeyStore::DidUpgradeDatabase,
  294. weak_factory_.GetWeakPtr()));
  295. }
  296. void GCMKeyStore::DidLoadKeys(
  297. bool success,
  298. std::unique_ptr<std::vector<EncryptionData>> entries) {
  299. UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.LoadKeyStoreSuccessRate", success);
  300. if (!success) {
  301. DVLOG(1) << "Unable to load entries into the GCM Key Store.";
  302. state_ = State::FAILED;
  303. delayed_task_controller_.SetReady();
  304. return;
  305. }
  306. for (const EncryptionData& entry : *entries) {
  307. std::string authorized_entity;
  308. if (entry.has_authorized_entity())
  309. authorized_entity = entry.authorized_entity();
  310. std::unique_ptr<crypto::ECPrivateKey> key;
  311. // The old format of EncryptionData has a KeyPair in it. Previously
  312. // we used to cache the key pair and auth secret in key_data_.
  313. // The new code adds the pair {ECPrivateKey, auth_secret} to
  314. // key_data_ instead.
  315. if (entry.keys_size()) {
  316. if (state_ == State::FAILED)
  317. return;
  318. // Old format of EncryptionData. Upgrade database so there are no such
  319. // entries. We'll reload keys from the database once this is done.
  320. UpgradeDatabase(std::move(entries));
  321. return;
  322. } else {
  323. std::string private_key_str = entry.private_key();
  324. if (private_key_str.empty())
  325. continue;
  326. std::vector<uint8_t> private_key(private_key_str.begin(),
  327. private_key_str.end());
  328. key = crypto::ECPrivateKey::CreateFromPrivateKeyInfo(private_key);
  329. }
  330. key_data_[entry.app_id()][authorized_entity] =
  331. std::make_pair(std::move(key), entry.auth_secret());
  332. }
  333. state_ = State::INITIALIZED;
  334. delayed_task_controller_.SetReady();
  335. }
  336. bool GCMKeyStore::DecryptPrivateKey(const std::string& to_decrypt,
  337. std::string* decrypted) {
  338. DCHECK(decrypted);
  339. std::vector<uint8_t> to_decrypt_vector(to_decrypt.begin(), to_decrypt.end());
  340. std::unique_ptr<crypto::ECPrivateKey> key_to_decrypt =
  341. crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
  342. to_decrypt_vector);
  343. if (!key_to_decrypt)
  344. return false;
  345. std::vector<uint8_t> decrypted_vector;
  346. if (!key_to_decrypt->ExportPrivateKey(&decrypted_vector))
  347. return false;
  348. decrypted->assign(decrypted_vector.begin(), decrypted_vector.end());
  349. return true;
  350. }
  351. } // namespace gcm