diff options
author | zelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-07 04:01:03 +0000 |
---|---|---|
committer | zelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-07 04:01:03 +0000 |
commit | 6e3d9a9cf7aec1dc9777c2860e39ee7751a3e004 (patch) | |
tree | 4aa823b32cdc4d026a15996a407f80f15913fee8 | |
parent | 3f7af10d3e7d931500433326908d261333710b31 (diff) | |
download | chromium_src-6e3d9a9cf7aec1dc9777c2860e39ee7751a3e004.zip chromium_src-6e3d9a9cf7aec1dc9777c2860e39ee7751a3e004.tar.gz chromium_src-6e3d9a9cf7aec1dc9777c2860e39ee7751a3e004.tar.bz2 |
Changed OAuth token+secret encryption to use supplemental user key from NSS DB.
BUG=chromium-os:18633
TEST=none
Review URL: http://codereview.chromium.org/7756025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99912 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/chromeos/cros/cert_library.cc | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/cert_library.h | 7 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/authenticator.h | 3 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/google_authenticator.cc | 5 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/google_authenticator.h | 2 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/login_utils.cc | 15 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/mock_authenticator.cc | 5 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/mock_authenticator.h | 2 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/parallel_authenticator.cc | 79 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/parallel_authenticator.h | 10 | ||||
-rw-r--r-- | crypto/nss_util.cc | 50 | ||||
-rw-r--r-- | crypto/nss_util.h | 10 | ||||
-rw-r--r-- | crypto/symmetric_key.h | 5 | ||||
-rw-r--r-- | crypto/symmetric_key_nss.cc | 7 |
14 files changed, 176 insertions, 28 deletions
diff --git a/chrome/browser/chromeos/cros/cert_library.cc b/chrome/browser/chromeos/cros/cert_library.cc index 895d752..ab57e76 100644 --- a/chrome/browser/chromeos/cros/cert_library.cc +++ b/chrome/browser/chromeos/cros/cert_library.cc @@ -176,6 +176,10 @@ class CertLibraryImpl return server_ca_certs_; } + virtual crypto::SymmetricKey* GetSupplementalUserKey() const { + return crypto::GetSupplementalUserKey(); + } + // net::CertDatabase::Observer implementation. Observer added on UI thread. virtual void OnCertTrustChanged(const net::X509Certificate* cert) OVERRIDE { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); diff --git a/chrome/browser/chromeos/cros/cert_library.h b/chrome/browser/chromeos/cros/cert_library.h index 3e384e0..f1f6310 100644 --- a/chrome/browser/chromeos/cros/cert_library.h +++ b/chrome/browser/chromeos/cros/cert_library.h @@ -12,6 +12,10 @@ #include "net/base/cert_database.h" #include "net/base/x509_certificate.h" +namespace crypto { +class SymmetricKey; +} + namespace chromeos { class CertLibrary { @@ -96,6 +100,9 @@ class CertLibrary { // Returns the current list of server CA certificates. virtual const CertList& GetCACertificates() const = 0; + + // Returns the supplemental user key. + virtual crypto::SymmetricKey* GetSupplementalUserKey() const = 0; }; } // namespace chromeos diff --git a/chrome/browser/chromeos/login/authenticator.h b/chrome/browser/chromeos/login/authenticator.h index 8099df6..7e40440 100644 --- a/chrome/browser/chromeos/login/authenticator.h +++ b/chrome/browser/chromeos/login/authenticator.h @@ -100,6 +100,9 @@ class Authenticator : public base::RefCountedThreadSafe<Authenticator> { // OAuth token encryption helpers. virtual std::string EncryptToken(const std::string& token) = 0; virtual std::string DecryptToken(const std::string& encrypted_token) = 0; + // TODO(zelidrag): Remove legacy encryption support in R16. + virtual std::string DecryptLegacyToken( + const std::string& encrypted_token) = 0; // Profile (usually off the record ) that was used to perform the last // authentication process. diff --git a/chrome/browser/chromeos/login/google_authenticator.cc b/chrome/browser/chromeos/login/google_authenticator.cc index d097430..a0877b4 100644 --- a/chrome/browser/chromeos/login/google_authenticator.cc +++ b/chrome/browser/chromeos/login/google_authenticator.cc @@ -422,6 +422,11 @@ std::string GoogleAuthenticator::DecryptToken(const std::string& unused) { return std::string(); } +std::string GoogleAuthenticator::DecryptLegacyToken(const std::string& unused) { + NOTIMPLEMENTED(); + return std::string(); +} + void GoogleAuthenticator::LoadSystemSalt() { if (!system_salt_.empty()) diff --git a/chrome/browser/chromeos/login/google_authenticator.h b/chrome/browser/chromeos/login/google_authenticator.h index 135aebf..6d38e11 100644 --- a/chrome/browser/chromeos/login/google_authenticator.h +++ b/chrome/browser/chromeos/login/google_authenticator.h @@ -120,6 +120,8 @@ class GoogleAuthenticator : public Authenticator, public GaiaAuthConsumer { const std::string& oauth1_secret) OVERRIDE; virtual std::string EncryptToken(const std::string& token) OVERRIDE; virtual std::string DecryptToken(const std::string& encrypted_token) OVERRIDE; + virtual std::string DecryptLegacyToken( + const std::string& encrypted_token) OVERRIDE; // Callbacks from GaiaAuthFetcher virtual void OnClientLoginFailure( diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc index e8ead44..915abc7 100644 --- a/chrome/browser/chromeos/login/login_utils.cc +++ b/chrome/browser/chromeos/login/login_utils.cc @@ -935,8 +935,19 @@ bool LoginUtilsImpl::ReadOAuth1AccessToken(Profile* user_profile, std::string decoded_token = authenticator_->DecryptToken(encoded_token); std::string decoded_secret = authenticator_->DecryptToken(encoded_secret); - if (!decoded_token.length() || !decoded_secret.length()) - return false; + if (!decoded_token.length() || !decoded_secret.length()) { + // TODO(zelidrag): Remove legacy encryption support in R16. + // Check if tokens were encoded with the legacy encryption instead. + decoded_token = authenticator_->DecryptLegacyToken(encoded_token); + decoded_secret = authenticator_->DecryptLegacyToken(encoded_secret); + if (!decoded_token.length() || !decoded_secret.length()) + return false; + + pref_service->SetString(prefs::kOAuth1Token, + authenticator_->EncryptToken(decoded_token)); + pref_service->SetString(prefs::kOAuth1Secret, + authenticator_->EncryptToken(decoded_secret)); + } *token = decoded_token; *secret = decoded_secret; diff --git a/chrome/browser/chromeos/login/mock_authenticator.cc b/chrome/browser/chromeos/login/mock_authenticator.cc index 177f896..3a85f88 100644 --- a/chrome/browser/chromeos/login/mock_authenticator.cc +++ b/chrome/browser/chromeos/login/mock_authenticator.cc @@ -69,6 +69,11 @@ std::string MockAuthenticator::DecryptToken( return std::string(); } +std::string MockAuthenticator::DecryptLegacyToken( + const std::string& encrypted_token) { + return std::string(); +} + //////////////////////////////////////////////////////////////////////////////// // MockLoginUtils diff --git a/chrome/browser/chromeos/login/mock_authenticator.h b/chrome/browser/chromeos/login/mock_authenticator.h index 34c2c55..5bc1e6c 100644 --- a/chrome/browser/chromeos/login/mock_authenticator.h +++ b/chrome/browser/chromeos/login/mock_authenticator.h @@ -71,6 +71,8 @@ class MockAuthenticator : public Authenticator { virtual std::string DecryptToken(const std::string& encrypted_token); + virtual std::string DecryptLegacyToken(const std::string& encrypted_token); + virtual void VerifyOAuth1AccessToken(const std::string& oauth1_access_token, const std::string& oauth1_secret) {} diff --git a/chrome/browser/chromeos/login/parallel_authenticator.cc b/chrome/browser/chromeos/login/parallel_authenticator.cc index 74975dd..781f090 100644 --- a/chrome/browser/chromeos/login/parallel_authenticator.cc +++ b/chrome/browser/chromeos/login/parallel_authenticator.cc @@ -16,6 +16,7 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/synchronization/lock.h" +#include "chrome/browser/chromeos/cros/cert_library.h" #include "chrome/browser/chromeos/cros/cryptohome_library.h" #include "chrome/browser/chromeos/login/auth_response_handler.h" #include "chrome/browser/chromeos/login/authentication_notification_details.h" @@ -46,6 +47,37 @@ using file_util::PathExists; using file_util::ReadFile; using file_util::ReadFileToString; +namespace { + +const int kPassHashLen = 32; +const size_t kKeySize = 16; + +// Decrypts (AES) hex encoded encrypted token given |key| and |salt|. +std::string DecryptTokenWithKey( + crypto::SymmetricKey* key, + const std::string& salt, + const std::string& encrypted_token_hex) { + std::vector<uint8> encrypted_token_bytes; + if (!base::HexStringToBytes(encrypted_token_hex, &encrypted_token_bytes)) + return std::string(); + + std::string encrypted_token( + reinterpret_cast<char*>(encrypted_token_bytes.data()), + encrypted_token_bytes.size()); + crypto::Encryptor encryptor; + if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) + return std::string(); + + std::string nonce = salt.substr(0, kKeySize); + std::string token; + CHECK(encryptor.SetCounter(nonce)); + if (!encryptor.Decrypt(encrypted_token, &token)) + return std::string(); + return token; +} + +} // namespace + namespace chromeos { // static @@ -56,9 +88,6 @@ const int ParallelAuthenticator::kClientLoginTimeoutMs = 10000; // static const int ParallelAuthenticator::kLocalaccountRetryIntervalMs = 20; -const int kPassHashLen = 32; -const size_t kKeySize = 16; - ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer) : Authenticator(consumer), already_reported_success_(false), @@ -673,6 +702,15 @@ void ParallelAuthenticator::LoadSystemSalt() { CHECK_EQ(system_salt_.size() % 2, 0U); } +bool ParallelAuthenticator::LoadSupplementalUserKey() { + if (!supplemental_user_key_.get()) { + supplemental_user_key_.reset( + CrosLibrary::Get()->GetCertLibrary()->GetSupplementalUserKey()); + } + return supplemental_user_key_.get() != NULL; +} + + void ParallelAuthenticator::LoadLocalaccount(const std::string& filename) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); { @@ -704,13 +742,11 @@ void ParallelAuthenticator::SetLocalaccount(const std::string& new_name) { } std::string ParallelAuthenticator::EncryptToken(const std::string& token) { - // TODO(zelidrag): Replace salt with - scoped_ptr<crypto::SymmetricKey> key( - crypto::SymmetricKey::DeriveKeyFromPassword( - crypto::SymmetricKey::AES, UserSupplementalKeyAsAscii(), - SaltAsAscii(), 1000, 256)); + if (!LoadSupplementalUserKey()) + return std::string(); crypto::Encryptor encryptor; - if (!encryptor.Init(key.get(), crypto::Encryptor::CTR, std::string())) + if (!encryptor.Init(supplemental_user_key_.get(), crypto::Encryptor::CTR, + std::string())) return std::string(); std::string nonce = SaltAsAscii().substr(0, kKeySize); @@ -723,33 +759,24 @@ std::string ParallelAuthenticator::EncryptToken(const std::string& token) { reinterpret_cast<const void*>(encoded_token.data()), encoded_token.size())); } - std::string ParallelAuthenticator::DecryptToken( const std::string& encrypted_token_hex) { - std::vector<uint8> encrypted_token_bytes; - if (!base::HexStringToBytes(encrypted_token_hex, &encrypted_token_bytes)) + if (!LoadSupplementalUserKey()) return std::string(); + return DecryptTokenWithKey(supplemental_user_key_.get(), + SaltAsAscii(), + encrypted_token_hex); +} - std::string encrypted_token( - reinterpret_cast<char*>(encrypted_token_bytes.data()), - encrypted_token_bytes.size()); +std::string ParallelAuthenticator::DecryptLegacyToken( + const std::string& encrypted_token_hex) { scoped_ptr<crypto::SymmetricKey> key( crypto::SymmetricKey::DeriveKeyFromPassword( crypto::SymmetricKey::AES, UserSupplementalKeyAsAscii(), SaltAsAscii(), 1000, 256)); - crypto::Encryptor encryptor; - if (!encryptor.Init(key.get(), crypto::Encryptor::CTR, std::string())) - return std::string(); - - std::string nonce = SaltAsAscii().substr(0, kKeySize); - std::string token; - CHECK(encryptor.SetCounter(nonce)); - if (!encryptor.Decrypt(encrypted_token, &token)) - return std::string(); - return token; + return DecryptTokenWithKey(key.get(), SaltAsAscii(), encrypted_token_hex); } - std::string ParallelAuthenticator::HashPassword(const std::string& password) { // Get salt, ascii encode, update sha with that, then update with ascii // of password, then end. diff --git a/chrome/browser/chromeos/login/parallel_authenticator.h b/chrome/browser/chromeos/login/parallel_authenticator.h index dffc253..e640058 100644 --- a/chrome/browser/chromeos/login/parallel_authenticator.h +++ b/chrome/browser/chromeos/login/parallel_authenticator.h @@ -32,6 +32,10 @@ namespace base { class Lock; } +namespace crypto { +class SymmetricKey; +} + namespace chromeos { class LoginStatusConsumer; @@ -149,6 +153,8 @@ class ParallelAuthenticator : public Authenticator, const std::string& oauth1_secret) OVERRIDE; virtual std::string EncryptToken(const std::string& token) OVERRIDE; virtual std::string DecryptToken(const std::string& encrypted_token) OVERRIDE; + virtual std::string DecryptLegacyToken( + const std::string& encrypted_token) OVERRIDE; // AuthAttemptStateResolver overrides. // Attempts to make a decision and call back |consumer_| based on @@ -220,6 +226,9 @@ class ParallelAuthenticator : public Authenticator, // If we don't have the system salt yet, loads it from the CryptohomeLibrary. void LoadSystemSalt(); + // If we don't have supplemental_user_key_ yet, loads it from the NSS DB. + // Returns false if the key can not be loaded/created. + bool LoadSupplementalUserKey(); // If we haven't already, looks in a file called |filename| next to // the browser executable for a "localaccount" name, and retrieves it @@ -275,6 +284,7 @@ class ParallelAuthenticator : public Authenticator, std::string ascii_hash_; chromeos::CryptohomeBlob system_salt_; + scoped_ptr<crypto::SymmetricKey> supplemental_user_key_; // When the user has changed her password, but gives us the old one, we will // be able to mount her cryptohome, but online authentication will fail. diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc index aa41ba2..9020e7e 100644 --- a/crypto/nss_util.cc +++ b/crypto/nss_util.cc @@ -31,6 +31,10 @@ #include "base/threading/thread_restrictions.h" #include "crypto/scoped_nss_types.h" +#if defined(OS_CHROMEOS) +#include "crypto/symmetric_key.h" +#endif + // USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't // use NSS for crypto or certificate verification, and we don't use the NSS @@ -83,6 +87,15 @@ FilePath GetDefaultConfigDirectory() { return dir; } +#if defined(OS_CHROMEOS) +// Supplemental user key id. +unsigned char kSupplementalUserKeyId[] = { + 0xCC, 0x13, 0x19, 0xDE, 0x75, 0x5E, 0xFE, 0xFA, + 0x5E, 0x71, 0xD4, 0xA6, 0xFB, 0x00, 0x00, 0xCC +}; +#endif // defined(OS_CHROMEOS) + + // On non-chromeos platforms, return the default config directory. // On chromeos, return a read-only directory with fake root CA certs for testing // (which will not exist on non-testing images). These root CA certs are used @@ -288,6 +301,40 @@ class NSSInitSingleton { return FindSlotWithTokenName(token_name); } + SymmetricKey* GetSupplementalUserKey() { + DCHECK(chromeos_user_logged_in_); + + PK11SlotInfo* slot = NULL; + PK11SymKey* key = NULL; + SECItem keyID; + CK_MECHANISM_TYPE type = CKM_AES_ECB; + + slot = GetPublicNSSKeySlot(); + if (!slot) + goto done; + + if (PK11_Authenticate(slot, PR_TRUE, NULL) != SECSuccess) + goto done; + + keyID.type = siBuffer; + keyID.data = kSupplementalUserKeyId; + keyID.len = static_cast<int>(sizeof(kSupplementalUserKeyId)); + + // Find/generate AES key. + key = PK11_FindFixedKey(slot, type, &keyID, NULL); + if (!key) { + const int kKeySizeInBytes = 32; + key = PK11_TokenKeyGen(slot, type, NULL, + kKeySizeInBytes, + &keyID, PR_TRUE, NULL); + } + + done: + if (slot) + PK11_FreeSlot(slot); + + return key ? SymmetricKey::CreateFromKey(key) : NULL; + } #endif // defined(OS_CHROMEOS) @@ -702,6 +749,9 @@ bool EnsureTPMTokenReady() { return g_nss_singleton.Get().EnsureTPMTokenReady(); } +SymmetricKey* GetSupplementalUserKey() { + return g_nss_singleton.Get().GetSupplementalUserKey(); +} #endif // defined(OS_CHROMEOS) // TODO(port): Implement this more simply. We can convert by subtracting an diff --git a/crypto/nss_util.h b/crypto/nss_util.h index 2a2e8a5..b87b4a0 100644 --- a/crypto/nss_util.h +++ b/crypto/nss_util.h @@ -24,6 +24,8 @@ class Time; // initialization functions. namespace crypto { +class SymmetricKey; + #if defined(USE_NSS) // EarlySetupForNSSInit performs lightweight setup which must occur before the // process goes multithreaded. This does not initialise NSS. For test, see @@ -133,6 +135,14 @@ CRYPTO_EXPORT bool IsTPMTokenReady(); // Same as IsTPMTokenReady() except this attempts to initialize the token // if necessary. CRYPTO_EXPORT bool EnsureTPMTokenReady(); + +// Gets supplemental user key. Creates one in NSS database if it does not exist. +// The supplemental user key is used for AES encryption of user data that is +// stored and protected by cryptohome. This additional layer of encryption of +// provided to ensure that sensitive data wouldn't be exposed in plain text in +// case when an attacker would somehow gain access to all content within +// cryptohome. +CRYPTO_EXPORT SymmetricKey* GetSupplementalUserKey(); #endif // Convert a NSS PRTime value into a base::Time object. diff --git a/crypto/symmetric_key.h b/crypto/symmetric_key.h index 5bb92b7..500324e 100644 --- a/crypto/symmetric_key.h +++ b/crypto/symmetric_key.h @@ -71,6 +71,11 @@ class CRYPTO_EXPORT SymmetricKey { // carefully. bool GetRawKey(std::string* raw_key); +#if defined(OS_CHROMEOS) + // Creates symmetric key from NSS key. Takes over the ownership of |key|. + static SymmetricKey* CreateFromKey(PK11SymKey* key); +#endif + private: #if defined(USE_OPENSSL) SymmetricKey() {} diff --git a/crypto/symmetric_key_nss.cc b/crypto/symmetric_key_nss.cc index 9690265..546c457 100644 --- a/crypto/symmetric_key_nss.cc +++ b/crypto/symmetric_key_nss.cc @@ -120,6 +120,13 @@ bool SymmetricKey::GetRawKey(std::string* raw_key) { return true; } +#if defined(OS_CHROMEOS) +// static +SymmetricKey* SymmetricKey::CreateFromKey(PK11SymKey* key) { + return new SymmetricKey(key); +} +#endif + SymmetricKey::SymmetricKey(PK11SymKey* key) : key_(key) { DCHECK(key); } |