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

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

Powered by Google App Engine
This is Rietveld 408576698