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

Side by Side Diff: chrome/browser/chromeos/network_settings/onc_validator.cc

Issue 10944009: Implementation of ONC signature, validator and normalizer. (Closed) Base URL: http://git.chromium.org/chromium/src.git@gperffix
Patch Set: Completed validator for complete ONC. Integrated into OncNetworkParser. Created 8 years, 1 month 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 unified diff | Download patch
OLDNEW
(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 #include "chrome/browser/chromeos/network_settings/onc_validator.h"
6
7 #include <string>
8
9 #include "base/logging.h"
10 #include "base/values.h"
11 #include "chrome/browser/chromeos/cros/onc_constants.h"
12 #include "chrome/browser/chromeos/network_settings/onc_signature.h"
13
14 namespace chromeos {
15 namespace onc {
16
17 Validator::Validator(
18 bool error_on_unknown_field,
19 bool error_on_wrong_recommended,
20 bool error_on_missing_field,
21 bool managed_onc)
22 : error_on_unknown_field_(error_on_unknown_field),
23 error_on_wrong_recommended_(error_on_wrong_recommended),
24 error_on_missing_field_(error_on_missing_field),
25 managed_onc_(managed_onc) {
26 }
27
28 Validator::~Validator() {
29 }
30
31 // static
32 scoped_ptr<Validator> Validator::CreateStrictValidator(bool managed_onc) {
33 return make_scoped_ptr(new Validator(true, true, true, managed_onc));
34 }
35
36 // static
37 scoped_ptr<Validator> Validator::CreateLiberalValidator(bool managed_onc) {
38 return make_scoped_ptr(new Validator(false, false, false, managed_onc));
39 }
40
41 scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
42 const OncValueSignature* object_signature,
43 const base::DictionaryValue& onc_object) {
44 CHECK(object_signature != NULL);
45 scoped_ptr<base::Value> result_value =
46 MapValue(*object_signature, onc_object);
47 base::DictionaryValue* result_dict = NULL;
48 if (result_value.get() != NULL) {
49 result_value.release()->GetAsDictionary(&result_dict);
50 CHECK(result_dict != NULL);
51 }
52
53 return make_scoped_ptr(result_dict);
54 }
55
56 scoped_ptr<base::Value> Validator::MapValue(
57 const OncValueSignature& signature,
58 const base::Value& onc_value) {
59 if (onc_value.GetType() != signature.onc_type) {
60 DVLOG(1) << "Wrong type. Expected " << signature.onc_type
61 << ", but found " << onc_value.GetType();
62 return scoped_ptr<base::Value>();
63 }
64
65 scoped_ptr<base::Value> repaired = Mapper::MapValue(signature, onc_value);
66 if (repaired.get() != NULL)
67 CHECK_EQ(repaired->GetType(), signature.onc_type);
68 return repaired.Pass();
69 }
70
71 scoped_ptr<base::DictionaryValue> Validator::MapObject(
72 const OncValueSignature& signature,
73 const base::DictionaryValue& onc_object) {
74 scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
75
76 bool valid;
77 if (&signature == &kNetworkConfigurationSignature)
78 valid = ValidateNetworkConfiguration(onc_object, repaired.get());
79 else if (&signature == &kEthernetSignature)
80 valid = ValidateEthernet(onc_object, repaired.get());
81 else if (&signature == &kIPConfigSignature)
82 valid = ValidateIPConfig(onc_object, repaired.get());
83 else if (&signature == &kWiFiSignature)
84 valid = ValidateWiFi(onc_object, repaired.get());
85 else if (&signature == &kVPNSignature)
86 valid = ValidateVPN(onc_object, repaired.get());
87 else if (&signature == &kIPsecSignature)
88 valid = ValidateIPsec(onc_object, repaired.get());
89 else if (&signature == &kOpenVPNSignature)
90 valid = ValidateOpenVPN(onc_object, repaired.get());
91 else if (&signature == &kCertificatePatternSignature)
92 valid = ValidateCertificatePattern(onc_object, repaired.get());
93 else if (&signature == &kProxySettingsSignature)
94 valid = ValidateProxySettings(onc_object, repaired.get());
95 else if (&signature == &kProxyLocationSignature)
96 valid = ValidateProxyLocation(onc_object, repaired.get());
97 else if (&signature == &kEAPSignature)
98 valid = ValidateEAP(onc_object, repaired.get());
99 else if (&signature == &kCertificateSignature)
100 valid = ValidateCertificate(onc_object, repaired.get());
101 else
102 valid = ValidateObjectDefault(signature, onc_object, repaired.get());
103
104 if (valid)
105 return repaired.Pass();
106 else
107 return scoped_ptr<base::DictionaryValue>();
108 }
109
110 bool Validator::ValidateObjectDefault(
111 const OncValueSignature& signature,
112 const base::DictionaryValue& onc_object,
113 base::DictionaryValue* result) {
114 bool found_unknown_field = false;
115 bool nested_error_occured = false;
116 MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
117 result);
118 if (nested_error_occured)
119 return false;
120
121 if (found_unknown_field) {
122 if (error_on_unknown_field_) {
123 DVLOG(1) << "Unknown field name. Aborting.";
124 return false;
125 }
126 DVLOG(1) << "Unknown field name. Ignoring.";
127 }
128
129 return ValidateRecommendedField(signature, result);
130 }
131
132 bool Validator::ValidateRecommendedField(
133 const OncValueSignature& object_signature,
134 base::DictionaryValue* result) {
135 CHECK(result != NULL);
136
137 scoped_ptr<base::ListValue> recommended;
138 {
139 base::Value* recommended_value;
140 // This remove passes ownership to |recommended_value|.
141 if (!result->RemoveWithoutPathExpansion(onc::kRecommended,
142 &recommended_value)) {
143 return true;
144 }
145 base::ListValue* recommended_list;
146 recommended_value->GetAsList(&recommended_list);
147 CHECK(recommended_list != NULL);
Mattias Nissler (ping if slow) 2012/11/02 10:10:00 Does this mean we'll crash if somebody feeds bad O
pneubeck (no reviews) 2012/11/05 12:04:48 This case should not occur as the type validation
Mattias Nissler (ping if slow) 2012/11/06 09:30:56 OK, makes sense.
148
149 recommended.reset(recommended_list);
150 }
151
152 if (!managed_onc_) {
Mattias Nissler (ping if slow) 2012/11/02 10:10:00 I would just drop this check. What additional bene
pneubeck (no reviews) 2012/11/05 12:04:48 At least, I would keep the message and the removal
153 DVLOG(1) << "Found kRecommended field in unmanaged ONC."
154 << (error_on_wrong_recommended_ ? " Aborting." : " Ignoring.");
155 return !error_on_wrong_recommended_;
156 }
157
158 scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue);
159 for (base::ListValue::iterator it = recommended->begin();
160 it != recommended->end(); ++it) {
161 std::string field_name;
162 if (!(*it)->GetAsString(&field_name)) {
163 NOTREACHED();
164 continue;
165 }
166
167 const OncFieldSignature* field_signature =
168 object_signature.GetFieldSignature(field_name);
169
170 bool found_error = false;
171 std::string error_cause;
172 if (field_signature == NULL) {
173 found_error = true;
174 error_cause = "unknown";
175 } else if (field_signature->value_signature->onc_type ==
176 base::Value::TYPE_DICTIONARY) {
177 found_error = true;
178 error_cause = "dictionary-typed";
179 }
180
181 if (found_error) {
182 DVLOG(1) << "Found " << error_cause << " field name '" << field_name
183 << "' in kRecommended array. "
184 << (error_on_wrong_recommended_ ? "Aborting." : "Ignoring.");
185 if (error_on_wrong_recommended_)
186 return false;
187 else
188 continue;
189 }
190
191 repaired_recommended->Append((*it)->DeepCopy());
192 }
193
194 result->Set(onc::kRecommended, repaired_recommended.release());
195 return true;
196 }
197
198 namespace {
199
200 bool RequireAnyOf(const std::string &actual, const std::string &v1,
Mattias Nissler (ping if slow) 2012/11/02 10:10:00 What's wrong with this: bool RequireAnyOf(const s
pneubeck (no reviews) 2012/11/05 12:04:48 Done.
201 const std::string &v2) {
202 if (actual == v1 || actual == v2)
203 return true;
204 DVLOG(1) << "Found " << actual << ", but expected one of "
205 << v1 << ", " << v2;
206 return false;
207 }
208
209 bool RequireAnyOf(const std::string &actual, const std::string &v1,
210 const std::string &v2, const std::string &v3) {
211 if (actual == v1 || actual == v2 || actual == v3)
212 return true;
213 DVLOG(1) << "Found " << actual << ", but expected one of "
214 << v1 << ", " << v2 << ", " << v3;
215 return false;
216 }
217
218 bool RequireAnyOf(const std::string &actual, const std::string &v1,
219 const std::string &v2, const std::string &v3,
220 const std::string &v4) {
221 if (actual == v1 || actual == v2 || actual == v3 || actual == v4)
222 return true;
223 DVLOG(1) << "Found " << actual << ", but expected one of "
224 << v1 << ", " << v2 << ", " << v3 << ", " << v4;
225 return false;
226 }
227
228 bool RequireAnyOf(const std::string &actual, const std::string &v1,
229 const std::string &v2, const std::string &v3,
230 const std::string &v4, const std::string &v5) {
231 if (actual == v1 || actual == v2 || actual == v3 || actual == v4 ||
232 actual == v5)
233 return true;
234 DVLOG(1) << "Found " << actual << ", but expected one of "
235 << v1 << ", " << v2 << ", " << v3 << ", " << v4 << ", " << v5;
236 return false;
237 }
238
239 bool RequireAnyOf(const std::string &actual, const std::string &v1,
240 const std::string &v2, const std::string &v3,
241 const std::string &v4, const std::string &v5,
242 const std::string &v6, const std::string &v7) {
243 if (actual == v1 || actual == v2 || actual == v3 || actual == v4 ||
244 actual == v5 || actual == v6 || actual == v7)
245 return true;
246 DVLOG(1) << "Found " << actual << ", but expected one of "
247 << v1 << ", " << v2 << ", " << v3 << ", " << v4 << ", " << v5 << ", "
248 << v6 << ", " << v7;
249 return false;
250 }
251
252 bool IsInRange(int actual, int lower_bound, int upper_bound) {
253 if (lower_bound <= actual && actual <= upper_bound)
254 return true;
255 DVLOG(1) << "Found " << actual << ", which is out of range [" << lower_bound
256 << ", " << upper_bound << "]";
257 return false;
258 }
259
260 bool RequireField(const base::DictionaryValue& dict, std::string key) {
261 if (dict.HasKey(key))
262 return true;
263 DVLOG(1) << "Required field " << key << " missing.";
264 return false;
265 }
266
267 } // namespace
268
269 bool Validator::ValidateNetworkConfiguration(
270 const base::DictionaryValue& onc_object,
271 base::DictionaryValue* result) {
272 if (!ValidateObjectDefault(kNetworkConfigurationSignature,
273 onc_object, result)) {
274 return false;
275 }
276
277 std::string type;
278 if (result->GetStringWithoutPathExpansion(kType, &type) &&
279 !RequireAnyOf(type, kEthernet, kVPN, kWiFi)) {
280 return false;
281 }
282
283 bool allRequiredExist = RequireField(*result, kGUID);
284
285 bool remove = false;
286 result->GetBooleanWithoutPathExpansion(kRemove, &remove);
287 if (!remove) {
288 if (!RequireField(*result, kName))
289 allRequiredExist = false;
Mattias Nissler (ping if slow) 2012/11/02 10:10:00 you could write all these as &=, but that's a matt
pneubeck (no reviews) 2012/11/05 12:04:48 Done.
290 if (!RequireField(*result, kType))
291 allRequiredExist = false;
292 if (!type.empty() && !RequireField(*result, type))
293 allRequiredExist = false;
294 }
295
296 return !error_on_missing_field_ || allRequiredExist;
297 }
298
299 bool Validator::ValidateEthernet(
300 const base::DictionaryValue& onc_object,
301 base::DictionaryValue* result) {
302 using namespace onc::ethernet;
303 if (!ValidateObjectDefault(kEthernetSignature, onc_object, result))
304 return false;
305
306 std::string auth;
307 if (result->GetStringWithoutPathExpansion(kAuthentication, &auth) &&
308 !RequireAnyOf(auth, kNone, k8021X)) {
309 return false;
310 }
311
312 bool allRequiredExist = true;
313 if (auth == k8021X && !RequireField(*result, kEAP))
314 allRequiredExist = false;
315
316 return !error_on_missing_field_ || allRequiredExist;
317 }
318
319 bool Validator::ValidateIPConfig(
320 const base::DictionaryValue& onc_object,
321 base::DictionaryValue* result) {
322 using namespace onc::ipconfig;
323 if (!ValidateObjectDefault(kIPConfigSignature, onc_object, result))
324 return false;
325
326 std::string type;
327 if (result->GetStringWithoutPathExpansion(kType, &type) &&
328 !RequireAnyOf(type, kIPv4, kIPv6)) {
329 return false;
330 }
331
332 int routing_prefix;
333 int lower_bound = 1;
334 // In case of missing type, choose higher upper_bound.
335 int upper_bound = (type == kIPv4) ? 32 : 128;
336 if (result->GetIntegerWithoutPathExpansion(kRoutingPrefix, &routing_prefix) &&
337 !IsInRange(routing_prefix, lower_bound, upper_bound)) {
338 return false;
339 }
340
341 bool allRequiredExist = RequireField(*result, kIPAddress) &&
342 RequireField(*result, kRoutingPrefix) &&
343 RequireField(*result, kType);
344
345 return !error_on_missing_field_ || allRequiredExist;
346 }
347
348 bool Validator::ValidateWiFi(
349 const base::DictionaryValue& onc_object,
350 base::DictionaryValue* result) {
351 using namespace onc::wifi;
352 if (!ValidateObjectDefault(kWiFiSignature, onc_object, result))
353 return false;
354
355 std::string security;
356 if (result->GetStringWithoutPathExpansion(kSecurity, &security) &&
357 !RequireAnyOf(security, kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK,
358 kWPA_EAP)) {
359 return false;
360 }
361
362 bool allRequiredExist = RequireField(*result, kSecurity) &&
363 RequireField(*result, kSSID);
364 if ((security == kWEP_8021X || security == kWPA_EAP) &&
365 !RequireField(*result, kEAP)) {
366 allRequiredExist = false;
367 } else if ((security == kWEP_PSK || security == kWPA_PSK) &&
368 !RequireField(*result, kPassphrase)) {
369 allRequiredExist = false;
370 }
371
372 return !error_on_missing_field_ || allRequiredExist;
373 }
374
375 bool Validator::ValidateVPN(
376 const base::DictionaryValue& onc_object,
377 base::DictionaryValue* result) {
378 using namespace vpn;
379 if (!ValidateObjectDefault(kVPNSignature, onc_object, result))
380 return false;
381
382 std::string type;
383 if (result->GetStringWithoutPathExpansion(kType, &type) &&
384 !RequireAnyOf(type, kIPsec, kTypeL2TP_IPsec, kOpenVPN)) {
385 return false;
386 }
387
388 bool allRequiredExist = RequireField(*result, kType);
389
390 if ((type == kOpenVPN && !RequireField(*result, kOpenVPN)) ||
391 (type == kIPsec && !RequireField(*result, kIPsec)) ||
392 (type == kTypeL2TP_IPsec && !RequireField(*result, kIPsec)) ||
393 (type == kTypeL2TP_IPsec && !RequireField(*result, kL2TP))) {
394 allRequiredExist = false;
395 }
396
397 return !error_on_missing_field_ || allRequiredExist;
398 }
399
400 bool Validator::ValidateIPsec(
401 const base::DictionaryValue& onc_object,
402 base::DictionaryValue* result) {
403 using namespace onc::vpn;
404 using namespace onc::certificate;
405 if (!ValidateObjectDefault(kIPsecSignature, onc_object, result))
406 return false;
407
408 std::string auth;
409 if (result->GetStringWithoutPathExpansion(kAuthenticationType, &auth) &&
410 !RequireAnyOf(auth, kPSK, kCert)) {
411 return false;
412 }
413
414 std::string cert_type;
415 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
416 !RequireAnyOf(cert_type, kRef, kPattern)) {
417 return false;
418 }
419
420 bool allRequiredExist = RequireField(*result, kAuthenticationType) &&
421 RequireField(*result, kIKEVersion);
422 if (auth == kCert && (!RequireField(*result, kClientCertType) ||
423 !RequireField(*result, kServerCARef))) {
424 allRequiredExist = false;
425 }
426 if (cert_type == kPattern && !RequireField(*result, kClientCertPattern))
427 allRequiredExist = false;
428 else if (cert_type == kRef && !RequireField(*result, kClientCertRef))
429 allRequiredExist = false;
430
431 return !error_on_missing_field_ || allRequiredExist;
432 }
433
434 bool Validator::ValidateOpenVPN(
435 const base::DictionaryValue& onc_object,
436 base::DictionaryValue* result) {
437 using namespace onc::vpn;
438 using namespace onc::openvpn;
439 using namespace onc::certificate;
440 if (!ValidateObjectDefault(kOpenVPNSignature, onc_object, result))
441 return false;
442
443 std::string auth_retry;
444 if (result->GetStringWithoutPathExpansion(kAuthRetry, &auth_retry) &&
445 !RequireAnyOf(auth_retry, openvpn::kNone, kInteract, kNoInteract )) {
446 return false;
447 }
448
449 std::string cert_type;
450 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
451 !RequireAnyOf(cert_type, onc::kNone, kRef, kPattern)) {
452 return false;
453 }
454
455 std::string cert_tls;
456 if (result->GetStringWithoutPathExpansion(kRemoteCertTLS, &cert_tls) &&
457 !RequireAnyOf(cert_tls, openvpn::kNone, openvpn::kServer)) {
458 return false;
459 }
460
461 bool allRequiredExist = RequireField(*result, kClientCertType);
462 if (cert_type == kPattern && !RequireField(*result, kClientCertPattern))
463 allRequiredExist = false;
464 else if (cert_type == kRef && !RequireField(*result, kClientCertRef))
465 allRequiredExist = false;
466
467 return !error_on_missing_field_ || allRequiredExist;
468 }
469
470 bool Validator::ValidateCertificatePattern(
471 const base::DictionaryValue& onc_object,
472 base::DictionaryValue* result) {
473 using namespace onc::certificate;
474 if (!ValidateObjectDefault(kCertificatePatternSignature, onc_object, result))
475 return false;
476
477 bool allRequiredExist = true;
478 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
479 !result->HasKey(kIssuerCARef)) {
480 allRequiredExist = false;
481 DVLOG(1) << "None of the fields " << kSubject << ", " << kIssuer << ", and "
482 << kIssuerCARef << " exists, but at least one is required.";
483 }
484
485 return !error_on_missing_field_ || allRequiredExist;
486 }
487
488 bool Validator::ValidateProxySettings(const base::DictionaryValue& onc_object,
489 base::DictionaryValue* result) {
490 using namespace onc::proxy;
491 if (!ValidateObjectDefault(kProxySettingsSignature, onc_object, result))
492 return false;
493
494 std::string type;
495 if (result->GetStringWithoutPathExpansion(kType, &type) &&
496 !RequireAnyOf(type, kDirect, kManual, kPAC, kWPAD)) {
497 return false;
498 }
499
500 bool allRequiredExist = RequireField(*result, kType);
501
502 if (type == kManual && !RequireField(*result, kManual))
503 allRequiredExist = false;
504 else if (type == kPAC && !RequireField(*result, kPAC))
505 allRequiredExist = false;
506
507 return !error_on_missing_field_ || allRequiredExist;
508 }
509
510 bool Validator::ValidateProxyLocation(const base::DictionaryValue& onc_object,
511 base::DictionaryValue* result) {
512 using namespace onc::proxy;
513 if (!ValidateObjectDefault(kProxyLocationSignature, onc_object, result))
514 return false;
515
516 bool allRequiredExist = RequireField(*result, kHost) &&
517 RequireField(*result, kPort);
518
519 return !error_on_missing_field_ || allRequiredExist;
520 }
521
522 bool Validator::ValidateEAP(const base::DictionaryValue& onc_object,
523 base::DictionaryValue* result) {
524 using namespace onc::eap;
525 using namespace onc::certificate;
526 if (!ValidateObjectDefault(kEAPSignature, onc_object, result))
527 return false;
528
529 std::string inner;
530 if (result->GetStringWithoutPathExpansion(kInner, &inner) &&
531 !RequireAnyOf(inner, kAutomatic, kMD5, kMSCHAPv2, kPAP)) {
532 return false;
533 }
534
535 std::string outer;
536 if (result->GetStringWithoutPathExpansion(kOuter, &outer) &&
537 !RequireAnyOf(outer, kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM,
538 kEAP_FAST, kEAP_AKA)) {
539 return false;
540 }
541
542 std::string cert_type;
543 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
544 !RequireAnyOf(cert_type, kRef, kPattern)) {
545 return false;
546 }
547
548 bool allRequiredExist = RequireField(*result, kOuter);
549
550 if (cert_type == kPattern && !RequireField(*result, kClientCertPattern))
551 allRequiredExist = false;
552 else if (cert_type == kRef && !RequireField(*result, kClientCertRef))
553 allRequiredExist = false;
554
555 return !error_on_missing_field_ || allRequiredExist;
556 }
557
558 bool Validator::ValidateCertificate(
559 const base::DictionaryValue& onc_object,
560 base::DictionaryValue* result) {
561 using namespace onc::certificate;
562 if (!ValidateObjectDefault(kCertificateSignature, onc_object, result))
563 return false;
564
565 std::string type;
566 if (result->GetStringWithoutPathExpansion(kType, &type) &&
567 !RequireAnyOf(type, kClient, kServer, kAuthority)) {
568 return false;
569 }
570
571 bool allRequiredExist = RequireField(*result, kGUID);
572
573 bool remove = false;
574 result->GetBooleanWithoutPathExpansion(kRemove, &remove);
575 if (!remove) {
576 if (!RequireField(*result, kType))
577 allRequiredExist = false;
578
579 if (type == kClient && !RequireField(*result, kPKCS12))
580 allRequiredExist = false;
581
582 if ((type == kServer || type == kAuthority) &&
583 !RequireField(*result, kX509)) {
584 allRequiredExist = false;
585 }
586 }
587
588 return !error_on_missing_field_ || allRequiredExist;
589 }
590
591 } // namespace onc
592 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698