| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/network/onc/onc_utils.h" | 5 #include "chromeos/network/onc/onc_utils.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
| 12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "base/values.h" | 13 #include "base/values.h" |
| 14 #include "chromeos/network/network_event_log.h" | 14 #include "chromeos/network/network_event_log.h" |
| 15 #include "chromeos/network/onc/onc_mapper.h" | 15 #include "chromeos/network/onc/onc_mapper.h" |
| 16 #include "chromeos/network/onc/onc_signature.h" | 16 #include "chromeos/network/onc/onc_signature.h" |
| 17 #include "chromeos/network/onc/onc_utils.h" | 17 #include "chromeos/network/onc/onc_utils.h" |
| 18 #include "chromeos/network/onc/onc_validator.h" | 18 #include "chromeos/network/onc/onc_validator.h" |
| 19 #include "components/device_event_log/device_event_log.h" |
| 19 #include "crypto/encryptor.h" | 20 #include "crypto/encryptor.h" |
| 20 #include "crypto/hmac.h" | 21 #include "crypto/hmac.h" |
| 21 #include "crypto/symmetric_key.h" | 22 #include "crypto/symmetric_key.h" |
| 22 #include "net/cert/pem_tokenizer.h" | 23 #include "net/cert/pem_tokenizer.h" |
| 23 #include "net/cert/x509_certificate.h" | 24 #include "net/cert/x509_certificate.h" |
| 24 | 25 |
| 25 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) | |
| 26 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) | |
| 27 | |
| 28 using namespace ::onc; | 26 using namespace ::onc; |
| 29 | 27 |
| 30 namespace chromeos { | 28 namespace chromeos { |
| 31 namespace onc { | 29 namespace onc { |
| 32 | 30 |
| 33 namespace { | 31 namespace { |
| 34 | 32 |
| 35 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; | 33 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; |
| 36 const char kUnableToDecode[] = "Unable to decode encrypted ONC"; | 34 const char kUnableToDecode[] = "Unable to decode encrypted ONC"; |
| 37 | 35 |
| 38 } // namespace | 36 } // namespace |
| 39 | 37 |
| 40 const char kEmptyUnencryptedConfiguration[] = | 38 const char kEmptyUnencryptedConfiguration[] = |
| 41 "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[]," | 39 "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[]," |
| 42 "\"Certificates\":[]}"; | 40 "\"Certificates\":[]}"; |
| 43 | 41 |
| 44 scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson( | 42 scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson( |
| 45 const std::string& json) { | 43 const std::string& json) { |
| 46 std::string error; | 44 std::string error; |
| 47 base::Value* root = base::JSONReader::ReadAndReturnError( | 45 base::Value* root = base::JSONReader::ReadAndReturnError( |
| 48 json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error); | 46 json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error); |
| 49 | 47 |
| 50 base::DictionaryValue* dict_ptr = NULL; | 48 base::DictionaryValue* dict_ptr = nullptr; |
| 51 if (!root || !root->GetAsDictionary(&dict_ptr)) { | 49 if (!root || !root->GetAsDictionary(&dict_ptr)) { |
| 52 ONC_LOG_ERROR("Invalid JSON Dictionary: " + error); | 50 NET_LOG(ERROR) << "Invalid JSON Dictionary: " << error; |
| 53 delete root; | 51 delete root; |
| 54 } | 52 } |
| 55 | 53 |
| 56 return make_scoped_ptr(dict_ptr); | 54 return make_scoped_ptr(dict_ptr); |
| 57 } | 55 } |
| 58 | 56 |
| 59 scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase, | 57 scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase, |
| 60 const base::DictionaryValue& root) { | 58 const base::DictionaryValue& root) { |
| 61 const int kKeySizeInBits = 256; | 59 const int kKeySizeInBits = 256; |
| 62 const int kMaxIterationCount = 500000; | 60 const int kMaxIterationCount = 500000; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 73 if (!root.GetString(encrypted::kCiphertext, &ciphertext) || | 71 if (!root.GetString(encrypted::kCiphertext, &ciphertext) || |
| 74 !root.GetString(encrypted::kCipher, &cipher) || | 72 !root.GetString(encrypted::kCipher, &cipher) || |
| 75 !root.GetString(encrypted::kHMAC, &hmac) || | 73 !root.GetString(encrypted::kHMAC, &hmac) || |
| 76 !root.GetString(encrypted::kHMACMethod, &hmac_method) || | 74 !root.GetString(encrypted::kHMACMethod, &hmac_method) || |
| 77 !root.GetString(encrypted::kIV, &initial_vector) || | 75 !root.GetString(encrypted::kIV, &initial_vector) || |
| 78 !root.GetInteger(encrypted::kIterations, &iterations) || | 76 !root.GetInteger(encrypted::kIterations, &iterations) || |
| 79 !root.GetString(encrypted::kSalt, &salt) || | 77 !root.GetString(encrypted::kSalt, &salt) || |
| 80 !root.GetString(encrypted::kStretch, &stretch_method) || | 78 !root.GetString(encrypted::kStretch, &stretch_method) || |
| 81 !root.GetString(toplevel_config::kType, &onc_type) || | 79 !root.GetString(toplevel_config::kType, &onc_type) || |
| 82 onc_type != toplevel_config::kEncryptedConfiguration) { | 80 onc_type != toplevel_config::kEncryptedConfiguration) { |
| 83 | 81 NET_LOG(ERROR) << "Encrypted ONC malformed."; |
| 84 ONC_LOG_ERROR("Encrypted ONC malformed."); | 82 return nullptr; |
| 85 return scoped_ptr<base::DictionaryValue>(); | |
| 86 } | 83 } |
| 87 | 84 |
| 88 if (hmac_method != encrypted::kSHA1 || | 85 if (hmac_method != encrypted::kSHA1 || |
| 89 cipher != encrypted::kAES256 || | 86 cipher != encrypted::kAES256 || |
| 90 stretch_method != encrypted::kPBKDF2) { | 87 stretch_method != encrypted::kPBKDF2) { |
| 91 ONC_LOG_ERROR("Encrypted ONC unsupported encryption scheme."); | 88 NET_LOG(ERROR) << "Encrypted ONC unsupported encryption scheme."; |
| 92 return scoped_ptr<base::DictionaryValue>(); | 89 return nullptr; |
| 93 } | 90 } |
| 94 | 91 |
| 95 // Make sure iterations != 0, since that's not valid. | 92 // Make sure iterations != 0, since that's not valid. |
| 96 if (iterations == 0) { | 93 if (iterations == 0) { |
| 97 ONC_LOG_ERROR(kUnableToDecrypt); | 94 NET_LOG(ERROR) << kUnableToDecrypt; |
| 98 return scoped_ptr<base::DictionaryValue>(); | 95 return nullptr; |
| 99 } | 96 } |
| 100 | 97 |
| 101 // Simply a sanity check to make sure we can't lock up the machine | 98 // Simply a sanity check to make sure we can't lock up the machine |
| 102 // for too long with a huge number (or a negative number). | 99 // for too long with a huge number (or a negative number). |
| 103 if (iterations < 0 || iterations > kMaxIterationCount) { | 100 if (iterations < 0 || iterations > kMaxIterationCount) { |
| 104 ONC_LOG_ERROR("Too many iterations in encrypted ONC"); | 101 NET_LOG(ERROR) << "Too many iterations in encrypted ONC"; |
| 105 return scoped_ptr<base::DictionaryValue>(); | 102 return nullptr; |
| 106 } | 103 } |
| 107 | 104 |
| 108 if (!base::Base64Decode(salt, &salt)) { | 105 if (!base::Base64Decode(salt, &salt)) { |
| 109 ONC_LOG_ERROR(kUnableToDecode); | 106 NET_LOG(ERROR) << kUnableToDecode; |
| 110 return scoped_ptr<base::DictionaryValue>(); | 107 return nullptr; |
| 111 } | 108 } |
| 112 | 109 |
| 113 scoped_ptr<crypto::SymmetricKey> key( | 110 scoped_ptr<crypto::SymmetricKey> key( |
| 114 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES, | 111 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES, |
| 115 passphrase, | 112 passphrase, |
| 116 salt, | 113 salt, |
| 117 iterations, | 114 iterations, |
| 118 kKeySizeInBits)); | 115 kKeySizeInBits)); |
| 119 | 116 |
| 120 if (!base::Base64Decode(initial_vector, &initial_vector)) { | 117 if (!base::Base64Decode(initial_vector, &initial_vector)) { |
| 121 ONC_LOG_ERROR(kUnableToDecode); | 118 NET_LOG(ERROR) << kUnableToDecode; |
| 122 return scoped_ptr<base::DictionaryValue>(); | 119 return nullptr; |
| 123 } | 120 } |
| 124 if (!base::Base64Decode(ciphertext, &ciphertext)) { | 121 if (!base::Base64Decode(ciphertext, &ciphertext)) { |
| 125 ONC_LOG_ERROR(kUnableToDecode); | 122 NET_LOG(ERROR) << kUnableToDecode; |
| 126 return scoped_ptr<base::DictionaryValue>(); | 123 return nullptr; |
| 127 } | 124 } |
| 128 if (!base::Base64Decode(hmac, &hmac)) { | 125 if (!base::Base64Decode(hmac, &hmac)) { |
| 129 ONC_LOG_ERROR(kUnableToDecode); | 126 NET_LOG(ERROR) << kUnableToDecode; |
| 130 return scoped_ptr<base::DictionaryValue>(); | 127 return nullptr; |
| 131 } | 128 } |
| 132 | 129 |
| 133 crypto::HMAC hmac_verifier(crypto::HMAC::SHA1); | 130 crypto::HMAC hmac_verifier(crypto::HMAC::SHA1); |
| 134 if (!hmac_verifier.Init(key.get()) || | 131 if (!hmac_verifier.Init(key.get()) || |
| 135 !hmac_verifier.Verify(ciphertext, hmac)) { | 132 !hmac_verifier.Verify(ciphertext, hmac)) { |
| 136 ONC_LOG_ERROR(kUnableToDecrypt); | 133 NET_LOG(ERROR) << kUnableToDecrypt; |
| 137 return scoped_ptr<base::DictionaryValue>(); | 134 return nullptr; |
| 138 } | 135 } |
| 139 | 136 |
| 140 crypto::Encryptor decryptor; | 137 crypto::Encryptor decryptor; |
| 141 if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) { | 138 if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) { |
| 142 ONC_LOG_ERROR(kUnableToDecrypt); | 139 NET_LOG(ERROR) << kUnableToDecrypt; |
| 143 return scoped_ptr<base::DictionaryValue>(); | 140 return nullptr; |
| 144 } | 141 } |
| 145 | 142 |
| 146 std::string plaintext; | 143 std::string plaintext; |
| 147 if (!decryptor.Decrypt(ciphertext, &plaintext)) { | 144 if (!decryptor.Decrypt(ciphertext, &plaintext)) { |
| 148 ONC_LOG_ERROR(kUnableToDecrypt); | 145 NET_LOG(ERROR) << kUnableToDecrypt; |
| 149 return scoped_ptr<base::DictionaryValue>(); | 146 return nullptr; |
| 150 } | 147 } |
| 151 | 148 |
| 152 scoped_ptr<base::DictionaryValue> new_root = | 149 scoped_ptr<base::DictionaryValue> new_root = |
| 153 ReadDictionaryFromJson(plaintext); | 150 ReadDictionaryFromJson(plaintext); |
| 154 if (new_root.get() == NULL) { | 151 if (!new_root) { |
| 155 ONC_LOG_ERROR("Property dictionary malformed."); | 152 NET_LOG(ERROR) << "Property dictionary malformed."; |
| 156 return scoped_ptr<base::DictionaryValue>(); | 153 return nullptr; |
| 157 } | 154 } |
| 158 | 155 |
| 159 return new_root.Pass(); | 156 return new_root.Pass(); |
| 160 } | 157 } |
| 161 | 158 |
| 162 std::string GetSourceAsString(ONCSource source) { | 159 std::string GetSourceAsString(ONCSource source) { |
| 163 switch (source) { | 160 switch (source) { |
| 164 case ONC_SOURCE_UNKNOWN: | 161 case ONC_SOURCE_UNKNOWN: |
| 165 return "unknown"; | 162 return "unknown"; |
| 166 case ONC_SOURCE_NONE: | 163 case ONC_SOURCE_NONE: |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 ExpandField(eap::kAnonymousIdentity, substitution, onc_object); | 205 ExpandField(eap::kAnonymousIdentity, substitution, onc_object); |
| 209 ExpandField(eap::kIdentity, substitution, onc_object); | 206 ExpandField(eap::kIdentity, substitution, onc_object); |
| 210 } else if (&signature == &kL2TPSignature || | 207 } else if (&signature == &kL2TPSignature || |
| 211 &signature == &kOpenVPNSignature) { | 208 &signature == &kOpenVPNSignature) { |
| 212 ExpandField(vpn::kUsername, substitution, onc_object); | 209 ExpandField(vpn::kUsername, substitution, onc_object); |
| 213 } | 210 } |
| 214 | 211 |
| 215 // Recurse into nested objects. | 212 // Recurse into nested objects. |
| 216 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); | 213 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); |
| 217 it.Advance()) { | 214 it.Advance()) { |
| 218 base::DictionaryValue* inner_object = NULL; | 215 base::DictionaryValue* inner_object = nullptr; |
| 219 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) | 216 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) |
| 220 continue; | 217 continue; |
| 221 | 218 |
| 222 const OncFieldSignature* field_signature = | 219 const OncFieldSignature* field_signature = |
| 223 GetFieldSignature(signature, it.key()); | 220 GetFieldSignature(signature, it.key()); |
| 224 if (!field_signature) | 221 if (!field_signature) |
| 225 continue; | 222 continue; |
| 226 | 223 |
| 227 ExpandStringsInOncObject(*field_signature->value_signature, | 224 ExpandStringsInOncObject(*field_signature->value_signature, |
| 228 substitution, inner_object); | 225 substitution, inner_object); |
| 229 } | 226 } |
| 230 } | 227 } |
| 231 | 228 |
| 232 void ExpandStringsInNetworks(const StringSubstitution& substitution, | 229 void ExpandStringsInNetworks(const StringSubstitution& substitution, |
| 233 base::ListValue* network_configs) { | 230 base::ListValue* network_configs) { |
| 234 for (base::ListValue::iterator it = network_configs->begin(); | 231 for (base::Value* entry : *network_configs) { |
| 235 it != network_configs->end(); ++it) { | 232 base::DictionaryValue* network = nullptr; |
| 236 base::DictionaryValue* network = NULL; | 233 entry->GetAsDictionary(&network); |
| 237 (*it)->GetAsDictionary(&network); | |
| 238 DCHECK(network); | 234 DCHECK(network); |
| 239 ExpandStringsInOncObject( | 235 ExpandStringsInOncObject( |
| 240 kNetworkConfigurationSignature, substitution, network); | 236 kNetworkConfigurationSignature, substitution, network); |
| 241 } | 237 } |
| 242 } | 238 } |
| 243 | 239 |
| 244 void FillInHexSSIDFieldsInOncObject(const OncValueSignature& signature, | 240 void FillInHexSSIDFieldsInOncObject(const OncValueSignature& signature, |
| 245 base::DictionaryValue* onc_object) { | 241 base::DictionaryValue* onc_object) { |
| 246 if (&signature == &kWiFiSignature) | 242 if (&signature == &kWiFiSignature) |
| 247 FillInHexSSIDField(onc_object); | 243 FillInHexSSIDField(onc_object); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 264 } | 260 } |
| 265 | 261 |
| 266 void FillInHexSSIDField(base::DictionaryValue* wifi_fields) { | 262 void FillInHexSSIDField(base::DictionaryValue* wifi_fields) { |
| 267 std::string ssid_string; | 263 std::string ssid_string; |
| 268 if (wifi_fields->HasKey(::onc::wifi::kHexSSID) || | 264 if (wifi_fields->HasKey(::onc::wifi::kHexSSID) || |
| 269 !wifi_fields->GetStringWithoutPathExpansion(::onc::wifi::kSSID, | 265 !wifi_fields->GetStringWithoutPathExpansion(::onc::wifi::kSSID, |
| 270 &ssid_string)) { | 266 &ssid_string)) { |
| 271 return; | 267 return; |
| 272 } | 268 } |
| 273 if (ssid_string.empty()) { | 269 if (ssid_string.empty()) { |
| 274 ONC_LOG_ERROR("Found empty SSID field."); | 270 NET_LOG(ERROR) << "Found empty SSID field."; |
| 275 return; | 271 return; |
| 276 } | 272 } |
| 277 wifi_fields->SetStringWithoutPathExpansion( | 273 wifi_fields->SetStringWithoutPathExpansion( |
| 278 ::onc::wifi::kHexSSID, | 274 ::onc::wifi::kHexSSID, |
| 279 base::HexEncode(ssid_string.c_str(), ssid_string.size())); | 275 base::HexEncode(ssid_string.c_str(), ssid_string.size())); |
| 280 } | 276 } |
| 281 | 277 |
| 282 namespace { | 278 namespace { |
| 283 | 279 |
| 284 class OncMaskValues : public Mapper { | 280 class OncMaskValues : public Mapper { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; | 344 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; |
| 349 return std::string(); | 345 return std::string(); |
| 350 } | 346 } |
| 351 } | 347 } |
| 352 return decoded; | 348 return decoded; |
| 353 } | 349 } |
| 354 | 350 |
| 355 CertPEMsByGUIDMap GetServerAndCACertsByGUID( | 351 CertPEMsByGUIDMap GetServerAndCACertsByGUID( |
| 356 const base::ListValue& certificates) { | 352 const base::ListValue& certificates) { |
| 357 CertPEMsByGUIDMap certs_by_guid; | 353 CertPEMsByGUIDMap certs_by_guid; |
| 358 for (base::ListValue::const_iterator it = certificates.begin(); | 354 for (const base::Value* entry : certificates) { |
| 359 it != certificates.end(); ++it) { | 355 const base::DictionaryValue* cert = nullptr; |
| 360 base::DictionaryValue* cert = NULL; | 356 entry->GetAsDictionary(&cert); |
| 361 (*it)->GetAsDictionary(&cert); | |
| 362 | 357 |
| 363 std::string guid; | 358 std::string guid; |
| 364 cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid); | 359 cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid); |
| 365 std::string cert_type; | 360 std::string cert_type; |
| 366 cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type); | 361 cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type); |
| 367 if (cert_type != certificate::kServer && | 362 if (cert_type != certificate::kServer && |
| 368 cert_type != certificate::kAuthority) { | 363 cert_type != certificate::kAuthority) { |
| 369 continue; | 364 continue; |
| 370 } | 365 } |
| 371 std::string x509_data; | 366 std::string x509_data; |
| 372 cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data); | 367 cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data); |
| 373 | 368 |
| 374 std::string der = DecodePEM(x509_data); | 369 std::string der = DecodePEM(x509_data); |
| 375 std::string pem; | 370 std::string pem; |
| 376 if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) { | 371 if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) { |
| 377 LOG(ERROR) << "Certificate with GUID " << guid | 372 LOG(ERROR) << "Certificate with GUID " << guid |
| 378 << " is not in PEM encoding."; | 373 << " is not in PEM encoding."; |
| 379 continue; | 374 continue; |
| 380 } | 375 } |
| 381 certs_by_guid[guid] = pem; | 376 certs_by_guid[guid] = pem; |
| 382 } | 377 } |
| 383 | 378 |
| 384 return certs_by_guid; | 379 return certs_by_guid; |
| 385 } | 380 } |
| 386 | 381 |
| 387 void FillInHexSSIDFieldsInNetworks(base::ListValue* network_configs) { | 382 void FillInHexSSIDFieldsInNetworks(base::ListValue* network_configs) { |
| 388 for (base::ListValue::iterator it = network_configs->begin(); | 383 for (base::Value* entry : *network_configs) { |
| 389 it != network_configs->end(); ++it) { | 384 base::DictionaryValue* network = nullptr; |
| 390 base::DictionaryValue* network = NULL; | 385 entry->GetAsDictionary(&network); |
| 391 (*it)->GetAsDictionary(&network); | |
| 392 DCHECK(network); | 386 DCHECK(network); |
| 393 FillInHexSSIDFieldsInOncObject(kNetworkConfigurationSignature, network); | 387 FillInHexSSIDFieldsInOncObject(kNetworkConfigurationSignature, network); |
| 394 } | 388 } |
| 395 } | 389 } |
| 396 | 390 |
| 397 } // namespace | 391 } // namespace |
| 398 | 392 |
| 399 bool ParseAndValidateOncForImport(const std::string& onc_blob, | 393 bool ParseAndValidateOncForImport(const std::string& onc_blob, |
| 400 ONCSource onc_source, | 394 ONCSource onc_source, |
| 401 const std::string& passphrase, | 395 const std::string& passphrase, |
| 402 base::ListValue* network_configs, | 396 base::ListValue* network_configs, |
| 403 base::DictionaryValue* global_network_config, | 397 base::DictionaryValue* global_network_config, |
| 404 base::ListValue* certificates) { | 398 base::ListValue* certificates) { |
| 405 network_configs->Clear(); | 399 network_configs->Clear(); |
| 406 global_network_config->Clear(); | 400 global_network_config->Clear(); |
| 407 certificates->Clear(); | 401 certificates->Clear(); |
| 408 if (onc_blob.empty()) | 402 if (onc_blob.empty()) |
| 409 return true; | 403 return true; |
| 410 | 404 |
| 411 scoped_ptr<base::DictionaryValue> toplevel_onc = | 405 scoped_ptr<base::DictionaryValue> toplevel_onc = |
| 412 ReadDictionaryFromJson(onc_blob); | 406 ReadDictionaryFromJson(onc_blob); |
| 413 if (toplevel_onc.get() == NULL) { | 407 if (!toplevel_onc) { |
| 414 LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source) | 408 LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source) |
| 415 << " is not a valid JSON dictionary."; | 409 << " is not a valid JSON dictionary."; |
| 416 return false; | 410 return false; |
| 417 } | 411 } |
| 418 | 412 |
| 419 // Check and see if this is an encrypted ONC file. If so, decrypt it. | 413 // Check and see if this is an encrypted ONC file. If so, decrypt it. |
| 420 std::string onc_type; | 414 std::string onc_type; |
| 421 toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType, | 415 toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType, |
| 422 &onc_type); | 416 &onc_type); |
| 423 if (onc_type == toplevel_config::kEncryptedConfiguration) { | 417 if (onc_type == toplevel_config::kEncryptedConfiguration) { |
| 424 toplevel_onc = Decrypt(passphrase, *toplevel_onc); | 418 toplevel_onc = Decrypt(passphrase, *toplevel_onc); |
| 425 if (toplevel_onc.get() == NULL) { | 419 if (!toplevel_onc) { |
| 426 LOG(ERROR) << "Couldn't decrypt the ONC from " | 420 LOG(ERROR) << "Couldn't decrypt the ONC from " |
| 427 << GetSourceAsString(onc_source); | 421 << GetSourceAsString(onc_source); |
| 428 return false; | 422 return false; |
| 429 } | 423 } |
| 430 } | 424 } |
| 431 | 425 |
| 432 bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY || | 426 bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY || |
| 433 onc_source == ONC_SOURCE_DEVICE_POLICY); | 427 onc_source == ONC_SOURCE_DEVICE_POLICY); |
| 434 | 428 |
| 435 // Validate the ONC dictionary. We are liberal and ignore unknown field | 429 // Validate the ONC dictionary. We are liberal and ignore unknown field |
| (...skipping 13 matching lines...) Expand all Loading... |
| 449 if (from_policy) { | 443 if (from_policy) { |
| 450 UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation", | 444 UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation", |
| 451 validation_result == Validator::VALID); | 445 validation_result == Validator::VALID); |
| 452 } | 446 } |
| 453 | 447 |
| 454 bool success = true; | 448 bool success = true; |
| 455 if (validation_result == Validator::VALID_WITH_WARNINGS) { | 449 if (validation_result == Validator::VALID_WITH_WARNINGS) { |
| 456 LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source) | 450 LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source) |
| 457 << " produced warnings."; | 451 << " produced warnings."; |
| 458 success = false; | 452 success = false; |
| 459 } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) { | 453 } else if (validation_result == Validator::INVALID || !toplevel_onc) { |
| 460 LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source) | 454 LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source) |
| 461 << " is invalid and couldn't be repaired."; | 455 << " is invalid and couldn't be repaired."; |
| 462 return false; | 456 return false; |
| 463 } | 457 } |
| 464 | 458 |
| 465 base::ListValue* validated_certs = NULL; | 459 base::ListValue* validated_certs = nullptr; |
| 466 if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates, | 460 if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates, |
| 467 &validated_certs)) { | 461 &validated_certs)) { |
| 468 certificates->Swap(validated_certs); | 462 certificates->Swap(validated_certs); |
| 469 } | 463 } |
| 470 | 464 |
| 471 base::ListValue* validated_networks = NULL; | 465 base::ListValue* validated_networks = nullptr; |
| 472 if (toplevel_onc->GetListWithoutPathExpansion( | 466 if (toplevel_onc->GetListWithoutPathExpansion( |
| 473 toplevel_config::kNetworkConfigurations, &validated_networks)) { | 467 toplevel_config::kNetworkConfigurations, &validated_networks)) { |
| 474 FillInHexSSIDFieldsInNetworks(validated_networks); | 468 FillInHexSSIDFieldsInNetworks(validated_networks); |
| 475 | 469 |
| 476 CertPEMsByGUIDMap server_and_ca_certs = | 470 CertPEMsByGUIDMap server_and_ca_certs = |
| 477 GetServerAndCACertsByGUID(*certificates); | 471 GetServerAndCACertsByGUID(*certificates); |
| 478 | 472 |
| 479 if (!ResolveServerCertRefsInNetworks(server_and_ca_certs, | 473 if (!ResolveServerCertRefsInNetworks(server_and_ca_certs, |
| 480 validated_networks)) { | 474 validated_networks)) { |
| 481 LOG(ERROR) << "Some certificate references in the ONC policy for source " | 475 LOG(ERROR) << "Some certificate references in the ONC policy for source " |
| 482 << GetSourceAsString(onc_source) << " could not be resolved."; | 476 << GetSourceAsString(onc_source) << " could not be resolved."; |
| 483 success = false; | 477 success = false; |
| 484 } | 478 } |
| 485 | 479 |
| 486 network_configs->Swap(validated_networks); | 480 network_configs->Swap(validated_networks); |
| 487 } | 481 } |
| 488 | 482 |
| 489 base::DictionaryValue* validated_global_config = NULL; | 483 base::DictionaryValue* validated_global_config = nullptr; |
| 490 if (toplevel_onc->GetDictionaryWithoutPathExpansion( | 484 if (toplevel_onc->GetDictionaryWithoutPathExpansion( |
| 491 toplevel_config::kGlobalNetworkConfiguration, | 485 toplevel_config::kGlobalNetworkConfiguration, |
| 492 &validated_global_config)) { | 486 &validated_global_config)) { |
| 493 global_network_config->Swap(validated_global_config); | 487 global_network_config->Swap(validated_global_config); |
| 494 } | 488 } |
| 495 | 489 |
| 496 return success; | 490 return success; |
| 497 } | 491 } |
| 498 | 492 |
| 499 scoped_refptr<net::X509Certificate> DecodePEMCertificate( | 493 scoped_refptr<net::X509Certificate> DecodePEMCertificate( |
| (...skipping 29 matching lines...) Expand all Loading... |
| 529 const std::string& key_pem, | 523 const std::string& key_pem, |
| 530 base::DictionaryValue* onc_object) { | 524 base::DictionaryValue* onc_object) { |
| 531 std::string guid_ref; | 525 std::string guid_ref; |
| 532 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) | 526 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) |
| 533 return true; | 527 return true; |
| 534 | 528 |
| 535 std::string pem_encoded; | 529 std::string pem_encoded; |
| 536 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) | 530 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) |
| 537 return false; | 531 return false; |
| 538 | 532 |
| 539 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL); | 533 onc_object->RemoveWithoutPathExpansion(key_guid_ref, nullptr); |
| 540 onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded); | 534 onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded); |
| 541 return true; | 535 return true; |
| 542 } | 536 } |
| 543 | 537 |
| 544 bool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid, | 538 bool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid, |
| 545 const std::string& key_guid_ref_list, | 539 const std::string& key_guid_ref_list, |
| 546 const std::string& key_pem_list, | 540 const std::string& key_pem_list, |
| 547 base::DictionaryValue* onc_object) { | 541 base::DictionaryValue* onc_object) { |
| 548 const base::ListValue* guid_ref_list = NULL; | 542 const base::ListValue* guid_ref_list = nullptr; |
| 549 if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list, | 543 if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list, |
| 550 &guid_ref_list)) { | 544 &guid_ref_list)) { |
| 551 return true; | 545 return true; |
| 552 } | 546 } |
| 553 | 547 |
| 554 scoped_ptr<base::ListValue> pem_list(new base::ListValue); | 548 scoped_ptr<base::ListValue> pem_list(new base::ListValue); |
| 555 for (base::ListValue::const_iterator it = guid_ref_list->begin(); | 549 for (const base::Value* entry : *guid_ref_list) { |
| 556 it != guid_ref_list->end(); ++it) { | |
| 557 std::string guid_ref; | 550 std::string guid_ref; |
| 558 (*it)->GetAsString(&guid_ref); | 551 entry->GetAsString(&guid_ref); |
| 559 | 552 |
| 560 std::string pem_encoded; | 553 std::string pem_encoded; |
| 561 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) | 554 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) |
| 562 return false; | 555 return false; |
| 563 | 556 |
| 564 pem_list->AppendString(pem_encoded); | 557 pem_list->AppendString(pem_encoded); |
| 565 } | 558 } |
| 566 | 559 |
| 567 onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, NULL); | 560 onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, nullptr); |
| 568 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release()); | 561 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release()); |
| 569 return true; | 562 return true; |
| 570 } | 563 } |
| 571 | 564 |
| 572 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid, | 565 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid, |
| 573 const std::string& key_guid_ref, | 566 const std::string& key_guid_ref, |
| 574 const std::string& key_pem_list, | 567 const std::string& key_pem_list, |
| 575 base::DictionaryValue* onc_object) { | 568 base::DictionaryValue* onc_object) { |
| 576 std::string guid_ref; | 569 std::string guid_ref; |
| 577 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) | 570 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) |
| 578 return true; | 571 return true; |
| 579 | 572 |
| 580 std::string pem_encoded; | 573 std::string pem_encoded; |
| 581 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) | 574 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded)) |
| 582 return false; | 575 return false; |
| 583 | 576 |
| 584 scoped_ptr<base::ListValue> pem_list(new base::ListValue); | 577 scoped_ptr<base::ListValue> pem_list(new base::ListValue); |
| 585 pem_list->AppendString(pem_encoded); | 578 pem_list->AppendString(pem_encoded); |
| 586 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL); | 579 onc_object->RemoveWithoutPathExpansion(key_guid_ref, nullptr); |
| 587 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release()); | 580 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release()); |
| 588 return true; | 581 return true; |
| 589 } | 582 } |
| 590 | 583 |
| 591 // Resolves the reference list at |key_guid_refs| if present and otherwise the | 584 // Resolves the reference list at |key_guid_refs| if present and otherwise the |
| 592 // single reference at |key_guid_ref|. Returns whether the respective resolving | 585 // single reference at |key_guid_ref|. Returns whether the respective resolving |
| 593 // was successful. | 586 // was successful. |
| 594 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid, | 587 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid, |
| 595 const std::string& key_guid_refs, | 588 const std::string& key_guid_refs, |
| 596 const std::string& key_guid_ref, | 589 const std::string& key_guid_ref, |
| 597 const std::string& key_pem_list, | 590 const std::string& key_pem_list, |
| 598 base::DictionaryValue* onc_object) { | 591 base::DictionaryValue* onc_object) { |
| 599 if (onc_object->HasKey(key_guid_refs)) { | 592 if (onc_object->HasKey(key_guid_refs)) { |
| 600 if (onc_object->HasKey(key_guid_ref)) { | 593 if (onc_object->HasKey(key_guid_ref)) { |
| 601 LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref | 594 LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref |
| 602 << ". Ignoring and removing the latter."; | 595 << ". Ignoring and removing the latter."; |
| 603 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL); | 596 onc_object->RemoveWithoutPathExpansion(key_guid_ref, nullptr); |
| 604 } | 597 } |
| 605 return ResolveCertRefList( | 598 return ResolveCertRefList( |
| 606 certs_by_guid, key_guid_refs, key_pem_list, onc_object); | 599 certs_by_guid, key_guid_refs, key_pem_list, onc_object); |
| 607 } | 600 } |
| 608 | 601 |
| 609 // Only resolve |key_guid_ref| if |key_guid_refs| isn't present. | 602 // Only resolve |key_guid_ref| if |key_guid_refs| isn't present. |
| 610 return ResolveSingleCertRefToList( | 603 return ResolveSingleCertRefToList( |
| 611 certs_by_guid, key_guid_ref, key_pem_list, onc_object); | 604 certs_by_guid, key_guid_ref, key_pem_list, onc_object); |
| 612 } | 605 } |
| 613 | 606 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 openvpn::kServerCARef, | 641 openvpn::kServerCARef, |
| 649 openvpn::kServerCAPEMs, | 642 openvpn::kServerCAPEMs, |
| 650 onc_object)) { | 643 onc_object)) { |
| 651 return false; | 644 return false; |
| 652 } | 645 } |
| 653 } | 646 } |
| 654 | 647 |
| 655 // Recurse into nested objects. | 648 // Recurse into nested objects. |
| 656 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); | 649 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); |
| 657 it.Advance()) { | 650 it.Advance()) { |
| 658 base::DictionaryValue* inner_object = NULL; | 651 base::DictionaryValue* inner_object = nullptr; |
| 659 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) | 652 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) |
| 660 continue; | 653 continue; |
| 661 | 654 |
| 662 const OncFieldSignature* field_signature = | 655 const OncFieldSignature* field_signature = |
| 663 GetFieldSignature(signature, it.key()); | 656 GetFieldSignature(signature, it.key()); |
| 664 if (!field_signature) | 657 if (!field_signature) |
| 665 continue; | 658 continue; |
| 666 | 659 |
| 667 if (!ResolveServerCertRefsInObject(certs_by_guid, | 660 if (!ResolveServerCertRefsInObject(certs_by_guid, |
| 668 *field_signature->value_signature, | 661 *field_signature->value_signature, |
| 669 inner_object)) { | 662 inner_object)) { |
| 670 return false; | 663 return false; |
| 671 } | 664 } |
| 672 } | 665 } |
| 673 return true; | 666 return true; |
| 674 } | 667 } |
| 675 | 668 |
| 676 } // namespace | 669 } // namespace |
| 677 | 670 |
| 678 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid, | 671 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid, |
| 679 base::ListValue* network_configs) { | 672 base::ListValue* network_configs) { |
| 680 bool success = true; | 673 bool success = true; |
| 681 for (base::ListValue::iterator it = network_configs->begin(); | 674 for (base::ListValue::iterator it = network_configs->begin(); |
| 682 it != network_configs->end(); ) { | 675 it != network_configs->end(); ) { |
| 683 base::DictionaryValue* network = NULL; | 676 base::DictionaryValue* network = nullptr; |
| 684 (*it)->GetAsDictionary(&network); | 677 (*it)->GetAsDictionary(&network); |
| 685 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) { | 678 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) { |
| 686 std::string guid; | 679 std::string guid; |
| 687 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid); | 680 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid); |
| 688 // This might happen even with correct validation, if the referenced | 681 // This might happen even with correct validation, if the referenced |
| 689 // certificate couldn't be imported. | 682 // certificate couldn't be imported. |
| 690 LOG(ERROR) << "Couldn't resolve some certificate reference of network " | 683 LOG(ERROR) << "Couldn't resolve some certificate reference of network " |
| 691 << guid; | 684 << guid; |
| 692 it = network_configs->Erase(it, NULL); | 685 it = network_configs->Erase(it, nullptr); |
| 693 success = false; | 686 success = false; |
| 694 continue; | 687 continue; |
| 695 } | 688 } |
| 696 ++it; | 689 ++it; |
| 697 } | 690 } |
| 698 return success; | 691 return success; |
| 699 } | 692 } |
| 700 | 693 |
| 701 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid, | 694 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid, |
| 702 base::DictionaryValue* network_config) { | 695 base::DictionaryValue* network_config) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 732 // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended' | 725 // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended' |
| 733 property_basename = property_key.substr(pos + 1); | 726 property_basename = property_key.substr(pos + 1); |
| 734 recommended_property_key = | 727 recommended_property_key = |
| 735 property_key.substr(0, pos + 1) + ::onc::kRecommended; | 728 property_key.substr(0, pos + 1) + ::onc::kRecommended; |
| 736 } else { | 729 } else { |
| 737 // 'Name' -> 'Name', 'Recommended' | 730 // 'Name' -> 'Name', 'Recommended' |
| 738 property_basename = property_key; | 731 property_basename = property_key; |
| 739 recommended_property_key = ::onc::kRecommended; | 732 recommended_property_key = ::onc::kRecommended; |
| 740 } | 733 } |
| 741 | 734 |
| 742 const base::ListValue* recommended_keys = NULL; | 735 const base::ListValue* recommended_keys = nullptr; |
| 743 return (onc->GetList(recommended_property_key, &recommended_keys) && | 736 return (onc->GetList(recommended_property_key, &recommended_keys) && |
| 744 recommended_keys->Find(base::StringValue(property_basename)) != | 737 recommended_keys->Find(base::StringValue(property_basename)) != |
| 745 recommended_keys->end()); | 738 recommended_keys->end()); |
| 746 } | 739 } |
| 747 | 740 |
| 748 } // namespace onc | 741 } // namespace onc |
| 749 } // namespace chromeos | 742 } // namespace chromeos |
| OLD | NEW |