Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / gcm_driver / crypto / gcm_key_store.cc
bloba9776fb4caa891f737dd0cb521648375d360863a
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.
5 #include "components/gcm_driver/crypto/gcm_key_store.h"
7 #include <utility>
9 #include "base/logging.h"
10 #include "components/leveldb_proto/proto_database_impl.h"
11 #include "crypto/curve25519.h"
12 #include "crypto/random.h"
14 namespace gcm {
16 enum class GCMKeyStore::State {
17 UNINITIALIZED,
18 INITIALIZING,
19 INITIALIZED,
20 FAILED
23 GCMKeyStore::GCMKeyStore(
24 const base::FilePath& key_store_path,
25 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
26 : key_store_path_(key_store_path),
27 blocking_task_runner_(blocking_task_runner),
28 state_(State::UNINITIALIZED),
29 weak_factory_(this) {
30 DCHECK(blocking_task_runner);
33 GCMKeyStore::~GCMKeyStore() {}
35 void GCMKeyStore::GetKeys(const std::string& app_id,
36 const KeysCallback& callback) {
37 LazyInitialize(base::Bind(&GCMKeyStore::GetKeysAfterInitialize,
38 weak_factory_.GetWeakPtr(), app_id, callback));
41 void GCMKeyStore::GetKeysAfterInitialize(const std::string& app_id,
42 const KeysCallback& callback) {
43 DCHECK(state_ == State::INITIALIZED || state_ == State::FAILED);
44 const auto iter = key_pairs_.find(app_id);
45 if (iter == key_pairs_.end() || state_ != State::INITIALIZED) {
46 callback.Run(KeyPair());
47 return;
50 callback.Run(iter->second);
53 void GCMKeyStore::CreateKeys(const std::string& app_id,
54 const KeysCallback& callback) {
55 LazyInitialize(base::Bind(&GCMKeyStore::CreateKeysAfterInitialize,
56 weak_factory_.GetWeakPtr(), app_id, callback));
59 void GCMKeyStore::CreateKeysAfterInitialize(const std::string& app_id,
60 const KeysCallback& callback) {
61 DCHECK(state_ == State::INITIALIZED || state_ == State::FAILED);
62 if (state_ != State::INITIALIZED) {
63 callback.Run(KeyPair());
64 return;
67 // Only allow creating new keys if no keys currently exist.
68 DCHECK_EQ(0u, key_pairs_.count(app_id));
70 // Create a Curve25519 private/public key-pair.
71 uint8_t private_key[crypto::curve25519::kScalarBytes];
72 uint8_t public_key[crypto::curve25519::kBytes];
74 crypto::RandBytes(private_key, sizeof(private_key));
76 // Compute the |public_key| based on the |private_key|.
77 crypto::curve25519::ScalarBaseMult(private_key, public_key);
79 // Store the keys in a new EncryptionData object.
80 EncryptionData encryption_data;
81 encryption_data.set_app_id(app_id);
83 KeyPair* pair = encryption_data.add_keys();
84 pair->set_type(KeyPair::ECDH_CURVE_25519);
85 pair->set_private_key(private_key, sizeof(private_key));
86 pair->set_public_key(public_key, sizeof(public_key));
88 using EntryVectorType =
89 leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
91 scoped_ptr<EntryVectorType> entries_to_save(new EntryVectorType());
92 scoped_ptr<std::vector<std::string>> keys_to_remove(
93 new std::vector<std::string>());
95 entries_to_save->push_back(std::make_pair(app_id, encryption_data));
97 database_->UpdateEntries(
98 entries_to_save.Pass(), keys_to_remove.Pass(),
99 base::Bind(&GCMKeyStore::DidStoreKeys, weak_factory_.GetWeakPtr(), app_id,
100 *pair, callback));
103 void GCMKeyStore::DidStoreKeys(const std::string& app_id,
104 const KeyPair& pair,
105 const KeysCallback& callback,
106 bool success) {
107 DCHECK_EQ(0u, key_pairs_.count(app_id));
109 if (!success) {
110 DVLOG(1) << "Unable to store the created key in the GCM Key Store.";
111 callback.Run(KeyPair());
112 return;
115 key_pairs_[app_id] = pair;
117 callback.Run(key_pairs_[app_id]);
120 void GCMKeyStore::DeleteKeys(const std::string& app_id,
121 const DeleteCallback& callback) {
122 LazyInitialize(base::Bind(&GCMKeyStore::DeleteKeysAfterInitialize,
123 weak_factory_.GetWeakPtr(), app_id, callback));
126 void GCMKeyStore::DeleteKeysAfterInitialize(const std::string& app_id,
127 const DeleteCallback& callback) {
128 DCHECK(state_ == State::INITIALIZED || state_ == State::FAILED);
129 const auto iter = key_pairs_.find(app_id);
130 if (iter == key_pairs_.end() || state_ != State::INITIALIZED) {
131 callback.Run(true /* success */);
132 return;
135 using EntryVectorType =
136 leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
138 scoped_ptr<EntryVectorType> entries_to_save(new EntryVectorType());
139 scoped_ptr<std::vector<std::string>> keys_to_remove(
140 new std::vector<std::string>(1, app_id));
142 database_->UpdateEntries(
143 entries_to_save.Pass(), keys_to_remove.Pass(),
144 base::Bind(&GCMKeyStore::DidDeleteKeys, weak_factory_.GetWeakPtr(),
145 app_id, callback));
148 void GCMKeyStore::DidDeleteKeys(const std::string& app_id,
149 const DeleteCallback& callback,
150 bool success) {
151 if (!success) {
152 DVLOG(1) << "Unable to delete a key from the GCM Key Store.";
153 callback.Run(false /* success */);
154 return;
157 key_pairs_.erase(app_id);
159 callback.Run(true /* success */);
162 void GCMKeyStore::LazyInitialize(const base::Closure& done_closure) {
163 if (delayed_task_controller_.CanRunTaskWithoutDelay()) {
164 done_closure.Run();
165 return;
168 delayed_task_controller_.AddTask(done_closure);
169 if (state_ == State::INITIALIZING)
170 return;
172 state_ = State::INITIALIZING;
174 database_.reset(new leveldb_proto::ProtoDatabaseImpl<EncryptionData>(
175 blocking_task_runner_));
177 database_->Init(key_store_path_, base::Bind(&GCMKeyStore::DidInitialize,
178 weak_factory_.GetWeakPtr()));
181 void GCMKeyStore::DidInitialize(bool success) {
182 if (!success) {
183 DVLOG(1) << "Unable to initialize the GCM Key Store.";
184 state_ = State::FAILED;
186 delayed_task_controller_.SetReady();
187 return;
190 database_->LoadEntries(
191 base::Bind(&GCMKeyStore::DidLoadKeys, weak_factory_.GetWeakPtr()));
194 void GCMKeyStore::DidLoadKeys(bool success,
195 scoped_ptr<std::vector<EncryptionData>> entries) {
196 if (!success) {
197 DVLOG(1) << "Unable to load entries into the GCM Key Store.";
198 state_ = State::FAILED;
200 delayed_task_controller_.SetReady();
201 return;
204 for (const EncryptionData& entry : *entries) {
205 DCHECK_EQ(1, entry.keys_size());
206 key_pairs_[entry.app_id()] = entry.keys(0);
209 state_ = State::INITIALIZED;
211 delayed_task_controller_.SetReady();
214 } // namespace gcm