Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(676)

Unified Diff: components/gcm_driver/crypto/gcm_key_store_unittest.cc

Issue 1953273002: Add support to GCMKeyStore for multiple keys per app_id (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@iid6fixstore
Patch Set: Simplify Decrypt fallback by banning IID token & GCM reg from sharing same app_id Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/gcm_driver/crypto/gcm_key_store_unittest.cc
diff --git a/components/gcm_driver/crypto/gcm_key_store_unittest.cc b/components/gcm_driver/crypto/gcm_key_store_unittest.cc
index 114f7f30a56702f4cca7703c4b0e6d6915147f97..91a0ed21730ef196f7ffed38925c12949375b061 100644
--- a/components/gcm_driver/crypto/gcm_key_store_unittest.cc
+++ b/components/gcm_driver/crypto/gcm_key_store_unittest.cc
@@ -4,6 +4,8 @@
#include "components/gcm_driver/crypto/gcm_key_store.h"
+#include <string>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/scoped_temp_dir.h"
@@ -12,6 +14,7 @@
#include "base/test/histogram_tester.h"
#include "base/thread_task_runner_handle.h"
#include "components/gcm_driver/crypto/p256_key_util.h"
+#include "net/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gcm {
@@ -20,6 +23,8 @@ namespace {
const char kFakeAppId[] = "my_app_id";
const char kSecondFakeAppId[] = "my_other_app_id";
+const char kFakeAuthorizedEntity[] = "my_sender_id";
+const char kSecondFakeAuthorizedEntity[] = "my_other_sender_id";
class GCMKeyStoreTest : public ::testing::Test {
public:
@@ -49,8 +54,10 @@ class GCMKeyStoreTest : public ::testing::Test {
// Callback to use with GCMKeyStore::{GetKeys, CreateKeys} calls.
void GotKeys(KeyPair* pair_out, std::string* auth_secret_out,
const KeyPair& pair, const std::string& auth_secret) {
- *pair_out = pair;
- *auth_secret_out = auth_secret;
+ if (pair_out)
Peter Beverloo 2016/05/09 14:10:10 nit: Could the new tests just pass dummy strings,
johnme 2016/05/09 18:15:55 Done.
Peter Beverloo 2016/05/10 12:52:38 No? The statements + calls w/ nullptr still exist.
johnme 2016/05/10 13:24:45 Done (weird, I swear I typed this into my editor,
+ *pair_out = pair;
+ if (auth_secret_out)
+ *auth_secret_out = auth_secret;
}
protected:
@@ -73,10 +80,11 @@ TEST_F(GCMKeyStoreTest, EmptyByDefault) {
KeyPair pair;
std::string auth_secret;
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
base::RunLoop().RunUntilIdle();
@@ -91,10 +99,10 @@ TEST_F(GCMKeyStoreTest, EmptyByDefault) {
TEST_F(GCMKeyStoreTest, CreateAndGetKeys) {
KeyPair pair;
std::string auth_secret;
- gcm_key_store()->CreateKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
base::RunLoop().RunUntilIdle();
@@ -112,10 +120,11 @@ TEST_F(GCMKeyStoreTest, CreateAndGetKeys) {
KeyPair read_pair;
std::string read_auth_secret;
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &read_pair,
- &read_auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
base::RunLoop().RunUntilIdle();
@@ -127,17 +136,101 @@ TEST_F(GCMKeyStoreTest, CreateAndGetKeys) {
EXPECT_EQ(auth_secret, read_auth_secret);
- histogram_tester()->ExpectBucketCount(
- "GCM.Crypto.GetKeySuccessRate", 1, 1); // failure
+ histogram_tester()->ExpectBucketCount("GCM.Crypto.GetKeySuccessRate", 1,
+ 1); // success
+
+ // GetKey should also succeed if fallback_to_empty_authorized_entity is true
+ // (fallback should not occur, since an exact match is found).
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ true /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(read_pair.IsInitialized());
+
+ EXPECT_EQ(pair.type(), read_pair.type());
+ EXPECT_EQ(pair.private_key(), read_pair.private_key());
+ EXPECT_EQ(pair.public_key(), read_pair.public_key());
+
+ EXPECT_EQ(auth_secret, read_auth_secret);
+
+ histogram_tester()->ExpectBucketCount("GCM.Crypto.GetKeySuccessRate", 1,
+ 2); // another success
+}
+
+TEST_F(GCMKeyStoreTest, GetKeysFallback) {
+ KeyPair pair;
+ std::string auth_secret;
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, "" /* empty authorized entity for legacy GCM registration */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(pair.IsInitialized());
+ ASSERT_TRUE(pair.has_private_key());
+ ASSERT_TRUE(pair.has_public_key());
+
+ EXPECT_GT(pair.public_key().size(), 0u);
+ EXPECT_GT(pair.private_key().size(), 0u);
+
+ ASSERT_GT(auth_secret.size(), 0u);
+
+ histogram_tester()->ExpectBucketCount("GCM.Crypto.CreateKeySuccessRate", 1,
+ 1); // success
+
+ // GetKeys should fail when fallback_to_empty_authorized_entity is false, as
+ // there is not an exact match for kFakeAuthorizedEntity.
+ KeyPair read_pair;
+ std::string read_auth_secret;
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_FALSE(read_pair.IsInitialized());
+ EXPECT_FALSE(read_pair.has_type());
+ EXPECT_EQ(0u, read_auth_secret.size());
+
+ histogram_tester()->ExpectBucketCount("GCM.Crypto.GetKeySuccessRate", 0,
+ 1); // failure
+
+ // GetKey should succeed when fallback_to_empty_authorized_entity is true, as
+ // falling back to empty authorized entity will match the created key.
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ true /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(read_pair.IsInitialized());
+
+ EXPECT_EQ(pair.type(), read_pair.type());
+ EXPECT_EQ(pair.private_key(), read_pair.private_key());
+ EXPECT_EQ(pair.public_key(), read_pair.public_key());
+
+ EXPECT_EQ(auth_secret, read_auth_secret);
+
+ histogram_tester()->ExpectBucketCount("GCM.Crypto.GetKeySuccessRate", 1,
+ 1); // success
}
TEST_F(GCMKeyStoreTest, KeysPersistenceBetweenInstances) {
KeyPair pair;
std::string auth_secret;
- gcm_key_store()->CreateKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
base::RunLoop().RunUntilIdle();
@@ -153,10 +246,11 @@ TEST_F(GCMKeyStoreTest, KeysPersistenceBetweenInstances) {
KeyPair read_pair;
std::string read_auth_secret;
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &read_pair,
- &read_auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
base::RunLoop().RunUntilIdle();
@@ -173,10 +267,10 @@ TEST_F(GCMKeyStoreTest, KeysPersistenceBetweenInstances) {
TEST_F(GCMKeyStoreTest, CreateAndRemoveKeys) {
KeyPair pair;
std::string auth_secret;
- gcm_key_store()->CreateKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
base::RunLoop().RunUntilIdle();
@@ -184,27 +278,30 @@ TEST_F(GCMKeyStoreTest, CreateAndRemoveKeys) {
KeyPair read_pair;
std::string read_auth_secret;
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &read_pair,
- &read_auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(read_pair.IsInitialized());
EXPECT_TRUE(read_pair.has_type());
- gcm_key_store()->RemoveKeys(kFakeAppId, base::Bind(&base::DoNothing));
+ gcm_key_store()->RemoveKeys(kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&base::DoNothing));
base::RunLoop().RunUntilIdle();
histogram_tester()->ExpectBucketCount(
"GCM.Crypto.RemoveKeySuccessRate", 1, 1); // success
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &read_pair,
- &read_auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
base::RunLoop().RunUntilIdle();
@@ -214,13 +311,14 @@ TEST_F(GCMKeyStoreTest, CreateAndRemoveKeys) {
TEST_F(GCMKeyStoreTest, CreateAndRemoveKeysSynchronously) {
KeyPair pair;
std::string auth_secret;
- gcm_key_store()->CreateKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
// Continue synchronously, without running RunUntilIdle first.
- gcm_key_store()->RemoveKeys(kFakeAppId, base::Bind(&base::DoNothing));
+ gcm_key_store()->RemoveKeys(kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&base::DoNothing));
base::RunLoop().RunUntilIdle();
@@ -232,32 +330,115 @@ TEST_F(GCMKeyStoreTest, CreateAndRemoveKeysSynchronously) {
KeyPair read_pair;
std::string read_auth_secret;
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &read_pair,
- &read_auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(read_pair.IsInitialized());
}
+TEST_F(GCMKeyStoreTest, RemoveKeysWildcardAuthorizedEntity) {
+ KeyPair pair1, pair2, pair3;
+ std::string auth_secret1, auth_secret2, auth_secret3;
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair1,
+ &auth_secret1));
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kSecondFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair2,
+ &auth_secret2));
+ gcm_key_store()->CreateKeys(
+ kSecondFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair3,
+ &auth_secret3));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(pair1.IsInitialized());
+ ASSERT_TRUE(pair2.IsInitialized());
+ ASSERT_TRUE(pair3.IsInitialized());
+
+ KeyPair read_pair1, read_pair2, read_pair3;
+ std::string read_auth_secret1, read_auth_secret2, read_auth_secret3;
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair1,
+ &read_auth_secret1));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kSecondFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair2,
+ &read_auth_secret2));
+ gcm_key_store()->GetKeys(
+ kSecondFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair3,
+ &read_auth_secret3));
+
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(read_pair1.IsInitialized());
+ EXPECT_TRUE(read_pair1.has_type());
+ ASSERT_TRUE(read_pair2.IsInitialized());
+ EXPECT_TRUE(read_pair2.has_type());
+ ASSERT_TRUE(read_pair3.IsInitialized());
+ EXPECT_TRUE(read_pair3.has_type());
+
+ gcm_key_store()->RemoveKeys(kFakeAppId,
+ "*" /* instance_id_authorized_entity */,
+ base::Bind(&base::DoNothing));
+
+ base::RunLoop().RunUntilIdle();
+
+ histogram_tester()->ExpectBucketCount("GCM.Crypto.RemoveKeySuccessRate", 1,
+ 1); // success
+
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair1,
+ &read_auth_secret1));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kSecondFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair2,
+ &read_auth_secret2));
+ gcm_key_store()->GetKeys(
+ kSecondFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair3,
+ &read_auth_secret3));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(read_pair1.IsInitialized());
+ EXPECT_FALSE(read_pair2.IsInitialized());
+ ASSERT_TRUE(read_pair3.IsInitialized());
+ EXPECT_TRUE(read_pair3.has_type());
+}
+
TEST_F(GCMKeyStoreTest, GetKeysMultipleAppIds) {
KeyPair pair;
std::string auth_secret;
- gcm_key_store()->CreateKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(pair.IsInitialized());
- gcm_key_store()->CreateKeys(kSecondFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->CreateKeys(
+ kSecondFakeAppId, kSecondFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
base::RunLoop().RunUntilIdle();
@@ -265,10 +446,11 @@ TEST_F(GCMKeyStoreTest, GetKeysMultipleAppIds) {
KeyPair read_pair;
std::string read_auth_secret;
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &read_pair,
- &read_auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
base::RunLoop().RunUntilIdle();
@@ -279,10 +461,10 @@ TEST_F(GCMKeyStoreTest, GetKeysMultipleAppIds) {
TEST_F(GCMKeyStoreTest, SuccessiveCallsBeforeInitialization) {
KeyPair pair;
std::string auth_secret;
- gcm_key_store()->CreateKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &pair,
- &auth_secret));
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &pair,
+ &auth_secret));
// Deliberately do not run the message loop, so that the callback has not
// been resolved yet. The following EXPECT() ensures this.
@@ -290,10 +472,11 @@ TEST_F(GCMKeyStoreTest, SuccessiveCallsBeforeInitialization) {
KeyPair read_pair;
std::string read_auth_secret;
- gcm_key_store()->GetKeys(kFakeAppId,
- base::Bind(&GCMKeyStoreTest::GotKeys,
- base::Unretained(this), &read_pair,
- &read_auth_secret));
+ gcm_key_store()->GetKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ false /* fallback_to_empty_authorized_entity */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &read_pair,
+ &read_auth_secret));
EXPECT_FALSE(read_pair.IsInitialized());
@@ -305,6 +488,55 @@ TEST_F(GCMKeyStoreTest, SuccessiveCallsBeforeInitialization) {
EXPECT_TRUE(pair.IsInitialized());
}
+TEST_F(GCMKeyStoreTest, CannotShareAppIdFromGCMToInstanceID) {
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, "" /* empty authorized entity for GCM registration */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), nullptr,
+ nullptr));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_DEBUG_DFATAL(
+ {
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+ nullptr, nullptr));
+
+ base::RunLoop().RunUntilIdle();
+ },
+ "Instance ID tokens cannot share an app_id with a legacy GCM "
+ "registration");
+}
+
+TEST_F(GCMKeyStoreTest, CannotShareAppIdFromInstanceIDToGCM) {
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), nullptr,
+ nullptr));
+
+ base::RunLoop().RunUntilIdle();
+
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, kSecondFakeAuthorizedEntity,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this), nullptr,
+ nullptr));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_DEBUG_DFATAL(
+ {
+ gcm_key_store()->CreateKeys(
+ kFakeAppId, "" /* empty authorized entity for GCM registration */,
+ base::Bind(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+ nullptr, nullptr));
+
+ base::RunLoop().RunUntilIdle();
+ },
+ "Instance ID tokens cannot share an app_id with a legacy GCM "
+ "registration");
+}
+
} // namespace
} // namespace gcm

Powered by Google App Engine
This is Rietveld 408576698