OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |