Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chromeos / network / onc / onc_utils.cc
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_utils.h"
6
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_util.h"
12 #include "base/values.h"
13 #include "chromeos/network/network_event_log.h"
14 #include "chromeos/network/onc/onc_mapper.h"
15 #include "chromeos/network/onc/onc_signature.h"
16 #include "chromeos/network/onc/onc_utils.h"
17 #include "chromeos/network/onc/onc_validator.h"
18 #include "crypto/encryptor.h"
19 #include "crypto/hmac.h"
20 #include "crypto/symmetric_key.h"
21 #include "net/cert/pem_tokenizer.h"
22 #include "net/cert/x509_certificate.h"
23
24 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
25 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
26
27 using namespace ::onc;
28
29 namespace chromeos {
30 namespace onc {
31
32 namespace {
33
34 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC";
35 const char kUnableToDecode[] = "Unable to decode encrypted ONC";
36
37 }  // namespace
38
39 const char kEmptyUnencryptedConfiguration[] =
40     "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[],"
41     "\"Certificates\":[]}";
42
43 scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson(
44     const std::string& json) {
45   std::string error;
46   base::Value* root = base::JSONReader::ReadAndReturnError(
47       json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error);
48
49   base::DictionaryValue* dict_ptr = NULL;
50   if (!root || !root->GetAsDictionary(&dict_ptr)) {
51     ONC_LOG_ERROR("Invalid JSON Dictionary: " + error);
52     delete root;
53   }
54
55   return make_scoped_ptr(dict_ptr);
56 }
57
58 scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase,
59                                           const base::DictionaryValue& root) {
60   const int kKeySizeInBits = 256;
61   const int kMaxIterationCount = 500000;
62   std::string onc_type;
63   std::string initial_vector;
64   std::string salt;
65   std::string cipher;
66   std::string stretch_method;
67   std::string hmac_method;
68   std::string hmac;
69   int iterations;
70   std::string ciphertext;
71
72   if (!root.GetString(encrypted::kCiphertext, &ciphertext) ||
73       !root.GetString(encrypted::kCipher, &cipher) ||
74       !root.GetString(encrypted::kHMAC, &hmac) ||
75       !root.GetString(encrypted::kHMACMethod, &hmac_method) ||
76       !root.GetString(encrypted::kIV, &initial_vector) ||
77       !root.GetInteger(encrypted::kIterations, &iterations) ||
78       !root.GetString(encrypted::kSalt, &salt) ||
79       !root.GetString(encrypted::kStretch, &stretch_method) ||
80       !root.GetString(toplevel_config::kType, &onc_type) ||
81       onc_type != toplevel_config::kEncryptedConfiguration) {
82
83     ONC_LOG_ERROR("Encrypted ONC malformed.");
84     return scoped_ptr<base::DictionaryValue>();
85   }
86
87   if (hmac_method != encrypted::kSHA1 ||
88       cipher != encrypted::kAES256 ||
89       stretch_method != encrypted::kPBKDF2) {
90     ONC_LOG_ERROR("Encrypted ONC unsupported encryption scheme.");
91     return scoped_ptr<base::DictionaryValue>();
92   }
93
94   // Make sure iterations != 0, since that's not valid.
95   if (iterations == 0) {
96     ONC_LOG_ERROR(kUnableToDecrypt);
97     return scoped_ptr<base::DictionaryValue>();
98   }
99
100   // Simply a sanity check to make sure we can't lock up the machine
101   // for too long with a huge number (or a negative number).
102   if (iterations < 0 || iterations > kMaxIterationCount) {
103     ONC_LOG_ERROR("Too many iterations in encrypted ONC");
104     return scoped_ptr<base::DictionaryValue>();
105   }
106
107   if (!base::Base64Decode(salt, &salt)) {
108     ONC_LOG_ERROR(kUnableToDecode);
109     return scoped_ptr<base::DictionaryValue>();
110   }
111
112   scoped_ptr<crypto::SymmetricKey> key(
113       crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
114                                                   passphrase,
115                                                   salt,
116                                                   iterations,
117                                                   kKeySizeInBits));
118
119   if (!base::Base64Decode(initial_vector, &initial_vector)) {
120     ONC_LOG_ERROR(kUnableToDecode);
121     return scoped_ptr<base::DictionaryValue>();
122   }
123   if (!base::Base64Decode(ciphertext, &ciphertext)) {
124     ONC_LOG_ERROR(kUnableToDecode);
125     return scoped_ptr<base::DictionaryValue>();
126   }
127   if (!base::Base64Decode(hmac, &hmac)) {
128     ONC_LOG_ERROR(kUnableToDecode);
129     return scoped_ptr<base::DictionaryValue>();
130   }
131
132   crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
133   if (!hmac_verifier.Init(key.get()) ||
134       !hmac_verifier.Verify(ciphertext, hmac)) {
135     ONC_LOG_ERROR(kUnableToDecrypt);
136     return scoped_ptr<base::DictionaryValue>();
137   }
138
139   crypto::Encryptor decryptor;
140   if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector))  {
141     ONC_LOG_ERROR(kUnableToDecrypt);
142     return scoped_ptr<base::DictionaryValue>();
143   }
144
145   std::string plaintext;
146   if (!decryptor.Decrypt(ciphertext, &plaintext)) {
147     ONC_LOG_ERROR(kUnableToDecrypt);
148     return scoped_ptr<base::DictionaryValue>();
149   }
150
151   scoped_ptr<base::DictionaryValue> new_root =
152       ReadDictionaryFromJson(plaintext);
153   if (new_root.get() == NULL) {
154     ONC_LOG_ERROR("Property dictionary malformed.");
155     return scoped_ptr<base::DictionaryValue>();
156   }
157
158   return new_root.Pass();
159 }
160
161 std::string GetSourceAsString(ONCSource source) {
162   switch (source) {
163     case ONC_SOURCE_DEVICE_POLICY:
164       return "device policy";
165     case ONC_SOURCE_USER_POLICY:
166       return "user policy";
167     case ONC_SOURCE_NONE:
168       return "none";
169     case ONC_SOURCE_USER_IMPORT:
170       return "user import";
171   }
172   NOTREACHED() << "unknown ONC source " << source;
173   return "unknown";
174 }
175
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;
182
183   std::string login_id;
184   if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) {
185     ReplaceSubstringsAfterOffset(&user_string, 0,
186                                  substitutes::kLoginIDField,
187                                  login_id);
188   }
189
190   std::string email;
191   if (substitution.GetSubstitute(substitutes::kEmailField, &email)) {
192     ReplaceSubstringsAfterOffset(&user_string, 0,
193                                  substitutes::kEmailField,
194                                  email);
195   }
196
197   onc_object->SetStringWithoutPathExpansion(fieldname, user_string);
198 }
199
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);
210   }
211
212   // Recurse into nested objects.
213   for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
214        it.Advance()) {
215     base::DictionaryValue* inner_object = NULL;
216     if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
217       continue;
218
219     const OncFieldSignature* field_signature =
220         GetFieldSignature(signature, it.key());
221     if (!field_signature)
222       continue;
223
224     ExpandStringsInOncObject(*field_signature->value_signature,
225                              substitution, inner_object);
226   }
227 }
228
229 void ExpandStringsInNetworks(const StringSubstitution& substitution,
230                              base::ListValue* network_configs) {
231   for (base::ListValue::iterator it = network_configs->begin();
232        it != network_configs->end(); ++it) {
233     base::DictionaryValue* network = NULL;
234     (*it)->GetAsDictionary(&network);
235     DCHECK(network);
236     ExpandStringsInOncObject(
237         kNetworkConfigurationSignature, substitution, network);
238   }
239 }
240
241 namespace {
242
243 class OncMaskValues : public Mapper {
244  public:
245   static scoped_ptr<base::DictionaryValue> Mask(
246       const OncValueSignature& signature,
247       const base::DictionaryValue& onc_object,
248       const std::string& mask) {
249     OncMaskValues masker(mask);
250     bool unused_error;
251     return masker.MapObject(signature, onc_object, &unused_error);
252   }
253
254  protected:
255   explicit OncMaskValues(const std::string& mask)
256       : mask_(mask) {
257   }
258
259   virtual scoped_ptr<base::Value> MapField(
260       const std::string& field_name,
261       const OncValueSignature& object_signature,
262       const base::Value& onc_value,
263       bool* found_unknown_field,
264       bool* error) OVERRIDE {
265     if (FieldIsCredential(object_signature, field_name)) {
266       return scoped_ptr<base::Value>(new base::StringValue(mask_));
267     } else {
268       return Mapper::MapField(field_name, object_signature, onc_value,
269                               found_unknown_field, error);
270     }
271   }
272
273   // Mask to insert in place of the sensitive values.
274   std::string mask_;
275 };
276
277 }  // namespace
278
279 scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
280     const OncValueSignature& signature,
281     const base::DictionaryValue& onc_object,
282     const std::string& mask) {
283   return OncMaskValues::Mask(signature, onc_object, mask);
284 }
285
286 namespace {
287
288 std::string DecodePEM(const std::string& pem_encoded) {
289   // The PEM block header used for DER certificates
290   const char kCertificateHeader[] = "CERTIFICATE";
291
292   // This is an older PEM marker for DER certificates.
293   const char kX509CertificateHeader[] = "X509 CERTIFICATE";
294
295   std::vector<std::string> pem_headers;
296   pem_headers.push_back(kCertificateHeader);
297   pem_headers.push_back(kX509CertificateHeader);
298
299   net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
300   std::string decoded;
301   if (pem_tokenizer.GetNext()) {
302     decoded = pem_tokenizer.data();
303   } else {
304     // If we failed to read the data as a PEM file, then try plain base64 decode
305     // in case the PEM marker strings are missing. For this to work, there has
306     // to be no white space, and it has to only contain the base64-encoded data.
307     if (!base::Base64Decode(pem_encoded, &decoded)) {
308       LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
309       return std::string();
310     }
311   }
312   return decoded;
313 }
314
315 CertPEMsByGUIDMap GetServerAndCACertsByGUID(
316     const base::ListValue& certificates) {
317   CertPEMsByGUIDMap certs_by_guid;
318   for (base::ListValue::const_iterator it = certificates.begin();
319       it != certificates.end(); ++it) {
320     base::DictionaryValue* cert = NULL;
321     (*it)->GetAsDictionary(&cert);
322
323     std::string guid;
324     cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid);
325     std::string cert_type;
326     cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type);
327     if (cert_type != certificate::kServer &&
328         cert_type != certificate::kAuthority) {
329       continue;
330     }
331     std::string x509_data;
332     cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data);
333
334     std::string der = DecodePEM(x509_data);
335     std::string pem;
336     if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) {
337       LOG(ERROR) << "Certificate with GUID " << guid
338                  << " is not in PEM encoding.";
339       continue;
340     }
341     certs_by_guid[guid] = pem;
342   }
343
344   return certs_by_guid;
345 }
346
347 }  // namespace
348
349 bool ParseAndValidateOncForImport(const std::string& onc_blob,
350                                   ONCSource onc_source,
351                                   const std::string& passphrase,
352                                   base::ListValue* network_configs,
353                                   base::DictionaryValue* global_network_config,
354                                   base::ListValue* certificates) {
355   network_configs->Clear();
356   global_network_config->Clear();
357   certificates->Clear();
358   if (onc_blob.empty())
359     return true;
360
361   scoped_ptr<base::DictionaryValue> toplevel_onc =
362       ReadDictionaryFromJson(onc_blob);
363   if (toplevel_onc.get() == NULL) {
364     LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source)
365                << " is not a valid JSON dictionary.";
366     return false;
367   }
368
369   // Check and see if this is an encrypted ONC file. If so, decrypt it.
370   std::string onc_type;
371   toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType,
372                                               &onc_type);
373   if (onc_type == toplevel_config::kEncryptedConfiguration) {
374     toplevel_onc = Decrypt(passphrase, *toplevel_onc);
375     if (toplevel_onc.get() == NULL) {
376       LOG(ERROR) << "Couldn't decrypt the ONC from "
377                  << GetSourceAsString(onc_source);
378       return false;
379     }
380   }
381
382   bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY ||
383                       onc_source == ONC_SOURCE_DEVICE_POLICY);
384
385   // Validate the ONC dictionary. We are liberal and ignore unknown field
386   // names and ignore invalid field names in kRecommended arrays.
387   Validator validator(false,  // Ignore unknown fields.
388                       false,  // Ignore invalid recommended field names.
389                       true,   // Fail on missing fields.
390                       from_policy);
391   validator.SetOncSource(onc_source);
392
393   Validator::Result validation_result;
394   toplevel_onc = validator.ValidateAndRepairObject(
395       &kToplevelConfigurationSignature,
396       *toplevel_onc,
397       &validation_result);
398
399   if (from_policy) {
400     UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
401                           validation_result == Validator::VALID);
402   }
403
404   bool success = true;
405   if (validation_result == Validator::VALID_WITH_WARNINGS) {
406     LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source)
407                  << " produced warnings.";
408     success = false;
409   } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) {
410     LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source)
411                << " is invalid and couldn't be repaired.";
412     return false;
413   }
414
415   base::ListValue* validated_certs = NULL;
416   if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates,
417                                                 &validated_certs)) {
418     certificates->Swap(validated_certs);
419   }
420
421   base::ListValue* validated_networks = NULL;
422   if (toplevel_onc->GetListWithoutPathExpansion(
423           toplevel_config::kNetworkConfigurations, &validated_networks)) {
424     CertPEMsByGUIDMap server_and_ca_certs =
425         GetServerAndCACertsByGUID(*certificates);
426
427     if (!ResolveServerCertRefsInNetworks(server_and_ca_certs,
428                                          validated_networks)) {
429       LOG(ERROR) << "Some certificate references in the ONC policy for source "
430                  << GetSourceAsString(onc_source) << " could not be resolved.";
431       success = false;
432     }
433
434     network_configs->Swap(validated_networks);
435   }
436
437   base::DictionaryValue* validated_global_config = NULL;
438   if (toplevel_onc->GetDictionaryWithoutPathExpansion(
439           toplevel_config::kGlobalNetworkConfiguration,
440           &validated_global_config)) {
441     global_network_config->Swap(validated_global_config);
442   }
443
444   return success;
445 }
446
447 scoped_refptr<net::X509Certificate> DecodePEMCertificate(
448     const std::string& pem_encoded) {
449   std::string decoded = DecodePEM(pem_encoded);
450   scoped_refptr<net::X509Certificate> cert =
451       net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size());
452   LOG_IF(ERROR, !cert.get()) << "Couldn't create certificate from X509 data: "
453                              << decoded;
454   return cert;
455 }
456
457 namespace {
458
459 bool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap& certs_by_guid,
460                           const std::string& guid_ref,
461                           std::string* pem_encoded) {
462   CertPEMsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref);
463   if (it == certs_by_guid.end()) {
464     LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
465     return false;
466   }
467   *pem_encoded = it->second;
468   if (pem_encoded->empty()) {
469     LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref;
470     return false;
471   }
472   return true;
473 }
474
475 bool ResolveSingleCertRef(const CertPEMsByGUIDMap& certs_by_guid,
476                           const std::string& key_guid_ref,
477                           const std::string& key_pem,
478                           base::DictionaryValue* onc_object) {
479   std::string guid_ref;
480   if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
481     return true;
482
483   std::string pem_encoded;
484   if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
485     return false;
486
487   onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
488   onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded);
489   return true;
490 }
491
492 bool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid,
493                         const std::string& key_guid_ref_list,
494                         const std::string& key_pem_list,
495                         base::DictionaryValue* onc_object) {
496   const base::ListValue* guid_ref_list = NULL;
497   if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list,
498                                                &guid_ref_list)) {
499     return true;
500   }
501
502   scoped_ptr<base::ListValue> pem_list(new base::ListValue);
503   for (base::ListValue::const_iterator it = guid_ref_list->begin();
504        it != guid_ref_list->end(); ++it) {
505     std::string guid_ref;
506     (*it)->GetAsString(&guid_ref);
507
508     std::string pem_encoded;
509     if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
510       return false;
511
512     pem_list->AppendString(pem_encoded);
513   }
514
515   onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, NULL);
516   onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
517   return true;
518 }
519
520 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid,
521                                 const std::string& key_guid_ref,
522                                 const std::string& key_pem_list,
523                                 base::DictionaryValue* onc_object) {
524   std::string guid_ref;
525   if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
526     return true;
527
528   std::string pem_encoded;
529   if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
530     return false;
531
532   scoped_ptr<base::ListValue> pem_list(new base::ListValue);
533   pem_list->AppendString(pem_encoded);
534   onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
535   onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
536   return true;
537 }
538
539 // Resolves the reference list at |key_guid_refs| if present and otherwise the
540 // single reference at |key_guid_ref|. Returns whether the respective resolving
541 // was successful.
542 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid,
543                                 const std::string& key_guid_refs,
544                                 const std::string& key_guid_ref,
545                                 const std::string& key_pem_list,
546                                 base::DictionaryValue* onc_object) {
547   if (onc_object->HasKey(key_guid_refs)) {
548     if (onc_object->HasKey(key_guid_ref)) {
549       LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref
550                  << ". Ignoring and removing the latter.";
551       onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
552     }
553     return ResolveCertRefList(
554         certs_by_guid, key_guid_refs, key_pem_list, onc_object);
555   }
556
557   // Only resolve |key_guid_ref| if |key_guid_refs| isn't present.
558   return ResolveSingleCertRefToList(
559       certs_by_guid, key_guid_ref, key_pem_list, onc_object);
560 }
561
562 bool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap& certs_by_guid,
563                                    const OncValueSignature& signature,
564                                    base::DictionaryValue* onc_object) {
565   if (&signature == &kCertificatePatternSignature) {
566     if (!ResolveCertRefList(certs_by_guid,
567                             client_cert::kIssuerCARef,
568                             client_cert::kIssuerCAPEMs,
569                             onc_object)) {
570       return false;
571     }
572   } else if (&signature == &kEAPSignature) {
573     if (!ResolveCertRefsOrRefToList(certs_by_guid,
574                                     eap::kServerCARefs,
575                                     eap::kServerCARef,
576                                     eap::kServerCAPEMs,
577                                     onc_object)) {
578       return false;
579     }
580   } else if (&signature == &kIPsecSignature) {
581     if (!ResolveCertRefsOrRefToList(certs_by_guid,
582                                     ipsec::kServerCARefs,
583                                     ipsec::kServerCARef,
584                                     ipsec::kServerCAPEMs,
585                                     onc_object)) {
586       return false;
587     }
588   } else if (&signature == &kIPsecSignature ||
589              &signature == &kOpenVPNSignature) {
590     if (!ResolveSingleCertRef(certs_by_guid,
591                               openvpn::kServerCertRef,
592                               openvpn::kServerCertPEM,
593                               onc_object) ||
594         !ResolveCertRefsOrRefToList(certs_by_guid,
595                                     openvpn::kServerCARefs,
596                                     openvpn::kServerCARef,
597                                     openvpn::kServerCAPEMs,
598                                     onc_object)) {
599       return false;
600     }
601   }
602
603   // Recurse into nested objects.
604   for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
605        it.Advance()) {
606     base::DictionaryValue* inner_object = NULL;
607     if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
608       continue;
609
610     const OncFieldSignature* field_signature =
611         GetFieldSignature(signature, it.key());
612     if (!field_signature)
613       continue;
614
615     if (!ResolveServerCertRefsInObject(certs_by_guid,
616                                        *field_signature->value_signature,
617                                        inner_object)) {
618       return false;
619     }
620   }
621   return true;
622 }
623
624 }  // namespace
625
626 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid,
627                                      base::ListValue* network_configs) {
628   bool success = true;
629   for (base::ListValue::iterator it = network_configs->begin();
630        it != network_configs->end(); ) {
631     base::DictionaryValue* network = NULL;
632     (*it)->GetAsDictionary(&network);
633     if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
634       std::string guid;
635       network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
636       // This might happen even with correct validation, if the referenced
637       // certificate couldn't be imported.
638       LOG(ERROR) << "Couldn't resolve some certificate reference of network "
639                  << guid;
640       it = network_configs->Erase(it, NULL);
641       success = false;
642       continue;
643     }
644     ++it;
645   }
646   return success;
647 }
648
649 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid,
650                                     base::DictionaryValue* network_config) {
651   return ResolveServerCertRefsInObject(certs_by_guid,
652                                        kNetworkConfigurationSignature,
653                                        network_config);
654 }
655
656 NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) {
657   if (type == ::onc::network_type::kAllTypes)
658     return NetworkTypePattern::Default();
659   if (type == ::onc::network_type::kCellular)
660     return NetworkTypePattern::Cellular();
661   if (type == ::onc::network_type::kEthernet)
662     return NetworkTypePattern::Ethernet();
663   if (type == ::onc::network_type::kVPN)
664     return NetworkTypePattern::VPN();
665   if (type == ::onc::network_type::kWiFi)
666     return NetworkTypePattern::WiFi();
667   if (type == ::onc::network_type::kWimax)
668     return NetworkTypePattern::Wimax();
669   if (type == ::onc::network_type::kWireless)
670     return NetworkTypePattern::Wireless();
671   NOTREACHED();
672   return NetworkTypePattern::Default();
673 }
674
675 bool IsRecommendedValue(const base::DictionaryValue* onc,
676                         const std::string& property_key) {
677   std::string property_basename, recommended_property_key;
678   size_t pos = property_key.find_last_of('.');
679   if (pos != std::string::npos) {
680     // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended'
681     property_basename = property_key.substr(pos + 1);
682     recommended_property_key =
683         property_key.substr(0, pos + 1) + ::onc::kRecommended;
684   } else {
685     // 'Name' -> 'Name', 'Recommended'
686     property_basename = property_key;
687     recommended_property_key = ::onc::kRecommended;
688   }
689
690   const base::ListValue* recommended_keys = NULL;
691   return (onc->GetList(recommended_property_key, &recommended_keys) &&
692           recommended_keys->Find(base::StringValue(property_basename)) !=
693           recommended_keys->end());
694 }
695
696 }  // namespace onc
697 }  // namespace chromeos