OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/common/origin_trials/trial_token.h" | |
6 | |
7 #include <openssl/curve25519.h> | |
8 | |
9 #include <vector> | |
10 | |
11 #include "base/base64.h" | |
12 #include "base/macros.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/string_split.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "base/strings/utf_string_conversions.h" | |
17 #include "base/time/time.h" | |
18 #include "url/origin.h" | |
19 | |
20 namespace content { | |
21 | |
22 namespace { | |
23 | |
24 // This is the default public key used for validating signatures. | |
25 // TODO(iclelland): Move this to the embedder, and provide a mechanism to allow | |
26 // for multiple signing keys. https://crbug.com/543220 | |
27 static const uint8_t kPublicKey[] = { | |
28 0x7c, 0xc4, 0xb8, 0x9a, 0x93, 0xba, 0x6e, 0xe2, 0xd0, 0xfd, 0x03, | |
29 0x1d, 0xfb, 0x32, 0x66, 0xc7, 0x3b, 0x72, 0xfd, 0x54, 0x3a, 0x07, | |
30 0x51, 0x14, 0x66, 0xaa, 0x02, 0x53, 0x4e, 0x33, 0xa1, 0x15, | |
31 }; | |
32 | |
33 const char* kFieldSeparator = "|"; | |
34 | |
35 } // namespace | |
36 | |
37 TrialToken::~TrialToken() {} | |
38 | |
39 scoped_ptr<TrialToken> TrialToken::Parse(const std::string& token_text) { | |
40 if (token_text.empty()) { | |
41 return nullptr; | |
42 } | |
43 | |
44 // A valid token should resemble: | |
45 // signature|origin|feature_name|expiry_timestamp | |
46 // TODO(iclelland): Add version code to token format to identify key algo | |
47 // https://crbug.com/570684 | |
48 std::vector<std::string> parts = SplitString( | |
49 token_text, kFieldSeparator, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | |
50 if (parts.size() != 4) { | |
51 return nullptr; | |
52 } | |
53 | |
54 const std::string& signature = parts[0]; | |
55 const std::string& origin_string = parts[1]; | |
56 const std::string& feature_name = parts[2]; | |
57 const std::string& expiry_string = parts[3]; | |
58 | |
59 uint64_t expiry_timestamp; | |
60 if (!base::StringToUint64(expiry_string, &expiry_timestamp)) { | |
61 return nullptr; | |
62 } | |
63 | |
64 // Ensure that the origin is a valid (non-unique) origin URL | |
65 GURL origin_url(origin_string); | |
66 if (url::Origin(origin_url).unique()) { | |
67 return nullptr; | |
68 } | |
69 | |
70 // signed data is (origin + "|" + feature_name + "|" + expiry). | |
71 std::string data = token_text.substr(signature.length() + 1); | |
72 | |
73 return make_scoped_ptr(new TrialToken(signature, data, origin_url, | |
74 feature_name, expiry_timestamp)); | |
75 } | |
76 | |
77 TrialToken::TrialToken(const std::string& signature, | |
78 const std::string& data, | |
79 const GURL& origin, | |
80 const std::string& feature_name, | |
81 uint64_t expiry_timestamp) | |
82 : signature_(signature), | |
83 data_(data), | |
84 origin_(origin), | |
85 feature_name_(feature_name), | |
86 expiry_timestamp_(expiry_timestamp) {} | |
87 | |
88 bool TrialToken::IsAppropriate(const std::string& origin, | |
89 const std::string& feature_name) const { | |
90 return ValidateOrigin(origin) && ValidateFeatureName(feature_name); | |
91 } | |
92 | |
93 bool TrialToken::IsValid(const base::Time& now) const { | |
94 // TODO(iclelland): Allow for multiple signing keys, and iterate over all | |
95 // active keys here. https://crbug.com/543220 | |
96 return ValidateDate(now) && | |
97 ValidateSignature(base::StringPiece( | |
98 reinterpret_cast<const char*>(kPublicKey), arraysize(kPublicKey))); | |
99 } | |
100 | |
101 bool TrialToken::ValidateOrigin(const std::string& origin) const { | |
102 return GURL(origin) == origin_; | |
103 } | |
104 | |
105 bool TrialToken::ValidateFeatureName(const std::string& feature_name) const { | |
106 return base::EqualsCaseInsensitiveASCII(feature_name, feature_name_); | |
107 } | |
108 | |
109 bool TrialToken::ValidateDate(const base::Time& now) const { | |
110 base::Time expiry_time = base::Time::FromDoubleT((double)expiry_timestamp_); | |
111 return expiry_time > now; | |
112 } | |
113 | |
114 bool TrialToken::ValidateSignature(const base::StringPiece& public_key) const { | |
115 return ValidateSignature(signature_, data_, public_key); | |
116 } | |
117 | |
118 // static | |
119 bool TrialToken::ValidateSignature(const std::string& signature_text, | |
120 const std::string& data, | |
121 const base::StringPiece& public_key) { | |
122 // Public key must be 32 bytes long for Ed25519. | |
123 CHECK_EQ(public_key.length(), 32UL); | |
124 | |
125 std::string signature; | |
126 // signature_text is base64-encoded; decode first. | |
127 if (!base::Base64Decode(signature_text, &signature)) { | |
128 return false; | |
129 } | |
130 | |
131 // Signature must be 64 bytes long | |
132 if (signature.length() != 64) { | |
133 return false; | |
134 } | |
135 | |
136 int result = ED25519_verify( | |
137 reinterpret_cast<const uint8_t*>(data.data()), data.length(), | |
138 reinterpret_cast<const uint8_t*>(signature.data()), | |
139 reinterpret_cast<const uint8_t*>(public_key.data())); | |
140 return (result != 0); | |
141 } | |
142 | |
143 } // namespace content | |
OLD | NEW |