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 "chromeos/login/auth/extended_authenticator_impl.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_util.h" 10 #include "chromeos/cryptohome/async_method_caller.h" 11 #include "chromeos/cryptohome/cryptohome_parameters.h" 12 #include "chromeos/cryptohome/homedir_methods.h" 13 #include "chromeos/cryptohome/system_salt_getter.h" 14 #include "chromeos/dbus/cryptohome_client.h" 15 #include "chromeos/dbus/dbus_thread_manager.h" 16 #include "chromeos/login/auth/auth_status_consumer.h" 17 #include "chromeos/login/auth/key.h" 18 #include "chromeos/login/auth/user_context.h" 19 #include "chromeos/login_event_recorder.h" 20 #include "crypto/sha2.h" 21 #include "google_apis/gaia/gaia_auth_util.h" 22 #include "third_party/cros_system_api/dbus/service_constants.h" 23 24 namespace chromeos { 25 26 namespace { 27 28 void RecordStartMarker(const std::string& marker) { 29 std::string full_marker = "Cryptohome-"; 30 full_marker.append(marker); 31 full_marker.append("-Start"); 32 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(full_marker, false); 33 } 34 35 void RecordEndMarker(const std::string& marker) { 36 std::string full_marker = "Cryptohome-"; 37 full_marker.append(marker); 38 full_marker.append("-End"); 39 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(full_marker, false); 40 } 41 42 } // namespace 43 44 ExtendedAuthenticatorImpl::ExtendedAuthenticatorImpl( 45 NewAuthStatusConsumer* consumer) 46 : salt_obtained_(false), consumer_(consumer), old_consumer_(NULL) { 47 SystemSaltGetter::Get()->GetSystemSalt( 48 base::Bind(&ExtendedAuthenticatorImpl::OnSaltObtained, this)); 49 } 50 51 ExtendedAuthenticatorImpl::ExtendedAuthenticatorImpl( 52 AuthStatusConsumer* consumer) 53 : salt_obtained_(false), consumer_(NULL), old_consumer_(consumer) { 54 SystemSaltGetter::Get()->GetSystemSalt( 55 base::Bind(&ExtendedAuthenticatorImpl::OnSaltObtained, this)); 56 } 57 58 void ExtendedAuthenticatorImpl::SetConsumer(AuthStatusConsumer* consumer) { 59 old_consumer_ = consumer; 60 } 61 62 void ExtendedAuthenticatorImpl::AuthenticateToMount( 63 const UserContext& context, 64 const ResultCallback& success_callback) { 65 TransformKeyIfNeeded( 66 context, 67 base::Bind(&ExtendedAuthenticatorImpl::DoAuthenticateToMount, 68 this, 69 success_callback)); 70 } 71 72 void ExtendedAuthenticatorImpl::AuthenticateToCheck( 73 const UserContext& context, 74 const base::Closure& success_callback) { 75 TransformKeyIfNeeded( 76 context, 77 base::Bind(&ExtendedAuthenticatorImpl::DoAuthenticateToCheck, 78 this, 79 success_callback)); 80 } 81 82 void ExtendedAuthenticatorImpl::CreateMount( 83 const std::string& user_id, 84 const std::vector<cryptohome::KeyDefinition>& keys, 85 const ResultCallback& success_callback) { 86 RecordStartMarker("MountEx"); 87 88 std::string canonicalized = gaia::CanonicalizeEmail(user_id); 89 cryptohome::Identification id(canonicalized); 90 cryptohome::Authorization auth(keys.front()); 91 cryptohome::MountParameters mount(false); 92 for (size_t i = 0; i < keys.size(); i++) { 93 mount.create_keys.push_back(keys[i]); 94 } 95 UserContext context(user_id); 96 Key key(keys.front().secret); 97 key.SetLabel(keys.front().label); 98 context.SetKey(key); 99 100 cryptohome::HomedirMethods::GetInstance()->MountEx( 101 id, 102 auth, 103 mount, 104 base::Bind(&ExtendedAuthenticatorImpl::OnMountComplete, 105 this, 106 "MountEx", 107 context, 108 success_callback)); 109 } 110 111 void ExtendedAuthenticatorImpl::AddKey(const UserContext& context, 112 const cryptohome::KeyDefinition& key, 113 bool replace_existing, 114 const base::Closure& success_callback) { 115 TransformKeyIfNeeded(context, 116 base::Bind(&ExtendedAuthenticatorImpl::DoAddKey, 117 this, 118 key, 119 replace_existing, 120 success_callback)); 121 } 122 123 void ExtendedAuthenticatorImpl::UpdateKeyAuthorized( 124 const UserContext& context, 125 const cryptohome::KeyDefinition& key, 126 const std::string& signature, 127 const base::Closure& success_callback) { 128 TransformKeyIfNeeded( 129 context, 130 base::Bind(&ExtendedAuthenticatorImpl::DoUpdateKeyAuthorized, 131 this, 132 key, 133 signature, 134 success_callback)); 135 } 136 137 void ExtendedAuthenticatorImpl::RemoveKey(const UserContext& context, 138 const std::string& key_to_remove, 139 const base::Closure& success_callback) { 140 TransformKeyIfNeeded(context, 141 base::Bind(&ExtendedAuthenticatorImpl::DoRemoveKey, 142 this, 143 key_to_remove, 144 success_callback)); 145 } 146 147 void ExtendedAuthenticatorImpl::TransformKeyIfNeeded( 148 const UserContext& user_context, 149 const ContextCallback& callback) { 150 if (user_context.GetKey()->GetKeyType() != Key::KEY_TYPE_PASSWORD_PLAIN) { 151 callback.Run(user_context); 152 return; 153 } 154 155 if (!salt_obtained_) { 156 system_salt_callbacks_.push_back( 157 base::Bind(&ExtendedAuthenticatorImpl::TransformKeyIfNeeded, 158 this, 159 user_context, 160 callback)); 161 return; 162 } 163 164 UserContext transformed_context = user_context; 165 transformed_context.GetKey()->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, 166 system_salt_); 167 callback.Run(transformed_context); 168 } 169 170 ExtendedAuthenticatorImpl::~ExtendedAuthenticatorImpl() { 171 } 172 173 void ExtendedAuthenticatorImpl::OnSaltObtained(const std::string& system_salt) { 174 salt_obtained_ = true; 175 system_salt_ = system_salt; 176 for (std::vector<base::Closure>::const_iterator it = 177 system_salt_callbacks_.begin(); 178 it != system_salt_callbacks_.end(); 179 ++it) { 180 it->Run(); 181 } 182 system_salt_callbacks_.clear(); 183 } 184 185 void ExtendedAuthenticatorImpl::DoAuthenticateToMount( 186 const ResultCallback& success_callback, 187 const UserContext& user_context) { 188 RecordStartMarker("MountEx"); 189 190 std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID()); 191 cryptohome::Identification id(canonicalized); 192 const Key* const key = user_context.GetKey(); 193 cryptohome::Authorization auth(key->GetSecret(), key->GetLabel()); 194 cryptohome::MountParameters mount(false); 195 196 cryptohome::HomedirMethods::GetInstance()->MountEx( 197 id, 198 auth, 199 mount, 200 base::Bind(&ExtendedAuthenticatorImpl::OnMountComplete, 201 this, 202 "MountEx", 203 user_context, 204 success_callback)); 205 } 206 207 void ExtendedAuthenticatorImpl::DoAuthenticateToCheck( 208 const base::Closure& success_callback, 209 const UserContext& user_context) { 210 RecordStartMarker("CheckKeyEx"); 211 212 std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID()); 213 cryptohome::Identification id(canonicalized); 214 const Key* const key = user_context.GetKey(); 215 cryptohome::Authorization auth(key->GetSecret(), key->GetLabel()); 216 217 cryptohome::HomedirMethods::GetInstance()->CheckKeyEx( 218 id, 219 auth, 220 base::Bind(&ExtendedAuthenticatorImpl::OnOperationComplete, 221 this, 222 "CheckKeyEx", 223 user_context, 224 success_callback)); 225 } 226 227 void ExtendedAuthenticatorImpl::DoAddKey(const cryptohome::KeyDefinition& key, 228 bool replace_existing, 229 const base::Closure& success_callback, 230 const UserContext& user_context) { 231 RecordStartMarker("AddKeyEx"); 232 233 std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID()); 234 cryptohome::Identification id(canonicalized); 235 const Key* const auth_key = user_context.GetKey(); 236 cryptohome::Authorization auth(auth_key->GetSecret(), auth_key->GetLabel()); 237 238 cryptohome::HomedirMethods::GetInstance()->AddKeyEx( 239 id, 240 auth, 241 key, 242 replace_existing, 243 base::Bind(&ExtendedAuthenticatorImpl::OnOperationComplete, 244 this, 245 "AddKeyEx", 246 user_context, 247 success_callback)); 248 } 249 250 void ExtendedAuthenticatorImpl::DoUpdateKeyAuthorized( 251 const cryptohome::KeyDefinition& key, 252 const std::string& signature, 253 const base::Closure& success_callback, 254 const UserContext& user_context) { 255 RecordStartMarker("UpdateKeyAuthorized"); 256 257 std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID()); 258 cryptohome::Identification id(canonicalized); 259 const Key* const auth_key = user_context.GetKey(); 260 cryptohome::Authorization auth(auth_key->GetSecret(), auth_key->GetLabel()); 261 262 cryptohome::HomedirMethods::GetInstance()->UpdateKeyEx( 263 id, 264 auth, 265 key, 266 signature, 267 base::Bind(&ExtendedAuthenticatorImpl::OnOperationComplete, 268 this, 269 "UpdateKeyAuthorized", 270 user_context, 271 success_callback)); 272 } 273 274 void ExtendedAuthenticatorImpl::DoRemoveKey(const std::string& key_to_remove, 275 const base::Closure& success_callback, 276 const UserContext& user_context) { 277 RecordStartMarker("RemoveKeyEx"); 278 279 std::string canonicalized = gaia::CanonicalizeEmail(user_context.GetUserID()); 280 cryptohome::Identification id(canonicalized); 281 const Key* const auth_key = user_context.GetKey(); 282 cryptohome::Authorization auth(auth_key->GetSecret(), auth_key->GetLabel()); 283 284 cryptohome::HomedirMethods::GetInstance()->RemoveKeyEx( 285 id, 286 auth, 287 key_to_remove, 288 base::Bind(&ExtendedAuthenticatorImpl::OnOperationComplete, 289 this, 290 "RemoveKeyEx", 291 user_context, 292 success_callback)); 293 } 294 295 void ExtendedAuthenticatorImpl::OnMountComplete( 296 const std::string& time_marker, 297 const UserContext& user_context, 298 const ResultCallback& success_callback, 299 bool success, 300 cryptohome::MountError return_code, 301 const std::string& mount_hash) { 302 RecordEndMarker(time_marker); 303 UserContext copy = user_context; 304 copy.SetUserIDHash(mount_hash); 305 if (return_code == cryptohome::MOUNT_ERROR_NONE) { 306 if (!success_callback.is_null()) 307 success_callback.Run(mount_hash); 308 if (old_consumer_) 309 old_consumer_->OnAuthSuccess(copy); 310 return; 311 } 312 AuthState state = FAILED_MOUNT; 313 if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR || 314 return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK || 315 return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) { 316 state = FAILED_TPM; 317 } 318 if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) { 319 state = NO_MOUNT; 320 } 321 if (consumer_) 322 consumer_->OnAuthenticationFailure(state); 323 if (old_consumer_) { 324 AuthFailure failure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME); 325 old_consumer_->OnAuthFailure(failure); 326 } 327 } 328 329 void ExtendedAuthenticatorImpl::OnOperationComplete( 330 const std::string& time_marker, 331 const UserContext& user_context, 332 const base::Closure& success_callback, 333 bool success, 334 cryptohome::MountError return_code) { 335 RecordEndMarker(time_marker); 336 if (return_code == cryptohome::MOUNT_ERROR_NONE) { 337 if (!success_callback.is_null()) 338 success_callback.Run(); 339 if (old_consumer_) 340 old_consumer_->OnAuthSuccess(user_context); 341 return; 342 } 343 344 LOG(ERROR) << "Supervised user cryptohome error, code: " << return_code; 345 346 AuthState state = FAILED_MOUNT; 347 348 if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR || 349 return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK || 350 return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) { 351 state = FAILED_TPM; 352 } 353 354 if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) 355 state = NO_MOUNT; 356 357 if (consumer_) 358 consumer_->OnAuthenticationFailure(state); 359 360 if (old_consumer_) { 361 AuthFailure failure(AuthFailure::UNLOCK_FAILED); 362 old_consumer_->OnAuthFailure(failure); 363 } 364 } 365 366 } // namespace chromeos 367