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 "chromeos/network/onc/onc_validator.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <algorithm>
11 #include <utility>
12
13 #include "base/json/json_writer.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/notreached.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/string_util.h"
21 #include "base/values.h"
22 #include "chromeos/network/onc/onc_signature.h"
23 #include "components/crx_file/id_util.h"
24 #include "components/device_event_log/device_event_log.h"
25 #include "components/onc/onc_constants.h"
26
27 namespace chromeos {
28 namespace onc {
29
30 namespace {
31
32 // According to the IEEE 802.11 standard the SSID is a series of 0 to 32 octets.
33 const int kMaximumSSIDLengthInBytes = 32;
34
AddKeyToList(const char * key,base::Value * list)35 void AddKeyToList(const char* key, base::Value* list) {
36 base::Value key_value(key);
37 if (!base::Contains(list->GetList(), key_value))
38 list->Append(std::move(key_value));
39 }
40
GetStringFromDict(const base::Value & dict,const char * key)41 std::string GetStringFromDict(const base::Value& dict, const char* key) {
42 const base::Value* value = dict.FindKeyOfType(key, base::Value::Type::STRING);
43 return value ? value->GetString() : std::string();
44 }
45
FieldIsRecommended(const base::DictionaryValue & object,const std::string & field_name)46 bool FieldIsRecommended(const base::DictionaryValue& object,
47 const std::string& field_name) {
48 const base::Value* recommended =
49 object.FindKeyOfType(::onc::kRecommended, base::Value::Type::LIST);
50 return recommended &&
51 base::Contains(recommended->GetList(), base::Value(field_name));
52 }
53
FieldIsSetToValueOrRecommended(const base::DictionaryValue & object,const std::string & field_name,const base::Value & expected_value)54 bool FieldIsSetToValueOrRecommended(const base::DictionaryValue& object,
55 const std::string& field_name,
56 const base::Value& expected_value) {
57 const base::Value* actual_value = object.FindKey(field_name);
58 if (actual_value && expected_value == *actual_value)
59 return true;
60
61 return FieldIsRecommended(object, field_name);
62 }
63
64 } // namespace
65
Validator(bool error_on_unknown_field,bool error_on_wrong_recommended,bool error_on_missing_field,bool managed_onc,bool log_warnings)66 Validator::Validator(bool error_on_unknown_field,
67 bool error_on_wrong_recommended,
68 bool error_on_missing_field,
69 bool managed_onc,
70 bool log_warnings)
71 : error_on_unknown_field_(error_on_unknown_field),
72 error_on_wrong_recommended_(error_on_wrong_recommended),
73 error_on_missing_field_(error_on_missing_field),
74 managed_onc_(managed_onc),
75 log_warnings_(log_warnings),
76 onc_source_(::onc::ONC_SOURCE_NONE) {}
77
78 Validator::~Validator() = default;
79
ValidateAndRepairObject(const OncValueSignature * object_signature,const base::Value & onc_object,Result * result)80 std::unique_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
81 const OncValueSignature* object_signature,
82 const base::Value& onc_object,
83 Result* result) {
84 CHECK(object_signature);
85 *result = VALID;
86 bool error = false;
87 std::unique_ptr<base::Value> result_value =
88 MapValue(*object_signature, onc_object, &error);
89 if (error) {
90 *result = INVALID;
91 result_value.reset();
92 } else if (!validation_issues_.empty()) {
93 *result = VALID_WITH_WARNINGS;
94 }
95 // The return value should be NULL if, and only if, |result| equals INVALID.
96 DCHECK_EQ(!result_value, *result == INVALID);
97 return base::DictionaryValue::From(std::move(result_value));
98 }
99
MapValue(const OncValueSignature & signature,const base::Value & onc_value,bool * error)100 std::unique_ptr<base::Value> Validator::MapValue(
101 const OncValueSignature& signature,
102 const base::Value& onc_value,
103 bool* error) {
104 if (onc_value.type() != signature.onc_type) {
105 *error = true;
106 std::ostringstream msg;
107 msg << "Found value of type '" << base::Value::GetTypeName(onc_value.type())
108 << "', but type '" << base::Value::GetTypeName(signature.onc_type)
109 << "' is required.";
110 AddValidationIssue(true /* is_error */, msg.str());
111 return std::unique_ptr<base::Value>();
112 }
113
114 std::unique_ptr<base::Value> repaired =
115 Mapper::MapValue(signature, onc_value, error);
116 if (repaired)
117 CHECK_EQ(repaired->type(), signature.onc_type);
118 return repaired;
119 }
120
MapObject(const OncValueSignature & signature,const base::Value & onc_object,bool * error)121 std::unique_ptr<base::DictionaryValue> Validator::MapObject(
122 const OncValueSignature& signature,
123 const base::Value& onc_object,
124 bool* error) {
125 std::unique_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
126
127 bool valid = ValidateObjectDefault(signature, onc_object, repaired.get());
128 if (valid) {
129 if (&signature == &kToplevelConfigurationSignature) {
130 valid = ValidateToplevelConfiguration(repaired.get());
131 } else if (&signature == &kNetworkConfigurationSignature) {
132 valid = ValidateNetworkConfiguration(repaired.get());
133 } else if (&signature == &kEthernetSignature) {
134 valid = ValidateEthernet(repaired.get());
135 } else if (&signature == &kIPConfigSignature ||
136 &signature == &kSavedIPConfigSignature) {
137 valid = ValidateIPConfig(repaired.get());
138 } else if (&signature == &kWiFiSignature) {
139 valid = ValidateWiFi(repaired.get());
140 } else if (&signature == &kVPNSignature) {
141 valid = ValidateVPN(repaired.get());
142 } else if (&signature == &kIPsecSignature) {
143 valid = ValidateIPsec(repaired.get());
144 } else if (&signature == &kOpenVPNSignature) {
145 valid = ValidateOpenVPN(repaired.get());
146 } else if (&signature == &kThirdPartyVPNSignature) {
147 valid = ValidateThirdPartyVPN(repaired.get());
148 } else if (&signature == &kARCVPNSignature) {
149 valid = ValidateARCVPN(repaired.get());
150 } else if (&signature == &kVerifyX509Signature) {
151 valid = ValidateVerifyX509(repaired.get());
152 } else if (&signature == &kCertificatePatternSignature) {
153 valid = ValidateCertificatePattern(repaired.get());
154 } else if (&signature == &kGlobalNetworkConfigurationSignature) {
155 valid = ValidateGlobalNetworkConfiguration(repaired.get());
156 } else if (&signature == &kProxySettingsSignature) {
157 valid = ValidateProxySettings(repaired.get());
158 } else if (&signature == &kProxyLocationSignature) {
159 valid = ValidateProxyLocation(repaired.get());
160 } else if (&signature == &kEAPSignature) {
161 valid = ValidateEAP(repaired.get());
162 } else if (&signature == &kEAPSubjectAlternativeNameMatchSignature) {
163 valid = ValidateSubjectAlternativeNameMatch(repaired.get());
164 } else if (&signature == &kCertificateSignature) {
165 valid = ValidateCertificate(repaired.get());
166 } else if (&signature == &kScopeSignature) {
167 valid = ValidateScope(repaired.get());
168 } else if (&signature == &kTetherWithStateSignature) {
169 valid = ValidateTether(repaired.get());
170 }
171 // StaticIPConfig is not validated here, because its correctness depends
172 // on NetworkConfiguration's 'IPAddressConfigType', 'NameServersConfigType'
173 // and 'Recommended' fields. It's validated in
174 // ValidateNetworkConfiguration() instead.
175 }
176
177 if (valid)
178 return repaired;
179
180 DCHECK(!validation_issues_.empty());
181 *error = true;
182 return std::unique_ptr<base::DictionaryValue>();
183 }
184
MapField(const std::string & field_name,const OncValueSignature & object_signature,const base::Value & onc_value,bool * found_unknown_field,bool * error)185 std::unique_ptr<base::Value> Validator::MapField(
186 const std::string& field_name,
187 const OncValueSignature& object_signature,
188 const base::Value& onc_value,
189 bool* found_unknown_field,
190 bool* error) {
191 path_.push_back(field_name);
192 bool current_field_unknown = false;
193 std::unique_ptr<base::Value> result = Mapper::MapField(
194 field_name, object_signature, onc_value, ¤t_field_unknown, error);
195
196 DCHECK_EQ(field_name, path_.back());
197 path_.pop_back();
198
199 if (current_field_unknown) {
200 *found_unknown_field = true;
201 std::ostringstream msg;
202 msg << "Field name '" << field_name << "' is unknown.";
203 AddValidationIssue(error_on_unknown_field_, msg.str());
204 }
205
206 return result;
207 }
208
MapArray(const OncValueSignature & array_signature,const base::ListValue & onc_array,bool * nested_error)209 std::unique_ptr<base::ListValue> Validator::MapArray(
210 const OncValueSignature& array_signature,
211 const base::ListValue& onc_array,
212 bool* nested_error) {
213 bool nested_error_in_current_array = false;
214 std::unique_ptr<base::ListValue> result = Mapper::MapArray(
215 array_signature, onc_array, &nested_error_in_current_array);
216
217 // Drop individual networks and certificates instead of rejecting all of
218 // the configuration.
219 if (nested_error_in_current_array &&
220 &array_signature != &kNetworkConfigurationListSignature &&
221 &array_signature != &kCertificateListSignature) {
222 *nested_error = nested_error_in_current_array;
223 }
224 return result;
225 }
226
MapEntry(int index,const OncValueSignature & signature,const base::Value & onc_value,bool * error)227 std::unique_ptr<base::Value> Validator::MapEntry(
228 int index,
229 const OncValueSignature& signature,
230 const base::Value& onc_value,
231 bool* error) {
232 std::string index_as_string = base::NumberToString(index);
233 path_.push_back(index_as_string);
234 std::unique_ptr<base::Value> result =
235 Mapper::MapEntry(index, signature, onc_value, error);
236 DCHECK_EQ(index_as_string, path_.back());
237 path_.pop_back();
238 if (!result.get() && (&signature == &kNetworkConfigurationSignature ||
239 &signature == &kCertificateSignature)) {
240 std::ostringstream msg;
241 msg << "Entry at index '" << index_as_string
242 << "' has been removed because it contained errors.";
243 AddValidationIssue(false /* is_error */, msg.str());
244 }
245 return result;
246 }
247
ValidateObjectDefault(const OncValueSignature & signature,const base::Value & onc_object,base::DictionaryValue * result)248 bool Validator::ValidateObjectDefault(const OncValueSignature& signature,
249 const base::Value& onc_object,
250 base::DictionaryValue* result) {
251 bool found_unknown_field = false;
252 bool nested_error_occured = false;
253 MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
254 result);
255
256 if (found_unknown_field && error_on_unknown_field_) {
257 DVLOG(1) << "Unknown field names are errors: Aborting.";
258 return false;
259 }
260
261 if (nested_error_occured)
262 return false;
263
264 return ValidateRecommendedField(signature, result);
265 }
266
ValidateRecommendedField(const OncValueSignature & object_signature,base::DictionaryValue * result)267 bool Validator::ValidateRecommendedField(
268 const OncValueSignature& object_signature,
269 base::DictionaryValue* result) {
270 CHECK(result);
271
272 base::Optional<base::Value> recommended_value =
273 result->ExtractKey(::onc::kRecommended);
274 // This remove passes ownership to |recommended_value|.
275 if (!recommended_value) {
276 return true;
277 }
278
279 base::ListValue* recommended_list = nullptr;
280 recommended_value->GetAsList(&recommended_list);
281 DCHECK(recommended_list); // The types of field values are already verified.
282
283 if (!managed_onc_) {
284 std::ostringstream msg;
285 msg << "Found the field '" << ::onc::kRecommended
286 << "' in an unmanaged ONC";
287 AddValidationIssue(false /* is_error */, msg.str());
288 return true;
289 }
290
291 std::unique_ptr<base::ListValue> repaired_recommended(new base::ListValue);
292 for (const auto& entry : *recommended_list) {
293 std::string field_name;
294 if (!entry.GetAsString(&field_name)) {
295 NOTREACHED(); // The types of field values are already verified.
296 continue;
297 }
298
299 const OncFieldSignature* field_signature =
300 GetFieldSignature(object_signature, field_name);
301
302 bool found_error = false;
303 std::string error_cause;
304 if (!field_signature) {
305 found_error = true;
306 error_cause = "unknown";
307 } else if (field_signature->value_signature->onc_type ==
308 base::Value::Type::DICTIONARY) {
309 found_error = true;
310 error_cause = "dictionary-typed";
311 }
312
313 if (found_error) {
314 path_.push_back(::onc::kRecommended);
315 std::ostringstream msg;
316 msg << "The " << error_cause << " field '" << field_name
317 << "' cannot be recommended.";
318 AddValidationIssue(error_on_wrong_recommended_, msg.str());
319 path_.pop_back();
320 if (error_on_wrong_recommended_)
321 return false;
322 continue;
323 }
324
325 repaired_recommended->AppendString(field_name);
326 }
327
328 result->Set(::onc::kRecommended, std::move(repaired_recommended));
329 return true;
330 }
331
ValidateClientCertFields(bool allow_cert_type_none,base::DictionaryValue * result)332 bool Validator::ValidateClientCertFields(bool allow_cert_type_none,
333 base::DictionaryValue* result) {
334 std::vector<const char*> valid_cert_types = {::onc::client_cert::kRef,
335 ::onc::client_cert::kPattern,
336 ::onc::client_cert::kPKCS11Id};
337 if (allow_cert_type_none)
338 valid_cert_types.push_back(::onc::client_cert::kClientCertTypeNone);
339
340 std::string cert_type =
341 GetStringFromDict(*result, ::onc::client_cert::kClientCertType);
342
343 // TODO(https://crbug.com/1049955): Remove the client certificate type empty
344 // check. Ignored fields should be removed by normalizer before validating.
345 if (cert_type.empty())
346 return true;
347
348 if (!IsValidValue(cert_type, valid_cert_types))
349 return false;
350
351 bool all_required_exist = true;
352
353 if (cert_type == ::onc::client_cert::kPattern)
354 all_required_exist &=
355 RequireField(*result, ::onc::client_cert::kClientCertPattern);
356 else if (cert_type == ::onc::client_cert::kRef)
357 all_required_exist &=
358 RequireField(*result, ::onc::client_cert::kClientCertRef);
359 else if (cert_type == ::onc::client_cert::kPKCS11Id)
360 all_required_exist &=
361 RequireField(*result, ::onc::client_cert::kClientCertPKCS11Id);
362
363 return !error_on_missing_field_ || all_required_exist;
364 }
365
366 namespace {
367
JoinStringRange(const std::vector<const char * > & strings,const std::string & separator)368 std::string JoinStringRange(const std::vector<const char*>& strings,
369 const std::string& separator) {
370 std::vector<base::StringPiece> string_vector(strings.begin(), strings.end());
371 return base::JoinString(string_vector, separator);
372 }
373
374 } // namespace
375
IsInDevicePolicy(base::DictionaryValue * result,const std::string & field_name)376 bool Validator::IsInDevicePolicy(base::DictionaryValue* result,
377 const std::string& field_name) {
378 if (result->HasKey(field_name)) {
379 if (onc_source_ != ::onc::ONC_SOURCE_DEVICE_POLICY) {
380 std::ostringstream msg;
381 msg << "Field '" << field_name << "' is only allowed in a device policy.";
382 AddValidationIssue(true /* is_error */, msg.str());
383 return false;
384 }
385 }
386 return true;
387 }
388
IsValidValue(const std::string & field_value,const std::vector<const char * > & valid_values)389 bool Validator::IsValidValue(const std::string& field_value,
390 const std::vector<const char*>& valid_values) {
391 for (const char* it : valid_values) {
392 if (field_value == it)
393 return true;
394 }
395
396 std::ostringstream msg;
397 msg << "Found value '" << field_value << "', but expected one of the values ["
398 << JoinStringRange(valid_values, ", ") << "]";
399 AddValidationIssue(true /* is_error */, msg.str());
400 return false;
401 }
402
FieldExistsAndHasNoValidValue(const base::DictionaryValue & object,const std::string & field_name,const std::vector<const char * > & valid_values)403 bool Validator::FieldExistsAndHasNoValidValue(
404 const base::DictionaryValue& object,
405 const std::string& field_name,
406 const std::vector<const char*>& valid_values) {
407 std::string actual_value;
408 if (!object.GetStringWithoutPathExpansion(field_name, &actual_value))
409 return false;
410
411 path_.push_back(field_name);
412 const bool valid = IsValidValue(actual_value, valid_values);
413 path_.pop_back();
414 return !valid;
415 }
416
FieldExistsAndIsNotInRange(const base::DictionaryValue & object,const std::string & field_name,int lower_bound,int upper_bound)417 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
418 const std::string& field_name,
419 int lower_bound,
420 int upper_bound) {
421 int actual_value;
422 if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
423 (lower_bound <= actual_value && actual_value <= upper_bound)) {
424 return false;
425 }
426
427 path_.push_back(field_name);
428 std::ostringstream msg;
429 msg << "Found value '" << actual_value
430 << "', but expected a value in the range [" << lower_bound << ", "
431 << upper_bound << "] (boundaries inclusive)";
432 AddValidationIssue(true /* is_error */, msg.str());
433 path_.pop_back();
434 return true;
435 }
436
FieldExistsAndIsEmpty(const base::DictionaryValue & object,const std::string & field_name)437 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object,
438 const std::string& field_name) {
439 const base::Value* value = NULL;
440 if (!object.GetWithoutPathExpansion(field_name, &value))
441 return false;
442
443 std::string str;
444 const base::ListValue* list = NULL;
445 if (value->GetAsString(&str)) {
446 if (!str.empty())
447 return false;
448 } else if (value->GetAsList(&list)) {
449 if (!list->empty())
450 return false;
451 } else {
452 NOTREACHED();
453 return false;
454 }
455
456 path_.push_back(field_name);
457 std::ostringstream msg;
458 msg << "Found an empty string, but expected a non-empty string.";
459 AddValidationIssue(true /* is_error */, msg.str());
460 path_.pop_back();
461 return true;
462 }
463
FieldShouldExistOrBeRecommended(const base::DictionaryValue & object,const std::string & field_name)464 bool Validator::FieldShouldExistOrBeRecommended(
465 const base::DictionaryValue& object,
466 const std::string& field_name) {
467 if (object.HasKey(field_name) || FieldIsRecommended(object, field_name))
468 return true;
469
470 std::ostringstream msg;
471 msg << "Field " << field_name << " is not found, but expected either to be "
472 << "set or to be recommended.";
473 AddValidationIssue(error_on_missing_field_, msg.str());
474 return !error_on_missing_field_;
475 }
476
OnlyOneFieldSet(const base::DictionaryValue & object,const std::string & field_name1,const std::string & field_name2)477 bool Validator::OnlyOneFieldSet(const base::DictionaryValue& object,
478 const std::string& field_name1,
479 const std::string& field_name2) {
480 if (object.HasKey(field_name1) && object.HasKey(field_name2)) {
481 std::ostringstream msg;
482 msg << "At most one of '" << field_name1 << "' and '" << field_name2
483 << "' can be set.";
484 AddValidationIssue(true /* is_error */, msg.str());
485 return false;
486 }
487 return true;
488 }
489
ListFieldContainsValidValues(const base::DictionaryValue & object,const std::string & field_name,const std::vector<const char * > & valid_values)490 bool Validator::ListFieldContainsValidValues(
491 const base::DictionaryValue& object,
492 const std::string& field_name,
493 const std::vector<const char*>& valid_values) {
494 const base::ListValue* list = NULL;
495 if (object.GetListWithoutPathExpansion(field_name, &list)) {
496 path_.push_back(field_name);
497 for (const auto& entry : *list) {
498 std::string value;
499 if (!entry.GetAsString(&value)) {
500 NOTREACHED(); // The types of field values are already verified.
501 continue;
502 }
503 if (!IsValidValue(value, valid_values)) {
504 path_.pop_back();
505 return false;
506 }
507 }
508 path_.pop_back();
509 }
510 return true;
511 }
512
ValidateSSIDAndHexSSID(base::DictionaryValue * object)513 bool Validator::ValidateSSIDAndHexSSID(base::DictionaryValue* object) {
514 const std::string kInvalidLength = "Invalid length";
515
516 // Check SSID validity.
517 std::string ssid_string;
518 if (object->GetStringWithoutPathExpansion(::onc::wifi::kSSID, &ssid_string) &&
519 (ssid_string.size() <= 0 ||
520 ssid_string.size() > kMaximumSSIDLengthInBytes)) {
521 path_.push_back(::onc::wifi::kSSID);
522 std::ostringstream msg;
523 msg << kInvalidLength;
524 // If the HexSSID field is present, ignore errors in SSID because these
525 // might be caused by the usage of a non-UTF-8 encoding when the SSID
526 // field was automatically added (see FillInHexSSIDField).
527 if (!object->HasKey(::onc::wifi::kHexSSID)) {
528 AddValidationIssue(true /* is_error */, msg.str());
529 path_.pop_back();
530 return false;
531 }
532 AddValidationIssue(false /* is_error */, msg.str());
533 path_.pop_back();
534 }
535
536 // Check HexSSID validity.
537 std::string hex_ssid_string;
538 if (object->GetStringWithoutPathExpansion(::onc::wifi::kHexSSID,
539 &hex_ssid_string)) {
540 std::string decoded_ssid;
541 if (!base::HexStringToString(hex_ssid_string, &decoded_ssid)) {
542 path_.push_back(::onc::wifi::kHexSSID);
543 std::ostringstream msg;
544 msg << "Not a valid hex representation: '" << hex_ssid_string << "'";
545 AddValidationIssue(true /* is_error */, msg.str());
546 path_.pop_back();
547 return false;
548 }
549 if (decoded_ssid.size() <= 0 ||
550 decoded_ssid.size() > kMaximumSSIDLengthInBytes) {
551 path_.push_back(::onc::wifi::kHexSSID);
552 std::ostringstream msg;
553 msg << kInvalidLength;
554 AddValidationIssue(true /* is_error */, msg.str());
555 path_.pop_back();
556 return false;
557 }
558
559 // If both SSID and HexSSID are set, check whether they are consistent, i.e.
560 // HexSSID contains the UTF-8 encoding of SSID. If not, remove the SSID
561 // field.
562 if (ssid_string.length() > 0) {
563 if (ssid_string != decoded_ssid) {
564 path_.push_back(::onc::wifi::kSSID);
565 std::ostringstream msg;
566 msg << "Fields '" << ::onc::wifi::kSSID << "' and '"
567 << ::onc::wifi::kHexSSID << "' contain inconsistent values.";
568 AddValidationIssue(false /* is_error */, msg.str());
569 path_.pop_back();
570 object->RemoveKey(::onc::wifi::kSSID);
571 }
572 }
573 }
574 return true;
575 }
576
RequireField(const base::DictionaryValue & dict,const std::string & field_name)577 bool Validator::RequireField(const base::DictionaryValue& dict,
578 const std::string& field_name) {
579 if (dict.HasKey(field_name))
580 return true;
581
582 std::ostringstream msg;
583 msg << "The required field '" << field_name << "' is missing.";
584 AddValidationIssue(error_on_missing_field_, msg.str());
585 return false;
586 }
587
CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue & dict,const std::string & key_guid,std::set<std::string> * guids)588 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict,
589 const std::string& key_guid,
590 std::set<std::string>* guids) {
591 std::string guid;
592 if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) {
593 if (guids->count(guid) != 0) {
594 path_.push_back(key_guid);
595 std::ostringstream msg;
596 msg << "Found a duplicate GUID '" << guid << "'.";
597 AddValidationIssue(true /* is_error */, msg.str());
598 path_.pop_back();
599 return false;
600 }
601 guids->insert(guid);
602 }
603 return true;
604 }
605
IsGlobalNetworkConfigInUserImport(const base::Value & onc_object)606 bool Validator::IsGlobalNetworkConfigInUserImport(
607 const base::Value& onc_object) {
608 if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT &&
609 onc_object.FindKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) {
610 std::ostringstream msg;
611 msg << "Field '" << ::onc::toplevel_config::kGlobalNetworkConfiguration
612 << "' is prohibited in ONC user imports";
613 AddValidationIssue(true /* is_error */, msg.str());
614 return true;
615 }
616 return false;
617 }
618
ValidateToplevelConfiguration(base::DictionaryValue * result)619 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) {
620 const std::vector<const char*> valid_types = {
621 ::onc::toplevel_config::kUnencryptedConfiguration,
622 ::onc::toplevel_config::kEncryptedConfiguration};
623 if (FieldExistsAndHasNoValidValue(*result, ::onc::toplevel_config::kType,
624 valid_types))
625 return false;
626
627 if (IsGlobalNetworkConfigInUserImport(*result))
628 return false;
629
630 return true;
631 }
632
ValidateNetworkConfiguration(base::DictionaryValue * result)633 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) {
634 const std::string* onc_type =
635 result->FindStringKey(::onc::network_config::kType);
636 if (onc_type && *onc_type == ::onc::network_type::kWimaxDeprecated) {
637 AddValidationIssue(/*is_error=*/false, "WiMax is deprecated");
638 return true;
639 }
640
641 const std::vector<const char*> valid_types = {
642 ::onc::network_type::kEthernet, ::onc::network_type::kVPN,
643 ::onc::network_type::kWiFi, ::onc::network_type::kCellular,
644 ::onc::network_type::kTether,
645 };
646 const std::vector<const char*> valid_ipconfig_types = {
647 ::onc::network_config::kIPConfigTypeDHCP,
648 ::onc::network_config::kIPConfigTypeStatic};
649 if (FieldExistsAndHasNoValidValue(*result, ::onc::network_config::kType,
650 valid_types) ||
651 FieldExistsAndHasNoValidValue(*result,
652 ::onc::network_config::kIPAddressConfigType,
653 valid_ipconfig_types) ||
654 FieldExistsAndHasNoValidValue(
655 *result, ::onc::network_config::kNameServersConfigType,
656 valid_ipconfig_types) ||
657 FieldExistsAndIsEmpty(*result, ::onc::network_config::kGUID)) {
658 return false;
659 }
660
661 if (!CheckGuidIsUniqueAndAddToSet(*result, ::onc::network_config::kGUID,
662 &network_guids_))
663 return false;
664
665 bool all_required_exist = RequireField(*result, ::onc::network_config::kGUID);
666
667 bool remove = false;
668 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
669 if (!remove) {
670 all_required_exist &= RequireField(*result, ::onc::network_config::kName) &&
671 RequireField(*result, ::onc::network_config::kType);
672
673 if (!NetworkHasCorrectStaticIPConfig(result))
674 return false;
675
676 std::string type = GetStringFromDict(*result, ::onc::network_config::kType);
677
678 // Prohibit anything but WiFi, Ethernet and VPN for device-level policy
679 // (which corresponds to shared networks). See also
680 // http://crosbug.com/28741.
681 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY && !type.empty() &&
682 type != ::onc::network_type::kVPN &&
683 type != ::onc::network_type::kWiFi &&
684 type != ::onc::network_type::kEthernet) {
685 std::ostringstream msg;
686 msg << "Networks of type '" << type
687 << "' are prohibited in ONC device policies.";
688 AddValidationIssue(true /* is_error */, msg.str());
689 return false;
690 }
691 if (type == ::onc::network_type::kWiFi) {
692 all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi);
693 } else if (type == ::onc::network_type::kEthernet) {
694 all_required_exist &=
695 RequireField(*result, ::onc::network_config::kEthernet);
696 } else if (type == ::onc::network_type::kCellular) {
697 all_required_exist &=
698 RequireField(*result, ::onc::network_config::kCellular);
699 } else if (type == ::onc::network_type::kWimaxDeprecated) {
700 all_required_exist &=
701 RequireField(*result, ::onc::network_config::kWimaxDeprecated);
702 } else if (type == ::onc::network_type::kVPN) {
703 all_required_exist &= RequireField(*result, ::onc::network_config::kVPN);
704 } else if (type == ::onc::network_type::kTether) {
705 all_required_exist &=
706 RequireField(*result, ::onc::network_config::kTether);
707 }
708 }
709
710 return !error_on_missing_field_ || all_required_exist;
711 }
712
ValidateEthernet(base::DictionaryValue * result)713 bool Validator::ValidateEthernet(base::DictionaryValue* result) {
714 const std::vector<const char*> valid_authentications = {
715 ::onc::ethernet::kAuthenticationNone, ::onc::ethernet::k8021X};
716 if (FieldExistsAndHasNoValidValue(*result, ::onc::ethernet::kAuthentication,
717 valid_authentications)) {
718 return false;
719 }
720
721 bool all_required_exist = true;
722 std::string auth =
723 GetStringFromDict(*result, ::onc::ethernet::kAuthentication);
724 if (auth == ::onc::ethernet::k8021X)
725 all_required_exist &= RequireField(*result, ::onc::ethernet::kEAP);
726
727 return !error_on_missing_field_ || all_required_exist;
728 }
729
ValidateIPConfig(base::DictionaryValue * result,bool require_fields)730 bool Validator::ValidateIPConfig(base::DictionaryValue* result,
731 bool require_fields) {
732 const std::vector<const char*> valid_types = {::onc::ipconfig::kIPv4,
733 ::onc::ipconfig::kIPv6};
734 if (FieldExistsAndHasNoValidValue(*result, ::onc::ipconfig::kType,
735 valid_types))
736 return false;
737
738 std::string type = GetStringFromDict(*result, ::onc::ipconfig::kType);
739 int lower_bound = 1;
740 // In case of missing type, choose higher upper_bound.
741 int upper_bound = (type == ::onc::ipconfig::kIPv4) ? 32 : 128;
742 if (FieldExistsAndIsNotInRange(*result, ::onc::ipconfig::kRoutingPrefix,
743 lower_bound, upper_bound)) {
744 return false;
745 }
746
747 bool all_required_exist = true;
748 if (require_fields) {
749 all_required_exist &= RequireField(*result, ::onc::ipconfig::kIPAddress);
750 all_required_exist &=
751 RequireField(*result, ::onc::ipconfig::kRoutingPrefix);
752 all_required_exist &= RequireField(*result, ::onc::ipconfig::kGateway);
753 } else {
754 all_required_exist &=
755 FieldShouldExistOrBeRecommended(*result, ::onc::ipconfig::kIPAddress);
756 all_required_exist &= FieldShouldExistOrBeRecommended(
757 *result, ::onc::ipconfig::kRoutingPrefix);
758 all_required_exist &=
759 FieldShouldExistOrBeRecommended(*result, ::onc::ipconfig::kGateway);
760 }
761
762 return !error_on_missing_field_ || all_required_exist;
763 }
764
NetworkHasCorrectStaticIPConfig(base::DictionaryValue * network)765 bool Validator::NetworkHasCorrectStaticIPConfig(
766 base::DictionaryValue* network) {
767 bool must_have_ip_config = FieldIsSetToValueOrRecommended(
768 *network, ::onc::network_config::kIPAddressConfigType,
769 base::Value(::onc::network_config::kIPConfigTypeStatic));
770 bool must_have_nameservers = FieldIsSetToValueOrRecommended(
771 *network, ::onc::network_config::kNameServersConfigType,
772 base::Value(::onc::network_config::kIPConfigTypeStatic));
773
774 if (!must_have_ip_config && !must_have_nameservers)
775 return true;
776
777 if (!RequireField(*network, ::onc::network_config::kStaticIPConfig))
778 return false;
779
780 base::DictionaryValue* static_ip_config = nullptr;
781 network->GetDictionary(::onc::network_config::kStaticIPConfig,
782 &static_ip_config);
783 bool valid = true;
784 // StaticIPConfig should have all fields required by the corresponding
785 // IPAddressConfigType and NameServersConfigType values.
786 if (must_have_ip_config)
787 valid &= ValidateIPConfig(static_ip_config, false /* require_fields */);
788 if (must_have_nameservers)
789 valid &= FieldShouldExistOrBeRecommended(*static_ip_config,
790 ::onc::ipconfig::kNameServers);
791 return valid;
792 }
793
ValidateWiFi(base::DictionaryValue * result)794 bool Validator::ValidateWiFi(base::DictionaryValue* result) {
795 const std::vector<const char*> valid_securities = {
796 ::onc::wifi::kSecurityNone, ::onc::wifi::kWEP_PSK,
797 ::onc::wifi::kWEP_8021X, ::onc::wifi::kWPA_PSK, ::onc::wifi::kWPA_EAP};
798 if (FieldExistsAndHasNoValidValue(*result, ::onc::wifi::kSecurity,
799 valid_securities))
800 return false;
801
802 if (!ValidateSSIDAndHexSSID(result))
803 return false;
804
805 bool all_required_exist = RequireField(*result, ::onc::wifi::kSecurity);
806
807 // One of {kSSID, kHexSSID} must be present.
808 if (!result->HasKey(::onc::wifi::kSSID))
809 all_required_exist &= RequireField(*result, ::onc::wifi::kHexSSID);
810 if (!result->HasKey(::onc::wifi::kHexSSID))
811 all_required_exist &= RequireField(*result, ::onc::wifi::kSSID);
812
813 std::string security = GetStringFromDict(*result, ::onc::wifi::kSecurity);
814 if (security == ::onc::wifi::kWEP_8021X || security == ::onc::wifi::kWPA_EAP)
815 all_required_exist &= RequireField(*result, ::onc::wifi::kEAP);
816 else if (security == ::onc::wifi::kWEP_PSK ||
817 security == ::onc::wifi::kWPA_PSK)
818 all_required_exist &= RequireField(*result, ::onc::wifi::kPassphrase);
819
820 return !error_on_missing_field_ || all_required_exist;
821 }
822
ValidateVPN(base::DictionaryValue * result)823 bool Validator::ValidateVPN(base::DictionaryValue* result) {
824 std::vector<const char*> valid_types = {
825 ::onc::vpn::kIPsec,
826 ::onc::vpn::kTypeL2TP_IPsec,
827 ::onc::vpn::kOpenVPN,
828 };
829
830 if (!managed_onc_) {
831 valid_types.push_back(::onc::vpn::kThirdPartyVpn);
832 valid_types.push_back(::onc::vpn::kArcVpn);
833 }
834
835 if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, valid_types))
836 return false;
837
838 bool all_required_exist = RequireField(*result, ::onc::vpn::kType);
839 std::string type = GetStringFromDict(*result, ::onc::vpn::kType);
840 if (type == ::onc::vpn::kOpenVPN) {
841 all_required_exist &= RequireField(*result, ::onc::vpn::kOpenVPN);
842 } else if (type == ::onc::vpn::kIPsec) {
843 all_required_exist &= RequireField(*result, ::onc::vpn::kIPsec);
844 } else if (type == ::onc::vpn::kTypeL2TP_IPsec) {
845 all_required_exist &= RequireField(*result, ::onc::vpn::kIPsec) &&
846 RequireField(*result, ::onc::vpn::kL2TP);
847 } else if (type == ::onc::vpn::kThirdPartyVpn) {
848 all_required_exist &= RequireField(*result, ::onc::vpn::kThirdPartyVpn);
849 } else if (type == ::onc::vpn::kArcVpn) {
850 all_required_exist &= RequireField(*result, ::onc::vpn::kArcVpn);
851 }
852
853 return !error_on_missing_field_ || all_required_exist;
854 }
855
ValidateIPsec(base::DictionaryValue * result)856 bool Validator::ValidateIPsec(base::DictionaryValue* result) {
857 const std::vector<const char*> valid_authentications = {::onc::ipsec::kPSK,
858 ::onc::ipsec::kCert};
859 if (FieldExistsAndHasNoValidValue(*result, ::onc::ipsec::kAuthenticationType,
860 valid_authentications) ||
861 FieldExistsAndIsEmpty(*result, ::onc::ipsec::kServerCARefs)) {
862 return false;
863 }
864
865 if (!OnlyOneFieldSet(*result, ::onc::ipsec::kServerCARefs,
866 ::onc::ipsec::kServerCARef))
867 return false;
868
869 if (!ValidateClientCertFields(/*allow_cert_type_none=*/false, result))
870 return false;
871
872 bool all_required_exist =
873 RequireField(*result, ::onc::ipsec::kAuthenticationType) &&
874 RequireField(*result, ::onc::ipsec::kIKEVersion);
875 std::string auth =
876 GetStringFromDict(*result, ::onc::ipsec::kAuthenticationType);
877 bool has_server_ca_cert = result->HasKey(::onc::ipsec::kServerCARefs) ||
878 result->HasKey(::onc::ipsec::kServerCARef);
879 if (auth == ::onc::ipsec::kCert) {
880 all_required_exist &=
881 RequireField(*result, ::onc::client_cert::kClientCertType);
882 if (!has_server_ca_cert) {
883 all_required_exist = false;
884 std::ostringstream msg;
885 msg << "The required field '" << ::onc::ipsec::kServerCARefs
886 << "' is missing.";
887 AddValidationIssue(error_on_missing_field_, msg.str());
888 }
889 } else if (has_server_ca_cert) {
890 std::ostringstream msg;
891 msg << "Field '" << ::onc::ipsec::kServerCARefs << "' (or '"
892 << ::onc::ipsec::kServerCARef << "') can only be set if '"
893 << ::onc::ipsec::kAuthenticationType << "' is set to '"
894 << ::onc::ipsec::kCert << "'.";
895 AddValidationIssue(true /* is_error */, msg.str());
896 return false;
897 }
898
899 return !error_on_missing_field_ || all_required_exist;
900 }
901
ValidateOpenVPN(base::DictionaryValue * result)902 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) {
903 const std::vector<const char*> valid_auth_retry_values = {
904 ::onc::openvpn::kNone, ::onc::openvpn::kInteract,
905 ::onc::openvpn::kNoInteract};
906 const std::vector<const char*> valid_cert_tls_values = {
907 ::onc::openvpn::kNone, ::onc::openvpn::kServer};
908 const std::vector<const char*> valid_compression_algorithm_values = {
909 ::onc::openvpn_compression_algorithm::kFramingOnly,
910 ::onc::openvpn_compression_algorithm::kLz4,
911 ::onc::openvpn_compression_algorithm::kLz4V2,
912 ::onc::openvpn_compression_algorithm::kLzo,
913 ::onc::openvpn_compression_algorithm::kNone};
914 const std::vector<const char*> valid_user_auth_types = {
915 ::onc::openvpn_user_auth_type::kNone, ::onc::openvpn_user_auth_type::kOTP,
916 ::onc::openvpn_user_auth_type::kPassword,
917 ::onc::openvpn_user_auth_type::kPasswordAndOTP};
918
919 if (FieldExistsAndHasNoValidValue(*result, ::onc::openvpn::kAuthRetry,
920 valid_auth_retry_values) ||
921 FieldExistsAndHasNoValidValue(*result, ::onc::openvpn::kRemoteCertTLS,
922 valid_cert_tls_values) ||
923 FieldExistsAndHasNoValidValue(*result,
924 ::onc::openvpn::kCompressionAlgorithm,
925 valid_compression_algorithm_values) ||
926 FieldExistsAndHasNoValidValue(*result,
927 ::onc::openvpn::kUserAuthenticationType,
928 valid_user_auth_types) ||
929 FieldExistsAndIsEmpty(*result, ::onc::openvpn::kServerCARefs)) {
930 return false;
931 }
932
933 // ONC policy prevents the UI from setting properties that are not explicitly
934 // listed as 'recommended' (i.e. the default is 'enforced'). Historically
935 // the configuration UI ignored this restriction. In order to support legacy
936 // ONC configurations, add recommended entries for user authentication
937 // properties where appropriate.
938 if ((onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY ||
939 onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)) {
940 base::Value* recommended =
941 result->FindKeyOfType(::onc::kRecommended, base::Value::Type::LIST);
942 if (!recommended)
943 recommended = result->SetKey(::onc::kRecommended, base::ListValue());
944
945 // If kUserAuthenticationType is unspecified, allow Password and OTP.
946 if (!result->FindStringKey(::onc::openvpn::kUserAuthenticationType)) {
947 AddKeyToList(::onc::openvpn::kPassword, recommended);
948 AddKeyToList(::onc::openvpn::kOTP, recommended);
949 }
950
951 // If client cert type is not provided, empty, or 'None', allow client cert
952 // properties.
953 std::string client_cert_type =
954 GetStringFromDict(*result, ::onc::client_cert::kClientCertType);
955 if (client_cert_type.empty() ||
956 client_cert_type == ::onc::client_cert::kClientCertTypeNone) {
957 AddKeyToList(::onc::client_cert::kClientCertType, recommended);
958 AddKeyToList(::onc::client_cert::kClientCertPKCS11Id, recommended);
959 }
960 }
961
962 if (!OnlyOneFieldSet(*result, ::onc::openvpn::kServerCARefs,
963 ::onc::openvpn::kServerCARef))
964 return false;
965
966 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result))
967 return false;
968
969 bool all_required_exist =
970 RequireField(*result, ::onc::client_cert::kClientCertType);
971
972 return !error_on_missing_field_ || all_required_exist;
973 }
974
ValidateThirdPartyVPN(base::DictionaryValue * result)975 bool Validator::ValidateThirdPartyVPN(base::DictionaryValue* result) {
976 const bool all_required_exist =
977 RequireField(*result, ::onc::third_party_vpn::kExtensionID);
978
979 return !error_on_missing_field_ || all_required_exist;
980 }
981
ValidateARCVPN(base::DictionaryValue * result)982 bool Validator::ValidateARCVPN(base::DictionaryValue* result) {
983 const bool all_required_exist =
984 RequireField(*result, ::onc::arc_vpn::kTunnelChrome);
985
986 return !error_on_missing_field_ || all_required_exist;
987 }
988
ValidateVerifyX509(base::DictionaryValue * result)989 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) {
990 const std::vector<const char*> valid_types = {
991 ::onc::verify_x509::types::kName, ::onc::verify_x509::types::kNamePrefix,
992 ::onc::verify_x509::types::kSubject};
993
994 if (FieldExistsAndHasNoValidValue(*result, ::onc::verify_x509::kType,
995 valid_types))
996 return false;
997
998 bool all_required_exist = RequireField(*result, ::onc::verify_x509::kName);
999
1000 return !error_on_missing_field_ || all_required_exist;
1001 }
1002
ValidateCertificatePattern(base::DictionaryValue * result)1003 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) {
1004 bool all_required_exist = true;
1005 if (!result->HasKey(::onc::client_cert::kSubject) &&
1006 !result->HasKey(::onc::client_cert::kIssuer) &&
1007 !result->HasKey(::onc::client_cert::kIssuerCARef)) {
1008 all_required_exist = false;
1009 std::ostringstream msg;
1010 msg << "None of the fields '" << ::onc::client_cert::kSubject << "', '"
1011 << ::onc::client_cert::kIssuer << "', and '"
1012 << ::onc::client_cert::kIssuerCARef
1013 << "' is present, but at least one is required.";
1014 AddValidationIssue(error_on_missing_field_, msg.str());
1015 }
1016
1017 return !error_on_missing_field_ || all_required_exist;
1018 }
1019
ValidateGlobalNetworkConfiguration(base::DictionaryValue * result)1020 bool Validator::ValidateGlobalNetworkConfiguration(
1021 base::DictionaryValue* result) {
1022 // Replace the deprecated kBlacklistedHexSSIDs with kBlockedHexSSIDs.
1023 if (!result->HasKey(::onc::global_network_config::kBlockedHexSSIDs)) {
1024 base::Optional<base::Value> blocked =
1025 result->ExtractKey(::onc::global_network_config::kBlacklistedHexSSIDs);
1026 if (blocked) {
1027 result->SetKey(::onc::global_network_config::kBlockedHexSSIDs,
1028 std::move(*blocked));
1029 }
1030 }
1031
1032 // Validate that kDisableNetworkTypes, kAllowOnlyPolicyNetworksToConnect and
1033 // kBlockedHexSSIDs are only allowed in device policy.
1034 if (!IsInDevicePolicy(result,
1035 ::onc::global_network_config::kDisableNetworkTypes) ||
1036 !IsInDevicePolicy(
1037 result,
1038 ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect) ||
1039 !IsInDevicePolicy(result,
1040 ::onc::global_network_config::
1041 kAllowOnlyPolicyNetworksToConnectIfAvailable) ||
1042 !IsInDevicePolicy(result,
1043 ::onc::global_network_config::kBlockedHexSSIDs)) {
1044 return false;
1045 }
1046
1047 // Ensure the list contains only legitimate network type identifiers.
1048 const std::vector<const char*> valid_network_type_values = {
1049 ::onc::network_config::kCellular, ::onc::network_config::kEthernet,
1050 ::onc::network_config::kTether, ::onc::network_config::kWiFi,
1051 ::onc::network_config::kVPN, ::onc::network_config::kWimaxDeprecated,
1052 };
1053 if (!ListFieldContainsValidValues(
1054 *result, ::onc::global_network_config::kDisableNetworkTypes,
1055 valid_network_type_values)) {
1056 return false;
1057 }
1058 return true;
1059 }
1060
ValidateProxySettings(base::DictionaryValue * result)1061 bool Validator::ValidateProxySettings(base::DictionaryValue* result) {
1062 const std::vector<const char*> valid_types = {
1063 ::onc::proxy::kDirect, ::onc::proxy::kManual, ::onc::proxy::kPAC,
1064 ::onc::proxy::kWPAD};
1065 if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, valid_types))
1066 return false;
1067
1068 bool all_required_exist = RequireField(*result, ::onc::proxy::kType);
1069 std::string type = GetStringFromDict(*result, ::onc::proxy::kType);
1070 if (type == ::onc::proxy::kManual)
1071 all_required_exist &= RequireField(*result, ::onc::proxy::kManual);
1072 else if (type == ::onc::proxy::kPAC)
1073 all_required_exist &= RequireField(*result, ::onc::proxy::kPAC);
1074
1075 return !error_on_missing_field_ || all_required_exist;
1076 }
1077
ValidateProxyLocation(base::DictionaryValue * result)1078 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) {
1079 bool all_required_exist = RequireField(*result, ::onc::proxy::kHost) &&
1080 RequireField(*result, ::onc::proxy::kPort);
1081
1082 return !error_on_missing_field_ || all_required_exist;
1083 }
1084
ValidateEAP(base::DictionaryValue * result)1085 bool Validator::ValidateEAP(base::DictionaryValue* result) {
1086 const std::vector<const char*> valid_inner_values = {
1087 ::onc::eap::kAutomatic, ::onc::eap::kGTC, ::onc::eap::kMD5,
1088 ::onc::eap::kMSCHAPv2, ::onc::eap::kPAP};
1089 const std::vector<const char*> valid_outer_values = {
1090 ::onc::eap::kPEAP, ::onc::eap::kEAP_TLS, ::onc::eap::kEAP_TTLS,
1091 ::onc::eap::kLEAP, ::onc::eap::kEAP_SIM, ::onc::eap::kEAP_FAST,
1092 ::onc::eap::kEAP_AKA};
1093
1094 if (FieldExistsAndHasNoValidValue(*result, ::onc::eap::kInner,
1095 valid_inner_values) ||
1096 FieldExistsAndHasNoValidValue(*result, ::onc::eap::kOuter,
1097 valid_outer_values) ||
1098 FieldExistsAndIsEmpty(*result, ::onc::eap::kServerCARefs)) {
1099 return false;
1100 }
1101
1102 if (!OnlyOneFieldSet(*result, ::onc::eap::kServerCARefs,
1103 ::onc::eap::kServerCARef))
1104 return false;
1105
1106 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result))
1107 return false;
1108
1109 bool all_required_exist = RequireField(*result, ::onc::eap::kOuter);
1110
1111 return !error_on_missing_field_ || all_required_exist;
1112 }
1113
ValidateSubjectAlternativeNameMatch(base::DictionaryValue * result)1114 bool Validator::ValidateSubjectAlternativeNameMatch(
1115 base::DictionaryValue* result) {
1116 const std::vector<const char*> valid_types = {
1117 ::onc::eap_subject_alternative_name_match::kEMAIL,
1118 ::onc::eap_subject_alternative_name_match::kDNS,
1119 ::onc::eap_subject_alternative_name_match::kURI};
1120
1121 if (FieldExistsAndHasNoValidValue(
1122 *result, ::onc::eap_subject_alternative_name_match::kType,
1123 valid_types)) {
1124 return false;
1125 }
1126
1127 bool all_required_exist =
1128 RequireField(*result, ::onc::eap_subject_alternative_name_match::kType) &&
1129 RequireField(*result, ::onc::eap_subject_alternative_name_match::kValue);
1130
1131 return !error_on_missing_field_ || all_required_exist;
1132 }
1133
ValidateCertificate(base::DictionaryValue * result)1134 bool Validator::ValidateCertificate(base::DictionaryValue* result) {
1135 const std::vector<const char*> valid_types = {::onc::certificate::kClient,
1136 ::onc::certificate::kServer,
1137 ::onc::certificate::kAuthority};
1138 if (FieldExistsAndHasNoValidValue(*result, ::onc::certificate::kType,
1139 valid_types) ||
1140 FieldExistsAndIsEmpty(*result, ::onc::certificate::kGUID)) {
1141 return false;
1142 }
1143
1144 std::string type = GetStringFromDict(*result, ::onc::certificate::kType);
1145
1146 if (!CheckGuidIsUniqueAndAddToSet(*result, ::onc::certificate::kGUID,
1147 &certificate_guids_))
1148 return false;
1149
1150 bool all_required_exist = RequireField(*result, ::onc::certificate::kGUID);
1151
1152 bool remove = false;
1153 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
1154 if (remove) {
1155 path_.push_back(::onc::kRemove);
1156 std::ostringstream msg;
1157 msg << "Removal of certificates is not supported.";
1158 AddValidationIssue(true /* is_error */, msg.str());
1159 path_.pop_back();
1160 return false;
1161 }
1162
1163 all_required_exist &= RequireField(*result, ::onc::certificate::kType);
1164
1165 if (type == ::onc::certificate::kClient)
1166 all_required_exist &= RequireField(*result, ::onc::certificate::kPKCS12);
1167 else if (type == ::onc::certificate::kServer ||
1168 type == ::onc::certificate::kAuthority)
1169 all_required_exist &= RequireField(*result, ::onc::certificate::kX509);
1170
1171 return !error_on_missing_field_ || all_required_exist;
1172 }
1173
ValidateScope(base::DictionaryValue * result)1174 bool Validator::ValidateScope(base::DictionaryValue* result) {
1175 const std::vector<const char*> valid_types = {::onc::scope::kDefault,
1176 ::onc::scope::kExtension};
1177 if (FieldExistsAndHasNoValidValue(*result, ::onc::scope::kType,
1178 valid_types) ||
1179 FieldExistsAndIsEmpty(*result, ::onc::scope::kId)) {
1180 return false;
1181 }
1182
1183 bool all_required_exist = RequireField(*result, ::onc::scope::kType);
1184 const std::string* type_string = result->FindStringKey(::onc::scope::kType);
1185 if (type_string && *type_string == ::onc::scope::kExtension) {
1186 all_required_exist &= RequireField(*result, ::onc::scope::kId);
1187 // Check Id validity for type 'Extension'.
1188 const std::string* id_string = result->FindStringKey(::onc::scope::kId);
1189 if (id_string && !crx_file::id_util::IdIsValid(*id_string)) {
1190 std::ostringstream msg;
1191 msg << "Field '" << ::onc::scope::kId << "' is not a valid extension id.";
1192 AddValidationIssue(false /* is_error */, msg.str());
1193 return false;
1194 }
1195 }
1196
1197 return !error_on_missing_field_ || all_required_exist;
1198 }
1199
ValidateTether(base::DictionaryValue * result)1200 bool Validator::ValidateTether(base::DictionaryValue* result) {
1201 if (FieldExistsAndIsNotInRange(*result, ::onc::tether::kBatteryPercentage, 0,
1202 100) ||
1203 FieldExistsAndIsNotInRange(*result, ::onc::tether::kSignalStrength, 0,
1204 100) ||
1205 FieldExistsAndIsEmpty(*result, ::onc::tether::kCarrier)) {
1206 return false;
1207 }
1208
1209 bool all_required_exist =
1210 RequireField(*result, ::onc::tether::kHasConnectedToHost);
1211 all_required_exist &=
1212 RequireField(*result, ::onc::tether::kBatteryPercentage);
1213 all_required_exist &= RequireField(*result, ::onc::tether::kSignalStrength);
1214 all_required_exist &= RequireField(*result, ::onc::tether::kCarrier);
1215
1216 return !error_on_missing_field_ || all_required_exist;
1217 }
1218
AddValidationIssue(bool is_error,const std::string & debug_info)1219 void Validator::AddValidationIssue(bool is_error,
1220 const std::string& debug_info) {
1221 std::ostringstream msg;
1222 msg << (is_error ? "ERROR: " : "WARNING: ") << debug_info << " (at "
1223 << (path_.empty() ? "toplevel" : base::JoinString(path_, ".")) << ")";
1224 std::string message = msg.str();
1225
1226 if (is_error)
1227 NET_LOG(ERROR) << message;
1228 else if (log_warnings_)
1229 NET_LOG(DEBUG) << message;
1230
1231 validation_issues_.push_back({is_error, message});
1232 }
1233
1234 } // namespace onc
1235 } // namespace chromeos
1236