| Index: chrome/browser/chromeos/cros/onc_network_parser.cc
|
| diff --git a/chrome/browser/chromeos/cros/onc_network_parser.cc b/chrome/browser/chromeos/cros/onc_network_parser.cc
|
| index 69ba0da80e4878f12978c52fb60bb23e3fee8943..a5f20782e73a90237b761d9b32097a8824ac97fd 100644
|
| --- a/chrome/browser/chromeos/cros/onc_network_parser.cc
|
| +++ b/chrome/browser/chromeos/cros/onc_network_parser.cc
|
| @@ -17,6 +17,10 @@
|
| #include "chrome/browser/chromeos/cros/network_library.h"
|
| #include "chrome/browser/chromeos/cros/onc_constants.h"
|
| #include "chrome/common/net/x509_certificate_model.h"
|
| +#include "crypto/encryptor.h"
|
| +#include "crypto/hmac.h"
|
| +#include "crypto/scoped_nss_types.h"
|
| +#include "crypto/symmetric_key.h"
|
| #include "grit/generated_resources.h"
|
| #include "net/base/cert_database.h"
|
| #include "net/base/crypto_module.h"
|
| @@ -199,6 +203,7 @@ std::string ConvertValueToString(const base::Value& value) {
|
| // -------------------- OncNetworkParser --------------------
|
|
|
| OncNetworkParser::OncNetworkParser(const std::string& onc_blob,
|
| + const std::string& passphrase,
|
| NetworkUIData::ONCSource onc_source)
|
| : NetworkParser(get_onc_mapper()),
|
| onc_source_(onc_source),
|
| @@ -213,15 +218,25 @@ OncNetworkParser::OncNetworkParser(const std::string& onc_blob,
|
| LOG(WARNING) << "OncNetworkParser received bad ONC file: " << parse_error_;
|
| } else {
|
| root_dict_.reset(static_cast<DictionaryValue*>(root.release()));
|
| +
|
| + // Check and see if this is an encrypted ONC file. If so, decrypt it.
|
| + std::string ciphertext_test;
|
| + if (root_dict_->GetString("Ciphertext", &ciphertext_test))
|
| + root_dict_.reset(Decrypt(passphrase, root_dict_.get()));
|
| +
|
| + // Decryption failed, errors will be in parse_error_;
|
| + if (!root_dict_.get())
|
| + return;
|
| +
|
| // At least one of NetworkConfigurations or Certificates is required.
|
| bool has_network_configurations =
|
| - root_dict_->GetList("NetworkConfigurations", &network_configs_);
|
| + root_dict_->GetList("NetworkConfigurations", &network_configs_);
|
| bool has_certificates =
|
| - root_dict_->GetList("Certificates", &certificates_);
|
| + root_dict_->GetList("Certificates", &certificates_);
|
| VLOG(2) << "ONC file has " << GetNetworkConfigsSize() << " networks and "
|
| << GetCertificatesSize() << " certificates";
|
| LOG_IF(WARNING, (!has_network_configurations && !has_certificates))
|
| - << "ONC file has no NetworkConfigurations or Certificates.";
|
| + << "ONC file has no NetworkConfigurations or Certificates.";
|
| }
|
| }
|
|
|
| @@ -239,6 +254,101 @@ const EnumMapper<PropertyIndex>* OncNetworkParser::property_mapper() {
|
| return get_onc_mapper();
|
| }
|
|
|
| +base::DictionaryValue* OncNetworkParser::Decrypt(
|
| + const std::string& passphrase,
|
| + base::DictionaryValue* root) {
|
| + std::string salt;
|
| + int iterations;
|
| + const int key_size_in_bits = 256;
|
| + std::string initial_vector_str;
|
| + std::string ciphertext;
|
| + std::string cipher;
|
| + std::string hmac_method;
|
| + std::string hmac;
|
| +
|
| + if (!root->GetString("Salt", &salt) ||
|
| + !root->GetInteger("Iterations", &iterations) ||
|
| + !root->GetString("Cipher", &cipher) ||
|
| + !root->GetString("HMACMethod", &hmac_method) ||
|
| + !root->GetString("HMAC", &hmac) ||
|
| + !root->GetString("IV", &initial_vector_str) ||
|
| + !root->GetString("Ciphertext", &ciphertext)) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_MALFORMED);
|
| + return NULL;
|
| + }
|
| +
|
| + if (hmac_method != "SHA1" || cipher != "AES256") {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNSUPPORTED_ENCRYPTION);
|
| + return NULL;
|
| + }
|
| +
|
| + if (!base::Base64Decode(salt, &salt)) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
|
| + return NULL;
|
| + }
|
| +
|
| + scoped_ptr<crypto::SymmetricKey> key(
|
| + crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
|
| + passphrase,
|
| + salt,
|
| + iterations,
|
| + key_size_in_bits));
|
| +
|
| +
|
| + crypto::Encryptor decryptor;
|
| + std::string initial_vector;
|
| + std::string plaintext;
|
| + if (!base::Base64Decode(initial_vector_str, &initial_vector)) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
|
| + return NULL;
|
| + }
|
| + if (!base::Base64Decode(ciphertext, &ciphertext)) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
|
| + return NULL;
|
| + }
|
| + if (!base::Base64Decode(hmac, &hmac)) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
|
| + return NULL;
|
| + }
|
| +
|
| + if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
|
| + return NULL;
|
| + }
|
| + // Verify the HMAC. If it fails, then we will still try to decrypt because
|
| + // we don't want to leak timing information.
|
| + bool hmac_failed = false;
|
| + crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
|
| + if (!hmac_verifier.Init(key.get()) || !hmac_verifier.Verify(ciphertext, hmac))
|
| + hmac_failed = true;
|
| +
|
| + if (!decryptor.Decrypt(ciphertext, &plaintext) || hmac_failed) {
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
|
| + return NULL;
|
| + }
|
| +
|
| + // Now we've decrypted it, let's deserialize the decrypted data.
|
| + JSONStringValueSerializer deserializer(plaintext);
|
| + deserializer.set_allow_trailing_comma(true);
|
| + scoped_ptr<base::Value> new_root(deserializer.Deserialize(NULL,
|
| + &parse_error_));
|
| + if (!new_root.get() || !new_root->IsType(base::Value::TYPE_DICTIONARY)) {
|
| + if (parse_error_.empty())
|
| + parse_error_ = l10n_util::GetStringUTF8(
|
| + IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
|
| + return NULL;
|
| + }
|
| + return static_cast<base::DictionaryValue*>(new_root.release());
|
| +}
|
| +
|
| int OncNetworkParser::GetNetworkConfigsSize() const {
|
| return network_configs_ ? network_configs_->GetSize() : 0;
|
| }
|
|
|