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 "crypto/encryptor.h"
20 #include "crypto/hmac.h"
21 #include "crypto/symmetric_key.h"
22 #include "net/cert/pem_tokenizer.h"
23 #include "net/cert/x509_certificate.h"
25 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
26 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
28 using namespace ::onc
;
35 const char kUnableToDecrypt
[] = "Unable to decrypt encrypted ONC";
36 const char kUnableToDecode
[] = "Unable to decode encrypted ONC";
40 const char kEmptyUnencryptedConfiguration
[] =
41 "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[],"
42 "\"Certificates\":[]}";
44 scoped_ptr
<base::DictionaryValue
> ReadDictionaryFromJson(
45 const std::string
& json
) {
47 base::Value
* root
= base::JSONReader::ReadAndReturnError(
48 json
, base::JSON_ALLOW_TRAILING_COMMAS
, NULL
, &error
);
50 base::DictionaryValue
* dict_ptr
= NULL
;
51 if (!root
|| !root
->GetAsDictionary(&dict_ptr
)) {
52 ONC_LOG_ERROR("Invalid JSON Dictionary: " + error
);
56 return make_scoped_ptr(dict_ptr
);
59 scoped_ptr
<base::DictionaryValue
> Decrypt(const std::string
& passphrase
,
60 const base::DictionaryValue
& root
) {
61 const int kKeySizeInBits
= 256;
62 const int kMaxIterationCount
= 500000;
64 std::string initial_vector
;
67 std::string stretch_method
;
68 std::string hmac_method
;
71 std::string ciphertext
;
73 if (!root
.GetString(encrypted::kCiphertext
, &ciphertext
) ||
74 !root
.GetString(encrypted::kCipher
, &cipher
) ||
75 !root
.GetString(encrypted::kHMAC
, &hmac
) ||
76 !root
.GetString(encrypted::kHMACMethod
, &hmac_method
) ||
77 !root
.GetString(encrypted::kIV
, &initial_vector
) ||
78 !root
.GetInteger(encrypted::kIterations
, &iterations
) ||
79 !root
.GetString(encrypted::kSalt
, &salt
) ||
80 !root
.GetString(encrypted::kStretch
, &stretch_method
) ||
81 !root
.GetString(toplevel_config::kType
, &onc_type
) ||
82 onc_type
!= toplevel_config::kEncryptedConfiguration
) {
84 ONC_LOG_ERROR("Encrypted ONC malformed.");
85 return scoped_ptr
<base::DictionaryValue
>();
88 if (hmac_method
!= encrypted::kSHA1
||
89 cipher
!= encrypted::kAES256
||
90 stretch_method
!= encrypted::kPBKDF2
) {
91 ONC_LOG_ERROR("Encrypted ONC unsupported encryption scheme.");
92 return scoped_ptr
<base::DictionaryValue
>();
95 // Make sure iterations != 0, since that's not valid.
96 if (iterations
== 0) {
97 ONC_LOG_ERROR(kUnableToDecrypt
);
98 return scoped_ptr
<base::DictionaryValue
>();
101 // Simply a sanity check to make sure we can't lock up the machine
102 // for too long with a huge number (or a negative number).
103 if (iterations
< 0 || iterations
> kMaxIterationCount
) {
104 ONC_LOG_ERROR("Too many iterations in encrypted ONC");
105 return scoped_ptr
<base::DictionaryValue
>();
108 if (!base::Base64Decode(salt
, &salt
)) {
109 ONC_LOG_ERROR(kUnableToDecode
);
110 return scoped_ptr
<base::DictionaryValue
>();
113 scoped_ptr
<crypto::SymmetricKey
> key(
114 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES
,
120 if (!base::Base64Decode(initial_vector
, &initial_vector
)) {
121 ONC_LOG_ERROR(kUnableToDecode
);
122 return scoped_ptr
<base::DictionaryValue
>();
124 if (!base::Base64Decode(ciphertext
, &ciphertext
)) {
125 ONC_LOG_ERROR(kUnableToDecode
);
126 return scoped_ptr
<base::DictionaryValue
>();
128 if (!base::Base64Decode(hmac
, &hmac
)) {
129 ONC_LOG_ERROR(kUnableToDecode
);
130 return scoped_ptr
<base::DictionaryValue
>();
133 crypto::HMAC
hmac_verifier(crypto::HMAC::SHA1
);
134 if (!hmac_verifier
.Init(key
.get()) ||
135 !hmac_verifier
.Verify(ciphertext
, hmac
)) {
136 ONC_LOG_ERROR(kUnableToDecrypt
);
137 return scoped_ptr
<base::DictionaryValue
>();
140 crypto::Encryptor decryptor
;
141 if (!decryptor
.Init(key
.get(), crypto::Encryptor::CBC
, initial_vector
)) {
142 ONC_LOG_ERROR(kUnableToDecrypt
);
143 return scoped_ptr
<base::DictionaryValue
>();
146 std::string plaintext
;
147 if (!decryptor
.Decrypt(ciphertext
, &plaintext
)) {
148 ONC_LOG_ERROR(kUnableToDecrypt
);
149 return scoped_ptr
<base::DictionaryValue
>();
152 scoped_ptr
<base::DictionaryValue
> new_root
=
153 ReadDictionaryFromJson(plaintext
);
154 if (new_root
.get() == NULL
) {
155 ONC_LOG_ERROR("Property dictionary malformed.");
156 return scoped_ptr
<base::DictionaryValue
>();
159 return new_root
.Pass();
162 std::string
GetSourceAsString(ONCSource source
) {
164 case ONC_SOURCE_UNKNOWN
:
166 case ONC_SOURCE_NONE
:
168 case ONC_SOURCE_DEVICE_POLICY
:
169 return "device policy";
170 case ONC_SOURCE_USER_POLICY
:
171 return "user policy";
172 case ONC_SOURCE_USER_IMPORT
:
173 return "user import";
175 NOTREACHED() << "unknown ONC source " << source
;
179 void ExpandField(const std::string
& fieldname
,
180 const StringSubstitution
& substitution
,
181 base::DictionaryValue
* onc_object
) {
182 std::string user_string
;
183 if (!onc_object
->GetStringWithoutPathExpansion(fieldname
, &user_string
))
186 std::string login_id
;
187 if (substitution
.GetSubstitute(substitutes::kLoginIDField
, &login_id
)) {
188 ReplaceSubstringsAfterOffset(&user_string
, 0,
189 substitutes::kLoginIDField
,
194 if (substitution
.GetSubstitute(substitutes::kEmailField
, &email
)) {
195 ReplaceSubstringsAfterOffset(&user_string
, 0,
196 substitutes::kEmailField
,
200 onc_object
->SetStringWithoutPathExpansion(fieldname
, user_string
);
203 void ExpandStringsInOncObject(
204 const OncValueSignature
& signature
,
205 const StringSubstitution
& substitution
,
206 base::DictionaryValue
* onc_object
) {
207 if (&signature
== &kEAPSignature
) {
208 ExpandField(eap::kAnonymousIdentity
, substitution
, onc_object
);
209 ExpandField(eap::kIdentity
, substitution
, onc_object
);
210 } else if (&signature
== &kL2TPSignature
||
211 &signature
== &kOpenVPNSignature
) {
212 ExpandField(vpn::kUsername
, substitution
, onc_object
);
215 // Recurse into nested objects.
216 for (base::DictionaryValue::Iterator
it(*onc_object
); !it
.IsAtEnd();
218 base::DictionaryValue
* inner_object
= NULL
;
219 if (!onc_object
->GetDictionaryWithoutPathExpansion(it
.key(), &inner_object
))
222 const OncFieldSignature
* field_signature
=
223 GetFieldSignature(signature
, it
.key());
224 if (!field_signature
)
227 ExpandStringsInOncObject(*field_signature
->value_signature
,
228 substitution
, inner_object
);
232 void ExpandStringsInNetworks(const StringSubstitution
& substitution
,
233 base::ListValue
* network_configs
) {
234 for (base::ListValue::iterator it
= network_configs
->begin();
235 it
!= network_configs
->end(); ++it
) {
236 base::DictionaryValue
* network
= NULL
;
237 (*it
)->GetAsDictionary(&network
);
239 ExpandStringsInOncObject(
240 kNetworkConfigurationSignature
, substitution
, network
);
244 void FillInHexSSIDFieldsInOncObject(const OncValueSignature
& signature
,
245 base::DictionaryValue
* onc_object
) {
246 if (&signature
== &kWiFiSignature
)
247 FillInHexSSIDField(onc_object
);
249 // Recurse into nested objects.
250 for (base::DictionaryValue::Iterator
it(*onc_object
); !it
.IsAtEnd();
252 base::DictionaryValue
* inner_object
= nullptr;
253 if (!onc_object
->GetDictionaryWithoutPathExpansion(it
.key(), &inner_object
))
256 const OncFieldSignature
* field_signature
=
257 GetFieldSignature(signature
, it
.key());
258 if (!field_signature
)
261 FillInHexSSIDFieldsInOncObject(*field_signature
->value_signature
,
266 void FillInHexSSIDField(base::DictionaryValue
* wifi_fields
) {
267 if (!wifi_fields
->HasKey(::onc::wifi::kHexSSID
)) {
268 std::string ssid_string
;
269 wifi_fields
->GetStringWithoutPathExpansion(::onc::wifi::kSSID
,
271 wifi_fields
->SetStringWithoutPathExpansion(
272 ::onc::wifi::kHexSSID
,
273 base::HexEncode(ssid_string
.c_str(), ssid_string
.size()));
279 class OncMaskValues
: public Mapper
{
281 static scoped_ptr
<base::DictionaryValue
> Mask(
282 const OncValueSignature
& signature
,
283 const base::DictionaryValue
& onc_object
,
284 const std::string
& mask
) {
285 OncMaskValues
masker(mask
);
287 return masker
.MapObject(signature
, onc_object
, &unused_error
);
291 explicit OncMaskValues(const std::string
& mask
)
295 scoped_ptr
<base::Value
> MapField(const std::string
& field_name
,
296 const OncValueSignature
& object_signature
,
297 const base::Value
& onc_value
,
298 bool* found_unknown_field
,
299 bool* error
) override
{
300 if (FieldIsCredential(object_signature
, field_name
)) {
301 return scoped_ptr
<base::Value
>(new base::StringValue(mask_
));
303 return Mapper::MapField(field_name
, object_signature
, onc_value
,
304 found_unknown_field
, error
);
308 // Mask to insert in place of the sensitive values.
314 scoped_ptr
<base::DictionaryValue
> MaskCredentialsInOncObject(
315 const OncValueSignature
& signature
,
316 const base::DictionaryValue
& onc_object
,
317 const std::string
& mask
) {
318 return OncMaskValues::Mask(signature
, onc_object
, mask
);
323 std::string
DecodePEM(const std::string
& pem_encoded
) {
324 // The PEM block header used for DER certificates
325 const char kCertificateHeader
[] = "CERTIFICATE";
327 // This is an older PEM marker for DER certificates.
328 const char kX509CertificateHeader
[] = "X509 CERTIFICATE";
330 std::vector
<std::string
> pem_headers
;
331 pem_headers
.push_back(kCertificateHeader
);
332 pem_headers
.push_back(kX509CertificateHeader
);
334 net::PEMTokenizer
pem_tokenizer(pem_encoded
, pem_headers
);
336 if (pem_tokenizer
.GetNext()) {
337 decoded
= pem_tokenizer
.data();
339 // If we failed to read the data as a PEM file, then try plain base64 decode
340 // in case the PEM marker strings are missing. For this to work, there has
341 // to be no white space, and it has to only contain the base64-encoded data.
342 if (!base::Base64Decode(pem_encoded
, &decoded
)) {
343 LOG(ERROR
) << "Unable to base64 decode X509 data: " << pem_encoded
;
344 return std::string();
350 CertPEMsByGUIDMap
GetServerAndCACertsByGUID(
351 const base::ListValue
& certificates
) {
352 CertPEMsByGUIDMap certs_by_guid
;
353 for (base::ListValue::const_iterator it
= certificates
.begin();
354 it
!= certificates
.end(); ++it
) {
355 base::DictionaryValue
* cert
= NULL
;
356 (*it
)->GetAsDictionary(&cert
);
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
) {
366 std::string x509_data
;
367 cert
->GetStringWithoutPathExpansion(certificate::kX509
, &x509_data
);
369 std::string der
= DecodePEM(x509_data
);
371 if (der
.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der
, &pem
)) {
372 LOG(ERROR
) << "Certificate with GUID " << guid
373 << " is not in PEM encoding.";
376 certs_by_guid
[guid
] = pem
;
379 return certs_by_guid
;
382 void FillInHexSSIDFieldsInNetworks(base::ListValue
* network_configs
) {
383 for (base::ListValue::iterator it
= network_configs
->begin();
384 it
!= network_configs
->end(); ++it
) {
385 base::DictionaryValue
* network
= NULL
;
386 (*it
)->GetAsDictionary(&network
);
388 FillInHexSSIDFieldsInOncObject(kNetworkConfigurationSignature
, network
);
394 bool ParseAndValidateOncForImport(const std::string
& onc_blob
,
395 ONCSource onc_source
,
396 const std::string
& passphrase
,
397 base::ListValue
* network_configs
,
398 base::DictionaryValue
* global_network_config
,
399 base::ListValue
* certificates
) {
400 network_configs
->Clear();
401 global_network_config
->Clear();
402 certificates
->Clear();
403 if (onc_blob
.empty())
406 scoped_ptr
<base::DictionaryValue
> toplevel_onc
=
407 ReadDictionaryFromJson(onc_blob
);
408 if (toplevel_onc
.get() == NULL
) {
409 LOG(ERROR
) << "ONC loaded from " << GetSourceAsString(onc_source
)
410 << " is not a valid JSON dictionary.";
414 // Check and see if this is an encrypted ONC file. If so, decrypt it.
415 std::string onc_type
;
416 toplevel_onc
->GetStringWithoutPathExpansion(toplevel_config::kType
,
418 if (onc_type
== toplevel_config::kEncryptedConfiguration
) {
419 toplevel_onc
= Decrypt(passphrase
, *toplevel_onc
);
420 if (toplevel_onc
.get() == NULL
) {
421 LOG(ERROR
) << "Couldn't decrypt the ONC from "
422 << GetSourceAsString(onc_source
);
427 bool from_policy
= (onc_source
== ONC_SOURCE_USER_POLICY
||
428 onc_source
== ONC_SOURCE_DEVICE_POLICY
);
430 // Validate the ONC dictionary. We are liberal and ignore unknown field
431 // names and ignore invalid field names in kRecommended arrays.
432 Validator
validator(false, // Ignore unknown fields.
433 false, // Ignore invalid recommended field names.
434 true, // Fail on missing fields.
436 validator
.SetOncSource(onc_source
);
438 Validator::Result validation_result
;
439 toplevel_onc
= validator
.ValidateAndRepairObject(
440 &kToplevelConfigurationSignature
,
445 UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
446 validation_result
== Validator::VALID
);
450 if (validation_result
== Validator::VALID_WITH_WARNINGS
) {
451 LOG(WARNING
) << "ONC from " << GetSourceAsString(onc_source
)
452 << " produced warnings.";
454 } else if (validation_result
== Validator::INVALID
|| toplevel_onc
== NULL
) {
455 LOG(ERROR
) << "ONC from " << GetSourceAsString(onc_source
)
456 << " is invalid and couldn't be repaired.";
460 base::ListValue
* validated_certs
= NULL
;
461 if (toplevel_onc
->GetListWithoutPathExpansion(toplevel_config::kCertificates
,
463 certificates
->Swap(validated_certs
);
466 base::ListValue
* validated_networks
= NULL
;
467 if (toplevel_onc
->GetListWithoutPathExpansion(
468 toplevel_config::kNetworkConfigurations
, &validated_networks
)) {
469 FillInHexSSIDFieldsInNetworks(validated_networks
);
471 CertPEMsByGUIDMap server_and_ca_certs
=
472 GetServerAndCACertsByGUID(*certificates
);
474 if (!ResolveServerCertRefsInNetworks(server_and_ca_certs
,
475 validated_networks
)) {
476 LOG(ERROR
) << "Some certificate references in the ONC policy for source "
477 << GetSourceAsString(onc_source
) << " could not be resolved.";
481 network_configs
->Swap(validated_networks
);
484 base::DictionaryValue
* validated_global_config
= NULL
;
485 if (toplevel_onc
->GetDictionaryWithoutPathExpansion(
486 toplevel_config::kGlobalNetworkConfiguration
,
487 &validated_global_config
)) {
488 global_network_config
->Swap(validated_global_config
);
494 scoped_refptr
<net::X509Certificate
> DecodePEMCertificate(
495 const std::string
& pem_encoded
) {
496 std::string decoded
= DecodePEM(pem_encoded
);
497 scoped_refptr
<net::X509Certificate
> cert
=
498 net::X509Certificate::CreateFromBytes(decoded
.data(), decoded
.size());
499 LOG_IF(ERROR
, !cert
.get()) << "Couldn't create certificate from X509 data: "
506 bool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap
& certs_by_guid
,
507 const std::string
& guid_ref
,
508 std::string
* pem_encoded
) {
509 CertPEMsByGUIDMap::const_iterator it
= certs_by_guid
.find(guid_ref
);
510 if (it
== certs_by_guid
.end()) {
511 LOG(ERROR
) << "Couldn't resolve certificate reference " << guid_ref
;
514 *pem_encoded
= it
->second
;
515 if (pem_encoded
->empty()) {
516 LOG(ERROR
) << "Couldn't PEM-encode certificate with GUID " << guid_ref
;
522 bool ResolveSingleCertRef(const CertPEMsByGUIDMap
& certs_by_guid
,
523 const std::string
& key_guid_ref
,
524 const std::string
& key_pem
,
525 base::DictionaryValue
* onc_object
) {
526 std::string guid_ref
;
527 if (!onc_object
->GetStringWithoutPathExpansion(key_guid_ref
, &guid_ref
))
530 std::string pem_encoded
;
531 if (!GUIDRefToPEMEncoding(certs_by_guid
, guid_ref
, &pem_encoded
))
534 onc_object
->RemoveWithoutPathExpansion(key_guid_ref
, NULL
);
535 onc_object
->SetStringWithoutPathExpansion(key_pem
, pem_encoded
);
539 bool ResolveCertRefList(const CertPEMsByGUIDMap
& certs_by_guid
,
540 const std::string
& key_guid_ref_list
,
541 const std::string
& key_pem_list
,
542 base::DictionaryValue
* onc_object
) {
543 const base::ListValue
* guid_ref_list
= NULL
;
544 if (!onc_object
->GetListWithoutPathExpansion(key_guid_ref_list
,
549 scoped_ptr
<base::ListValue
> pem_list(new base::ListValue
);
550 for (base::ListValue::const_iterator it
= guid_ref_list
->begin();
551 it
!= guid_ref_list
->end(); ++it
) {
552 std::string guid_ref
;
553 (*it
)->GetAsString(&guid_ref
);
555 std::string pem_encoded
;
556 if (!GUIDRefToPEMEncoding(certs_by_guid
, guid_ref
, &pem_encoded
))
559 pem_list
->AppendString(pem_encoded
);
562 onc_object
->RemoveWithoutPathExpansion(key_guid_ref_list
, NULL
);
563 onc_object
->SetWithoutPathExpansion(key_pem_list
, pem_list
.release());
567 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap
& certs_by_guid
,
568 const std::string
& key_guid_ref
,
569 const std::string
& key_pem_list
,
570 base::DictionaryValue
* onc_object
) {
571 std::string guid_ref
;
572 if (!onc_object
->GetStringWithoutPathExpansion(key_guid_ref
, &guid_ref
))
575 std::string pem_encoded
;
576 if (!GUIDRefToPEMEncoding(certs_by_guid
, guid_ref
, &pem_encoded
))
579 scoped_ptr
<base::ListValue
> pem_list(new base::ListValue
);
580 pem_list
->AppendString(pem_encoded
);
581 onc_object
->RemoveWithoutPathExpansion(key_guid_ref
, NULL
);
582 onc_object
->SetWithoutPathExpansion(key_pem_list
, pem_list
.release());
586 // Resolves the reference list at |key_guid_refs| if present and otherwise the
587 // single reference at |key_guid_ref|. Returns whether the respective resolving
589 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap
& certs_by_guid
,
590 const std::string
& key_guid_refs
,
591 const std::string
& key_guid_ref
,
592 const std::string
& key_pem_list
,
593 base::DictionaryValue
* onc_object
) {
594 if (onc_object
->HasKey(key_guid_refs
)) {
595 if (onc_object
->HasKey(key_guid_ref
)) {
596 LOG(ERROR
) << "Found both " << key_guid_refs
<< " and " << key_guid_ref
597 << ". Ignoring and removing the latter.";
598 onc_object
->RemoveWithoutPathExpansion(key_guid_ref
, NULL
);
600 return ResolveCertRefList(
601 certs_by_guid
, key_guid_refs
, key_pem_list
, onc_object
);
604 // Only resolve |key_guid_ref| if |key_guid_refs| isn't present.
605 return ResolveSingleCertRefToList(
606 certs_by_guid
, key_guid_ref
, key_pem_list
, onc_object
);
609 bool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap
& certs_by_guid
,
610 const OncValueSignature
& signature
,
611 base::DictionaryValue
* onc_object
) {
612 if (&signature
== &kCertificatePatternSignature
) {
613 if (!ResolveCertRefList(certs_by_guid
,
614 client_cert::kIssuerCARef
,
615 client_cert::kIssuerCAPEMs
,
619 } else if (&signature
== &kEAPSignature
) {
620 if (!ResolveCertRefsOrRefToList(certs_by_guid
,
627 } else if (&signature
== &kIPsecSignature
) {
628 if (!ResolveCertRefsOrRefToList(certs_by_guid
,
629 ipsec::kServerCARefs
,
631 ipsec::kServerCAPEMs
,
635 } else if (&signature
== &kIPsecSignature
||
636 &signature
== &kOpenVPNSignature
) {
637 if (!ResolveSingleCertRef(certs_by_guid
,
638 openvpn::kServerCertRef
,
639 openvpn::kServerCertPEM
,
641 !ResolveCertRefsOrRefToList(certs_by_guid
,
642 openvpn::kServerCARefs
,
643 openvpn::kServerCARef
,
644 openvpn::kServerCAPEMs
,
650 // Recurse into nested objects.
651 for (base::DictionaryValue::Iterator
it(*onc_object
); !it
.IsAtEnd();
653 base::DictionaryValue
* inner_object
= NULL
;
654 if (!onc_object
->GetDictionaryWithoutPathExpansion(it
.key(), &inner_object
))
657 const OncFieldSignature
* field_signature
=
658 GetFieldSignature(signature
, it
.key());
659 if (!field_signature
)
662 if (!ResolveServerCertRefsInObject(certs_by_guid
,
663 *field_signature
->value_signature
,
673 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap
& certs_by_guid
,
674 base::ListValue
* network_configs
) {
676 for (base::ListValue::iterator it
= network_configs
->begin();
677 it
!= network_configs
->end(); ) {
678 base::DictionaryValue
* network
= NULL
;
679 (*it
)->GetAsDictionary(&network
);
680 if (!ResolveServerCertRefsInNetwork(certs_by_guid
, network
)) {
682 network
->GetStringWithoutPathExpansion(network_config::kGUID
, &guid
);
683 // This might happen even with correct validation, if the referenced
684 // certificate couldn't be imported.
685 LOG(ERROR
) << "Couldn't resolve some certificate reference of network "
687 it
= network_configs
->Erase(it
, NULL
);
696 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap
& certs_by_guid
,
697 base::DictionaryValue
* network_config
) {
698 return ResolveServerCertRefsInObject(certs_by_guid
,
699 kNetworkConfigurationSignature
,
703 NetworkTypePattern
NetworkTypePatternFromOncType(const std::string
& type
) {
704 if (type
== ::onc::network_type::kAllTypes
)
705 return NetworkTypePattern::Default();
706 if (type
== ::onc::network_type::kCellular
)
707 return NetworkTypePattern::Cellular();
708 if (type
== ::onc::network_type::kEthernet
)
709 return NetworkTypePattern::Ethernet();
710 if (type
== ::onc::network_type::kVPN
)
711 return NetworkTypePattern::VPN();
712 if (type
== ::onc::network_type::kWiFi
)
713 return NetworkTypePattern::WiFi();
714 if (type
== ::onc::network_type::kWimax
)
715 return NetworkTypePattern::Wimax();
716 if (type
== ::onc::network_type::kWireless
)
717 return NetworkTypePattern::Wireless();
719 return NetworkTypePattern::Default();
722 bool IsRecommendedValue(const base::DictionaryValue
* onc
,
723 const std::string
& property_key
) {
724 std::string property_basename
, recommended_property_key
;
725 size_t pos
= property_key
.find_last_of('.');
726 if (pos
!= std::string::npos
) {
727 // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended'
728 property_basename
= property_key
.substr(pos
+ 1);
729 recommended_property_key
=
730 property_key
.substr(0, pos
+ 1) + ::onc::kRecommended
;
732 // 'Name' -> 'Name', 'Recommended'
733 property_basename
= property_key
;
734 recommended_property_key
= ::onc::kRecommended
;
737 const base::ListValue
* recommended_keys
= NULL
;
738 return (onc
->GetList(recommended_property_key
, &recommended_keys
) &&
739 recommended_keys
->Find(base::StringValue(property_basename
)) !=
740 recommended_keys
->end());
744 } // namespace chromeos