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/signin/easy_unlock_auth_attempt.h" 6 7 #include "base/logging.h" 8 #include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/signin/screenlock_bridge.h" 11 #include "crypto/encryptor.h" 12 #include "crypto/symmetric_key.h" 13 14 15 #if defined(OS_CHROMEOS) 16 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" 17 #endif 18 19 namespace { 20 21 // Fake secret used to force invalid login. 22 const char kStubSecret[] = "\xFF\x00"; 23 24 // Decrypts the secret that should be used to login from |wrapped_secret| using 25 // raw AES key |raw_key|. 26 // In a case of error, an empty string is returned. 27 std::string UnwrapSecret(const std::string& wrapped_secret, 28 const std::string& raw_key) { 29 if (raw_key.empty()) 30 return std::string(); 31 32 // Import the key structure. 33 scoped_ptr<crypto::SymmetricKey> key( 34 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key)); 35 36 if (!key) 37 return std::string(); 38 39 std::string iv(raw_key.size(), ' '); 40 crypto::Encryptor encryptor; 41 if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)) 42 return std::string(); 43 44 std::string secret; 45 if (!encryptor.Decrypt(wrapped_secret, &secret)) 46 return std::string(); 47 48 return secret; 49 } 50 51 } // namespace 52 53 EasyUnlockAuthAttempt::EasyUnlockAuthAttempt(Profile* profile, 54 const std::string& user_id, 55 Type type) 56 : profile_(profile), 57 state_(STATE_IDLE), 58 user_id_(user_id), 59 type_(type) { 60 } 61 62 EasyUnlockAuthAttempt::~EasyUnlockAuthAttempt() { 63 if (state_ == STATE_RUNNING) 64 Cancel(user_id_); 65 } 66 67 bool EasyUnlockAuthAttempt::Start(const std::string& user_id) { 68 DCHECK(state_ == STATE_IDLE); 69 70 if (!ScreenlockBridge::Get()->IsLocked()) 71 return false; 72 73 if (user_id != user_id_) { 74 Cancel(user_id); 75 return false; 76 } 77 78 ScreenlockBridge::LockHandler::AuthType auth_type = 79 ScreenlockBridge::Get()->lock_handler()->GetAuthType(user_id); 80 81 if (auth_type != ScreenlockBridge::LockHandler::USER_CLICK) { 82 Cancel(user_id); 83 return false; 84 } 85 86 state_ = STATE_RUNNING; 87 88 // TODO(tbarzic): Replace this with an easyUnlockPrivate event that will 89 // report more context to the app (e.g. user id, whether the attempt is for 90 // signin or unlock). 91 extensions::ScreenlockPrivateEventRouter* router = 92 extensions::ScreenlockPrivateEventRouter::GetFactoryInstance()->Get( 93 profile_); 94 return router->OnAuthAttempted(auth_type, ""); 95 } 96 97 void EasyUnlockAuthAttempt::FinalizeUnlock(const std::string& user_id, 98 bool success) { 99 if (state_ != STATE_RUNNING || user_id != user_id_) 100 return; 101 102 if (type_ != TYPE_UNLOCK) { 103 Cancel(user_id_); 104 return; 105 } 106 107 if (!ScreenlockBridge::Get()->IsLocked()) 108 return; 109 110 if (success) { 111 ScreenlockBridge::Get()->lock_handler()->Unlock(user_id_); 112 } else { 113 ScreenlockBridge::Get()->lock_handler()->EnableInput(); 114 } 115 116 state_ = STATE_DONE; 117 } 118 119 void EasyUnlockAuthAttempt::FinalizeSignin(const std::string& user_id, 120 const std::string& wrapped_secret, 121 const std::string& raw_session_key) { 122 if (state_ != STATE_RUNNING || user_id != user_id_) 123 return; 124 125 if (type_ != TYPE_SIGNIN) { 126 Cancel(user_id_); 127 return; 128 } 129 130 if (!ScreenlockBridge::Get()->IsLocked()) 131 return; 132 133 134 std::string unwrapped_secret = UnwrapSecret(wrapped_secret, raw_session_key); 135 136 // If secret is not set, set it to an arbitrary value, otherwise there will 137 // be no authenitcation attempt and the ui will get stuck. 138 // TODO(tbarzic): Find a better way to handle this case. 139 if (unwrapped_secret.empty()) 140 unwrapped_secret = kStubSecret; 141 142 std::string key_label; 143 #if defined(OS_CHROMEOS) 144 key_label = chromeos::EasyUnlockKeyManager::GetKeyLabel(0u); 145 #endif // defined(OS_CHROMEOS) 146 147 ScreenlockBridge::Get()->lock_handler()->AttemptEasySignin( 148 user_id, 149 unwrapped_secret, 150 key_label); 151 state_ = STATE_DONE; 152 } 153 154 void EasyUnlockAuthAttempt::Cancel(const std::string& user_id) { 155 if (type_ == TYPE_UNLOCK) 156 FinalizeUnlock(user_id, false); 157 else 158 FinalizeSignin(user_id, "", ""); 159 state_ = STATE_DONE; 160 } 161