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