Skip to content

Commit

Permalink
This adds support for encrypted ONC import to Chrome.
Browse files Browse the repository at this point in the history
We now can import standalone ONC files that are encrypted by the
Spigots management app.

TBR=joaodasilva@chromium.org
BUG=chromium-os:19397
TEST=Ran new unit tests, imported encrypted ONC on device.



Review URL: http://codereview.chromium.org/8949056

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@117321 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
gspencer@chromium.org committed Jan 11, 2012
1 parent 98a4a4f commit 2c9f0de
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 27 deletions.
15 changes: 15 additions & 0 deletions chrome/app/generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -11777,6 +11777,21 @@ Some features may be unavailable. Please check that the profile exists and you
<message name="IDS_NETWORK_CONFIG_ERROR_CERT_IMPORT" desc="Error for network configuration: Certificate import error.">
Certificate import error
</message>
<message name="IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_MALFORMED" desc="Displayed when importing an encrypted ONC file and the ONC file is malformed.">
Encrypted ONC file is malformed.
</message>
<message name="IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNSUPPORTED_ENCRYPTION" desc="Displayed when importing an encrypted ONC file and the ONC file uses an encryption protocol that is not supported.">
Encrypted ONC file uses an unsupported encryption scheme.
</message>
<message name="IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE" desc="Displayed when importing an encrypted ONC file and the encryption parameters are not able to be parsed.">
Unable to parse some parameters in the encrypted ONC file.
</message>
<message name="IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT" desc="Displayed when importing an encrypted ONC file and it is not able to be decrypted.">
Unable to decrypt the encrypted ONC file.
</message>
<message name="IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_TOO_MANY_ITERATIONS" desc="Displayed when importing an encrypted ONC file and the iteration count is too large.">
Passphrase iteration count is too large.
</message>
<message name="IDS_NETWORK_PURCHASE_MORE_MESSAGE" desc="Message for purchase more link on notification when there is no cellular plan">
Buy plan...
</message>
Expand Down
7 changes: 3 additions & 4 deletions chrome/browser/chromeos/cros/network_library.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1773,7 +1773,7 @@ class NetworkLibraryImplBase : public NetworkLibrary {
// virtual SetIPConfig implemented in derived classes.
virtual void SwitchToPreferredNetwork() OVERRIDE;
virtual bool LoadOncNetworks(const std::string& onc_blob,
const std::string& passcode,
const std::string& passphrase,
NetworkUIData::ONCSource source,
std::string* error) OVERRIDE;
virtual bool SetActiveNetwork(ConnectionType type,
Expand Down Expand Up @@ -2891,11 +2891,10 @@ void NetworkLibraryImplBase::SwitchToPreferredNetwork() {
}

bool NetworkLibraryImplBase::LoadOncNetworks(const std::string& onc_blob,
const std::string& passcode,
const std::string& passphrase,
NetworkUIData::ONCSource source,
std::string* error) {
// TODO(gspencer): Add support for decrypting onc files. crbug.com/19397
OncNetworkParser parser(onc_blob, source);
OncNetworkParser parser(onc_blob, passphrase, source);

if (!parser.parse_error().empty()) {
if (error)
Expand Down
132 changes: 129 additions & 3 deletions chrome/browser/chromeos/cros/onc_network_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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),
Expand All @@ -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.";
}
}

Expand All @@ -239,6 +254,117 @@ const EnumMapper<PropertyIndex>* OncNetworkParser::property_mapper() {
return get_onc_mapper();
}

base::DictionaryValue* OncNetworkParser::Decrypt(
const std::string& passphrase,
base::DictionaryValue* root) {
const int kKeySizeInBits = 256;
const int kMaxIterationCount = 500000;
std::string onc_type;
std::string initial_vector;
std::string salt;
std::string cipher;
std::string stretch_method;
std::string hmac_method;
std::string hmac;
int iterations;
std::string ciphertext;

if (!root->GetString("Ciphertext", &ciphertext) ||
!root->GetString("Cipher", &cipher) ||
!root->GetString("HMAC", &hmac) ||
!root->GetString("HMACMethod", &hmac_method) ||
!root->GetString("IV", &initial_vector) ||
!root->GetInteger("Iterations", &iterations) ||
!root->GetString("Salt", &salt) ||
!root->GetString("Stretch", &stretch_method) ||
!root->GetString("Type", &onc_type) ||
onc_type != "EncryptedConfiguration") {
parse_error_ = l10n_util::GetStringUTF8(
IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_MALFORMED);
return NULL;
}

if (hmac_method != "SHA1" ||
cipher != "AES256" ||
stretch_method != "PBKDF2") {
parse_error_ = l10n_util::GetStringUTF8(
IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNSUPPORTED_ENCRYPTION);
return NULL;
}

// Simply a sanity check to make sure we can't lock up the machine
// for too long with a huge number.
if (iterations > kMaxIterationCount) {
parse_error_ = l10n_util::GetStringUTF8(
IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_TOO_MANY_ITERATIONS);
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,
kKeySizeInBits));

if (!base::Base64Decode(initial_vector, &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;
}

crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
if (!hmac_verifier.Init(key.get()) ||
!hmac_verifier.Verify(ciphertext, hmac)) {
parse_error_ = l10n_util::GetStringUTF8(
IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
return NULL;
}

crypto::Encryptor decryptor;
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;
}

std::string plaintext;
if (!decryptor.Decrypt(ciphertext, &plaintext)) {
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;
}
Expand Down
4 changes: 4 additions & 0 deletions chrome/browser/chromeos/cros/onc_network_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class OncNetworkParser : public NetworkParser {
Network*);

OncNetworkParser(const std::string& onc_blob,
const std::string& passphrase,
NetworkUIData::ONCSource onc_source);
virtual ~OncNetworkParser();
static const EnumMapper<PropertyIndex>* property_mapper();
Expand Down Expand Up @@ -147,6 +148,9 @@ class OncNetworkParser : public NetworkParser {
const std::string& guid,
base::DictionaryValue* certificate);

base::DictionaryValue* Decrypt(const std::string& passphrase,
base::DictionaryValue* root);

// Error message from the JSON parser, if applicable.
std::string parse_error_;

Expand Down
Loading

0 comments on commit 2c9f0de

Please sign in to comment.