Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(414)

Side by Side Diff: chrome/browser/chromeos/login/easy_unlock/easy_unlock_create_keys_operation.cc

Issue 554043003: cros: Create cryptohome keys for Easy sign-in. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix use-after-free Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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/chromeos/login/easy_unlock/easy_unlock_create_keys_oper ation.h"
6
7 #include <string>
8
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_util.h"
14 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
15 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_types.h"
16 #include "chromeos/cryptohome/homedir_methods.h"
17 #include "chromeos/dbus/dbus_thread_manager.h"
18 #include "chromeos/dbus/easy_unlock_client.h"
19 #include "crypto/encryptor.h"
20 #include "crypto/random.h"
21 #include "crypto/symmetric_key.h"
22 #include "google_apis/gaia/gaia_auth_util.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
24
25 namespace chromeos {
26
27 namespace {
28
29 const int kUserKeyByteSize = 16;
30 const int kSessionKeyByteSize = 16;
31
32 const int kEasyUnlockKeyRevision = 1;
33 const int kEasyUnlockKeyPrivileges =
34 cryptohome::PRIV_MOUNT | cryptohome::PRIV_ADD | cryptohome::PRIV_REMOVE;
35
36 bool WebSafeBase64Decode(const std::string& encoded, std::string* decoded) {
37 std::string adjusted_encoded = encoded;
38 base::ReplaceChars(adjusted_encoded, "-", "+", &adjusted_encoded);
39 base::ReplaceChars(adjusted_encoded, "_", "/", &adjusted_encoded);
40
41 return base::Base64Decode(adjusted_encoded, decoded);
42 }
43
44 } // namespace
45
46 /////////////////////////////////////////////////////////////////////////////
47 // EasyUnlockCreateKeysOperation::ChallengeCreator
48
49 class EasyUnlockCreateKeysOperation::ChallengeCreator {
50 public:
51 typedef base::Callback<void (bool success)> ChallengeCreatedCallback;
52 ChallengeCreator(const std::string& user_key,
53 const std::string& session_key,
54 const std::string& tpm_pub_key,
55 EasyUnlockDeviceKeyData* device,
56 const ChallengeCreatedCallback& callback);
57 ~ChallengeCreator();
58
59 void Start();
60
61 const std::string& user_key() const { return user_key_; }
62
63 private:
64 void OnEcKeyPairGenerated(const std::string& ec_public_key,
65 const std::string& ec_private_key);
66 void OnEskGenerated(const std::string& esk);
67
68 void GeneratePayload();
69 void OnPayloadMessageGenerated(const std::string& payload_message);
70 void OnPayloadGenerated(const std::string& payload);
71
72 void OnChallengeGenerated(const std::string& challenge);
73
74 const std::string user_key_;
75 const std::string session_key_;
76 const std::string tpm_pub_key_;
77 EasyUnlockDeviceKeyData* device_;
78 ChallengeCreatedCallback callback_;
79
80 std::string ec_public_key_;
81 std::string esk_;
82
83 // Owned by DBusThreadManager
84 chromeos::EasyUnlockClient* easy_unlock_client_;
85
86 base::WeakPtrFactory<ChallengeCreator> weak_ptr_factory_;
87
88 DISALLOW_COPY_AND_ASSIGN(ChallengeCreator);
89 };
90
91 EasyUnlockCreateKeysOperation::ChallengeCreator::ChallengeCreator(
92 const std::string& user_key,
93 const std::string& session_key,
94 const std::string& tpm_pub_key,
95 EasyUnlockDeviceKeyData* device,
96 const ChallengeCreatedCallback& callback)
97 : user_key_(user_key),
98 session_key_(session_key),
99 tpm_pub_key_(tpm_pub_key),
100 device_(device),
101 callback_(callback),
102 easy_unlock_client_(
103 chromeos::DBusThreadManager::Get()->GetEasyUnlockClient()),
104 weak_ptr_factory_(this) {
105 }
106
107 EasyUnlockCreateKeysOperation::ChallengeCreator::~ChallengeCreator() {
108 }
109
110 void EasyUnlockCreateKeysOperation::ChallengeCreator::Start() {
111 easy_unlock_client_->GenerateEcP256KeyPair(
112 base::Bind(&ChallengeCreator::OnEcKeyPairGenerated,
113 weak_ptr_factory_.GetWeakPtr()));
114 }
115
116 void EasyUnlockCreateKeysOperation::ChallengeCreator::OnEcKeyPairGenerated(
117 const std::string& ec_private_key,
118 const std::string& ec_public_key) {
119 if (ec_private_key.empty() || ec_public_key.empty()) {
120 LOG(ERROR) << "Easy unlock failed to generate ec key pair.";
121 callback_.Run(false);
122 return;
123 }
124
125 std::string device_pub_key;
126 if (!WebSafeBase64Decode(device_->public_key, &device_pub_key)) {
127 LOG(ERROR) << "Easy unlock failed to decode device public key.";
128 callback_.Run(false);
129 return;
130 }
131
132 ec_public_key_ = ec_public_key;
133 easy_unlock_client_->PerformECDHKeyAgreement(
134 ec_private_key,
135 device_pub_key,
136 base::Bind(&ChallengeCreator::OnEskGenerated,
137 weak_ptr_factory_.GetWeakPtr()));
138 }
139
140 void EasyUnlockCreateKeysOperation::ChallengeCreator::OnEskGenerated(
141 const std::string& esk) {
142 if (esk.empty()) {
143 LOG(ERROR) << "Easy unlock failed to generate challenge esk.";
144 callback_.Run(false);
145 return;
146 }
147
148 esk_ = esk;
149 GeneratePayload();
150 }
151
152 void EasyUnlockCreateKeysOperation::ChallengeCreator::GeneratePayload() {
153 // Work around to get HeaderAndBody bytes to use as challenge payload.
154 easy_unlock_client_->CreateSecureMessage(
155 session_key_,
156 esk_,
157 std::string(), // associated data
158 std::string(), // public meta
159 tpm_pub_key_,
tbarzic 2014/09/09 19:32:21 I think android expect this to be GenericPublicKey
xiyuan 2014/09/09 20:25:30 Yep. Added a TODO to wrap it in GenericPublicKey p
160 std::string(), // decryption key id
161 easy_unlock::kEncryptionTypeAES256CBC,
162 easy_unlock::kSignatureTypeHMACSHA256,
163 base::Bind(&ChallengeCreator::OnPayloadMessageGenerated,
164 weak_ptr_factory_.GetWeakPtr()));
165 }
166
167 void
168 EasyUnlockCreateKeysOperation::ChallengeCreator::OnPayloadMessageGenerated(
169 const std::string& payload_message) {
170 easy_unlock_client_->UnwrapSecureMessage(
171 payload_message,
172 esk_,
173 std::string(), // associated data
174 easy_unlock::kEncryptionTypeAES256CBC,
175 easy_unlock::kSignatureTypeHMACSHA256,
176 base::Bind(&ChallengeCreator::OnPayloadGenerated,
177 weak_ptr_factory_.GetWeakPtr()));
178 }
179
180 void EasyUnlockCreateKeysOperation::ChallengeCreator::OnPayloadGenerated(
181 const std::string& payload) {
182 if (payload.empty()) {
183 LOG(ERROR) << "Easy unlock failed to generate challenge payload.";
184 callback_.Run(false);
185 return;
186 }
187
188 easy_unlock_client_->CreateSecureMessage(
189 payload,
190 esk_,
191 std::string(), // associated data
192 std::string(), // public meta
193 std::string(), // verification key id
194 ec_public_key_, // decryption key id
195 easy_unlock::kEncryptionTypeAES256CBC,
196 easy_unlock::kSignatureTypeHMACSHA256,
197 base::Bind(&ChallengeCreator::OnChallengeGenerated,
198 weak_ptr_factory_.GetWeakPtr()));
199 }
200
201 void EasyUnlockCreateKeysOperation::ChallengeCreator::OnChallengeGenerated(
202 const std::string& challenge) {
203 if (challenge.empty()) {
204 LOG(ERROR) << "Easy unlock failed to generate challenge.";
205 callback_.Run(false);
206 return;
207 }
208
209 device_->challenge = challenge;
210 callback_.Run(true);
211 }
212
213 /////////////////////////////////////////////////////////////////////////////
214 // EasyUnlockCreateKeysOperation
215
216 EasyUnlockCreateKeysOperation::EasyUnlockCreateKeysOperation(
217 const UserContext& user_context,
218 const EasyUnlockDeviceKeyDataList& devices,
219 const CreateKeysCallback& callback)
220 : user_context_(user_context),
221 devices_(devices),
222 callback_(callback),
223 key_creation_index_(-1),
224 weak_ptr_factory_(this) {
225 // Must have the secret and callback.
226 DCHECK(!user_context_.GetKey()->GetSecret().empty());
227 DCHECK(!callback_.is_null());
228 }
229
230 EasyUnlockCreateKeysOperation::~EasyUnlockCreateKeysOperation() {
231 }
232
233 void EasyUnlockCreateKeysOperation::Start() {
234 key_creation_index_ = 0;
235 CreateKeyForDeviceAtIndex(key_creation_index_);
236 }
237
238 void EasyUnlockCreateKeysOperation::CreateKeyForDeviceAtIndex(int index) {
239 DCHECK(index >= 0);
240 if (index == static_cast<int>(devices_.size())) {
tbarzic 2014/09/09 19:32:21 I'd rather make key_creation_index_ size_t; and ma
xiyuan 2014/09/09 20:25:30 Done. Changed to size_t. Not really need a started
241 callback_.Run(true);
242 return;
243 }
244
245 std::string user_key;
246 crypto::RandBytes(WriteInto(&user_key, kUserKeyByteSize + 1),
247 kUserKeyByteSize);
248
249 scoped_ptr<crypto::SymmetricKey> session_key(
250 crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES,
251 kSessionKeyByteSize * 8));
252
253 std::string iv(kSessionKeyByteSize, ' ');
254 crypto::Encryptor encryptor;
255 if (!encryptor.Init(session_key.get(), crypto::Encryptor::CBC, iv)) {
256 LOG(ERROR) << "Easy unlock failed to init encryptor for key creation.";
257 callback_.Run(false);
258 return;
259 }
260
261 EasyUnlockDeviceKeyData* device = &devices_[index];
262 if (!encryptor.Encrypt(user_key, &device->wrapped_secret)) {
263 LOG(ERROR) << "Easy unlock failed to encrypt user key for key creation.";
264 callback_.Run(false);
265 return;
266 }
267
268 std::string raw_session_key;
269 session_key->GetRawKey(&raw_session_key);
270
271 challenge_creator_.reset(new ChallengeCreator(
272 user_key,
273 raw_session_key,
274 std::string(),
275 device,
276 base::Bind(&EasyUnlockCreateKeysOperation::OnChallengeCreated,
277 weak_ptr_factory_.GetWeakPtr(),
278 index)));
279 challenge_creator_->Start();
280 }
281
282 void EasyUnlockCreateKeysOperation::OnChallengeCreated(int index,
283 bool success) {
284 DCHECK_EQ(key_creation_index_, index);
285
286 if (!success) {
287 LOG(ERROR) << "Easy unlock failed to create challenge for key creation.";
288 callback_.Run(false);
289 return;
290 }
291
292 EasyUnlockDeviceKeyData* device = &devices_[index];
293
294 cryptohome::KeyDefinition key_def(
295 challenge_creator_->user_key(),
296 EasyUnlockKeyManager::GetKeyLabel(index),
297 kEasyUnlockKeyPrivileges);
298 key_def.revision = kEasyUnlockKeyRevision;
299 key_def.provider_data.push_back(
300 cryptohome::ProviderDataEntry(kEasyUnlockKeyMetaNameBluetoothAddress,
301 device->bluetooth_address));
302 key_def.provider_data.push_back(
303 cryptohome::ProviderDataEntry(kEasyUnlockKeyMetaNamePsk,
304 device->psk));
305 key_def.provider_data.push_back(
306 cryptohome::ProviderDataEntry(kEasyUnlockKeyMetaNamePubKey,
307 device->public_key));
308 key_def.provider_data.push_back(
309 cryptohome::ProviderDataEntry(kEasyUnlockKeyMetaNameChallenge,
310 device->challenge));
311 // TODO(xiyuan): Store wrapped secret when all pieces are in place.
312 key_def.provider_data.push_back(
313 cryptohome::ProviderDataEntry(kEasyUnlockKeyMetaNameWrappedSecret,
314 key_def.key));
315
316 // Add cryptohome key.
317 std::string canonicalized =
318 gaia::CanonicalizeEmail(user_context_.GetUserID());
319 cryptohome::Identification id(canonicalized);
320 const Key* const auth_key = user_context_.GetKey();
321 cryptohome::Authorization auth(auth_key->GetSecret(), auth_key->GetLabel());
322 cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
323 id,
324 auth,
325 key_def,
326 true, // clobber
327 base::Bind(&EasyUnlockCreateKeysOperation::OnKeyCreated,
328 weak_ptr_factory_.GetWeakPtr(),
329 index));
330 }
331
332 void EasyUnlockCreateKeysOperation::OnKeyCreated(
333 int index,
334 bool success,
335 cryptohome::MountError return_code) {
336 DCHECK_EQ(key_creation_index_, index);
337
338 if (!success) {
339 LOG(ERROR) << "Easy unlock failed to create key, code=" << return_code;
340 callback_.Run(false);
341 return;
342 }
343
344 ++key_creation_index_;
345 CreateKeyForDeviceAtIndex(key_creation_index_);
346 }
347
348 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698