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
This commit is contained in:
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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())
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -69,6 +69,11 @@ std::string MockAuthenticator::DecryptToken(
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string MockAuthenticator::DecryptLegacyToken(
|
||||
const std::string& encrypted_token) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MockLoginUtils
|
||||
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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() {}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user