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 27using namespace ::onc; 28 29namespace chromeos { 30namespace onc { 31 32namespace { 33 34const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; 35const char kUnableToDecode[] = "Unable to decode encrypted ONC"; 36 37} // namespace 38 39const char kEmptyUnencryptedConfiguration[] = 40 "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[]," 41 "\"Certificates\":[]}"; 42 43scoped_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 58scoped_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 161std::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 178void 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 202void 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 231void 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 243namespace { 244 245class 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 281scoped_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 288namespace { 289 290std::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 317CertPEMsByGUIDMap 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 351bool 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 449scoped_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 459namespace { 460 461bool 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 477bool 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 494bool 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 522bool 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. 544bool 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 564bool 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 628bool 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 651bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid, 652 base::DictionaryValue* network_config) { 653 return ResolveServerCertRefsInObject(certs_by_guid, 654 kNetworkConfigurationSignature, 655 network_config); 656} 657 658NetworkTypePattern 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 677bool 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 700