Refactors gesture conversion functions to ui/events/blink
[chromium-blink-merge.git] / chromeos / network / onc / onc_utils.cc
blobaf0171c4dfa87519a1f0736ffdb14231233daf9f
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.
5 #include "chromeos/network/onc/onc_utils.h"
7 #include "base/base64.h"
8 #include "base/json/json_reader.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "chromeos/network/network_event_log.h"
15 #include "chromeos/network/onc/onc_mapper.h"
16 #include "chromeos/network/onc/onc_signature.h"
17 #include "chromeos/network/onc/onc_utils.h"
18 #include "chromeos/network/onc/onc_validator.h"
19 #include "components/device_event_log/device_event_log.h"
20 #include "crypto/encryptor.h"
21 #include "crypto/hmac.h"
22 #include "crypto/symmetric_key.h"
23 #include "net/cert/pem_tokenizer.h"
24 #include "net/cert/x509_certificate.h"
26 using namespace ::onc;
28 namespace chromeos {
29 namespace onc {
31 namespace {
33 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC";
34 const char kUnableToDecode[] = "Unable to decode encrypted ONC";
36 } // namespace
38 const char kEmptyUnencryptedConfiguration[] =
39 "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[],"
40 "\"Certificates\":[]}";
42 scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson(
43 const std::string& json) {
44 std::string error;
45 base::Value* root = base::JSONReader::ReadAndReturnError(
46 json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
48 base::DictionaryValue* dict_ptr = nullptr;
49 if (!root || !root->GetAsDictionary(&dict_ptr)) {
50 NET_LOG(ERROR) << "Invalid JSON Dictionary: " << error;
51 delete root;
54 return make_scoped_ptr(dict_ptr);
57 scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase,
58 const base::DictionaryValue& root) {
59 const int kKeySizeInBits = 256;
60 const int kMaxIterationCount = 500000;
61 std::string onc_type;
62 std::string initial_vector;
63 std::string salt;
64 std::string cipher;
65 std::string stretch_method;
66 std::string hmac_method;
67 std::string hmac;
68 int iterations;
69 std::string ciphertext;
71 if (!root.GetString(encrypted::kCiphertext, &ciphertext) ||
72 !root.GetString(encrypted::kCipher, &cipher) ||
73 !root.GetString(encrypted::kHMAC, &hmac) ||
74 !root.GetString(encrypted::kHMACMethod, &hmac_method) ||
75 !root.GetString(encrypted::kIV, &initial_vector) ||
76 !root.GetInteger(encrypted::kIterations, &iterations) ||
77 !root.GetString(encrypted::kSalt, &salt) ||
78 !root.GetString(encrypted::kStretch, &stretch_method) ||
79 !root.GetString(toplevel_config::kType, &onc_type) ||
80 onc_type != toplevel_config::kEncryptedConfiguration) {
81 NET_LOG(ERROR) << "Encrypted ONC malformed.";
82 return nullptr;
85 if (hmac_method != encrypted::kSHA1 ||
86 cipher != encrypted::kAES256 ||
87 stretch_method != encrypted::kPBKDF2) {
88 NET_LOG(ERROR) << "Encrypted ONC unsupported encryption scheme.";
89 return nullptr;
92 // Make sure iterations != 0, since that's not valid.
93 if (iterations == 0) {
94 NET_LOG(ERROR) << kUnableToDecrypt;
95 return nullptr;
98 // Simply a sanity check to make sure we can't lock up the machine
99 // for too long with a huge number (or a negative number).
100 if (iterations < 0 || iterations > kMaxIterationCount) {
101 NET_LOG(ERROR) << "Too many iterations in encrypted ONC";
102 return nullptr;
105 if (!base::Base64Decode(salt, &salt)) {
106 NET_LOG(ERROR) << kUnableToDecode;
107 return nullptr;
110 scoped_ptr<crypto::SymmetricKey> key(
111 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
112 passphrase,
113 salt,
114 iterations,
115 kKeySizeInBits));
117 if (!base::Base64Decode(initial_vector, &initial_vector)) {
118 NET_LOG(ERROR) << kUnableToDecode;
119 return nullptr;
121 if (!base::Base64Decode(ciphertext, &ciphertext)) {
122 NET_LOG(ERROR) << kUnableToDecode;
123 return nullptr;
125 if (!base::Base64Decode(hmac, &hmac)) {
126 NET_LOG(ERROR) << kUnableToDecode;
127 return nullptr;
130 crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
131 if (!hmac_verifier.Init(key.get()) ||
132 !hmac_verifier.Verify(ciphertext, hmac)) {
133 NET_LOG(ERROR) << kUnableToDecrypt;
134 return nullptr;
137 crypto::Encryptor decryptor;
138 if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) {
139 NET_LOG(ERROR) << kUnableToDecrypt;
140 return nullptr;
143 std::string plaintext;
144 if (!decryptor.Decrypt(ciphertext, &plaintext)) {
145 NET_LOG(ERROR) << kUnableToDecrypt;
146 return nullptr;
149 scoped_ptr<base::DictionaryValue> new_root =
150 ReadDictionaryFromJson(plaintext);
151 if (!new_root) {
152 NET_LOG(ERROR) << "Property dictionary malformed.";
153 return nullptr;
156 return new_root.Pass();
159 std::string GetSourceAsString(ONCSource source) {
160 switch (source) {
161 case ONC_SOURCE_UNKNOWN:
162 return "unknown";
163 case ONC_SOURCE_NONE:
164 return "none";
165 case ONC_SOURCE_DEVICE_POLICY:
166 return "device policy";
167 case ONC_SOURCE_USER_POLICY:
168 return "user policy";
169 case ONC_SOURCE_USER_IMPORT:
170 return "user import";
172 NOTREACHED() << "unknown ONC source " << source;
173 return "unknown";
176 void ExpandField(const std::string& fieldname,
177 const StringSubstitution& substitution,
178 base::DictionaryValue* onc_object) {
179 std::string user_string;
180 if (!onc_object->GetStringWithoutPathExpansion(fieldname, &user_string))
181 return;
183 std::string login_id;
184 if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) {
185 ReplaceSubstringsAfterOffset(&user_string, 0,
186 substitutes::kLoginIDField,
187 login_id);
190 std::string email;
191 if (substitution.GetSubstitute(substitutes::kEmailField, &email)) {
192 ReplaceSubstringsAfterOffset(&user_string, 0,
193 substitutes::kEmailField,
194 email);
197 onc_object->SetStringWithoutPathExpansion(fieldname, user_string);
200 void ExpandStringsInOncObject(
201 const OncValueSignature& signature,
202 const StringSubstitution& substitution,
203 base::DictionaryValue* onc_object) {
204 if (&signature == &kEAPSignature) {
205 ExpandField(eap::kAnonymousIdentity, substitution, onc_object);
206 ExpandField(eap::kIdentity, substitution, onc_object);
207 } else if (&signature == &kL2TPSignature ||
208 &signature == &kOpenVPNSignature) {
209 ExpandField(vpn::kUsername, substitution, onc_object);
212 // Recurse into nested objects.
213 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
214 it.Advance()) {
215 base::DictionaryValue* inner_object = nullptr;
216 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
217 continue;
219 const OncFieldSignature* field_signature =
220 GetFieldSignature(signature, it.key());
221 if (!field_signature)
222 continue;
224 ExpandStringsInOncObject(*field_signature->value_signature,
225 substitution, inner_object);
229 void ExpandStringsInNetworks(const StringSubstitution& substitution,
230 base::ListValue* network_configs) {
231 for (base::Value* entry : *network_configs) {
232 base::DictionaryValue* network = nullptr;
233 entry->GetAsDictionary(&network);
234 DCHECK(network);
235 ExpandStringsInOncObject(
236 kNetworkConfigurationSignature, substitution, network);
240 void FillInHexSSIDFieldsInOncObject(const OncValueSignature& signature,
241 base::DictionaryValue* onc_object) {
242 if (&signature == &kWiFiSignature)
243 FillInHexSSIDField(onc_object);
245 // Recurse into nested objects.
246 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
247 it.Advance()) {
248 base::DictionaryValue* inner_object = nullptr;
249 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
250 continue;
252 const OncFieldSignature* field_signature =
253 GetFieldSignature(signature, it.key());
254 if (!field_signature)
255 continue;
257 FillInHexSSIDFieldsInOncObject(*field_signature->value_signature,
258 inner_object);
262 void FillInHexSSIDField(base::DictionaryValue* wifi_fields) {
263 std::string ssid_string;
264 if (wifi_fields->HasKey(::onc::wifi::kHexSSID) ||
265 !wifi_fields->GetStringWithoutPathExpansion(::onc::wifi::kSSID,
266 &ssid_string)) {
267 return;
269 if (ssid_string.empty()) {
270 NET_LOG(ERROR) << "Found empty SSID field.";
271 return;
273 wifi_fields->SetStringWithoutPathExpansion(
274 ::onc::wifi::kHexSSID,
275 base::HexEncode(ssid_string.c_str(), ssid_string.size()));
278 namespace {
280 class OncMaskValues : public Mapper {
281 public:
282 static scoped_ptr<base::DictionaryValue> Mask(
283 const OncValueSignature& signature,
284 const base::DictionaryValue& onc_object,
285 const std::string& mask) {
286 OncMaskValues masker(mask);
287 bool unused_error;
288 return masker.MapObject(signature, onc_object, &unused_error);
291 protected:
292 explicit OncMaskValues(const std::string& mask)
293 : mask_(mask) {
296 scoped_ptr<base::Value> MapField(const std::string& field_name,
297 const OncValueSignature& object_signature,
298 const base::Value& onc_value,
299 bool* found_unknown_field,
300 bool* error) override {
301 if (FieldIsCredential(object_signature, field_name)) {
302 return scoped_ptr<base::Value>(new base::StringValue(mask_));
303 } else {
304 return Mapper::MapField(field_name, object_signature, onc_value,
305 found_unknown_field, error);
309 // Mask to insert in place of the sensitive values.
310 std::string mask_;
313 } // namespace
315 scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
316 const OncValueSignature& signature,
317 const base::DictionaryValue& onc_object,
318 const std::string& mask) {
319 return OncMaskValues::Mask(signature, onc_object, mask);
322 namespace {
324 std::string DecodePEM(const std::string& pem_encoded) {
325 // The PEM block header used for DER certificates
326 const char kCertificateHeader[] = "CERTIFICATE";
328 // This is an older PEM marker for DER certificates.
329 const char kX509CertificateHeader[] = "X509 CERTIFICATE";
331 std::vector<std::string> pem_headers;
332 pem_headers.push_back(kCertificateHeader);
333 pem_headers.push_back(kX509CertificateHeader);
335 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
336 std::string decoded;
337 if (pem_tokenizer.GetNext()) {
338 decoded = pem_tokenizer.data();
339 } else {
340 // If we failed to read the data as a PEM file, then try plain base64 decode
341 // in case the PEM marker strings are missing. For this to work, there has
342 // to be no white space, and it has to only contain the base64-encoded data.
343 if (!base::Base64Decode(pem_encoded, &decoded)) {
344 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
345 return std::string();
348 return decoded;
351 CertPEMsByGUIDMap GetServerAndCACertsByGUID(
352 const base::ListValue& certificates) {
353 CertPEMsByGUIDMap certs_by_guid;
354 for (const base::Value* entry : certificates) {
355 const base::DictionaryValue* cert = nullptr;
356 entry->GetAsDictionary(&cert);
358 std::string guid;
359 cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid);
360 std::string cert_type;
361 cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type);
362 if (cert_type != certificate::kServer &&
363 cert_type != certificate::kAuthority) {
364 continue;
366 std::string x509_data;
367 cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data);
369 std::string der = DecodePEM(x509_data);
370 std::string pem;
371 if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) {
372 LOG(ERROR) << "Certificate with GUID " << guid
373 << " is not in PEM encoding.";
374 continue;
376 certs_by_guid[guid] = pem;
379 return certs_by_guid;
382 void FillInHexSSIDFieldsInNetworks(base::ListValue* network_configs) {
383 for (base::Value* entry : *network_configs) {
384 base::DictionaryValue* network = nullptr;
385 entry->GetAsDictionary(&network);
386 DCHECK(network);
387 FillInHexSSIDFieldsInOncObject(kNetworkConfigurationSignature, network);
391 } // namespace
393 bool ParseAndValidateOncForImport(const std::string& onc_blob,
394 ONCSource onc_source,
395 const std::string& passphrase,
396 base::ListValue* network_configs,
397 base::DictionaryValue* global_network_config,
398 base::ListValue* certificates) {
399 network_configs->Clear();
400 global_network_config->Clear();
401 certificates->Clear();
402 if (onc_blob.empty())
403 return true;
405 scoped_ptr<base::DictionaryValue> toplevel_onc =
406 ReadDictionaryFromJson(onc_blob);
407 if (!toplevel_onc) {
408 LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source)
409 << " is not a valid JSON dictionary.";
410 return false;
413 // Check and see if this is an encrypted ONC file. If so, decrypt it.
414 std::string onc_type;
415 toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType,
416 &onc_type);
417 if (onc_type == toplevel_config::kEncryptedConfiguration) {
418 toplevel_onc = Decrypt(passphrase, *toplevel_onc);
419 if (!toplevel_onc) {
420 LOG(ERROR) << "Couldn't decrypt the ONC from "
421 << GetSourceAsString(onc_source);
422 return false;
426 bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY ||
427 onc_source == ONC_SOURCE_DEVICE_POLICY);
429 // Validate the ONC dictionary. We are liberal and ignore unknown field
430 // names and ignore invalid field names in kRecommended arrays.
431 Validator validator(false, // Ignore unknown fields.
432 false, // Ignore invalid recommended field names.
433 true, // Fail on missing fields.
434 from_policy);
435 validator.SetOncSource(onc_source);
437 Validator::Result validation_result;
438 toplevel_onc = validator.ValidateAndRepairObject(
439 &kToplevelConfigurationSignature,
440 *toplevel_onc,
441 &validation_result);
443 if (from_policy) {
444 UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
445 validation_result == Validator::VALID);
448 bool success = true;
449 if (validation_result == Validator::VALID_WITH_WARNINGS) {
450 LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source)
451 << " produced warnings.";
452 success = false;
453 } else if (validation_result == Validator::INVALID || !toplevel_onc) {
454 LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source)
455 << " is invalid and couldn't be repaired.";
456 return false;
459 base::ListValue* validated_certs = nullptr;
460 if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates,
461 &validated_certs)) {
462 certificates->Swap(validated_certs);
465 base::ListValue* validated_networks = nullptr;
466 if (toplevel_onc->GetListWithoutPathExpansion(
467 toplevel_config::kNetworkConfigurations, &validated_networks)) {
468 FillInHexSSIDFieldsInNetworks(validated_networks);
470 CertPEMsByGUIDMap server_and_ca_certs =
471 GetServerAndCACertsByGUID(*certificates);
473 if (!ResolveServerCertRefsInNetworks(server_and_ca_certs,
474 validated_networks)) {
475 LOG(ERROR) << "Some certificate references in the ONC policy for source "
476 << GetSourceAsString(onc_source) << " could not be resolved.";
477 success = false;
480 network_configs->Swap(validated_networks);
483 base::DictionaryValue* validated_global_config = nullptr;
484 if (toplevel_onc->GetDictionaryWithoutPathExpansion(
485 toplevel_config::kGlobalNetworkConfiguration,
486 &validated_global_config)) {
487 global_network_config->Swap(validated_global_config);
490 return success;
493 scoped_refptr<net::X509Certificate> DecodePEMCertificate(
494 const std::string& pem_encoded) {
495 std::string decoded = DecodePEM(pem_encoded);
496 scoped_refptr<net::X509Certificate> cert =
497 net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size());
498 LOG_IF(ERROR, !cert.get()) << "Couldn't create certificate from X509 data: "
499 << decoded;
500 return cert;
503 namespace {
505 bool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap& certs_by_guid,
506 const std::string& guid_ref,
507 std::string* pem_encoded) {
508 CertPEMsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref);
509 if (it == certs_by_guid.end()) {
510 LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
511 return false;
513 *pem_encoded = it->second;
514 if (pem_encoded->empty()) {
515 LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref;
516 return false;
518 return true;
521 bool ResolveSingleCertRef(const CertPEMsByGUIDMap& certs_by_guid,
522 const std::string& key_guid_ref,
523 const std::string& key_pem,
524 base::DictionaryValue* onc_object) {
525 std::string guid_ref;
526 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
527 return true;
529 std::string pem_encoded;
530 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
531 return false;
533 onc_object->RemoveWithoutPathExpansion(key_guid_ref, nullptr);
534 onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded);
535 return true;
538 bool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid,
539 const std::string& key_guid_ref_list,
540 const std::string& key_pem_list,
541 base::DictionaryValue* onc_object) {
542 const base::ListValue* guid_ref_list = nullptr;
543 if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list,
544 &guid_ref_list)) {
545 return true;
548 scoped_ptr<base::ListValue> pem_list(new base::ListValue);
549 for (const base::Value* entry : *guid_ref_list) {
550 std::string guid_ref;
551 entry->GetAsString(&guid_ref);
553 std::string pem_encoded;
554 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
555 return false;
557 pem_list->AppendString(pem_encoded);
560 onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, nullptr);
561 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
562 return true;
565 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid,
566 const std::string& key_guid_ref,
567 const std::string& key_pem_list,
568 base::DictionaryValue* onc_object) {
569 std::string guid_ref;
570 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
571 return true;
573 std::string pem_encoded;
574 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
575 return false;
577 scoped_ptr<base::ListValue> pem_list(new base::ListValue);
578 pem_list->AppendString(pem_encoded);
579 onc_object->RemoveWithoutPathExpansion(key_guid_ref, nullptr);
580 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
581 return true;
584 // Resolves the reference list at |key_guid_refs| if present and otherwise the
585 // single reference at |key_guid_ref|. Returns whether the respective resolving
586 // was successful.
587 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid,
588 const std::string& key_guid_refs,
589 const std::string& key_guid_ref,
590 const std::string& key_pem_list,
591 base::DictionaryValue* onc_object) {
592 if (onc_object->HasKey(key_guid_refs)) {
593 if (onc_object->HasKey(key_guid_ref)) {
594 LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref
595 << ". Ignoring and removing the latter.";
596 onc_object->RemoveWithoutPathExpansion(key_guid_ref, nullptr);
598 return ResolveCertRefList(
599 certs_by_guid, key_guid_refs, key_pem_list, onc_object);
602 // Only resolve |key_guid_ref| if |key_guid_refs| isn't present.
603 return ResolveSingleCertRefToList(
604 certs_by_guid, key_guid_ref, key_pem_list, onc_object);
607 bool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap& certs_by_guid,
608 const OncValueSignature& signature,
609 base::DictionaryValue* onc_object) {
610 if (&signature == &kCertificatePatternSignature) {
611 if (!ResolveCertRefList(certs_by_guid,
612 client_cert::kIssuerCARef,
613 client_cert::kIssuerCAPEMs,
614 onc_object)) {
615 return false;
617 } else if (&signature == &kEAPSignature) {
618 if (!ResolveCertRefsOrRefToList(certs_by_guid,
619 eap::kServerCARefs,
620 eap::kServerCARef,
621 eap::kServerCAPEMs,
622 onc_object)) {
623 return false;
625 } else if (&signature == &kIPsecSignature) {
626 if (!ResolveCertRefsOrRefToList(certs_by_guid,
627 ipsec::kServerCARefs,
628 ipsec::kServerCARef,
629 ipsec::kServerCAPEMs,
630 onc_object)) {
631 return false;
633 } else if (&signature == &kIPsecSignature ||
634 &signature == &kOpenVPNSignature) {
635 if (!ResolveSingleCertRef(certs_by_guid,
636 openvpn::kServerCertRef,
637 openvpn::kServerCertPEM,
638 onc_object) ||
639 !ResolveCertRefsOrRefToList(certs_by_guid,
640 openvpn::kServerCARefs,
641 openvpn::kServerCARef,
642 openvpn::kServerCAPEMs,
643 onc_object)) {
644 return false;
648 // Recurse into nested objects.
649 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
650 it.Advance()) {
651 base::DictionaryValue* inner_object = nullptr;
652 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
653 continue;
655 const OncFieldSignature* field_signature =
656 GetFieldSignature(signature, it.key());
657 if (!field_signature)
658 continue;
660 if (!ResolveServerCertRefsInObject(certs_by_guid,
661 *field_signature->value_signature,
662 inner_object)) {
663 return false;
666 return true;
669 } // namespace
671 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid,
672 base::ListValue* network_configs) {
673 bool success = true;
674 for (base::ListValue::iterator it = network_configs->begin();
675 it != network_configs->end(); ) {
676 base::DictionaryValue* network = nullptr;
677 (*it)->GetAsDictionary(&network);
678 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
679 std::string guid;
680 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
681 // This might happen even with correct validation, if the referenced
682 // certificate couldn't be imported.
683 LOG(ERROR) << "Couldn't resolve some certificate reference of network "
684 << guid;
685 it = network_configs->Erase(it, nullptr);
686 success = false;
687 continue;
689 ++it;
691 return success;
694 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid,
695 base::DictionaryValue* network_config) {
696 return ResolveServerCertRefsInObject(certs_by_guid,
697 kNetworkConfigurationSignature,
698 network_config);
701 NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) {
702 if (type == ::onc::network_type::kAllTypes)
703 return NetworkTypePattern::Default();
704 if (type == ::onc::network_type::kCellular)
705 return NetworkTypePattern::Cellular();
706 if (type == ::onc::network_type::kEthernet)
707 return NetworkTypePattern::Ethernet();
708 if (type == ::onc::network_type::kVPN)
709 return NetworkTypePattern::VPN();
710 if (type == ::onc::network_type::kWiFi)
711 return NetworkTypePattern::WiFi();
712 if (type == ::onc::network_type::kWimax)
713 return NetworkTypePattern::Wimax();
714 if (type == ::onc::network_type::kWireless)
715 return NetworkTypePattern::Wireless();
716 NOTREACHED();
717 return NetworkTypePattern::Default();
720 bool IsRecommendedValue(const base::DictionaryValue* onc,
721 const std::string& property_key) {
722 std::string property_basename, recommended_property_key;
723 size_t pos = property_key.find_last_of('.');
724 if (pos != std::string::npos) {
725 // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended'
726 property_basename = property_key.substr(pos + 1);
727 recommended_property_key =
728 property_key.substr(0, pos + 1) + ::onc::kRecommended;
729 } else {
730 // 'Name' -> 'Name', 'Recommended'
731 property_basename = property_key;
732 recommended_property_key = ::onc::kRecommended;
735 const base::ListValue* recommended_keys = nullptr;
736 return (onc->GetList(recommended_property_key, &recommended_keys) &&
737 recommended_keys->Find(base::StringValue(property_basename)) !=
738 recommended_keys->end());
741 } // namespace onc
742 } // namespace chromeos