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

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: Handling decryption errors better Created 8 years, 11 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/hmac.h"
21 #include "crypto/scoped_nss_types.h"
22 #include "crypto/symmetric_key.h"
23 #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.
20 #include "grit/generated_resources.h" 24 #include "grit/generated_resources.h"
21 #include "net/base/cert_database.h" 25 #include "net/base/cert_database.h"
22 #include "net/base/crypto_module.h" 26 #include "net/base/crypto_module.h"
23 #include "net/base/net_errors.h" 27 #include "net/base/net_errors.h"
24 #include "net/base/x509_certificate.h" 28 #include "net/base/x509_certificate.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h" 29 #include "third_party/cros_system_api/dbus/service_constants.h"
26 #include "ui/base/l10n/l10n_util.h" 30 #include "ui/base/l10n/l10n_util.h"
27 31
28 namespace chromeos { 32 namespace chromeos {
29 33
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 std::string value_json; 196 std::string value_json;
193 base::JSONWriter::Write(&value, false, &value_json); 197 base::JSONWriter::Write(&value, false, &value_json);
194 return value_json; 198 return value_json;
195 } 199 }
196 200
197 } // namespace 201 } // namespace
198 202
199 // -------------------- OncNetworkParser -------------------- 203 // -------------------- OncNetworkParser --------------------
200 204
201 OncNetworkParser::OncNetworkParser(const std::string& onc_blob, 205 OncNetworkParser::OncNetworkParser(const std::string& onc_blob,
206 const std::string& passphrase,
202 NetworkUIData::ONCSource onc_source) 207 NetworkUIData::ONCSource onc_source)
203 : NetworkParser(get_onc_mapper()), 208 : NetworkParser(get_onc_mapper()),
204 onc_source_(onc_source), 209 onc_source_(onc_source),
205 network_configs_(NULL), 210 network_configs_(NULL),
206 certificates_(NULL) { 211 certificates_(NULL) {
207 VLOG(2) << __func__ << ": OncNetworkParser called on " << onc_blob; 212 VLOG(2) << __func__ << ": OncNetworkParser called on " << onc_blob;
208 JSONStringValueSerializer deserializer(onc_blob); 213 JSONStringValueSerializer deserializer(onc_blob);
209 deserializer.set_allow_trailing_comma(true); 214 deserializer.set_allow_trailing_comma(true);
210 scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &parse_error_)); 215 scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, &parse_error_));
211 216
212 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) { 217 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) {
213 LOG(WARNING) << "OncNetworkParser received bad ONC file: " << parse_error_; 218 LOG(WARNING) << "OncNetworkParser received bad ONC file: " << parse_error_;
214 } else { 219 } else {
215 root_dict_.reset(static_cast<DictionaryValue*>(root.release())); 220 root_dict_.reset(static_cast<DictionaryValue*>(root.release()));
221
222 // Check and see if this is an encrypted ONC file. If so, decrypt it.
223 std::string ciphertext_test;
224 if (root_dict_->GetString("Ciphertext", &ciphertext_test))
225 root_dict_.reset(Decrypt(passphrase, root_dict_.get()));
226
227 // Decryption failed, errors will be in parse_error_;
228 if (!root_dict_.get())
229 return;
230
216 // At least one of NetworkConfigurations or Certificates is required. 231 // At least one of NetworkConfigurations or Certificates is required.
217 bool has_network_configurations = 232 bool has_network_configurations =
218 root_dict_->GetList("NetworkConfigurations", &network_configs_); 233 root_dict_->GetList("NetworkConfigurations", &network_configs_);
219 bool has_certificates = 234 bool has_certificates =
220 root_dict_->GetList("Certificates", &certificates_); 235 root_dict_->GetList("Certificates", &certificates_);
221 VLOG(2) << "ONC file has " << GetNetworkConfigsSize() << " networks and " 236 VLOG(2) << "ONC file has " << GetNetworkConfigsSize() << " networks and "
222 << GetCertificatesSize() << " certificates"; 237 << GetCertificatesSize() << " certificates";
223 LOG_IF(WARNING, (!has_network_configurations && !has_certificates)) 238 LOG_IF(WARNING, (!has_network_configurations && !has_certificates))
224 << "ONC file has no NetworkConfigurations or Certificates."; 239 << "ONC file has no NetworkConfigurations or Certificates.";
225 } 240 }
226 } 241 }
227 242
228 OncNetworkParser::OncNetworkParser() 243 OncNetworkParser::OncNetworkParser()
229 : NetworkParser(get_onc_mapper()), 244 : NetworkParser(get_onc_mapper()),
230 network_configs_(NULL), 245 network_configs_(NULL),
231 certificates_(NULL) { 246 certificates_(NULL) {
232 } 247 }
233 248
234 OncNetworkParser::~OncNetworkParser() { 249 OncNetworkParser::~OncNetworkParser() {
235 } 250 }
236 251
237 // static 252 // static
238 const EnumMapper<PropertyIndex>* OncNetworkParser::property_mapper() { 253 const EnumMapper<PropertyIndex>* OncNetworkParser::property_mapper() {
239 return get_onc_mapper(); 254 return get_onc_mapper();
240 } 255 }
241 256
257 base::DictionaryValue* OncNetworkParser::Decrypt(
258 const std::string& passphrase,
259 base::DictionaryValue* root) {
260 std::string salt;
261 int iterations;
262 const int key_size_in_bits = 256;
263 std::string initial_vector_str;
264 std::string ciphertext;
265 std::string cipher;
266 std::string hmac_method;
267 std::string hmac;
268
269 if (!root->GetString("Salt", &salt) ||
270 !root->GetInteger("Iterations", &iterations) ||
271 !root->GetString("Cipher", &cipher) ||
272 !root->GetString("HMACMethod", &hmac_method) ||
273 !root->GetString("HMAC", &hmac) ||
274 !root->GetString("IV", &initial_vector_str) ||
275 !root->GetString("Ciphertext", &ciphertext)) {
276 parse_error_ = l10n_util::GetStringUTF8(
277 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_MALFORMED);
278 return NULL;
279 }
280
281 if (hmac_method != "SHA1" || cipher != "AES256") {
282 parse_error_ = l10n_util::GetStringUTF8(
283 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNSUPPORTED_ENCRYPTION);
284 return NULL;
285 }
286
287 if (!base::Base64Decode(salt, &salt)) {
288 parse_error_ = l10n_util::GetStringUTF8(
289 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
290 return NULL;
291 }
292
293 scoped_ptr<crypto::SymmetricKey> key(
294 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
295 passphrase,
296 salt,
297 iterations,
298 key_size_in_bits));
299
300
301 crypto::Encryptor decryptor;
302 std::string initial_vector;
303 std::string plaintext;
304 if (!base::Base64Decode(initial_vector_str, &initial_vector)) {
305 parse_error_ = l10n_util::GetStringUTF8(
306 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
307 return NULL;
308 }
309 if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) {
310 parse_error_ = l10n_util::GetStringUTF8(
311 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
312 return NULL;
313 }
314 if (!base::Base64Decode(ciphertext, &ciphertext)) {
315 parse_error_ = l10n_util::GetStringUTF8(
316 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
317 return NULL;
318 }
319 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
320 parse_error_ = l10n_util::GetStringUTF8(
321 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECODE);
322 return NULL;
323 }
324
325 // Verify the HMAC. If it fails, then we will still try to decrypt because
326 // we don't want to leak timing information.
327 bool hmac_failed = false;
328 crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
329 if (!hmac_verifier.Init(*key) || !hmac_verifier.Verify(ciphertext, hmac))
330 hmac_failed = true;
331
332 if (!decryptor.Decrypt(ciphertext, &plaintext) || hmac_failed) {
333 parse_error_ = l10n_util::GetStringUTF8(
334 IDS_NETWORK_CONFIG_ERROR_ENCRYPTED_ONC_UNABLE_TO_DECRYPT);
335 return NULL;
336 }
337
338 // Now we've decrypted it, let's deserialize the decrypted data.
339 JSONStringValueSerializer deserializer(plaintext);
340 deserializer.set_allow_trailing_comma(true);
341 scoped_ptr<base::Value> new_root(deserializer.Deserialize(NULL,
342 &parse_error_));
343 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.
344 if (parse_error_.empty())
345 parse_error_ = l10n_util::GetStringUTF8(
346 IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
347 return NULL;
348 }
349 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
350 }
351
242 int OncNetworkParser::GetNetworkConfigsSize() const { 352 int OncNetworkParser::GetNetworkConfigsSize() const {
243 return network_configs_ ? network_configs_->GetSize() : 0; 353 return network_configs_ ? network_configs_->GetSize() : 0;
244 } 354 }
245 355
246 const base::DictionaryValue* OncNetworkParser::GetNetworkConfig(int n) { 356 const base::DictionaryValue* OncNetworkParser::GetNetworkConfig(int n) {
247 CHECK(network_configs_); 357 CHECK(network_configs_);
248 CHECK(static_cast<size_t>(n) < network_configs_->GetSize()); 358 CHECK(static_cast<size_t>(n) < network_configs_->GetSize());
249 CHECK_GE(n, 0); 359 CHECK_GE(n, 0);
250 base::DictionaryValue* info = NULL; 360 base::DictionaryValue* info = NULL;
251 if (!network_configs_->GetDictionary(n, &info)) { 361 if (!network_configs_->GetDictionary(n, &info)) {
(...skipping 1017 matching lines...) Expand 10 before | Expand all | Expand 10 after
1269 // on the value of AuthenticationType. 1379 // on the value of AuthenticationType.
1270 { "L2TP-IPsec", PROVIDER_TYPE_L2TP_IPSEC_PSK }, 1380 { "L2TP-IPsec", PROVIDER_TYPE_L2TP_IPSEC_PSK },
1271 { "OpenVPN", PROVIDER_TYPE_OPEN_VPN }, 1381 { "OpenVPN", PROVIDER_TYPE_OPEN_VPN },
1272 }; 1382 };
1273 CR_DEFINE_STATIC_LOCAL(EnumMapper<ProviderType>, parser, 1383 CR_DEFINE_STATIC_LOCAL(EnumMapper<ProviderType>, parser,
1274 (table, arraysize(table), PROVIDER_TYPE_MAX)); 1384 (table, arraysize(table), PROVIDER_TYPE_MAX));
1275 return parser.Get(type); 1385 return parser.Get(type);
1276 } 1386 }
1277 1387
1278 } // namespace chromeos 1388 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698