Chromium Code Reviews| Index: chrome/browser/chromeos/network_settings/onc_validator.cc |
| diff --git a/chrome/browser/chromeos/network_settings/onc_validator.cc b/chrome/browser/chromeos/network_settings/onc_validator.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..69871ed8a4afa6b82809273c6706747dd96f6c51 |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/network_settings/onc_validator.cc |
| @@ -0,0 +1,592 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/chromeos/network_settings/onc_validator.h" |
| + |
| +#include <string> |
| + |
| +#include "base/logging.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/chromeos/cros/onc_constants.h" |
| +#include "chrome/browser/chromeos/network_settings/onc_signature.h" |
| + |
| +namespace chromeos { |
| +namespace onc { |
| + |
| +Validator::Validator( |
| + bool error_on_unknown_field, |
| + bool error_on_wrong_recommended, |
| + bool error_on_missing_field, |
| + bool managed_onc) |
| + : error_on_unknown_field_(error_on_unknown_field), |
| + error_on_wrong_recommended_(error_on_wrong_recommended), |
| + error_on_missing_field_(error_on_missing_field), |
| + managed_onc_(managed_onc) { |
| +} |
| + |
| +Validator::~Validator() { |
| +} |
| + |
| +// static |
| +scoped_ptr<Validator> Validator::CreateStrictValidator(bool managed_onc) { |
| + return make_scoped_ptr(new Validator(true, true, true, managed_onc)); |
| +} |
| + |
| +// static |
| +scoped_ptr<Validator> Validator::CreateLiberalValidator(bool managed_onc) { |
| + return make_scoped_ptr(new Validator(false, false, false, managed_onc)); |
| +} |
| + |
| +scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject( |
| + const OncValueSignature* object_signature, |
| + const base::DictionaryValue& onc_object) { |
| + CHECK(object_signature != NULL); |
| + scoped_ptr<base::Value> result_value = |
| + MapValue(*object_signature, onc_object); |
| + base::DictionaryValue* result_dict = NULL; |
| + if (result_value.get() != NULL) { |
| + result_value.release()->GetAsDictionary(&result_dict); |
| + CHECK(result_dict != NULL); |
| + } |
| + |
| + return make_scoped_ptr(result_dict); |
| +} |
| + |
| +scoped_ptr<base::Value> Validator::MapValue( |
| + const OncValueSignature& signature, |
| + const base::Value& onc_value) { |
| + if (onc_value.GetType() != signature.onc_type) { |
| + DVLOG(1) << "Wrong type. Expected " << signature.onc_type |
| + << ", but found " << onc_value.GetType(); |
| + return scoped_ptr<base::Value>(); |
| + } |
| + |
| + scoped_ptr<base::Value> repaired = Mapper::MapValue(signature, onc_value); |
| + if (repaired.get() != NULL) |
| + CHECK_EQ(repaired->GetType(), signature.onc_type); |
| + return repaired.Pass(); |
| +} |
| + |
| +scoped_ptr<base::DictionaryValue> Validator::MapObject( |
| + const OncValueSignature& signature, |
| + const base::DictionaryValue& onc_object) { |
| + scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue); |
| + |
| + bool valid; |
| + if (&signature == &kNetworkConfigurationSignature) |
| + valid = ValidateNetworkConfiguration(onc_object, repaired.get()); |
| + else if (&signature == &kEthernetSignature) |
| + valid = ValidateEthernet(onc_object, repaired.get()); |
| + else if (&signature == &kIPConfigSignature) |
| + valid = ValidateIPConfig(onc_object, repaired.get()); |
| + else if (&signature == &kWiFiSignature) |
| + valid = ValidateWiFi(onc_object, repaired.get()); |
| + else if (&signature == &kVPNSignature) |
| + valid = ValidateVPN(onc_object, repaired.get()); |
| + else if (&signature == &kIPsecSignature) |
| + valid = ValidateIPsec(onc_object, repaired.get()); |
| + else if (&signature == &kOpenVPNSignature) |
| + valid = ValidateOpenVPN(onc_object, repaired.get()); |
| + else if (&signature == &kCertificatePatternSignature) |
| + valid = ValidateCertificatePattern(onc_object, repaired.get()); |
| + else if (&signature == &kProxySettingsSignature) |
| + valid = ValidateProxySettings(onc_object, repaired.get()); |
| + else if (&signature == &kProxyLocationSignature) |
| + valid = ValidateProxyLocation(onc_object, repaired.get()); |
| + else if (&signature == &kEAPSignature) |
| + valid = ValidateEAP(onc_object, repaired.get()); |
| + else if (&signature == &kCertificateSignature) |
| + valid = ValidateCertificate(onc_object, repaired.get()); |
| + else |
| + valid = ValidateObjectDefault(signature, onc_object, repaired.get()); |
| + |
| + if (valid) |
| + return repaired.Pass(); |
| + else |
| + return scoped_ptr<base::DictionaryValue>(); |
| +} |
| + |
| +bool Validator::ValidateObjectDefault( |
| + const OncValueSignature& signature, |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + bool found_unknown_field = false; |
| + bool nested_error_occured = false; |
| + MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured, |
| + result); |
| + if (nested_error_occured) |
| + return false; |
| + |
| + if (found_unknown_field) { |
| + if (error_on_unknown_field_) { |
| + DVLOG(1) << "Unknown field name. Aborting."; |
| + return false; |
| + } |
| + DVLOG(1) << "Unknown field name. Ignoring."; |
| + } |
| + |
| + return ValidateRecommendedField(signature, result); |
| +} |
| + |
| +bool Validator::ValidateRecommendedField( |
| + const OncValueSignature& object_signature, |
| + base::DictionaryValue* result) { |
| + CHECK(result != NULL); |
| + |
| + scoped_ptr<base::ListValue> recommended; |
| + { |
| + base::Value* recommended_value; |
| + // This remove passes ownership to |recommended_value|. |
| + if (!result->RemoveWithoutPathExpansion(onc::kRecommended, |
| + &recommended_value)) { |
| + return true; |
| + } |
| + base::ListValue* recommended_list; |
| + recommended_value->GetAsList(&recommended_list); |
| + CHECK(recommended_list != NULL); |
|
Mattias Nissler (ping if slow)
2012/11/02 10:10:00
Does this mean we'll crash if somebody feeds bad O
pneubeck (no reviews)
2012/11/05 12:04:48
This case should not occur as the type validation
Mattias Nissler (ping if slow)
2012/11/06 09:30:56
OK, makes sense.
|
| + |
| + recommended.reset(recommended_list); |
| + } |
| + |
| + if (!managed_onc_) { |
|
Mattias Nissler (ping if slow)
2012/11/02 10:10:00
I would just drop this check. What additional bene
pneubeck (no reviews)
2012/11/05 12:04:48
At least, I would keep the message and the removal
|
| + DVLOG(1) << "Found kRecommended field in unmanaged ONC." |
| + << (error_on_wrong_recommended_ ? " Aborting." : " Ignoring."); |
| + return !error_on_wrong_recommended_; |
| + } |
| + |
| + scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue); |
| + for (base::ListValue::iterator it = recommended->begin(); |
| + it != recommended->end(); ++it) { |
| + std::string field_name; |
| + if (!(*it)->GetAsString(&field_name)) { |
| + NOTREACHED(); |
| + continue; |
| + } |
| + |
| + const OncFieldSignature* field_signature = |
| + object_signature.GetFieldSignature(field_name); |
| + |
| + bool found_error = false; |
| + std::string error_cause; |
| + if (field_signature == NULL) { |
| + found_error = true; |
| + error_cause = "unknown"; |
| + } else if (field_signature->value_signature->onc_type == |
| + base::Value::TYPE_DICTIONARY) { |
| + found_error = true; |
| + error_cause = "dictionary-typed"; |
| + } |
| + |
| + if (found_error) { |
| + DVLOG(1) << "Found " << error_cause << " field name '" << field_name |
| + << "' in kRecommended array. " |
| + << (error_on_wrong_recommended_ ? "Aborting." : "Ignoring."); |
| + if (error_on_wrong_recommended_) |
| + return false; |
| + else |
| + continue; |
| + } |
| + |
| + repaired_recommended->Append((*it)->DeepCopy()); |
| + } |
| + |
| + result->Set(onc::kRecommended, repaired_recommended.release()); |
| + return true; |
| +} |
| + |
| +namespace { |
| + |
| +bool RequireAnyOf(const std::string &actual, const std::string &v1, |
|
Mattias Nissler (ping if slow)
2012/11/02 10:10:00
What's wrong with this:
bool RequireAnyOf(const s
pneubeck (no reviews)
2012/11/05 12:04:48
Done.
|
| + const std::string &v2) { |
| + if (actual == v1 || actual == v2) |
| + return true; |
| + DVLOG(1) << "Found " << actual << ", but expected one of " |
| + << v1 << ", " << v2; |
| + return false; |
| +} |
| + |
| +bool RequireAnyOf(const std::string &actual, const std::string &v1, |
| + const std::string &v2, const std::string &v3) { |
| + if (actual == v1 || actual == v2 || actual == v3) |
| + return true; |
| + DVLOG(1) << "Found " << actual << ", but expected one of " |
| + << v1 << ", " << v2 << ", " << v3; |
| + return false; |
| +} |
| + |
| +bool RequireAnyOf(const std::string &actual, const std::string &v1, |
| + const std::string &v2, const std::string &v3, |
| + const std::string &v4) { |
| + if (actual == v1 || actual == v2 || actual == v3 || actual == v4) |
| + return true; |
| + DVLOG(1) << "Found " << actual << ", but expected one of " |
| + << v1 << ", " << v2 << ", " << v3 << ", " << v4; |
| + return false; |
| +} |
| + |
| +bool RequireAnyOf(const std::string &actual, const std::string &v1, |
| + const std::string &v2, const std::string &v3, |
| + const std::string &v4, const std::string &v5) { |
| + if (actual == v1 || actual == v2 || actual == v3 || actual == v4 || |
| + actual == v5) |
| + return true; |
| + DVLOG(1) << "Found " << actual << ", but expected one of " |
| + << v1 << ", " << v2 << ", " << v3 << ", " << v4 << ", " << v5; |
| + return false; |
| +} |
| + |
| +bool RequireAnyOf(const std::string &actual, const std::string &v1, |
| + const std::string &v2, const std::string &v3, |
| + const std::string &v4, const std::string &v5, |
| + const std::string &v6, const std::string &v7) { |
| + if (actual == v1 || actual == v2 || actual == v3 || actual == v4 || |
| + actual == v5 || actual == v6 || actual == v7) |
| + return true; |
| + DVLOG(1) << "Found " << actual << ", but expected one of " |
| + << v1 << ", " << v2 << ", " << v3 << ", " << v4 << ", " << v5 << ", " |
| + << v6 << ", " << v7; |
| + return false; |
| +} |
| + |
| +bool IsInRange(int actual, int lower_bound, int upper_bound) { |
| + if (lower_bound <= actual && actual <= upper_bound) |
| + return true; |
| + DVLOG(1) << "Found " << actual << ", which is out of range [" << lower_bound |
| + << ", " << upper_bound << "]"; |
| + return false; |
| +} |
| + |
| +bool RequireField(const base::DictionaryValue& dict, std::string key) { |
| + if (dict.HasKey(key)) |
| + return true; |
| + DVLOG(1) << "Required field " << key << " missing."; |
| + return false; |
| +} |
| + |
| +} // namespace |
| + |
| +bool Validator::ValidateNetworkConfiguration( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + if (!ValidateObjectDefault(kNetworkConfigurationSignature, |
| + onc_object, result)) { |
| + return false; |
| + } |
| + |
| + std::string type; |
| + if (result->GetStringWithoutPathExpansion(kType, &type) && |
| + !RequireAnyOf(type, kEthernet, kVPN, kWiFi)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kGUID); |
| + |
| + bool remove = false; |
| + result->GetBooleanWithoutPathExpansion(kRemove, &remove); |
| + if (!remove) { |
| + if (!RequireField(*result, kName)) |
| + allRequiredExist = false; |
|
Mattias Nissler (ping if slow)
2012/11/02 10:10:00
you could write all these as &=, but that's a matt
pneubeck (no reviews)
2012/11/05 12:04:48
Done.
|
| + if (!RequireField(*result, kType)) |
| + allRequiredExist = false; |
| + if (!type.empty() && !RequireField(*result, type)) |
| + allRequiredExist = false; |
| + } |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateEthernet( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::ethernet; |
| + if (!ValidateObjectDefault(kEthernetSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string auth; |
| + if (result->GetStringWithoutPathExpansion(kAuthentication, &auth) && |
| + !RequireAnyOf(auth, kNone, k8021X)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = true; |
| + if (auth == k8021X && !RequireField(*result, kEAP)) |
| + allRequiredExist = false; |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateIPConfig( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::ipconfig; |
| + if (!ValidateObjectDefault(kIPConfigSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string type; |
| + if (result->GetStringWithoutPathExpansion(kType, &type) && |
| + !RequireAnyOf(type, kIPv4, kIPv6)) { |
| + return false; |
| + } |
| + |
| + int routing_prefix; |
| + int lower_bound = 1; |
| + // In case of missing type, choose higher upper_bound. |
| + int upper_bound = (type == kIPv4) ? 32 : 128; |
| + if (result->GetIntegerWithoutPathExpansion(kRoutingPrefix, &routing_prefix) && |
| + !IsInRange(routing_prefix, lower_bound, upper_bound)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kIPAddress) && |
| + RequireField(*result, kRoutingPrefix) && |
| + RequireField(*result, kType); |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateWiFi( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::wifi; |
| + if (!ValidateObjectDefault(kWiFiSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string security; |
| + if (result->GetStringWithoutPathExpansion(kSecurity, &security) && |
| + !RequireAnyOf(security, kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, |
| + kWPA_EAP)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kSecurity) && |
| + RequireField(*result, kSSID); |
| + if ((security == kWEP_8021X || security == kWPA_EAP) && |
| + !RequireField(*result, kEAP)) { |
| + allRequiredExist = false; |
| + } else if ((security == kWEP_PSK || security == kWPA_PSK) && |
| + !RequireField(*result, kPassphrase)) { |
| + allRequiredExist = false; |
| + } |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateVPN( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace vpn; |
| + if (!ValidateObjectDefault(kVPNSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string type; |
| + if (result->GetStringWithoutPathExpansion(kType, &type) && |
| + !RequireAnyOf(type, kIPsec, kTypeL2TP_IPsec, kOpenVPN)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kType); |
| + |
| + if ((type == kOpenVPN && !RequireField(*result, kOpenVPN)) || |
| + (type == kIPsec && !RequireField(*result, kIPsec)) || |
| + (type == kTypeL2TP_IPsec && !RequireField(*result, kIPsec)) || |
| + (type == kTypeL2TP_IPsec && !RequireField(*result, kL2TP))) { |
| + allRequiredExist = false; |
| + } |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateIPsec( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::vpn; |
| + using namespace onc::certificate; |
| + if (!ValidateObjectDefault(kIPsecSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string auth; |
| + if (result->GetStringWithoutPathExpansion(kAuthenticationType, &auth) && |
| + !RequireAnyOf(auth, kPSK, kCert)) { |
| + return false; |
| + } |
| + |
| + std::string cert_type; |
| + if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && |
| + !RequireAnyOf(cert_type, kRef, kPattern)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kAuthenticationType) && |
| + RequireField(*result, kIKEVersion); |
| + if (auth == kCert && (!RequireField(*result, kClientCertType) || |
| + !RequireField(*result, kServerCARef))) { |
| + allRequiredExist = false; |
| + } |
| + if (cert_type == kPattern && !RequireField(*result, kClientCertPattern)) |
| + allRequiredExist = false; |
| + else if (cert_type == kRef && !RequireField(*result, kClientCertRef)) |
| + allRequiredExist = false; |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateOpenVPN( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::vpn; |
| + using namespace onc::openvpn; |
| + using namespace onc::certificate; |
| + if (!ValidateObjectDefault(kOpenVPNSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string auth_retry; |
| + if (result->GetStringWithoutPathExpansion(kAuthRetry, &auth_retry) && |
| + !RequireAnyOf(auth_retry, openvpn::kNone, kInteract, kNoInteract )) { |
| + return false; |
| + } |
| + |
| + std::string cert_type; |
| + if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && |
| + !RequireAnyOf(cert_type, onc::kNone, kRef, kPattern)) { |
| + return false; |
| + } |
| + |
| + std::string cert_tls; |
| + if (result->GetStringWithoutPathExpansion(kRemoteCertTLS, &cert_tls) && |
| + !RequireAnyOf(cert_tls, openvpn::kNone, openvpn::kServer)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kClientCertType); |
| + if (cert_type == kPattern && !RequireField(*result, kClientCertPattern)) |
| + allRequiredExist = false; |
| + else if (cert_type == kRef && !RequireField(*result, kClientCertRef)) |
| + allRequiredExist = false; |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateCertificatePattern( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::certificate; |
| + if (!ValidateObjectDefault(kCertificatePatternSignature, onc_object, result)) |
| + return false; |
| + |
| + bool allRequiredExist = true; |
| + if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) && |
| + !result->HasKey(kIssuerCARef)) { |
| + allRequiredExist = false; |
| + DVLOG(1) << "None of the fields " << kSubject << ", " << kIssuer << ", and " |
| + << kIssuerCARef << " exists, but at least one is required."; |
| + } |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateProxySettings(const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::proxy; |
| + if (!ValidateObjectDefault(kProxySettingsSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string type; |
| + if (result->GetStringWithoutPathExpansion(kType, &type) && |
| + !RequireAnyOf(type, kDirect, kManual, kPAC, kWPAD)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kType); |
| + |
| + if (type == kManual && !RequireField(*result, kManual)) |
| + allRequiredExist = false; |
| + else if (type == kPAC && !RequireField(*result, kPAC)) |
| + allRequiredExist = false; |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateProxyLocation(const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::proxy; |
| + if (!ValidateObjectDefault(kProxyLocationSignature, onc_object, result)) |
| + return false; |
| + |
| + bool allRequiredExist = RequireField(*result, kHost) && |
| + RequireField(*result, kPort); |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateEAP(const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::eap; |
| + using namespace onc::certificate; |
| + if (!ValidateObjectDefault(kEAPSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string inner; |
| + if (result->GetStringWithoutPathExpansion(kInner, &inner) && |
| + !RequireAnyOf(inner, kAutomatic, kMD5, kMSCHAPv2, kPAP)) { |
| + return false; |
| + } |
| + |
| + std::string outer; |
| + if (result->GetStringWithoutPathExpansion(kOuter, &outer) && |
| + !RequireAnyOf(outer, kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, |
| + kEAP_FAST, kEAP_AKA)) { |
| + return false; |
| + } |
| + |
| + std::string cert_type; |
| + if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && |
| + !RequireAnyOf(cert_type, kRef, kPattern)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kOuter); |
| + |
| + if (cert_type == kPattern && !RequireField(*result, kClientCertPattern)) |
| + allRequiredExist = false; |
| + else if (cert_type == kRef && !RequireField(*result, kClientCertRef)) |
| + allRequiredExist = false; |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +bool Validator::ValidateCertificate( |
| + const base::DictionaryValue& onc_object, |
| + base::DictionaryValue* result) { |
| + using namespace onc::certificate; |
| + if (!ValidateObjectDefault(kCertificateSignature, onc_object, result)) |
| + return false; |
| + |
| + std::string type; |
| + if (result->GetStringWithoutPathExpansion(kType, &type) && |
| + !RequireAnyOf(type, kClient, kServer, kAuthority)) { |
| + return false; |
| + } |
| + |
| + bool allRequiredExist = RequireField(*result, kGUID); |
| + |
| + bool remove = false; |
| + result->GetBooleanWithoutPathExpansion(kRemove, &remove); |
| + if (!remove) { |
| + if (!RequireField(*result, kType)) |
| + allRequiredExist = false; |
| + |
| + if (type == kClient && !RequireField(*result, kPKCS12)) |
| + allRequiredExist = false; |
| + |
| + if ((type == kServer || type == kAuthority) && |
| + !RequireField(*result, kX509)) { |
| + allRequiredExist = false; |
| + } |
| + } |
| + |
| + return !error_on_missing_field_ || allRequiredExist; |
| +} |
| + |
| +} // namespace onc |
| +} // namespace chromeos |