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, &current_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