Upstream version 10.39.225.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_UNKNOWN:
164       return "unknown";
165     case ONC_SOURCE_NONE:
166       return "none";
167     case ONC_SOURCE_DEVICE_POLICY:
168       return "device policy";
169     case ONC_SOURCE_USER_POLICY:
170       return "user policy";
171     case ONC_SOURCE_USER_IMPORT:
172       return "user import";
173   }
174   NOTREACHED() << "unknown ONC source " << source;
175   return "unknown";
176 }
177
178 void ExpandField(const std::string& fieldname,
179                  const StringSubstitution& substitution,
180                  base::DictionaryValue* onc_object) {
181   std::string user_string;
182   if (!onc_object->GetStringWithoutPathExpansion(fieldname, &user_string))
183     return;
184
185   std::string login_id;
186   if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) {
187     ReplaceSubstringsAfterOffset(&user_string, 0,
188                                  substitutes::kLoginIDField,
189                                  login_id);
190   }
191
192   std::string email;
193   if (substitution.GetSubstitute(substitutes::kEmailField, &email)) {
194     ReplaceSubstringsAfterOffset(&user_string, 0,
195                                  substitutes::kEmailField,
196                                  email);
197   }
198
199   onc_object->SetStringWithoutPathExpansion(fieldname, user_string);
200 }
201
202 void ExpandStringsInOncObject(
203     const OncValueSignature& signature,
204     const StringSubstitution& substitution,
205     base::DictionaryValue* onc_object) {
206   if (&signature == &kEAPSignature) {
207     ExpandField(eap::kAnonymousIdentity, substitution, onc_object);
208     ExpandField(eap::kIdentity, substitution, onc_object);
209   } else if (&signature == &kL2TPSignature ||
210              &signature == &kOpenVPNSignature) {
211     ExpandField(vpn::kUsername, substitution, onc_object);
212   }
213
214   // Recurse into nested objects.
215   for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
216        it.Advance()) {
217     base::DictionaryValue* inner_object = NULL;
218     if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
219       continue;
220
221     const OncFieldSignature* field_signature =
222         GetFieldSignature(signature, it.key());
223     if (!field_signature)
224       continue;
225
226     ExpandStringsInOncObject(*field_signature->value_signature,
227                              substitution, inner_object);
228   }
229 }
230
231 void ExpandStringsInNetworks(const StringSubstitution& substitution,
232                              base::ListValue* network_configs) {
233   for (base::ListValue::iterator it = network_configs->begin();
234        it != network_configs->end(); ++it) {
235     base::DictionaryValue* network = NULL;
236     (*it)->GetAsDictionary(&network);
237     DCHECK(network);
238     ExpandStringsInOncObject(
239         kNetworkConfigurationSignature, substitution, network);
240   }
241 }
242
243 namespace {
244
245 class OncMaskValues : public Mapper {
246  public:
247   static scoped_ptr<base::DictionaryValue> Mask(
248       const OncValueSignature& signature,
249       const base::DictionaryValue& onc_object,
250       const std::string& mask) {
251     OncMaskValues masker(mask);
252     bool unused_error;
253     return masker.MapObject(signature, onc_object, &unused_error);
254   }
255
256  protected:
257   explicit OncMaskValues(const std::string& mask)
258       : mask_(mask) {
259   }
260
261   virtual scoped_ptr<base::Value> MapField(
262       const std::string& field_name,
263       const OncValueSignature& object_signature,
264       const base::Value& onc_value,
265       bool* found_unknown_field,
266       bool* error) OVERRIDE {
267     if (FieldIsCredential(object_signature, field_name)) {
268       return scoped_ptr<base::Value>(new base::StringValue(mask_));
269     } else {
270       return Mapper::MapField(field_name, object_signature, onc_value,
271                               found_unknown_field, error);
272     }
273   }
274
275   // Mask to insert in place of the sensitive values.
276   std::string mask_;
277 };
278
279 }  // namespace
280
281 scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
282     const OncValueSignature& signature,
283     const base::DictionaryValue& onc_object,
284     const std::string& mask) {
285   return OncMaskValues::Mask(signature, onc_object, mask);
286 }
287
288 namespace {
289
290 std::string DecodePEM(const std::string& pem_encoded) {
291   // The PEM block header used for DER certificates
292   const char kCertificateHeader[] = "CERTIFICATE";
293
294   // This is an older PEM marker for DER certificates.
295   const char kX509CertificateHeader[] = "X509 CERTIFICATE";
296
297   std::vector<std::string> pem_headers;
298   pem_headers.push_back(kCertificateHeader);
299   pem_headers.push_back(kX509CertificateHeader);
300
301   net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
302   std::string decoded;
303   if (pem_tokenizer.GetNext()) {
304     decoded = pem_tokenizer.data();
305   } else {
306     // If we failed to read the data as a PEM file, then try plain base64 decode
307     // in case the PEM marker strings are missing. For this to work, there has
308     // to be no white space, and it has to only contain the base64-encoded data.
309     if (!base::Base64Decode(pem_encoded, &decoded)) {
310       LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
311       return std::string();
312     }
313   }
314   return decoded;
315 }
316
317 CertPEMsByGUIDMap GetServerAndCACertsByGUID(
318     const base::ListValue& certificates) {
319   CertPEMsByGUIDMap certs_by_guid;
320   for (base::ListValue::const_iterator it = certificates.begin();
321       it != certificates.end(); ++it) {
322     base::DictionaryValue* cert = NULL;
323     (*it)->GetAsDictionary(&cert);
324
325     std::string guid;
326     cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid);
327     std::string cert_type;
328     cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type);
329     if (cert_type != certificate::kServer &&
330         cert_type != certificate::kAuthority) {
331       continue;
332     }
333     std::string x509_data;
334     cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data);
335
336     std::string der = DecodePEM(x509_data);
337     std::string pem;
338     if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) {
339       LOG(ERROR) << "Certificate with GUID " << guid
340                  << " is not in PEM encoding.";
341       continue;
342     }
343     certs_by_guid[guid] = pem;
344   }
345
346   return certs_by_guid;
347 }
348
349 }  // namespace
350
351 bool ParseAndValidateOncForImport(const std::string& onc_blob,
352                                   ONCSource onc_source,
353                                   const std::string& passphrase,
354                                   base::ListValue* network_configs,
355                                   base::DictionaryValue* global_network_config,
356                                   base::ListValue* certificates) {
357   network_configs->Clear();
358   global_network_config->Clear();
359   certificates->Clear();
360   if (onc_blob.empty())
361     return true;
362
363   scoped_ptr<base::DictionaryValue> toplevel_onc =
364       ReadDictionaryFromJson(onc_blob);
365   if (toplevel_onc.get() == NULL) {
366     LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source)
367                << " is not a valid JSON dictionary.";
368     return false;
369   }
370
371   // Check and see if this is an encrypted ONC file. If so, decrypt it.
372   std::string onc_type;
373   toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType,
374                                               &onc_type);
375   if (onc_type == toplevel_config::kEncryptedConfiguration) {
376     toplevel_onc = Decrypt(passphrase, *toplevel_onc);
377     if (toplevel_onc.get() == NULL) {
378       LOG(ERROR) << "Couldn't decrypt the ONC from "
379                  << GetSourceAsString(onc_source);
380       return false;
381     }
382   }
383
384   bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY ||
385                       onc_source == ONC_SOURCE_DEVICE_POLICY);
386
387   // Validate the ONC dictionary. We are liberal and ignore unknown field
388   // names and ignore invalid field names in kRecommended arrays.
389   Validator validator(false,  // Ignore unknown fields.
390                       false,  // Ignore invalid recommended field names.
391                       true,   // Fail on missing fields.
392                       from_policy);
393   validator.SetOncSource(onc_source);
394
395   Validator::Result validation_result;
396   toplevel_onc = validator.ValidateAndRepairObject(
397       &kToplevelConfigurationSignature,
398       *toplevel_onc,
399       &validation_result);
400
401   if (from_policy) {
402     UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
403                           validation_result == Validator::VALID);
404   }
405
406   bool success = true;
407   if (validation_result == Validator::VALID_WITH_WARNINGS) {
408     LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source)
409                  << " produced warnings.";
410     success = false;
411   } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) {
412     LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source)
413                << " is invalid and couldn't be repaired.";
414     return false;
415   }
416
417   base::ListValue* validated_certs = NULL;
418   if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates,
419                                                 &validated_certs)) {
420     certificates->Swap(validated_certs);
421   }
422
423   base::ListValue* validated_networks = NULL;
424   if (toplevel_onc->GetListWithoutPathExpansion(
425           toplevel_config::kNetworkConfigurations, &validated_networks)) {
426     CertPEMsByGUIDMap server_and_ca_certs =
427         GetServerAndCACertsByGUID(*certificates);
428
429     if (!ResolveServerCertRefsInNetworks(server_and_ca_certs,
430                                          validated_networks)) {
431       LOG(ERROR) << "Some certificate references in the ONC policy for source "
432                  << GetSourceAsString(onc_source) << " could not be resolved.";
433       success = false;
434     }
435
436     network_configs->Swap(validated_networks);
437   }
438
439   base::DictionaryValue* validated_global_config = NULL;
440   if (toplevel_onc->GetDictionaryWithoutPathExpansion(
441           toplevel_config::kGlobalNetworkConfiguration,
442           &validated_global_config)) {
443     global_network_config->Swap(validated_global_config);
444   }
445
446   return success;
447 }
448
449 scoped_refptr<net::X509Certificate> DecodePEMCertificate(
450     const std::string& pem_encoded) {
451   std::string decoded = DecodePEM(pem_encoded);
452   scoped_refptr<net::X509Certificate> cert =
453       net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size());
454   LOG_IF(ERROR, !cert.get()) << "Couldn't create certificate from X509 data: "
455                              << decoded;
456   return cert;
457 }
458
459 namespace {
460
461 bool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap& certs_by_guid,
462                           const std::string& guid_ref,
463                           std::string* pem_encoded) {
464   CertPEMsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref);
465   if (it == certs_by_guid.end()) {
466     LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
467     return false;
468   }
469   *pem_encoded = it->second;
470   if (pem_encoded->empty()) {
471     LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref;
472     return false;
473   }
474   return true;
475 }
476
477 bool ResolveSingleCertRef(const CertPEMsByGUIDMap& certs_by_guid,
478                           const std::string& key_guid_ref,
479                           const std::string& key_pem,
480                           base::DictionaryValue* onc_object) {
481   std::string guid_ref;
482   if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
483     return true;
484
485   std::string pem_encoded;
486   if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
487     return false;
488
489   onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
490   onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded);
491   return true;
492 }
493
494 bool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid,
495                         const std::string& key_guid_ref_list,
496                         const std::string& key_pem_list,
497                         base::DictionaryValue* onc_object) {
498   const base::ListValue* guid_ref_list = NULL;
499   if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list,
500                                                &guid_ref_list)) {
501     return true;
502   }
503
504   scoped_ptr<base::ListValue> pem_list(new base::ListValue);
505   for (base::ListValue::const_iterator it = guid_ref_list->begin();
506        it != guid_ref_list->end(); ++it) {
507     std::string guid_ref;
508     (*it)->GetAsString(&guid_ref);
509
510     std::string pem_encoded;
511     if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
512       return false;
513
514     pem_list->AppendString(pem_encoded);
515   }
516
517   onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, NULL);
518   onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
519   return true;
520 }
521
522 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid,
523                                 const std::string& key_guid_ref,
524                                 const std::string& key_pem_list,
525                                 base::DictionaryValue* onc_object) {
526   std::string guid_ref;
527   if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
528     return true;
529
530   std::string pem_encoded;
531   if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
532     return false;
533
534   scoped_ptr<base::ListValue> pem_list(new base::ListValue);
535   pem_list->AppendString(pem_encoded);
536   onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
537   onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
538   return true;
539 }
540
541 // Resolves the reference list at |key_guid_refs| if present and otherwise the
542 // single reference at |key_guid_ref|. Returns whether the respective resolving
543 // was successful.
544 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid,
545                                 const std::string& key_guid_refs,
546                                 const std::string& key_guid_ref,
547                                 const std::string& key_pem_list,
548                                 base::DictionaryValue* onc_object) {
549   if (onc_object->HasKey(key_guid_refs)) {
550     if (onc_object->HasKey(key_guid_ref)) {
551       LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref
552                  << ". Ignoring and removing the latter.";
553       onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
554     }
555     return ResolveCertRefList(
556         certs_by_guid, key_guid_refs, key_pem_list, onc_object);
557   }
558
559   // Only resolve |key_guid_ref| if |key_guid_refs| isn't present.
560   return ResolveSingleCertRefToList(
561       certs_by_guid, key_guid_ref, key_pem_list, onc_object);
562 }
563
564 bool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap& certs_by_guid,
565                                    const OncValueSignature& signature,
566                                    base::DictionaryValue* onc_object) {
567   if (&signature == &kCertificatePatternSignature) {
568     if (!ResolveCertRefList(certs_by_guid,
569                             client_cert::kIssuerCARef,
570                             client_cert::kIssuerCAPEMs,
571                             onc_object)) {
572       return false;
573     }
574   } else if (&signature == &kEAPSignature) {
575     if (!ResolveCertRefsOrRefToList(certs_by_guid,
576                                     eap::kServerCARefs,
577                                     eap::kServerCARef,
578                                     eap::kServerCAPEMs,
579                                     onc_object)) {
580       return false;
581     }
582   } else if (&signature == &kIPsecSignature) {
583     if (!ResolveCertRefsOrRefToList(certs_by_guid,
584                                     ipsec::kServerCARefs,
585                                     ipsec::kServerCARef,
586                                     ipsec::kServerCAPEMs,
587                                     onc_object)) {
588       return false;
589     }
590   } else if (&signature == &kIPsecSignature ||
591              &signature == &kOpenVPNSignature) {
592     if (!ResolveSingleCertRef(certs_by_guid,
593                               openvpn::kServerCertRef,
594                               openvpn::kServerCertPEM,
595                               onc_object) ||
596         !ResolveCertRefsOrRefToList(certs_by_guid,
597                                     openvpn::kServerCARefs,
598                                     openvpn::kServerCARef,
599                                     openvpn::kServerCAPEMs,
600                                     onc_object)) {
601       return false;
602     }
603   }
604
605   // Recurse into nested objects.
606   for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
607        it.Advance()) {
608     base::DictionaryValue* inner_object = NULL;
609     if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
610       continue;
611
612     const OncFieldSignature* field_signature =
613         GetFieldSignature(signature, it.key());
614     if (!field_signature)
615       continue;
616
617     if (!ResolveServerCertRefsInObject(certs_by_guid,
618                                        *field_signature->value_signature,
619                                        inner_object)) {
620       return false;
621     }
622   }
623   return true;
624 }
625
626 }  // namespace
627
628 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid,
629                                      base::ListValue* network_configs) {
630   bool success = true;
631   for (base::ListValue::iterator it = network_configs->begin();
632        it != network_configs->end(); ) {
633     base::DictionaryValue* network = NULL;
634     (*it)->GetAsDictionary(&network);
635     if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
636       std::string guid;
637       network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
638       // This might happen even with correct validation, if the referenced
639       // certificate couldn't be imported.
640       LOG(ERROR) << "Couldn't resolve some certificate reference of network "
641                  << guid;
642       it = network_configs->Erase(it, NULL);
643       success = false;
644       continue;
645     }
646     ++it;
647   }
648   return success;
649 }
650
651 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid,
652                                     base::DictionaryValue* network_config) {
653   return ResolveServerCertRefsInObject(certs_by_guid,
654                                        kNetworkConfigurationSignature,
655                                        network_config);
656 }
657
658 NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) {
659   if (type == ::onc::network_type::kAllTypes)
660     return NetworkTypePattern::Default();
661   if (type == ::onc::network_type::kCellular)
662     return NetworkTypePattern::Cellular();
663   if (type == ::onc::network_type::kEthernet)
664     return NetworkTypePattern::Ethernet();
665   if (type == ::onc::network_type::kVPN)
666     return NetworkTypePattern::VPN();
667   if (type == ::onc::network_type::kWiFi)
668     return NetworkTypePattern::WiFi();
669   if (type == ::onc::network_type::kWimax)
670     return NetworkTypePattern::Wimax();
671   if (type == ::onc::network_type::kWireless)
672     return NetworkTypePattern::Wireless();
673   NOTREACHED();
674   return NetworkTypePattern::Default();
675 }
676
677 bool IsRecommendedValue(const base::DictionaryValue* onc,
678                         const std::string& property_key) {
679   std::string property_basename, recommended_property_key;
680   size_t pos = property_key.find_last_of('.');
681   if (pos != std::string::npos) {
682     // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended'
683     property_basename = property_key.substr(pos + 1);
684     recommended_property_key =
685         property_key.substr(0, pos + 1) + ::onc::kRecommended;
686   } else {
687     // 'Name' -> 'Name', 'Recommended'
688     property_basename = property_key;
689     recommended_property_key = ::onc::kRecommended;
690   }
691
692   const base::ListValue* recommended_keys = NULL;
693   return (onc->GetList(recommended_property_key, &recommended_keys) &&
694           recommended_keys->Find(base::StringValue(property_basename)) !=
695           recommended_keys->end());
696 }
697
698 }  // namespace onc
699 }  // namespace chromeos