Chromium Code Reviews| 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..f2eb75d18a0cdebba2421ef0240e6861fdd25cbc 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/hmac.h" |
| +#include "crypto/scoped_nss_types.h" |
| +#include "crypto/symmetric_key.h" |
| +#include "crypto/encryptor.h" |
|
Ryan Sleevi
2012/01/04 01:33:43
nit: lexicographical sort
Greg Spencer (Chromium)
2012/01/05 22:18:03
Done.
|
| #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 (!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; |
| + } |
| + 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)) { |
|
Ryan Sleevi
2012/01/04 01:33:43
nit: Move these decodes (Line 304, 314, 319) above
Greg Spencer (Chromium)
2012/01/05 22:18:03
Done.
Ryan Sleevi
2012/01/05 22:34:11
For in-progress code, I think it's fine as-is, as
|
| + parse_error_ = l10n_util::GetStringUTF8( |
| + IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE); |
| + 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) || !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->GetType() != base::Value::TYPE_DICTIONARY) { |
|
Ryan Sleevi
2012/01/04 01:33:43
nit: I believe the preference is to use
new_root-
Greg Spencer (Chromium)
2012/01/05 22:18:03
Done.
|
| + 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()); |
|
Ryan Sleevi
2012/01/04 01:33:43
side nit: From an API perspective, it's unclear wh
Greg Spencer (Chromium)
2012/01/05 22:18:03
I see your point, but this is what it translates i
Ryan Sleevi
2012/01/05 22:34:11
Agreed - but it does seem like the API (of the bas
|
| +} |
| + |
| int OncNetworkParser::GetNetworkConfigsSize() const { |
| return network_configs_ ? network_configs_->GetSize() : 0; |
| } |