Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chromeos/network/onc/onc_utils.h" | 5 #include "chromeos/network/onc/onc_utils.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/strings/string_number_conversions.h" | |
| 11 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 12 #include "base/values.h" | 13 #include "base/values.h" |
| 13 #include "chromeos/network/network_event_log.h" | 14 #include "chromeos/network/network_event_log.h" |
| 14 #include "chromeos/network/onc/onc_mapper.h" | 15 #include "chromeos/network/onc/onc_mapper.h" |
| 15 #include "chromeos/network/onc/onc_signature.h" | 16 #include "chromeos/network/onc/onc_signature.h" |
| 16 #include "chromeos/network/onc/onc_utils.h" | 17 #include "chromeos/network/onc/onc_utils.h" |
| 17 #include "chromeos/network/onc/onc_validator.h" | 18 #include "chromeos/network/onc/onc_validator.h" |
| 18 #include "crypto/encryptor.h" | 19 #include "crypto/encryptor.h" |
| 19 #include "crypto/hmac.h" | 20 #include "crypto/hmac.h" |
| 20 #include "crypto/symmetric_key.h" | 21 #include "crypto/symmetric_key.h" |
| 22 #include "net/base/hash_value.h" | |
| 21 #include "net/cert/pem_tokenizer.h" | 23 #include "net/cert/pem_tokenizer.h" |
| 24 #include "net/cert/x509_certificate.h" | |
| 22 | 25 |
| 23 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) | 26 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) |
| 24 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) | 27 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) |
| 25 | 28 |
| 26 namespace chromeos { | 29 namespace chromeos { |
| 27 namespace onc { | 30 namespace onc { |
| 28 | 31 |
| 29 namespace { | 32 namespace { |
| 30 | 33 |
| 31 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; | 34 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 340 | 343 |
| 341 base::ListValue* validated_networks = NULL; | 344 base::ListValue* validated_networks = NULL; |
| 342 if (toplevel_onc->GetListWithoutPathExpansion( | 345 if (toplevel_onc->GetListWithoutPathExpansion( |
| 343 toplevel_config::kNetworkConfigurations, &validated_networks)) { | 346 toplevel_config::kNetworkConfigurations, &validated_networks)) { |
| 344 network_configs->Swap(validated_networks); | 347 network_configs->Swap(validated_networks); |
| 345 } | 348 } |
| 346 | 349 |
| 347 return success; | 350 return success; |
| 348 } | 351 } |
| 349 | 352 |
| 353 std::string GetHexFingerprintOfCert(const net::X509Certificate& cert) { | |
| 354 net::SHA1HashValue fingerprint = cert.fingerprint(); | |
| 355 return base::HexEncode(fingerprint.data, sizeof(fingerprint.data)); | |
| 356 } | |
| 357 | |
| 358 net::X509Certificate* FindCertByFingerprint( | |
| 359 const net::CertificateList& cert_list, const std::string& fingerprint) { | |
| 360 net::X509Certificate* found = NULL; | |
| 361 for (net::CertificateList::const_iterator it = cert_list.begin(); | |
| 362 it != cert_list.end(); ++it) { | |
| 363 if (GetHexFingerprintOfCert(**it) != fingerprint) | |
| 364 continue; | |
| 365 if (found != NULL) { | |
| 366 LOG(ERROR) << "Fingerprint not unique in list."; | |
|
Mattias Nissler (ping if slow)
2013/06/24 12:45:09
Rather, cert present twice in list. I don't think
pneubeck (no reviews)
2013/06/24 15:35:41
Done.
| |
| 367 return NULL; | |
| 368 } | |
| 369 found = it->get(); | |
| 370 } | |
| 371 return found; | |
| 372 } | |
| 373 | |
| 374 std::string GetPEMEncodedCertFromFingerprint( | |
| 375 const net::CertificateList& cert_list, | |
| 376 const std::string& fingerprint) { | |
| 377 net::X509Certificate* cert = FindCertByFingerprint(cert_list, fingerprint); | |
| 378 if (!cert) { | |
| 379 LOG(ERROR) << "Couldn't find a certificate with fingerprint " | |
| 380 << fingerprint; | |
| 381 return std::string(); | |
| 382 } | |
| 383 | |
| 384 std::string pem_encoded_cert; | |
| 385 if (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(), | |
| 386 &pem_encoded_cert)) { | |
| 387 LOG(ERROR) << "Couldn't PEM-encode certificate with fingerprint " | |
| 388 << fingerprint; | |
| 389 return std::string(); | |
| 390 } | |
| 391 | |
| 392 return pem_encoded_cert; | |
| 393 } | |
| 394 | |
| 350 scoped_refptr<net::X509Certificate> DecodePEMCertificate( | 395 scoped_refptr<net::X509Certificate> DecodePEMCertificate( |
| 351 const std::string& pem_encoded, | 396 const std::string& pem_encoded) { |
| 352 const std::string& nickname) { | |
| 353 // The PEM block header used for DER certificates | 397 // The PEM block header used for DER certificates |
| 354 static const char kCertificateHeader[] = "CERTIFICATE"; | 398 static const char kCertificateHeader[] = "CERTIFICATE"; |
| 355 // This is an older PEM marker for DER certificates. | 399 // This is an older PEM marker for DER certificates. |
| 356 static const char kX509CertificateHeader[] = "X509 CERTIFICATE"; | 400 static const char kX509CertificateHeader[] = "X509 CERTIFICATE"; |
| 357 | 401 |
| 358 std::vector<std::string> pem_headers; | 402 std::vector<std::string> pem_headers; |
| 359 pem_headers.push_back(kCertificateHeader); | 403 pem_headers.push_back(kCertificateHeader); |
| 360 pem_headers.push_back(kX509CertificateHeader); | 404 pem_headers.push_back(kX509CertificateHeader); |
| 361 | 405 |
| 362 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers); | 406 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers); |
| 363 std::string decoded; | 407 std::string decoded; |
| 364 if (pem_tokenizer.GetNext()) { | 408 if (pem_tokenizer.GetNext()) { |
| 365 decoded = pem_tokenizer.data(); | 409 decoded = pem_tokenizer.data(); |
| 366 } else { | 410 } else { |
| 367 // If we failed to read the data as a PEM file, then try plain base64 decode | 411 // If we failed to read the data as a PEM file, then try plain base64 decode |
| 368 // in case the PEM marker strings are missing. For this to work, there has | 412 // in case the PEM marker strings are missing. For this to work, there has |
| 369 // to be no white space, and it has to only contain the base64-encoded data. | 413 // to be no white space, and it has to only contain the base64-encoded data. |
| 370 if (!base::Base64Decode(pem_encoded, &decoded)) { | 414 if (!base::Base64Decode(pem_encoded, &decoded)) { |
| 371 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; | 415 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; |
| 372 return scoped_refptr<net::X509Certificate>(); | 416 return scoped_refptr<net::X509Certificate>(); |
| 373 } | 417 } |
| 374 } | 418 } |
| 375 | 419 |
| 376 scoped_refptr<net::X509Certificate> cert = | 420 scoped_refptr<net::X509Certificate> cert = |
| 377 net::X509Certificate::CreateFromBytesWithNickname(decoded.data(), | 421 net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size()); |
| 378 decoded.size(), | |
| 379 nickname.c_str()); | |
| 380 LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: " | 422 LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: " |
| 381 << decoded; | 423 << decoded; |
| 382 return cert; | 424 return cert; |
| 383 } | 425 } |
| 384 | 426 |
| 427 namespace { | |
| 428 | |
| 429 bool ResolveCertRef( | |
| 430 const std::map<std::string, | |
| 431 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
| 432 const std::string& key_guid_ref, | |
| 433 const std::string& key_fingerprint, | |
| 434 base::DictionaryValue* dict) { | |
| 435 std::string guid_ref; | |
| 436 if (!dict->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) | |
| 437 return true; | |
| 438 std::map<std::string, scoped_refptr<net::X509Certificate> >::const_iterator | |
| 439 it = certs_by_guid.find(guid_ref); | |
| 440 if (it == certs_by_guid.end()) { | |
| 441 LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref; | |
| 442 return false; | |
| 443 } | |
| 444 | |
| 445 dict->SetStringWithoutPathExpansion( | |
| 446 key_fingerprint, | |
| 447 GetHexFingerprintOfCert(*it->second)); | |
| 448 return true; | |
| 449 } | |
| 450 | |
| 451 bool ResolveServerCertRefsInObject( | |
| 452 const std::map<std::string, | |
| 453 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
| 454 const OncValueSignature& signature, | |
| 455 base::DictionaryValue* onc_object) { | |
| 456 if (&signature == &kEAPSignature) { | |
| 457 if (!ResolveCertRef(certs_by_guid, eap::kServerCARef, | |
| 458 eap::kServerCAFingerprint, onc_object)) { | |
| 459 return false; | |
| 460 } | |
| 461 } else if (&signature == &kL2TPSignature || | |
| 462 &signature == &kOpenVPNSignature) { | |
| 463 if (!ResolveCertRef(certs_by_guid, vpn::kServerCARef, | |
| 464 vpn::kServerCAFingerprint, onc_object) || | |
| 465 !ResolveCertRef(certs_by_guid, vpn::kServerCertRef, | |
| 466 vpn::kServerCertFingerprint, onc_object)) { | |
| 467 return false;; | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 // Recurse into nested objects. | |
| 472 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); | |
| 473 it.Advance()) { | |
| 474 base::DictionaryValue* inner_object = NULL; | |
| 475 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) | |
| 476 continue; | |
| 477 | |
| 478 const OncFieldSignature* field_signature = | |
| 479 GetFieldSignature(signature, it.key()); | |
| 480 if (!field_signature) | |
| 481 continue; | |
| 482 | |
| 483 if (!ResolveServerCertRefsInObject(certs_by_guid, | |
| 484 *field_signature->value_signature, | |
| 485 inner_object)) { | |
| 486 return false; | |
| 487 } | |
| 488 } | |
| 489 return true; | |
| 490 } | |
| 491 | |
| 492 } // namespace | |
| 493 | |
| 494 bool ResolveServerCertRefsInNetworks( | |
| 495 const std::map<std::string, | |
| 496 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
| 497 base::ListValue* network_configs) { | |
| 498 bool success = true; | |
| 499 for (base::ListValue::iterator it = network_configs->begin(); | |
| 500 it != network_configs->end(); ) { | |
| 501 base::DictionaryValue* network = NULL; | |
| 502 (*it)->GetAsDictionary(&network); | |
| 503 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) { | |
| 504 std::string guid; | |
| 505 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid); | |
| 506 // This might happen even with correct validation, if the referenced | |
| 507 // certificate couldn't be imported. | |
| 508 LOG(ERROR) << "Couldn't resolve some certificate reference of network " | |
| 509 << guid; | |
| 510 it = network_configs->Erase(it, NULL); | |
| 511 success = false; | |
| 512 continue; | |
| 513 } | |
| 514 ++it; | |
| 515 } | |
| 516 return success; | |
| 517 } | |
| 518 | |
| 519 bool ResolveServerCertRefsInNetwork( | |
| 520 const std::map<std::string, | |
| 521 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
| 522 base::DictionaryValue* network_config) { | |
| 523 return ResolveServerCertRefsInObject(certs_by_guid, | |
| 524 kNetworkConfigurationSignature, | |
| 525 network_config); | |
| 526 } | |
| 527 | |
| 385 } // namespace onc | 528 } // namespace onc |
| 386 } // namespace chromeos | 529 } // namespace chromeos |
| OLD | NEW |