12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/onc/onc_utils.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/base64.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_reader.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/histogram.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/network_event_log.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_mapper.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_signature.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_utils.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_validator.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/encryptor.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/hmac.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/symmetric_key.h" 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/pem_tokenizer.h" 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/x509_certificate.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using namespace ::onc; 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos { 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace onc { 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUnableToDecode[] = "Unable to decode encrypted ONC"; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kEmptyUnencryptedConfiguration[] = 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[]," 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "\"Certificates\":[]}"; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson( 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& json) { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string error; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Value* root = base::JSONReader::ReadAndReturnError( 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error); 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::DictionaryValue* dict_ptr = NULL; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!root || !root->GetAsDictionary(&dict_ptr)) { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR("Invalid JSON Dictionary: " + error); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete root; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return make_scoped_ptr(dict_ptr); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase, 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::DictionaryValue& root) { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int kKeySizeInBits = 256; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int kMaxIterationCount = 500000; 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string onc_type; 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string initial_vector; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string salt; 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string cipher; 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string stretch_method; 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string hmac_method; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string hmac; 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int iterations; 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string ciphertext; 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!root.GetString(encrypted::kCiphertext, &ciphertext) || 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetString(encrypted::kCipher, &cipher) || 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetString(encrypted::kHMAC, &hmac) || 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetString(encrypted::kHMACMethod, &hmac_method) || 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetString(encrypted::kIV, &initial_vector) || 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetInteger(encrypted::kIterations, &iterations) || 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetString(encrypted::kSalt, &salt) || 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetString(encrypted::kStretch, &stretch_method) || 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !root.GetString(toplevel_config::kType, &onc_type) || 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) onc_type != toplevel_config::kEncryptedConfiguration) { 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR("Encrypted ONC malformed."); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (hmac_method != encrypted::kSHA1 || 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cipher != encrypted::kAES256 || 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stretch_method != encrypted::kPBKDF2) { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR("Encrypted ONC unsupported encryption scheme."); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make sure iterations != 0, since that's not valid. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (iterations == 0) { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecrypt); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Simply a sanity check to make sure we can't lock up the machine 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // for too long with a huge number (or a negative number). 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (iterations < 0 || iterations > kMaxIterationCount) { 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR("Too many iterations in encrypted ONC"); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base::Base64Decode(salt, &salt)) { 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecode); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<crypto::SymmetricKey> key( 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES, 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) passphrase, 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) salt, 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iterations, 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kKeySizeInBits)); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base::Base64Decode(initial_vector, &initial_vector)) { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecode); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base::Base64Decode(ciphertext, &ciphertext)) { 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecode); 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base::Base64Decode(hmac, &hmac)) { 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecode); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) crypto::HMAC hmac_verifier(crypto::HMAC::SHA1); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!hmac_verifier.Init(key.get()) || 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !hmac_verifier.Verify(ciphertext, hmac)) { 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecrypt); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) crypto::Encryptor decryptor; 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) { 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecrypt); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string plaintext; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!decryptor.Decrypt(ciphertext, &plaintext)) { 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR(kUnableToDecrypt); 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<base::DictionaryValue> new_root = 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ReadDictionaryFromJson(plaintext); 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (new_root.get() == NULL) { 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ONC_LOG_ERROR("Property dictionary malformed."); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<base::DictionaryValue>(); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return new_root.Pass(); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string GetSourceAsString(ONCSource source) { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (source) { 1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case ONC_SOURCE_UNKNOWN: 1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return "unknown"; 1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case ONC_SOURCE_NONE: 1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return "none"; 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ONC_SOURCE_DEVICE_POLICY: 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return "device policy"; 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ONC_SOURCE_USER_POLICY: 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return "user policy"; 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ONC_SOURCE_USER_IMPORT: 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return "user import"; 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED() << "unknown ONC source " << source; 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return "unknown"; 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ExpandField(const std::string& fieldname, 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const StringSubstitution& substitution, 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::DictionaryValue* onc_object) { 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string user_string; 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!onc_object->GetStringWithoutPathExpansion(fieldname, &user_string)) 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string login_id; 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) { 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ReplaceSubstringsAfterOffset(&user_string, 0, 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch substitutes::kLoginIDField, 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) login_id); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string email; 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (substitution.GetSubstitute(substitutes::kEmailField, &email)) { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ReplaceSubstringsAfterOffset(&user_string, 0, 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch substitutes::kEmailField, 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) email); 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) onc_object->SetStringWithoutPathExpansion(fieldname, user_string); 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExpandStringsInOncObject( 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const OncValueSignature& signature, 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const StringSubstitution& substitution, 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::DictionaryValue* onc_object) { 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (&signature == &kEAPSignature) { 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExpandField(eap::kAnonymousIdentity, substitution, onc_object); 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExpandField(eap::kIdentity, substitution, onc_object); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (&signature == &kL2TPSignature || 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &signature == &kOpenVPNSignature) { 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExpandField(vpn::kUsername, substitution, onc_object); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Recurse into nested objects. 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it.Advance()) { 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::DictionaryValue* inner_object = NULL; 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const OncFieldSignature* field_signature = 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetFieldSignature(signature, it.key()); 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!field_signature) 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) continue; 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExpandStringsInOncObject(*field_signature->value_signature, 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) substitution, inner_object); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid ExpandStringsInNetworks(const StringSubstitution& substitution, 232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch base::ListValue* network_configs) { 233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch for (base::ListValue::iterator it = network_configs->begin(); 234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch it != network_configs->end(); ++it) { 235ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch base::DictionaryValue* network = NULL; 236ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch (*it)->GetAsDictionary(&network); 237ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch DCHECK(network); 238ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch ExpandStringsInOncObject( 239ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch kNetworkConfigurationSignature, substitution, network); 240ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 242ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass OncMaskValues : public Mapper { 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static scoped_ptr<base::DictionaryValue> Mask( 248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const OncValueSignature& signature, 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::DictionaryValue& onc_object, 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& mask) { 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OncMaskValues masker(mask); 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool unused_error; 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return masker.MapObject(signature, onc_object, &unused_error); 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected: 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) explicit OncMaskValues(const std::string& mask) 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : mask_(mask) { 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual scoped_ptr<base::Value> MapField( 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& field_name, 263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const OncValueSignature& object_signature, 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Value& onc_value, 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool* found_unknown_field, 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool* error) OVERRIDE { 267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (FieldIsCredential(object_signature, field_name)) { 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return scoped_ptr<base::Value>(new base::StringValue(mask_)); 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return Mapper::MapField(field_name, object_signature, onc_value, 271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch found_unknown_field, error); 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Mask to insert in place of the sensitive values. 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string mask_; 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject( 282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const OncValueSignature& signature, 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::DictionaryValue& onc_object, 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& mask) { 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return OncMaskValues::Mask(signature, onc_object, mask); 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace { 289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstd::string DecodePEM(const std::string& pem_encoded) { 291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // The PEM block header used for DER certificates 292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const char kCertificateHeader[] = "CERTIFICATE"; 293ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 294ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // This is an older PEM marker for DER certificates. 295ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const char kX509CertificateHeader[] = "X509 CERTIFICATE"; 296ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 297ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::vector<std::string> pem_headers; 298ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch pem_headers.push_back(kCertificateHeader); 299ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch pem_headers.push_back(kX509CertificateHeader); 300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 301ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers); 302ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::string decoded; 303ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (pem_tokenizer.GetNext()) { 304ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch decoded = pem_tokenizer.data(); 305ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } else { 306ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // If we failed to read the data as a PEM file, then try plain base64 decode 307ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // in case the PEM marker strings are missing. For this to work, there has 308ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // to be no white space, and it has to only contain the base64-encoded data. 309ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!base::Base64Decode(pem_encoded, &decoded)) { 310ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; 311ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return std::string(); 312ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return decoded; 315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochCertPEMsByGUIDMap GetServerAndCACertsByGUID( 318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch const base::ListValue& certificates) { 319ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch CertPEMsByGUIDMap certs_by_guid; 320ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch for (base::ListValue::const_iterator it = certificates.begin(); 321ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch it != certificates.end(); ++it) { 322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch base::DictionaryValue* cert = NULL; 323ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch (*it)->GetAsDictionary(&cert); 324ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 325ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::string guid; 326ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid); 327ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::string cert_type; 328ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type); 329ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (cert_type != certificate::kServer && 330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch cert_type != certificate::kAuthority) { 331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch continue; 332ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::string x509_data; 334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data); 335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 336ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::string der = DecodePEM(x509_data); 337ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::string pem; 338ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) { 339ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch LOG(ERROR) << "Certificate with GUID " << guid 340ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch << " is not in PEM encoding."; 341ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch continue; 342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch certs_by_guid[guid] = pem; 344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return certs_by_guid; 347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} // namespace 350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ParseAndValidateOncForImport(const std::string& onc_blob, 352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ONCSource onc_source, 353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& passphrase, 354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ListValue* network_configs, 3558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::DictionaryValue* global_network_config, 356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ListValue* certificates) { 357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) network_configs->Clear(); 3588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) global_network_config->Clear(); 3598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) certificates->Clear(); 360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (onc_blob.empty()) 361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<base::DictionaryValue> toplevel_onc = 364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ReadDictionaryFromJson(onc_blob); 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (toplevel_onc.get() == NULL) { 366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source) 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) << " is not a valid JSON dictionary."; 368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Check and see if this is an encrypted ONC file. If so, decrypt it. 372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string onc_type; 373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType, 374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &onc_type); 375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (onc_type == toplevel_config::kEncryptedConfiguration) { 376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch toplevel_onc = Decrypt(passphrase, *toplevel_onc); 377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (toplevel_onc.get() == NULL) { 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(ERROR) << "Couldn't decrypt the ONC from " 379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << GetSourceAsString(onc_source); 380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY || 385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch onc_source == ONC_SOURCE_DEVICE_POLICY); 386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Validate the ONC dictionary. We are liberal and ignore unknown field 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // names and ignore invalid field names in kRecommended arrays. 389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Validator validator(false, // Ignore unknown fields. 390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch false, // Ignore invalid recommended field names. 391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch true, // Fail on missing fields. 392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch from_policy); 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) validator.SetOncSource(onc_source); 394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Validator::Result validation_result; 396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) toplevel_onc = validator.ValidateAndRepairObject( 397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch &kToplevelConfigurationSignature, 398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *toplevel_onc, 399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &validation_result); 400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (from_policy) { 402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation", 403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch validation_result == Validator::VALID); 404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool success = true; 407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (validation_result == Validator::VALID_WITH_WARNINGS) { 408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source) 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) << " produced warnings."; 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) success = false; 411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) { 412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source) 413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) << " is invalid and couldn't be repaired."; 414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::ListValue* validated_certs = NULL; 418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates, 419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch &validated_certs)) { 420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) certificates->Swap(validated_certs); 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::ListValue* validated_networks = NULL; 424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (toplevel_onc->GetListWithoutPathExpansion( 425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch toplevel_config::kNetworkConfigurations, &validated_networks)) { 426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch CertPEMsByGUIDMap server_and_ca_certs = 427ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch GetServerAndCACertsByGUID(*certificates); 428ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!ResolveServerCertRefsInNetworks(server_and_ca_certs, 430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch validated_networks)) { 431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch LOG(ERROR) << "Some certificate references in the ONC policy for source " 432ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch << GetSourceAsString(onc_source) << " could not be resolved."; 433ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch success = false; 434ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 435ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) network_configs->Swap(validated_networks); 437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) base::DictionaryValue* validated_global_config = NULL; 4408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (toplevel_onc->GetDictionaryWithoutPathExpansion( 4418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) toplevel_config::kGlobalNetworkConfiguration, 4428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) &validated_global_config)) { 4438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) global_network_config->Swap(validated_global_config); 4448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 4458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return success; 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_refptr<net::X509Certificate> DecodePEMCertificate( 450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& pem_encoded) { 451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string decoded = DecodePEM(pem_encoded); 452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_refptr<net::X509Certificate> cert = 453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size()); 4547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LOG_IF(ERROR, !cert.get()) << "Couldn't create certificate from X509 data: " 4557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch << decoded; 456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return cert; 457eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 458eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace { 460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 461ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap& certs_by_guid, 462eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& guid_ref, 463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string* pem_encoded) { 464ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch CertPEMsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref); 465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (it == certs_by_guid.end()) { 466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref; 467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 469ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *pem_encoded = it->second; 470ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (pem_encoded->empty()) { 471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref; 472eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 477ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveSingleCertRef(const CertPEMsByGUIDMap& certs_by_guid, 478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& key_guid_ref, 479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& key_pem, 480eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* onc_object) { 481eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string guid_ref; 482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) 483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string pem_encoded; 486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) 487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL); 490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded); 491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid, 495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& key_guid_ref_list, 496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& key_pem_list, 497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* onc_object) { 498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const base::ListValue* guid_ref_list = NULL; 499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list, 500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch &guid_ref_list)) { 501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_ptr<base::ListValue> pem_list(new base::ListValue); 505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (base::ListValue::const_iterator it = guid_ref_list->begin(); 506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it != guid_ref_list->end(); ++it) { 507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string guid_ref; 508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*it)->GetAsString(&guid_ref); 509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string pem_encoded; 511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) 512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pem_list->AppendString(pem_encoded); 515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, NULL); 518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release()); 519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 522ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid, 523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& key_guid_ref, 524eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& key_pem_list, 525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* onc_object) { 526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string guid_ref; 527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) 528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 529eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 530eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string pem_encoded; 531eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) 532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_ptr<base::ListValue> pem_list(new base::ListValue); 535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pem_list->AppendString(pem_encoded); 536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL); 537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release()); 538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 540eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Resolves the reference list at |key_guid_refs| if present and otherwise the 5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// single reference at |key_guid_ref|. Returns whether the respective resolving 5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// was successful. 5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid, 5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& key_guid_refs, 5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& key_guid_ref, 5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& key_pem_list, 5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::DictionaryValue* onc_object) { 5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (onc_object->HasKey(key_guid_refs)) { 5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (onc_object->HasKey(key_guid_ref)) { 5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref 5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << ". Ignoring and removing the latter."; 5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL); 5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return ResolveCertRefList( 5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) certs_by_guid, key_guid_refs, key_pem_list, onc_object); 5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Only resolve |key_guid_ref| if |key_guid_refs| isn't present. 5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return ResolveSingleCertRefToList( 5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) certs_by_guid, key_guid_ref, key_pem_list, onc_object); 5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap& certs_by_guid, 565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const OncValueSignature& signature, 566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* onc_object) { 567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (&signature == &kCertificatePatternSignature) { 568116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!ResolveCertRefList(certs_by_guid, 569116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch client_cert::kIssuerCARef, 570116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch client_cert::kIssuerCAPEMs, 571116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch onc_object)) { 572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (&signature == &kEAPSignature) { 5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!ResolveCertRefsOrRefToList(certs_by_guid, 5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) eap::kServerCARefs, 5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) eap::kServerCARef, 5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) eap::kServerCAPEMs, 5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) onc_object)) { 580eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 581eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 582eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (&signature == &kIPsecSignature) { 5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!ResolveCertRefsOrRefToList(certs_by_guid, 5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ipsec::kServerCARefs, 5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ipsec::kServerCARef, 5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ipsec::kServerCAPEMs, 5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) onc_object)) { 588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 589eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 590eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (&signature == &kIPsecSignature || 591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch &signature == &kOpenVPNSignature) { 5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!ResolveSingleCertRef(certs_by_guid, 5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) openvpn::kServerCertRef, 5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) openvpn::kServerCertPEM, 5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) onc_object) || 5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !ResolveCertRefsOrRefToList(certs_by_guid, 5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) openvpn::kServerCARefs, 5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) openvpn::kServerCARef, 5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) openvpn::kServerCAPEMs, 6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) onc_object)) { 601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 602eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 604eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 605eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Recurse into nested objects. 606eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); 607eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it.Advance()) { 608eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* inner_object = NULL; 609eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) 610eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 611eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 612eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const OncFieldSignature* field_signature = 613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch GetFieldSignature(signature, it.key()); 614eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!field_signature) 615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 616eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 617eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!ResolveServerCertRefsInObject(certs_by_guid, 618eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *field_signature->value_signature, 619eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch inner_object)) { 620eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 621eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 622eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 623eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 624eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 625eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 626eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 627eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 628ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid, 629eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ListValue* network_configs) { 630eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool success = true; 631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (base::ListValue::iterator it = network_configs->begin(); 632eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it != network_configs->end(); ) { 633eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* network = NULL; 634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*it)->GetAsDictionary(&network); 635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) { 636eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string guid; 637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch network->GetStringWithoutPathExpansion(network_config::kGUID, &guid); 638eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // This might happen even with correct validation, if the referenced 639eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // certificate couldn't be imported. 640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(ERROR) << "Couldn't resolve some certificate reference of network " 641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << guid; 642eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it = network_configs->Erase(it, NULL); 643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch success = false; 644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++it; 647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return success; 649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 651ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid, 652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::DictionaryValue* network_config) { 653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ResolveServerCertRefsInObject(certs_by_guid, 654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kNetworkConfigurationSignature, 655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch network_config); 656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 658010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) { 659010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (type == ::onc::network_type::kAllTypes) 660010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NetworkTypePattern::Default(); 661010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (type == ::onc::network_type::kCellular) 662010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NetworkTypePattern::Cellular(); 663010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (type == ::onc::network_type::kEthernet) 664010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NetworkTypePattern::Ethernet(); 665010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (type == ::onc::network_type::kVPN) 666010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NetworkTypePattern::VPN(); 667010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (type == ::onc::network_type::kWiFi) 668010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NetworkTypePattern::WiFi(); 669cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (type == ::onc::network_type::kWimax) 670cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return NetworkTypePattern::Wimax(); 671cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (type == ::onc::network_type::kWireless) 672cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return NetworkTypePattern::Wireless(); 673010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) NOTREACHED(); 674010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NetworkTypePattern::Default(); 675010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 676010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 6775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsRecommendedValue(const base::DictionaryValue* onc, 6785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string& property_key) { 6795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string property_basename, recommended_property_key; 6805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t pos = property_key.find_last_of('.'); 6815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pos != std::string::npos) { 6825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended' 6835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) property_basename = property_key.substr(pos + 1); 6845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) recommended_property_key = 6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) property_key.substr(0, pos + 1) + ::onc::kRecommended; 6865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 6875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 'Name' -> 'Name', 'Recommended' 6885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) property_basename = property_key; 6895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) recommended_property_key = ::onc::kRecommended; 6905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 6915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::ListValue* recommended_keys = NULL; 6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return (onc->GetList(recommended_property_key, &recommended_keys) && 6945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) recommended_keys->Find(base::StringValue(property_basename)) != 6955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) recommended_keys->end()); 6965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 6975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace onc 6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace chromeos 700