Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3173)

Unified Diff: chrome/browser/chromeos/cros/onc_network_parser.cc

Issue 8949056: This adds support for encrypted ONC import (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..bf0151acdac3b7cfe843886d065b84ab6e48f229 100644
--- a/chrome/browser/chromeos/cros/onc_network_parser.cc
+++ b/chrome/browser/chromeos/cros/onc_network_parser.cc
@@ -17,6 +17,9 @@
#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/scoped_nss_types.h"
+#include "crypto/symmetric_key.h"
+#include "crypto/encryptor.h"
#include "grit/generated_resources.h"
#include "net/base/cert_database.h"
#include "net/base/crypto_module.h"
@@ -194,11 +197,65 @@ std::string ConvertValueToString(const base::Value& value) {
return value_json;
}
+bool VerifyHMAC(const std::string& hmac,
+ const std::string& plaintext,
+ const crypto::SymmetricKey* key) {
Ryan Sleevi 2011/12/24 07:34:08 See crypto::HMAC::Verify() Same implementation, b
+ SECItem empty_parameters;
+ empty_parameters.type = siBuffer;
+ empty_parameters.data = 0;
+ empty_parameters.len = 0;
+
+ SECStatus status = SECSuccess;
+ crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
+ CKM_SHA_1_HMAC,
+ CKA_SIGN,
+ key->key(),
+ &empty_parameters));
+ if (!context.get()) {
+ LOG(WARNING) << "PK11_CreateContextBySymKey failed";
+ return false;
+ }
+
+ status = PK11_DigestBegin(context.get());
+ if (status != SECSuccess) {
+ LOG(WARNING) << "PK11_DigestBegin failed";
+ return false;
+ }
+
+ status = PK11_DigestOp(
+ context.get(),
+ reinterpret_cast<const unsigned char*>(plaintext.c_str()),
+ plaintext.size());
+
+ if (status != SECSuccess) {
+ LOG(WARNING) << "PK11_DigestOp failed";
+ return false;
+ }
+
+ // SHA1 HMACs are 160 bits.
+ char digest[20];
+ unsigned int length = 0;
+ status = PK11_DigestFinal(context.get(),
+ reinterpret_cast<unsigned char*>(&digest[0]),
+ &length,
+ 20);
+ if (status != SECSuccess) {
+ LOG(WARNING) << "PK11_DigestFinal failed";
+ return false;
+ }
+
+ if (std::string(digest, length) == hmac)
Ryan Sleevi 2011/12/24 07:34:08 See above comment. This comparison is not a consta
+ return true;
+
+ return false;
Charlie Lee 2011/12/22 20:55:17 should add a log warning here for why this would f
+}
+
} // namespace
// -------------------- 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,6 +270,12 @@ 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()));
+
// At least one of NetworkConfigurations or Certificates is required.
bool has_network_configurations =
root_dict_->GetList("NetworkConfigurations", &network_configs_);
@@ -239,6 +302,103 @@ 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;
+
+ if (!root->GetString("Salt", &salt) ||
+ !root->GetInteger("Iterations", &iterations) ||
+ !root->GetString("Cipher", &cipher) ||
+ !root->GetString("HMAC", &hmac_method) ||
+ !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 (!decryptor.Decrypt(ciphertext, &plaintext)) {
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
+ return NULL;
+ }
+
+ // Split out the HMAC.
Ryan Sleevi 2011/12/24 07:34:08 As a drive-by, if it's not too late, wouldn't this
+ std::string::size_type split = plaintext.find_last_of('|');
+ std::string hmac = plaintext.substr(split + 1, plaintext.size() - split - 1);
+ plaintext = plaintext.substr(0, split);
+ if (!base::Base64Decode(hmac, &hmac)) {
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
+ return NULL;
+ }
+
+ // Verify the HMAC. If it fails, then we have failed to decrypt (even though
+ // we decrypted *something*, it's been tampered with).
+ if (!VerifyHMAC(hmac, plaintext, key.get())) {
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_HMAC_CHECK_FAILED);
Ryan Sleevi 2011/12/24 07:34:08 The fact that HMAC errors are distinguished from e
+ 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) {
+ if (parse_error_.empty())
Charlie Lee 2011/12/22 20:55:17 when would this not be empty?
Greg Spencer (Chromium) 2012/01/03 21:54:22 When the Deserialize call above places an error in
+ 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;
}
« no previous file with comments | « chrome/browser/chromeos/cros/onc_network_parser.h ('k') | chrome/browser/chromeos/cros/onc_network_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698