OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 #ifndef CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_VALIDATOR_H_ | |
6 #define CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_VALIDATOR_H_ | |
7 | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/basictypes.h" | |
12 #include "base/bind.h" | |
13 #include "base/callback.h" | |
14 #include "base/memory/ref_counted.h" | |
15 #include "base/memory/scoped_ptr.h" | |
16 #include "base/sequenced_task_runner.h" | |
17 #include "base/time/time.h" | |
18 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h" | |
19 #include "policy/proto/cloud_policy.pb.h" | |
20 | |
21 namespace base { | |
22 class MessageLoopProxy; | |
23 } | |
24 | |
25 namespace google { | |
26 namespace protobuf { | |
27 class MessageLite; | |
28 } | |
29 } | |
30 | |
31 namespace enterprise_management { | |
32 class PolicyData; | |
33 class PolicyFetchResponse; | |
34 } | |
35 | |
36 namespace policy { | |
37 | |
38 // Helper class that implements the gory details of validating a policy blob. | |
39 // Since signature checks are expensive, validation can happen on a background | |
40 // thread. The pattern is to create a validator, configure its behavior through | |
41 // the ValidateXYZ() functions, and then call StartValidation(). Alternatively, | |
42 // RunValidation() can be used to perform validation on the current thread. | |
43 class CloudPolicyValidatorBase { | |
44 public: | |
45 // Validation result codes. These values are also used for UMA histograms; | |
46 // they must stay stable, and the UMA counters must be updated if new elements | |
47 // are appended at the end. | |
48 enum Status { | |
49 // Indicates successful validation. | |
50 VALIDATION_OK, | |
51 // Bad signature on the initial key. | |
52 VALIDATION_BAD_INITIAL_SIGNATURE, | |
53 // Bad signature. | |
54 VALIDATION_BAD_SIGNATURE, | |
55 // Policy blob contains error code. | |
56 VALIDATION_ERROR_CODE_PRESENT, | |
57 // Policy payload failed to decode. | |
58 VALIDATION_PAYLOAD_PARSE_ERROR, | |
59 // Unexpected policy type. | |
60 VALIDATION_WRONG_POLICY_TYPE, | |
61 // Unexpected settings entity id. | |
62 VALIDATION_WRONG_SETTINGS_ENTITY_ID, | |
63 // Time stamp from the future. | |
64 VALIDATION_BAD_TIMESTAMP, | |
65 // Token doesn't match. | |
66 VALIDATION_WRONG_TOKEN, | |
67 // Username doesn't match. | |
68 VALIDATION_BAD_USERNAME, | |
69 // Policy payload protobuf parse error. | |
70 VALIDATION_POLICY_PARSE_ERROR, | |
71 }; | |
72 | |
73 enum ValidateDMTokenOption { | |
74 // The policy must have a non-empty DMToken. | |
75 DM_TOKEN_REQUIRED, | |
76 | |
77 // The policy may have an empty or missing DMToken, if the expected token | |
78 // is also empty. | |
79 DM_TOKEN_NOT_REQUIRED, | |
80 }; | |
81 | |
82 enum ValidateTimestampOption { | |
83 // The policy must have a timestamp field and it should be checked against | |
84 // both the start and end times. | |
85 TIMESTAMP_REQUIRED, | |
86 | |
87 // The timestamp should only be compared vs the |not_before| value (this | |
88 // is appropriate for platforms with unreliable system times, where we want | |
89 // to ensure that fresh policy is newer than existing policy, but we can't | |
90 // do any other validation). | |
91 TIMESTAMP_NOT_BEFORE, | |
92 | |
93 // No timestamp field is required. | |
94 TIMESTAMP_NOT_REQUIRED, | |
95 }; | |
96 | |
97 virtual ~CloudPolicyValidatorBase(); | |
98 | |
99 // Validation status which can be read after completion has been signaled. | |
100 Status status() const { return status_; } | |
101 bool success() const { return status_ == VALIDATION_OK; } | |
102 | |
103 // The policy objects owned by the validator. These are scoped_ptr | |
104 // references, so ownership can be passed on once validation is complete. | |
105 scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() { | |
106 return policy_; | |
107 } | |
108 scoped_ptr<enterprise_management::PolicyData>& policy_data() { | |
109 return policy_data_; | |
110 } | |
111 | |
112 // Instructs the validator to check that the policy timestamp is not before | |
113 // |not_before| and not after |not_after| + grace interval. If | |
114 // |timestamp_option| is set to TIMESTAMP_REQUIRED, then the policy will fail | |
115 // validation if it does not have a timestamp field. | |
116 void ValidateTimestamp(base::Time not_before, | |
117 base::Time not_after, | |
118 ValidateTimestampOption timestamp_option); | |
119 | |
120 // Validates the username in the policy blob matches |expected_user|. | |
121 void ValidateUsername(const std::string& expected_user); | |
122 | |
123 // Validates the policy blob is addressed to |expected_domain|. This uses the | |
124 // domain part of the username field in the policy for the check. | |
125 void ValidateDomain(const std::string& expected_domain); | |
126 | |
127 // Makes sure the DM token on the policy matches |expected_token|. | |
128 // If |dm_token_option| is DM_TOKEN_REQUIRED, then the policy will fail | |
129 // validation if it does not have a non-empty request_token field. | |
130 void ValidateDMToken(const std::string& dm_token, | |
131 ValidateDMTokenOption dm_token_option); | |
132 | |
133 // Validates the policy type. | |
134 void ValidatePolicyType(const std::string& policy_type); | |
135 | |
136 // Validates the settings_entity_id value. | |
137 void ValidateSettingsEntityId(const std::string& settings_entity_id); | |
138 | |
139 // Validates that the payload can be decoded successfully. | |
140 void ValidatePayload(); | |
141 | |
142 // Verifies that the signature on the policy blob verifies against |key|. If | | |
143 // |allow_key_rotation| is true and there is a key rotation present in the | |
144 // policy blob, this checks the signature on the new key against |key| and the | |
145 // policy blob against the new key. | |
146 void ValidateSignature(const std::vector<uint8>& key, | |
147 bool allow_key_rotation); | |
148 | |
149 // Similar to StartSignatureVerification(), this checks the signature on the | |
150 // policy blob. However, this variant expects a new policy key set in the | |
151 // policy blob and makes sure the policy is signed using that key. This should | |
152 // be called at setup time when there is no existing policy key present to | |
153 // check against. | |
154 void ValidateInitialKey(); | |
155 | |
156 // Convenience helper that configures timestamp and token validation based on | |
157 // the current policy blob. |policy_data| may be NULL, in which case the | |
158 // timestamp validation will drop the lower bound. |dm_token_option| | |
159 // and |timestamp_option| have the same effect as the corresponding | |
160 // parameters for ValidateTimestamp() and ValidateDMToken(). | |
161 void ValidateAgainstCurrentPolicy( | |
162 const enterprise_management::PolicyData* policy_data, | |
163 ValidateTimestampOption timestamp_option, | |
164 ValidateDMTokenOption dm_token_option); | |
165 | |
166 // Immediately performs validation on the current thread. | |
167 void RunValidation(); | |
168 | |
169 protected: | |
170 // Create a new validator that checks |policy_response|. |payload| is the | |
171 // message that the policy payload will be parsed to, and it needs to stay | |
172 // valid for the lifetime of the validator. | |
173 CloudPolicyValidatorBase( | |
174 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, | |
175 google::protobuf::MessageLite* payload, | |
176 scoped_refptr<base::SequencedTaskRunner> background_task_runner); | |
177 | |
178 // Posts an asynchronous calls to PerformValidation, which will eventually | |
179 // report its result via |completion_callback|. | |
180 void PostValidationTask(const base::Closure& completion_callback); | |
181 | |
182 private: | |
183 // Internal flags indicating what to check. | |
184 enum ValidationFlags { | |
185 VALIDATE_TIMESTAMP = 1 << 0, | |
186 VALIDATE_USERNAME = 1 << 1, | |
187 VALIDATE_DOMAIN = 1 << 2, | |
188 VALIDATE_TOKEN = 1 << 3, | |
189 VALIDATE_POLICY_TYPE = 1 << 4, | |
190 VALIDATE_ENTITY_ID = 1 << 5, | |
191 VALIDATE_PAYLOAD = 1 << 6, | |
192 VALIDATE_SIGNATURE = 1 << 7, | |
193 VALIDATE_INITIAL_KEY = 1 << 8, | |
194 }; | |
195 | |
196 // Performs validation, called on a background thread. | |
197 static void PerformValidation( | |
198 scoped_ptr<CloudPolicyValidatorBase> self, | |
199 scoped_refptr<base::MessageLoopProxy> message_loop, | |
200 const base::Closure& completion_callback); | |
201 | |
202 // Reports completion to the |completion_callback_|. | |
203 static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self, | |
204 const base::Closure& completion_callback); | |
205 | |
206 // Invokes all the checks and reports the result. | |
207 void RunChecks(); | |
208 | |
209 // Helper functions implementing individual checks. | |
210 Status CheckTimestamp(); | |
211 Status CheckUsername(); | |
212 Status CheckDomain(); | |
213 Status CheckToken(); | |
214 Status CheckPolicyType(); | |
215 Status CheckEntityId(); | |
216 Status CheckPayload(); | |
217 Status CheckSignature(); | |
218 Status CheckInitialKey(); | |
219 | |
220 // Verifies the SHA1/RSA |signature| on |data| against |key|. | |
221 static bool VerifySignature(const std::string& data, | |
222 const std::string& key, | |
223 const std::string& signature); | |
224 | |
225 Status status_; | |
226 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_; | |
227 scoped_ptr<enterprise_management::PolicyData> policy_data_; | |
228 google::protobuf::MessageLite* payload_; | |
229 | |
230 int validation_flags_; | |
231 int64 timestamp_not_before_; | |
232 int64 timestamp_not_after_; | |
233 ValidateTimestampOption timestamp_option_; | |
234 ValidateDMTokenOption dm_token_option_; | |
235 std::string user_; | |
236 std::string domain_; | |
237 std::string token_; | |
238 std::string policy_type_; | |
239 std::string settings_entity_id_; | |
240 std::string key_; | |
241 bool allow_key_rotation_; | |
242 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; | |
243 | |
244 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase); | |
245 }; | |
246 | |
247 // A simple type-parameterized extension of CloudPolicyValidator that | |
248 // facilitates working with the actual protobuf payload type. | |
249 template<typename PayloadProto> | |
250 class CloudPolicyValidator : public CloudPolicyValidatorBase { | |
251 public: | |
252 typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)> | |
253 CompletionCallback; | |
254 | |
255 virtual ~CloudPolicyValidator() {} | |
256 | |
257 // Creates a new validator. | |
258 // |background_task_runner| is optional; if RunValidation() is used directly | |
259 // and StartValidation() is not used then it can be NULL. | |
260 static CloudPolicyValidator<PayloadProto>* Create( | |
261 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, | |
262 scoped_refptr<base::SequencedTaskRunner> background_task_runner) { | |
263 return new CloudPolicyValidator( | |
264 policy_response.Pass(), | |
265 scoped_ptr<PayloadProto>(new PayloadProto()), | |
266 background_task_runner); | |
267 } | |
268 | |
269 scoped_ptr<PayloadProto>& payload() { | |
270 return payload_; | |
271 } | |
272 | |
273 // Kicks off asynchronous validation. |completion_callback| is invoked when | |
274 // done. From this point on, the validator manages its own lifetime - this | |
275 // allows callers to provide a WeakPtr in the callback without leaking the | |
276 // validator. | |
277 void StartValidation(const CompletionCallback& completion_callback) { | |
278 PostValidationTask(base::Bind(completion_callback, this)); | |
279 } | |
280 | |
281 private: | |
282 CloudPolicyValidator( | |
283 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, | |
284 scoped_ptr<PayloadProto> payload, | |
285 scoped_refptr<base::SequencedTaskRunner> background_task_runner) | |
286 : CloudPolicyValidatorBase(policy_response.Pass(), | |
287 payload.get(), | |
288 background_task_runner), | |
289 payload_(payload.Pass()) {} | |
290 | |
291 scoped_ptr<PayloadProto> payload_; | |
292 | |
293 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator); | |
294 }; | |
295 | |
296 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings> | |
297 UserCloudPolicyValidator; | |
298 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData> | |
299 ComponentCloudPolicyValidator; | |
300 | |
301 } // namespace policy | |
302 | |
303 #endif // CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_VALIDATOR_H_ | |
OLD | NEW |