summaryrefslogtreecommitdiffstats
path: root/content/renderer
diff options
context:
space:
mode:
authoriclelland <iclelland@chromium.org>2016-02-12 12:22:20 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-12 20:24:07 +0000
commit17b143af6e640744583640b405531b410569dd73 (patch)
tree786f367e854fee48ef918f5e7ff7a1072ee7200b /content/renderer
parentefa9ef721be99f95f420258e467ee44d46ce041d (diff)
downloadchromium_src-17b143af6e640744583640b405531b410569dd73.zip
chromium_src-17b143af6e640744583640b405531b410569dd73.tar.gz
chromium_src-17b143af6e640744583640b405531b410569dd73.tar.bz2
[Experimental Framework] Move the trial token public key out of content and into the embedder.
In order to make the code changes easier to reason about, this is now part 2 of a two-part commit. Part 1: https://codereview.chromium.org/1680873002/ BUG=543220 Review URL: https://codereview.chromium.org/1653263005 Cr-Commit-Position: refs/heads/master@{#375244}
Diffstat (limited to 'content/renderer')
-rw-r--r--content/renderer/origin_trials/trial_token.cc16
-rw-r--r--content/renderer/origin_trials/trial_token.h3
-rw-r--r--content/renderer/origin_trials/trial_token_unittest.cc48
-rw-r--r--content/renderer/origin_trials/trial_token_validator.cc17
-rw-r--r--content/renderer/origin_trials/trial_token_validator.h4
-rw-r--r--content/renderer/origin_trials/trial_token_validator_unittest.cc140
6 files changed, 200 insertions, 28 deletions
diff --git a/content/renderer/origin_trials/trial_token.cc b/content/renderer/origin_trials/trial_token.cc
index 46624b6..5cf69ac 100644
--- a/content/renderer/origin_trials/trial_token.cc
+++ b/content/renderer/origin_trials/trial_token.cc
@@ -24,15 +24,6 @@ namespace {
// Version 1 is the only token version currently supported
const uint8_t kVersion1 = 1;
-// This is the default public key used for validating signatures.
-// TODO(iclelland): Move this to the embedder, and provide a mechanism to allow
-// for multiple signing keys. https://crbug.com/543220
-static const uint8_t kPublicKey[] = {
- 0x7c, 0xc4, 0xb8, 0x9a, 0x93, 0xba, 0x6e, 0xe2, 0xd0, 0xfd, 0x03,
- 0x1d, 0xfb, 0x32, 0x66, 0xc7, 0x3b, 0x72, 0xfd, 0x54, 0x3a, 0x07,
- 0x51, 0x14, 0x66, 0xaa, 0x02, 0x53, 0x4e, 0x33, 0xa1, 0x15,
-};
-
const char* kFieldSeparator = "|";
} // namespace
@@ -116,12 +107,11 @@ bool TrialToken::IsAppropriate(const std::string& origin,
return ValidateOrigin(origin) && ValidateFeatureName(feature_name);
}
-bool TrialToken::IsValid(const base::Time& now) const {
+bool TrialToken::IsValid(const base::Time& now,
+ const base::StringPiece& public_key) const {
// TODO(iclelland): Allow for multiple signing keys, and iterate over all
// active keys here. https://crbug.com/543220
- return ValidateDate(now) &&
- ValidateSignature(base::StringPiece(
- reinterpret_cast<const char*>(kPublicKey), arraysize(kPublicKey)));
+ return ValidateDate(now) && ValidateSignature(public_key);
}
bool TrialToken::ValidateOrigin(const std::string& origin) const {
diff --git a/content/renderer/origin_trials/trial_token.h b/content/renderer/origin_trials/trial_token.h
index c133bbb..7ad75df 100644
--- a/content/renderer/origin_trials/trial_token.h
+++ b/content/renderer/origin_trials/trial_token.h
@@ -44,7 +44,8 @@ class CONTENT_EXPORT TrialToken {
const std::string& featureName) const;
// Returns true if this token has a valid signature, and has not expired.
- bool IsValid(const base::Time& now) const;
+ bool IsValid(const base::Time& now,
+ const base::StringPiece& public_key) const;
uint8_t version() { return version_; }
std::string signature() { return signature_; }
diff --git a/content/renderer/origin_trials/trial_token_unittest.cc b/content/renderer/origin_trials/trial_token_unittest.cc
index 2a19db7..2552152 100644
--- a/content/renderer/origin_trials/trial_token_unittest.cc
+++ b/content/renderer/origin_trials/trial_token_unittest.cc
@@ -6,6 +6,7 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
@@ -30,6 +31,21 @@ const uint8_t kTestPublicKey[] = {
0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0,
};
+// This is a valid, but incorrect, public key for testing signatures against.
+// The corresponding private key is:
+//
+// 0x21, 0xee, 0xfa, 0x81, 0x6a, 0xff, 0xdf, 0xb8, 0xc1, 0xdd, 0x75,
+// 0x05, 0x04, 0x29, 0x68, 0x67, 0x60, 0x85, 0x91, 0xd0, 0x50, 0x16,
+// 0x0a, 0xcf, 0xa2, 0x37, 0xa3, 0x2e, 0x11, 0x7a, 0x17, 0x96, 0x50,
+// 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, 0x47,
+// 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, 0x3e,
+// 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca
+const uint8_t kTestPublicKey2[] = {
+ 0x50, 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c,
+ 0x47, 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51,
+ 0x3e, 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca,
+};
+
// This is a good trial token, signed with the above test private key.
const char* kSampleToken =
"1|UsEO0cNxoUtBnHDJdGPWTlXuLENjXcEIPL7Bs7sbvicPCcvAtyqhQuTJ9h/u1R3VZpWigtI+"
@@ -97,9 +113,12 @@ const size_t kNumInvalidTokens = arraysize(kInvalidTokens);
class TrialTokenTest : public testing::Test {
public:
TrialTokenTest()
- : public_key_(
+ : correct_public_key_(
base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey),
- arraysize(kTestPublicKey))) {}
+ arraysize(kTestPublicKey))),
+ incorrect_public_key_(
+ base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey2),
+ arraysize(kTestPublicKey2))) {}
protected:
bool ValidateOrigin(TrialToken* token, const char* origin) {
@@ -119,10 +138,14 @@ class TrialTokenTest : public testing::Test {
return token->ValidateSignature(public_key);
}
- const base::StringPiece& public_key() { return public_key_; };
+ const base::StringPiece& correct_public_key() { return correct_public_key_; }
+ const base::StringPiece& incorrect_public_key() {
+ return incorrect_public_key_;
+ }
private:
- base::StringPiece public_key_;
+ base::StringPiece correct_public_key_;
+ base::StringPiece incorrect_public_key_;
};
TEST_F(TrialTokenTest, ParseEmptyString) {
@@ -183,20 +206,27 @@ TEST_F(TrialTokenTest, TokenIsAppropriateForOriginAndFeature) {
TEST_F(TrialTokenTest, ValidateValidSignature) {
scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken);
ASSERT_TRUE(token);
- EXPECT_TRUE(ValidateSignature(token.get(), public_key()));
+ EXPECT_TRUE(ValidateSignature(token.get(), correct_public_key()));
}
TEST_F(TrialTokenTest, ValidateInvalidSignature) {
scoped_ptr<TrialToken> token = TrialToken::Parse(kInvalidSignatureToken);
ASSERT_TRUE(token);
- EXPECT_FALSE(ValidateSignature(token.get(), public_key()));
+ EXPECT_FALSE(ValidateSignature(token.get(), correct_public_key()));
+}
+
+TEST_F(TrialTokenTest, ValidateTokenWithCorrectKey) {
+ scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken);
+ ASSERT_TRUE(token);
+ EXPECT_TRUE(token->IsValid(base::Time::FromDoubleT(kValidTimestamp),
+ correct_public_key()));
}
-TEST_F(TrialTokenTest, ValidateSignatureOnWrongKey) {
+TEST_F(TrialTokenTest, ValidateSignatureWithIncorrectKey) {
scoped_ptr<TrialToken> token = TrialToken::Parse(kSampleToken);
ASSERT_TRUE(token);
- // Signature will be invalid if tested against the real public key
- EXPECT_FALSE(token->IsValid(base::Time::FromDoubleT(kValidTimestamp)));
+ EXPECT_FALSE(token->IsValid(base::Time::FromDoubleT(kValidTimestamp),
+ incorrect_public_key()));
}
TEST_F(TrialTokenTest, ValidateWhenNotExpired) {
diff --git a/content/renderer/origin_trials/trial_token_validator.cc b/content/renderer/origin_trials/trial_token_validator.cc
index bbdd857..1df8dc78 100644
--- a/content/renderer/origin_trials/trial_token_validator.cc
+++ b/content/renderer/origin_trials/trial_token_validator.cc
@@ -5,6 +5,8 @@
#include "content/renderer/origin_trials/trial_token_validator.h"
#include "base/time/time.h"
+#include "content/public/common/content_client.h"
+#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/origin_trials/trial_token.h"
namespace content {
@@ -15,10 +17,17 @@ TrialTokenValidator::~TrialTokenValidator() {}
bool TrialTokenValidator::validateToken(const blink::WebString& token,
const blink::WebString& origin,
const blink::WebString& featureName) {
- scoped_ptr<TrialToken> trialToken = TrialToken::Parse(token.utf8());
- return trialToken &&
- trialToken->IsAppropriate(origin.utf8(), featureName.utf8()) &&
- trialToken->IsValid(base::Time::Now());
+ scoped_ptr<TrialToken> trial_token = TrialToken::Parse(token.utf8());
+
+ ContentClient* content_client = GetContentClient();
+ CHECK(content_client);
+
+ base::StringPiece public_key =
+ content_client->renderer()->GetOriginTrialPublicKey();
+
+ return !public_key.empty() && trial_token &&
+ trial_token->IsAppropriate(origin.utf8(), featureName.utf8()) &&
+ trial_token->IsValid(base::Time::Now(), public_key);
}
} // namespace content
diff --git a/content/renderer/origin_trials/trial_token_validator.h b/content/renderer/origin_trials/trial_token_validator.h
index 6afd01b..a0ce6c2 100644
--- a/content/renderer/origin_trials/trial_token_validator.h
+++ b/content/renderer/origin_trials/trial_token_validator.h
@@ -6,6 +6,7 @@
#define CONTENT_RENDERER_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_
#include <string>
+#include "content/common/content_export.h"
#include "third_party/WebKit/public/platform/WebTrialTokenValidator.h"
namespace content {
@@ -14,7 +15,8 @@ namespace content {
// to validate tokens to enable experimental features.
//
// This class is thread-safe.
-class TrialTokenValidator : public blink::WebTrialTokenValidator {
+class CONTENT_EXPORT TrialTokenValidator
+ : public NON_EXPORTED_BASE(blink::WebTrialTokenValidator) {
public:
TrialTokenValidator();
~TrialTokenValidator() override;
diff --git a/content/renderer/origin_trials/trial_token_validator_unittest.cc b/content/renderer/origin_trials/trial_token_validator_unittest.cc
new file mode 100644
index 0000000..2bdb8883
--- /dev/null
+++ b/content/renderer/origin_trials/trial_token_validator_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/origin_trials/trial_token_validator.h"
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+// This is a sample public key for testing the API. The corresponding private
+// key (use this to generate new samples for this test file) is:
+//
+// 0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13,
+// 0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba,
+// 0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75,
+// 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a,
+// 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64,
+// 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0
+const uint8_t kTestPublicKey[] = {
+ 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2,
+ 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f,
+ 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0,
+};
+
+// 0x21, 0xee, 0xfa, 0x81, 0x6a, 0xff, 0xdf, 0xb8, 0xc1, 0xdd, 0x75,
+// 0x05, 0x04, 0x29, 0x68, 0x67, 0x60, 0x85, 0x91, 0xd0, 0x50, 0x16,
+// 0x0a, 0xcf, 0xa2, 0x37, 0xa3, 0x2e, 0x11, 0x7a, 0x17, 0x96, 0x50,
+// 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c, 0x47,
+// 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51, 0x3e,
+// 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca
+const uint8_t kTestPublicKey2[] = {
+ 0x50, 0x07, 0x4d, 0x76, 0x55, 0x56, 0x42, 0x17, 0x2d, 0x8a, 0x9c,
+ 0x47, 0x96, 0x25, 0xda, 0x70, 0xaa, 0xb9, 0xfd, 0x53, 0x5d, 0x51,
+ 0x3e, 0x16, 0xab, 0xb4, 0x86, 0xea, 0xf3, 0x35, 0xc6, 0xca,
+};
+
+// This is a good trial token, signed with the above test private key.
+// TODO(iclelland): This token expires in 2033. Update it or find a way
+// to autogenerate it before then.
+const char kSampleToken[] =
+ "1|w694328Rl8l2vd96nkbAumpwvOOnvhWTj9/pfBRkvcWMDAsmiMEhZGEPzdBRy5Yao6il5qC"
+ "OyS6Ah7uuHf7JAQ==|https://valid.example.com|Frobulate|2000000000";
+
+// The token should be valid for this origin and for this feature.
+const char kAppropriateOrigin[] = "https://valid.example.com";
+const char kAppropriateFeatureName[] = "Frobulate";
+
+const char kInappropriateFeatureName[] = "Grokalyze";
+const char kInappropriateOrigin[] = "https://invalid.example.com";
+const char kInsecureOrigin[] = "http://valid.example.com";
+
+// Well-formed trial token with an invalid signature.
+const char kInvalidSignatureToken[] =
+ "1|CO8hDne98QeFeOJ0DbRZCBN3uE0nyaPgaLlkYhSWnbRoDfEAg+TXELaYfQPfEvKYFauBg/h"
+ "nxmba765hz0mXMc==|https://valid.example.com|Frobulate|2000000000";
+
+// Well-formed, but expired, trial token. (Expired in 2001)
+const char kExpiredToken[] =
+ "1|Vtzq/H0qMxsMXPThIgGEvI13d3Fd8K3W11/0E+FrJJXqBpx6n/dFkeFkEUsPaP3KeT8PCPF"
+ "1zpZ7kVgWYRLpAA==|https://valid.example.com|Frobulate|1000000000";
+
+const char kUnparsableToken[] = "abcde";
+
+class TestContentRendererClient : public content::ContentRendererClient {
+ public:
+ base::StringPiece GetOriginTrialPublicKey() override {
+ return base::StringPiece(reinterpret_cast<const char*>(key_),
+ arraysize(kTestPublicKey));
+ }
+ void SetOriginTrialPublicKey(const uint8_t* key) { key_ = key; }
+ const uint8_t* key_ = nullptr;
+};
+
+} // namespace
+
+class TrialTokenValidatorTest : public testing::Test {
+ public:
+ TrialTokenValidatorTest() {
+ SetPublicKey(kTestPublicKey);
+ SetRendererClientForTesting(&test_content_renderer_client_);
+ }
+
+ void SetPublicKey(const uint8_t* key) {
+ test_content_renderer_client_.SetOriginTrialPublicKey(key);
+ }
+
+ TrialTokenValidator trial_token_validator_;
+
+ private:
+ TestContentRendererClient test_content_renderer_client_;
+};
+
+TEST_F(TrialTokenValidatorTest, ValidateValidToken) {
+ EXPECT_TRUE(trial_token_validator_.validateToken(
+ kSampleToken, kAppropriateOrigin, kAppropriateFeatureName));
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateInappropriateOrigin) {
+ EXPECT_FALSE(TrialTokenValidator().validateToken(
+ kSampleToken, kInappropriateOrigin, kAppropriateFeatureName));
+ EXPECT_FALSE(TrialTokenValidator().validateToken(
+ kSampleToken, kInsecureOrigin, kAppropriateFeatureName));
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateInappropriateFeature) {
+ EXPECT_FALSE(TrialTokenValidator().validateToken(
+ kSampleToken, kAppropriateOrigin, kInappropriateFeatureName));
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateInvalidSignature) {
+ EXPECT_FALSE(TrialTokenValidator().validateToken(
+ kInvalidSignatureToken, kAppropriateOrigin, kAppropriateFeatureName));
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateUnparsableToken) {
+ EXPECT_FALSE(TrialTokenValidator().validateToken(
+ kUnparsableToken, kAppropriateOrigin, kAppropriateFeatureName));
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateExpiredToken) {
+ EXPECT_FALSE(TrialTokenValidator().validateToken(
+ kExpiredToken, kAppropriateOrigin, kAppropriateFeatureName));
+}
+
+TEST_F(TrialTokenValidatorTest, ValidateValidTokenWithIncorrectKey) {
+ SetPublicKey(kTestPublicKey2);
+ EXPECT_FALSE(TrialTokenValidator().validateToken(
+ kSampleToken, kAppropriateOrigin, kAppropriateFeatureName));
+}
+
+} // namespace content