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

Side by Side 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 8 years, 12 months 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/chromeos/cros/onc_network_parser.h" 5 #include "chrome/browser/chromeos/cros/onc_network_parser.h"
6 6
7 #include <keyhi.h> 7 #include <keyhi.h>
8 #include <pk11pub.h> 8 #include <pk11pub.h>
9 9
10 #include "base/base64.h" 10 #include "base/base64.h"
11 #include "base/json/json_value_serializer.h" 11 #include "base/json/json_value_serializer.h"
12 #include "base/json/json_writer.h" // for debug output only. 12 #include "base/json/json_writer.h" // for debug output only.
13 #include "base/stringprintf.h" 13 #include "base/stringprintf.h"
14 #include "base/values.h" 14 #include "base/values.h"
15 #include "chrome/browser/chromeos/cros/native_network_constants.h" 15 #include "chrome/browser/chromeos/cros/native_network_constants.h"
16 #include "chrome/browser/chromeos/cros/native_network_parser.h" 16 #include "chrome/browser/chromeos/cros/native_network_parser.h"
17 #include "chrome/browser/chromeos/cros/network_library.h" 17 #include "chrome/browser/chromeos/cros/network_library.h"
18 #include "chrome/browser/chromeos/cros/onc_constants.h" 18 #include "chrome/browser/chromeos/cros/onc_constants.h"
19 #include "chrome/common/net/x509_certificate_model.h" 19 #include "chrome/common/net/x509_certificate_model.h"
20 #include "crypto/scoped_nss_types.h"
21 #include "crypto/symmetric_key.h"
22 #include "crypto/encryptor.h"
20 #include "grit/generated_resources.h" 23 #include "grit/generated_resources.h"
21 #include "net/base/cert_database.h" 24 #include "net/base/cert_database.h"
22 #include "net/base/crypto_module.h" 25 #include "net/base/crypto_module.h"
23 #include "net/base/net_errors.h" 26 #include "net/base/net_errors.h"
24 #include "net/base/x509_certificate.h" 27 #include "net/base/x509_certificate.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h" 28 #include "third_party/cros_system_api/dbus/service_constants.h"
26 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
27 30
28 namespace chromeos { 31 namespace chromeos {
29 32
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 value.GetAsBoolean(&bool_value); 190 value.GetAsBoolean(&bool_value);
188 return bool_value; 191 return bool_value;
189 } 192 }
190 193
191 std::string ConvertValueToString(const base::Value& value) { 194 std::string ConvertValueToString(const base::Value& value) {
192 std::string value_json; 195 std::string value_json;
193 base::JSONWriter::Write(&value, false, &value_json); 196 base::JSONWriter::Write(&value, false, &value_json);
194 return value_json; 197 return value_json;
195 } 198 }
196 199
200 bool VerifyHMAC(const std::string& hmac,
201 const std::string& plaintext,
202 const crypto::SymmetricKey* key) {
Ryan Sleevi 2011/12/24 07:34:08 See crypto::HMAC::Verify() Same implementation, b
203 SECItem empty_parameters;
204 empty_parameters.type = siBuffer;
205 empty_parameters.data = 0;
206 empty_parameters.len = 0;
207
208 SECStatus status = SECSuccess;
209 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey(
210 CKM_SHA_1_HMAC,
211 CKA_SIGN,
212 key->key(),
213 &empty_parameters));
214 if (!context.get()) {
215 LOG(WARNING) << "PK11_CreateContextBySymKey failed";
216 return false;
217 }
218
219 status = PK11_DigestBegin(context.get());
220 if (status != SECSuccess) {
221 LOG(WARNING) << "PK11_DigestBegin failed";
222 return false;
223 }
224
225 status = PK11_DigestOp(
226 context.get(),
227 reinterpret_cast<const unsigned char*>(plaintext.c_str()),
228 plaintext.size());
229
230 if (status != SECSuccess) {
231 LOG(WARNING) << "PK11_DigestOp failed";
232 return false;
233 }
234
235 // SHA1 HMACs are 160 bits.
236 char digest[20];
237 unsigned int length = 0;
238 status = PK11_DigestFinal(context.get(),
239 reinterpret_cast<unsigned char*>(&digest[0]),
240 &length,
241 20);
242 if (status != SECSuccess) {
243 LOG(WARNING) << "PK11_DigestFinal failed";
244 return false;
245 }
246
247 if (std::string(digest, length) == hmac)
Ryan Sleevi 2011/12/24 07:34:08 See above comment. This comparison is not a consta
248 return true;
249
250 return false;
Charlie Lee 2011/12/22 20:55:17 should add a log warning here for why this would f
251 }
252
197 } // namespace 253 } // namespace
198 254
199 // -------------------- OncNetworkParser -------------------- 255 // -------------------- OncNetworkParser --------------------
200 256
201 OncNetworkParser::OncNetworkParser(const std::string& onc_blob, 257 OncNetworkParser::OncNetworkParser(const std::string& onc_blob,
258 const std::string& passphrase,
202 NetworkUIData::ONCSource onc_source) 259 NetworkUIData::ONCSource onc_source)
203 : NetworkParser(get_onc_mapper()), 260 : NetworkParser(get_onc_mapper()),
204 onc_source_(onc_source), 261 onc_source_(onc_source),
205 network_configs_(NULL), 262 network_configs_(NULL),
206 certificates_(NULL) { 263 certificates_(NULL) {
207 VLOG(2) << __func__ << ": OncNetworkParser called on " << onc_blob; 264 VLOG(2) << __func__ << ": OncNetworkParser called on " << onc_blob;
208 JSONStringValueSerializer deserializer(onc_blob); 265 JSONStringValueSerializer deserializer(onc_blob);
209 deserializer.set_allow_trailing_comma(true); 266 deserializer.set_allow_trailing_comma(true);
210 scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &parse_error_)); 267 scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &parse_error_));
211 268
212 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) { 269 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) {
213 LOG(WARNING) << "OncNetworkParser received bad ONC file: " << parse_error_; 270 LOG(WARNING) << "OncNetworkParser received bad ONC file: " << parse_error_;
214 } else { 271 } else {
215 root_dict_.reset(static_cast<DictionaryValue*>(root.release())); 272 root_dict_.reset(static_cast<DictionaryValue*>(root.release()));
273
274 // Check and see if this is an encrypted ONC file. If so, decrypt it.
275 std::string ciphertext_test;
276 if (root_dict_->GetString("Ciphertext", &ciphertext_test))
277 root_dict_.reset(Decrypt(passphrase, root_dict_.get()));
278
216 // At least one of NetworkConfigurations or Certificates is required. 279 // At least one of NetworkConfigurations or Certificates is required.
217 bool has_network_configurations = 280 bool has_network_configurations =
218 root_dict_->GetList("NetworkConfigurations", &network_configs_); 281 root_dict_->GetList("NetworkConfigurations", &network_configs_);
219 bool has_certificates = 282 bool has_certificates =
220 root_dict_->GetList("Certificates", &certificates_); 283 root_dict_->GetList("Certificates", &certificates_);
221 VLOG(2) << "ONC file has " << GetNetworkConfigsSize() << " networks and " 284 VLOG(2) << "ONC file has " << GetNetworkConfigsSize() << " networks and "
222 << GetCertificatesSize() << " certificates"; 285 << GetCertificatesSize() << " certificates";
223 LOG_IF(WARNING, (!has_network_configurations && !has_certificates)) 286 LOG_IF(WARNING, (!has_network_configurations && !has_certificates))
224 << "ONC file has no NetworkConfigurations or Certificates."; 287 << "ONC file has no NetworkConfigurations or Certificates.";
225 } 288 }
226 } 289 }
227 290
228 OncNetworkParser::OncNetworkParser() 291 OncNetworkParser::OncNetworkParser()
229 : NetworkParser(get_onc_mapper()), 292 : NetworkParser(get_onc_mapper()),
230 network_configs_(NULL), 293 network_configs_(NULL),
231 certificates_(NULL) { 294 certificates_(NULL) {
232 } 295 }
233 296
234 OncNetworkParser::~OncNetworkParser() { 297 OncNetworkParser::~OncNetworkParser() {
235 } 298 }
236 299
237 // static 300 // static
238 const EnumMapper<PropertyIndex>* OncNetworkParser::property_mapper() { 301 const EnumMapper<PropertyIndex>* OncNetworkParser::property_mapper() {
239 return get_onc_mapper(); 302 return get_onc_mapper();
240 } 303 }
241 304
305 base::DictionaryValue* OncNetworkParser::Decrypt(
306 const std::string& passphrase,
307 base::DictionaryValue* root) {
308 std::string salt;
309 int iterations;
310 const int key_size_in_bits = 256;
311 std::string initial_vector_str;
312 std::string ciphertext;
313 std::string cipher;
314 std::string hmac_method;
315
316 if (!root->GetString("Salt", &salt) ||
317 !root->GetInteger("Iterations", &iterations) ||
318 !root->GetString("Cipher", &cipher) ||
319 !root->GetString("HMAC", &hmac_method) ||
320 !root->GetString("IV", &initial_vector_str) ||
321 !root->GetString("Ciphertext", &ciphertext)) {
322 parse_error_ = l10n_util::GetStringUTF8(
323 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_MALFORMED);
324 return NULL;
325 }
326
327 if (hmac_method != "SHA1" || cipher != "AES256") {
328 parse_error_ = l10n_util::GetStringUTF8(
329 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNSUPPORTED_ENCRYPTION);
330 return NULL;
331 }
332
333 if (!base::Base64Decode(salt, &salt)) {
334 parse_error_ = l10n_util::GetStringUTF8(
335 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
336 return NULL;
337 }
338
339 scoped_ptr<crypto::SymmetricKey> key(
340 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
341 passphrase,
342 salt,
343 iterations,
344 key_size_in_bits));
345
346 crypto::Encryptor decryptor;
347 std::string initial_vector;
348 std::string plaintext;
349 if (!base::Base64Decode(initial_vector_str, &initial_vector)) {
350 parse_error_ = l10n_util::GetStringUTF8(
351 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
352 return NULL;
353 }
354 if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) {
355 parse_error_ = l10n_util::GetStringUTF8(
356 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
357 return NULL;
358 }
359 if (!base::Base64Decode(ciphertext, &ciphertext)) {
360 parse_error_ = l10n_util::GetStringUTF8(
361 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
362 return NULL;
363 }
364 if (!decryptor.Decrypt(ciphertext, &plaintext)) {
365 parse_error_ = l10n_util::GetStringUTF8(
366 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
367 return NULL;
368 }
369
370 // 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
371 std::string::size_type split = plaintext.find_last_of('|');
372 std::string hmac = plaintext.substr(split + 1, plaintext.size() - split - 1);
373 plaintext = plaintext.substr(0, split);
374 if (!base::Base64Decode(hmac, &hmac)) {
375 parse_error_ = l10n_util::GetStringUTF8(
376 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
377 return NULL;
378 }
379
380 // Verify the HMAC. If it fails, then we have failed to decrypt (even though
381 // we decrypted *something*, it's been tampered with).
382 if (!VerifyHMAC(hmac, plaintext, key.get())) {
383 parse_error_ = l10n_util::GetStringUTF8(
384 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
385 return NULL;
386 }
387
388 // Now we've decrypted it, let's deserialize the decrypted data.
389 JSONStringValueSerializer deserializer(plaintext);
390 deserializer.set_allow_trailing_comma(true);
391 scoped_ptr<base::Value> new_root(deserializer.Deserialize(NULL,
392 &parse_error_));
393 if (!new_root.get() || new_root->GetType() != base::Value::TYPE_DICTIONARY) {
394 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
395 parse_error_ = l10n_util::GetStringUTF8(
396 IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
397 return NULL;
398 }
399 return static_cast<base::DictionaryValue*>(new_root.release());
400 }
401
242 int OncNetworkParser::GetNetworkConfigsSize() const { 402 int OncNetworkParser::GetNetworkConfigsSize() const {
243 return network_configs_ ? network_configs_->GetSize() : 0; 403 return network_configs_ ? network_configs_->GetSize() : 0;
244 } 404 }
245 405
246 const base::DictionaryValue* OncNetworkParser::GetNetworkConfig(int n) { 406 const base::DictionaryValue* OncNetworkParser::GetNetworkConfig(int n) {
247 CHECK(network_configs_); 407 CHECK(network_configs_);
248 CHECK(static_cast<size_t>(n) < network_configs_->GetSize()); 408 CHECK(static_cast<size_t>(n) < network_configs_->GetSize());
249 CHECK_GE(n, 0); 409 CHECK_GE(n, 0);
250 base::DictionaryValue* info = NULL; 410 base::DictionaryValue* info = NULL;
251 if (!network_configs_->GetDictionary(n, &info)) { 411 if (!network_configs_->GetDictionary(n, &info)) {
(...skipping 1017 matching lines...) Expand 10 before | Expand all | Expand 10 after
1269 // on the value of AuthenticationType. 1429 // on the value of AuthenticationType.
1270 { "L2TP-IPsec", PROVIDER_TYPE_L2TP_IPSEC_PSK }, 1430 { "L2TP-IPsec", PROVIDER_TYPE_L2TP_IPSEC_PSK },
1271 { "OpenVPN", PROVIDER_TYPE_OPEN_VPN }, 1431 { "OpenVPN", PROVIDER_TYPE_OPEN_VPN },
1272 }; 1432 };
1273 CR_DEFINE_STATIC_LOCAL(EnumMapper<ProviderType>, parser, 1433 CR_DEFINE_STATIC_LOCAL(EnumMapper<ProviderType>, parser,
1274 (table, arraysize(table), PROVIDER_TYPE_MAX)); 1434 (table, arraysize(table), PROVIDER_TYPE_MAX));
1275 return parser.Get(type); 1435 return parser.Get(type);
1276 } 1436 }
1277 1437
1278 } // namespace chromeos 1438 } // namespace chromeos
OLDNEW
« 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