summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-07 04:01:03 +0000
committerzelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-07 04:01:03 +0000
commit6e3d9a9cf7aec1dc9777c2860e39ee7751a3e004 (patch)
tree4aa823b32cdc4d026a15996a407f80f15913fee8
parent3f7af10d3e7d931500433326908d261333710b31 (diff)
downloadchromium_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.cc4
-rw-r--r--chrome/browser/chromeos/cros/cert_library.h7
-rw-r--r--chrome/browser/chromeos/login/authenticator.h3
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.cc5
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.h2
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc15
-rw-r--r--chrome/browser/chromeos/login/mock_authenticator.cc5
-rw-r--r--chrome/browser/chromeos/login/mock_authenticator.h2
-rw-r--r--chrome/browser/chromeos/login/parallel_authenticator.cc79
-rw-r--r--chrome/browser/chromeos/login/parallel_authenticator.h10
-rw-r--r--crypto/nss_util.cc50
-rw-r--r--crypto/nss_util.h10
-rw-r--r--crypto/symmetric_key.h5
-rw-r--r--crypto/symmetric_key_nss.cc7
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);
}