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
ReadDictionaryFromJson(const std::string & json)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
Decrypt(const std::string & passphrase,const base::DictionaryValue & root)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
GetSourceAsString(ONCSource source)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
ExpandField(const std::string & fieldname,const StringSubstitution & substitution,base::DictionaryValue * onc_object)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
ExpandStringsInOncObject(const OncValueSignature & signature,const StringSubstitution & substitution,base::DictionaryValue * onc_object)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
ExpandStringsInNetworks(const StringSubstitution & substitution,base::ListValue * network_configs)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:
Mask(const OncValueSignature & signature,const base::DictionaryValue & onc_object,const std::string & mask)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:
OncMaskValues(const std::string & mask)255 explicit OncMaskValues(const std::string& mask)
256 : mask_(mask) {
257 }
258
MapField(const std::string & field_name,const OncValueSignature & object_signature,const base::Value & onc_value,bool * found_unknown_field,bool * error)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
MaskCredentialsInOncObject(const OncValueSignature & signature,const base::DictionaryValue & onc_object,const std::string & mask)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
DecodePEM(const std::string & pem_encoded)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
GetServerAndCACertsByGUID(const base::ListValue & certificates)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
ParseAndValidateOncForImport(const std::string & onc_blob,ONCSource onc_source,const std::string & passphrase,base::ListValue * network_configs,base::DictionaryValue * global_network_config,base::ListValue * certificates)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
DecodePEMCertificate(const std::string & pem_encoded)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
GUIDRefToPEMEncoding(const CertPEMsByGUIDMap & certs_by_guid,const std::string & guid_ref,std::string * pem_encoded)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
ResolveSingleCertRef(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_ref,const std::string & key_pem,base::DictionaryValue * onc_object)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
ResolveCertRefList(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_ref_list,const std::string & key_pem_list,base::DictionaryValue * onc_object)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
ResolveSingleCertRefToList(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_ref,const std::string & key_pem_list,base::DictionaryValue * onc_object)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.
ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_refs,const std::string & key_guid_ref,const std::string & key_pem_list,base::DictionaryValue * onc_object)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
ResolveServerCertRefsInObject(const CertPEMsByGUIDMap & certs_by_guid,const OncValueSignature & signature,base::DictionaryValue * onc_object)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, certificate::kIssuerCARef,
567 certificate::kIssuerCAPEMs, onc_object)) {
568 return false;
569 }
570 } else if (&signature == &kEAPSignature) {
571 if (!ResolveCertRefsOrRefToList(certs_by_guid,
572 eap::kServerCARefs,
573 eap::kServerCARef,
574 eap::kServerCAPEMs,
575 onc_object)) {
576 return false;
577 }
578 } else if (&signature == &kIPsecSignature) {
579 if (!ResolveCertRefsOrRefToList(certs_by_guid,
580 ipsec::kServerCARefs,
581 ipsec::kServerCARef,
582 ipsec::kServerCAPEMs,
583 onc_object)) {
584 return false;
585 }
586 } else if (&signature == &kIPsecSignature ||
587 &signature == &kOpenVPNSignature) {
588 if (!ResolveSingleCertRef(certs_by_guid,
589 openvpn::kServerCertRef,
590 openvpn::kServerCertPEM,
591 onc_object) ||
592 !ResolveCertRefsOrRefToList(certs_by_guid,
593 openvpn::kServerCARefs,
594 openvpn::kServerCARef,
595 openvpn::kServerCAPEMs,
596 onc_object)) {
597 return false;
598 }
599 }
600
601 // Recurse into nested objects.
602 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
603 it.Advance()) {
604 base::DictionaryValue* inner_object = NULL;
605 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
606 continue;
607
608 const OncFieldSignature* field_signature =
609 GetFieldSignature(signature, it.key());
610 if (!field_signature)
611 continue;
612
613 if (!ResolveServerCertRefsInObject(certs_by_guid,
614 *field_signature->value_signature,
615 inner_object)) {
616 return false;
617 }
618 }
619 return true;
620 }
621
622 } // namespace
623
ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap & certs_by_guid,base::ListValue * network_configs)624 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid,
625 base::ListValue* network_configs) {
626 bool success = true;
627 for (base::ListValue::iterator it = network_configs->begin();
628 it != network_configs->end(); ) {
629 base::DictionaryValue* network = NULL;
630 (*it)->GetAsDictionary(&network);
631 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
632 std::string guid;
633 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
634 // This might happen even with correct validation, if the referenced
635 // certificate couldn't be imported.
636 LOG(ERROR) << "Couldn't resolve some certificate reference of network "
637 << guid;
638 it = network_configs->Erase(it, NULL);
639 success = false;
640 continue;
641 }
642 ++it;
643 }
644 return success;
645 }
646
ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap & certs_by_guid,base::DictionaryValue * network_config)647 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid,
648 base::DictionaryValue* network_config) {
649 return ResolveServerCertRefsInObject(certs_by_guid,
650 kNetworkConfigurationSignature,
651 network_config);
652 }
653
NetworkTypePatternFromOncType(const std::string & type)654 NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) {
655 if (type == ::onc::network_type::kAllTypes)
656 return NetworkTypePattern::Default();
657 if (type == ::onc::network_type::kCellular)
658 return NetworkTypePattern::Cellular();
659 if (type == ::onc::network_type::kEthernet)
660 return NetworkTypePattern::Ethernet();
661 if (type == ::onc::network_type::kVPN)
662 return NetworkTypePattern::VPN();
663 if (type == ::onc::network_type::kWiFi)
664 return NetworkTypePattern::WiFi();
665 if (type == ::onc::network_type::kWimax)
666 return NetworkTypePattern::Wimax();
667 if (type == ::onc::network_type::kWireless)
668 return NetworkTypePattern::Wireless();
669 NOTREACHED();
670 return NetworkTypePattern::Default();
671 }
672
673 } // namespace onc
674 } // namespace chromeos
675