diff options
author | sergeyv <sergeyv@chromium.org> | 2015-01-21 07:27:39 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-01-21 15:28:39 +0000 |
commit | f752426485290ebf878ef5af21b6335ad5a47141 (patch) | |
tree | 6c4273ea035fa474a4adbe38893f13b821d95c98 | |
parent | e98e8e7654b7e51f98e92514897f8e1284eaa571 (diff) | |
download | chromium_src-f752426485290ebf878ef5af21b6335ad5a47141.zip chromium_src-f752426485290ebf878ef5af21b6335ad5a47141.tar.gz chromium_src-f752426485290ebf878ef5af21b6335ad5a47141.tar.bz2 |
Revert of Re-landing of issue 792353002 (patchset #1 id:1 of https://codereview.chromium.org/854693002/)
Reason for revert:
Speculative revert. I suppose that now it is breaking Linux GN:
http://build.chromium.org/p/chromium.linux/builders/Linux%20GN%20%28dbg%29/builds/20625/steps/compile/logs/stdio
Original issue's description:
> The purpose of this CL is to re-land issue 792353002 (https://codereview.chromium.org/792353002/), which landed, but was reverted due to a ChromiumOS GN build failure. The failure was caused by a double inclusion of networking_private_credentials_getter_chromeos.cc.cc file in chrome_browser_extensions.gypi. This CL includes the original patch and the fix of the build failure.
>
> Original CL description follows:
>
> Refactoring of Cast-related crypto code to use the same certificate validation logic in chrome.networkingPrivate API and Cast Channel authentication.
>
> Here's what's being done here:
> * Code from cast_auth_util_nss/openssl formed the basis a common Cast device validation component in /src/extensions/common/cast/cast_cert_validator*, and is now being extensively cleaned up in response to rsleevi's comments in this CL.
> * Both networking_private_crypto* and cast_auth_util* have been updated to use the new common code.
> * The current D-Bus-based implementation of VerifyDestination is going away per discussion with ChromeOS team, and is replaced with in-Chrome code in networking_private crypto*.
>
> BUG=442650
>
> Committed: https://crrev.com/57988d1f46e6ce2a2d65aa87c01b29b2732a110f
> Cr-Commit-Position: refs/heads/master@{#312369}
TBR=rockot@chromium.org,stevenjb@chromium.org,brettw@chromium.org,mfoltz@chromium.org,vadimgo@chromium.org,mef@chromium.org,kmarshall@chromium.org,rsleevi@chromium.org,sheretov@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=442650
Review URL: https://codereview.chromium.org/865583003
Cr-Commit-Position: refs/heads/master@{#312391}
30 files changed, 737 insertions, 797 deletions
diff --git a/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc b/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc index 1960a12..da34f3f 100644 --- a/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc +++ b/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc @@ -38,8 +38,8 @@ bool DecodeAndVerifyCredentials( return false; } *verified = networking_private_crypto::VerifyCredentials( - credentials.certificate, credentials.intermediate_certificates, - decoded_signed_data, credentials.unsigned_data, credentials.device_bssid); + credentials.certificate, decoded_signed_data, credentials.unsigned_data, + credentials.device_bssid); return true; } @@ -158,8 +158,6 @@ void VerifyAndEncryptCredentialsCompleted( CryptoVerifyImpl::Credentials::Credentials( const VerificationProperties& properties) { certificate = properties.certificate; - if (properties.intermediate_certificates.get()) - intermediate_certificates = *properties.intermediate_certificates; signed_data = properties.signed_data; std::vector<std::string> data_parts; diff --git a/chrome/browser/extensions/api/networking_private/crypto_verify_impl.h b/chrome/browser/extensions/api/networking_private/crypto_verify_impl.h index b35021a..bacdc5a 100644 --- a/chrome/browser/extensions/api/networking_private/crypto_verify_impl.h +++ b/chrome/browser/extensions/api/networking_private/crypto_verify_impl.h @@ -29,7 +29,6 @@ class CryptoVerifyImpl : public NetworkingPrivateDelegate::VerifyDelegate { ~Credentials(); std::string certificate; - std::vector<std::string> intermediate_certificates; std::string signed_data; std::string unsigned_data; std::string device_bssid; diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc index d2aa61c..ac57b5d 100644 --- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc +++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc @@ -9,9 +9,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/helper.h" #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h" -#include "chrome/browser/extensions/api/networking_private/networking_private_chromeos.h" -#include "chrome/browser/extensions/api/networking_private/networking_private_credentials_getter.h" -#include "chrome/browser/extensions/api/networking_private/networking_private_delegate_factory.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chromeos/chromeos_switches.h" #include "chromeos/dbus/cryptohome_client.h" @@ -64,10 +61,6 @@ using chromeos::ShillManagerClient; using chromeos::ShillProfileClient; using chromeos::ShillServiceClient; -using extensions::NetworkingPrivateDelegate; -using extensions::NetworkingPrivateDelegateFactory; -using extensions::NetworkingPrivateChromeOS; - namespace { const char kUser1ProfilePath[] = "/profile/user1/shill"; @@ -75,33 +68,6 @@ const char kWifiDevicePath[] = "/device/stub_wifi_device1"; const char kCellularDevicePath[] = "/device/stub_cellular_device1"; const char kIPConfigPath[] = "/ipconfig/ipconfig1"; -// Stub Verify* methods implementation to satisfy expectations of -// networking_private_apitest. -class CryptoVerifyStub : public NetworkingPrivateDelegate::VerifyDelegate { - void VerifyDestination( - const VerificationProperties& verification_properties, - const BoolCallback& success_callback, - const FailureCallback& failure_callback) override { - success_callback.Run(true); - } - - void VerifyAndEncryptCredentials( - const std::string& guid, - const VerificationProperties& verification_properties, - const StringCallback& success_callback, - const FailureCallback& failure_callback) override { - success_callback.Run("encrypted_credentials"); - } - - void VerifyAndEncryptData( - const VerificationProperties& verification_properties, - const std::string& data, - const StringCallback& success_callback, - const FailureCallback& failure_callback) override { - success_callback.Run("encrypted_data"); - } -}; - class TestListener : public content::NotificationObserver { public: TestListener(const std::string& message, const base::Closure& callback) @@ -230,12 +196,6 @@ class NetworkingPrivateChromeOSApiTest : public ExtensionApiTest { true /* add_to_visible */); } - static KeyedService* CreateNetworkingPrivateServiceClient( - content::BrowserContext* profile) { - scoped_ptr<CryptoVerifyStub> crypto_verify(new CryptoVerifyStub); - return new NetworkingPrivateChromeOS(profile, crypto_verify.Pass()); - } - void SetUpOnMainThread() override { detector_ = new NetworkPortalDetectorTestImpl(); NetworkPortalDetector::InitializeForTesting(detector_); @@ -243,9 +203,6 @@ class NetworkingPrivateChromeOSApiTest : public ExtensionApiTest { ExtensionApiTest::SetUpOnMainThread(); content::RunAllPendingInMessageLoop(); - NetworkingPrivateDelegateFactory::GetInstance()->SetTestingFactory( - profile(), &CreateNetworkingPrivateServiceClient); - InitializeSanitizedUsername(); DBusThreadManager* dbus_manager = DBusThreadManager::Get(); diff --git a/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_chromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_chromeos.cc deleted file mode 100644 index a47b2e9..0000000 --- a/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_chromeos.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/extensions/api/networking_private/networking_private_credentials_getter.h" - -const char kErrorNotImplemented[] = "Error.NotImplemented"; - -namespace extensions { - -class NetworkingPrivateCredentialsGetterChromeos - : public NetworkingPrivateCredentialsGetter { - public: - NetworkingPrivateCredentialsGetterChromeos() {} - - void Start(const std::string& network_guid, - const std::string& public_key, - const CredentialsCallback& callback) override; - - private: - ~NetworkingPrivateCredentialsGetterChromeos() override; - - DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateCredentialsGetterChromeos); -}; - -NetworkingPrivateCredentialsGetterChromeos:: - ~NetworkingPrivateCredentialsGetterChromeos() { -} - -void NetworkingPrivateCredentialsGetterChromeos::Start( - const std::string& network_guid, - const std::string& public_key, - const CredentialsCallback& callback) { - // TODO(sheretov) add credential slurping from sync. - callback.Run(std::string(), kErrorNotImplemented); -} - -NetworkingPrivateCredentialsGetter* -NetworkingPrivateCredentialsGetter::Create() { - return new NetworkingPrivateCredentialsGetterChromeos(); -} - -} // namespace extensions diff --git a/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.cc new file mode 100644 index 0000000..a4d06a1 --- /dev/null +++ b/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.cc @@ -0,0 +1,114 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.h" + +#include "base/bind.h" +#include "chrome/browser/extensions/api/networking_private/networking_private_api.h" +#include "chrome/common/extensions/api/networking_private.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/shill_manager_client.h" +#include "chromeos/network/network_handler.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" + +using chromeos::ShillManagerClient; + +namespace { + +ShillManagerClient* GetShillManagerClient() { + return chromeos::DBusThreadManager::Get()->GetShillManagerClient(); +} + +bool GetServicePathFromGuid(const std::string& guid, + std::string* service_path, + std::string* error) { + const chromeos::NetworkState* network = chromeos::NetworkHandler::Get() + ->network_state_handler() + ->GetNetworkStateFromGuid(guid); + if (!network) { + *error = extensions::networking_private::kErrorInvalidNetworkGuid; + return false; + } + *service_path = network->path(); + return true; +} + +ShillManagerClient::VerificationProperties ConvertVerificationProperties( + const extensions::api::networking_private::VerificationProperties& input) { + ShillManagerClient::VerificationProperties output; + output.certificate = input.certificate; + output.public_key = input.public_key; + output.nonce = input.nonce; + output.signed_data = input.signed_data; + output.device_serial = input.device_serial; + output.device_ssid = input.device_ssid; + output.device_bssid = input.device_bssid; + return output; +} + +void ShillFailureCallback( + const extensions::NetworkingPrivateDelegate::FailureCallback& callback, + const std::string& error_name, + const std::string& error_message) { + callback.Run(error_name); +} + +} // namespace + +namespace extensions { + +NetworkingPrivateVerifyDelegateChromeOS:: + NetworkingPrivateVerifyDelegateChromeOS() { +} + +NetworkingPrivateVerifyDelegateChromeOS:: + ~NetworkingPrivateVerifyDelegateChromeOS() { +} + +void NetworkingPrivateVerifyDelegateChromeOS::VerifyDestination( + const VerificationProperties& verification_properties, + const BoolCallback& success_callback, + const FailureCallback& failure_callback) { + ShillManagerClient::VerificationProperties verification_property_struct = + ConvertVerificationProperties(verification_properties); + + GetShillManagerClient()->VerifyDestination( + verification_property_struct, success_callback, + base::Bind(&ShillFailureCallback, failure_callback)); +} + +void NetworkingPrivateVerifyDelegateChromeOS::VerifyAndEncryptCredentials( + const std::string& guid, + const VerificationProperties& verification_properties, + const StringCallback& success_callback, + const FailureCallback& failure_callback) { + std::string service_path, error; + if (!GetServicePathFromGuid(guid, &service_path, &error)) { + failure_callback.Run(error); + return; + } + + ShillManagerClient::VerificationProperties verification_property_struct = + ConvertVerificationProperties(verification_properties); + + GetShillManagerClient()->VerifyAndEncryptCredentials( + verification_property_struct, service_path, success_callback, + base::Bind(&ShillFailureCallback, failure_callback)); +} + +void NetworkingPrivateVerifyDelegateChromeOS::VerifyAndEncryptData( + const VerificationProperties& verification_properties, + const std::string& data, + const StringCallback& success_callback, + const FailureCallback& failure_callback) { + ShillManagerClient::VerificationProperties verification_property_struct = + ConvertVerificationProperties(verification_properties); + + GetShillManagerClient()->VerifyAndEncryptData( + verification_property_struct, data, success_callback, + base::Bind(&ShillFailureCallback, failure_callback)); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.h b/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.h new file mode 100644 index 0000000..dbef880 --- /dev/null +++ b/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.h @@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_VERIFY_DELEGATE_CHROMEOS_H_ +#define CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_VERIFY_DELEGATE_CHROMEOS_H_ + +#include "chrome/browser/extensions/api/networking_private/networking_private_delegate.h" + +namespace extensions { + +class NetworkingPrivateVerifyDelegateChromeOS + : public NetworkingPrivateDelegate::VerifyDelegate { + public: + NetworkingPrivateVerifyDelegateChromeOS(); + ~NetworkingPrivateVerifyDelegateChromeOS() override; + + void VerifyDestination(const VerificationProperties& verification_properties, + const BoolCallback& success_callback, + const FailureCallback& failure_callback) override; + void VerifyAndEncryptCredentials( + const std::string& guid, + const VerificationProperties& verification_properties, + const StringCallback& success_callback, + const FailureCallback& failure_callback) override; + void VerifyAndEncryptData( + const VerificationProperties& verification_properties, + const std::string& data, + const StringCallback& success_callback, + const FailureCallback& failure_callback) override; + + private: + DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateVerifyDelegateChromeOS); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_VERIFY_DELEGATE_CHROMEOS_H_ diff --git a/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.cc b/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.cc index 44226d5..f2884d0 100644 --- a/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.cc +++ b/chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.cc @@ -4,7 +4,11 @@ #include "chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.h" +#elif defined(OS_WIN) || defined(OSMACOSX) #include "chrome/browser/extensions/api/networking_private/crypto_verify_impl.h" +#endif namespace extensions { @@ -18,7 +22,9 @@ NetworkingPrivateVerifyDelegateFactoryImpl:: scoped_ptr<NetworkingPrivateDelegate::VerifyDelegate> NetworkingPrivateVerifyDelegateFactoryImpl::CreateDelegate() { -#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_MACOSX) +#if defined(OS_CHROMEOS) + return make_scoped_ptr(new NetworkingPrivateVerifyDelegateChromeOS()); +#elif defined(OS_WIN) || defined(OSMACOSX) return make_scoped_ptr(new CryptoVerifyImpl()); #else return nullptr; diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 1100287..3d5a783 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -343,13 +343,10 @@ 'browser/extensions/api/music_manager_private/device_id_win.cc', 'browser/extensions/api/music_manager_private/music_manager_private_api.cc', 'browser/extensions/api/music_manager_private/music_manager_private_api.h', - 'browser/extensions/api/networking_private/crypto_verify_impl.cc', - 'browser/extensions/api/networking_private/crypto_verify_impl.h', 'browser/extensions/api/networking_private/networking_private_api.cc', 'browser/extensions/api/networking_private/networking_private_api.h', 'browser/extensions/api/networking_private/networking_private_chromeos.cc', 'browser/extensions/api/networking_private/networking_private_chromeos.h', - 'browser/extensions/api/networking_private/networking_private_credentials_getter_chromeos.cc', 'browser/extensions/api/networking_private/networking_private_delegate.cc', 'browser/extensions/api/networking_private/networking_private_delegate.h', 'browser/extensions/api/networking_private/networking_private_delegate_observer.h', @@ -359,6 +356,8 @@ 'browser/extensions/api/networking_private/networking_private_event_router_factory.h', 'browser/extensions/api/networking_private/networking_private_delegate_factory.cc', 'browser/extensions/api/networking_private/networking_private_delegate_factory.h', + 'browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.cc', + 'browser/extensions/api/networking_private/networking_private_verify_delegate_chromeos.h', 'browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.cc', 'browser/extensions/api/networking_private/networking_private_verify_delegate_factory_impl.h', 'browser/extensions/api/notification_provider/notification_provider_api.cc', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 028de4f..83a320d 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -252,23 +252,16 @@ 'common/service_process_util_win.cc', ], 'chrome_common_win_mac_sources': [ + 'common/extensions/api/networking_private/networking_private_crypto_nss.cc', + 'common/extensions/api/networking_private/networking_private_crypto_openssl.cc', + 'common/extensions/api/networking_private/networking_private_crypto.cc', + 'common/extensions/api/networking_private/networking_private_crypto.h', 'common/media_galleries/itunes_library.cc', 'common/media_galleries/itunes_library.h', 'common/media_galleries/picasa_types.cc', 'common/media_galleries/picasa_types.h', 'common/media_galleries/pmp_constants.h', ], - 'chrome_common_networking_private_sources_openssl' : [ - 'common/extensions/api/networking_private/networking_private_crypto_openssl.cc', - 'common/extensions/api/networking_private/networking_private_crypto.cc', - 'common/extensions/api/networking_private/networking_private_crypto.h', - ], - 'chrome_common_networking_private_sources_nss' : [ - 'common/extensions/api/networking_private/networking_private_crypto_nss.cc', - 'common/extensions/api/networking_private/networking_private_crypto.cc', - 'common/extensions/api/networking_private/networking_private_crypto.h', - ], - 'chrome_common_mac_sources': [ 'common/media_galleries/iphoto_library.cc', 'common/media_galleries/iphoto_library.h', @@ -351,15 +344,12 @@ ['OS=="win" or OS=="mac"', { 'sources': [ '<@(chrome_common_win_mac_sources)' ], }], - ['(OS=="win" or OS=="mac" or chromeos==1) and use_openssl==1', { - 'sources': [ '<@(chrome_common_networking_private_sources_openssl)' ], + ['(OS=="win" or OS=="mac") and use_openssl==1', { + # networking_private_crypto_openssl.cc depends on boringssl. 'dependencies': [ '../third_party/boringssl/boringssl.gyp:boringssl', ], }], - ['(OS=="win" or OS=="mac" or chromeos==1) and use_openssl!=1', { - 'sources': [ '<@(chrome_common_networking_private_sources_nss)' ], - }], ['OS=="mac"', { 'sources': [ '<@(chrome_common_mac_sources)' ], }], @@ -503,6 +493,17 @@ ['safe_browsing==2', { 'defines': [ 'MOBILE_SAFE_BROWSING' ], }], + ['use_openssl==1', { + 'sources!': [ + 'common/extensions/api/networking_private/networking_private_crypto_nss.cc', + ], + }, + { # else !use_openssl + 'sources!': [ + 'common/extensions/api/networking_private/networking_private_crypto_openssl.cc', + ], + }, + ], ], 'target_conditions': [ ['OS == "ios"', { diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index d66a6e5..546cffa 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -2422,11 +2422,6 @@ ['OS=="win" or OS=="mac"', { 'sources': [ '<@(chrome_unit_tests_win_mac_sources)' ], }], - ['OS=="win" or OS=="mac" or chromeos==1', { - 'sources': [ - 'common/extensions/api/networking_private/networking_private_crypto_unittest.cc', - ], - }], ['enable_rlz!=0', { 'dependencies': [ '../rlz/rlz.gyp:test_support_rlz', diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index d6a03e0..6fd6111 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn @@ -114,23 +114,15 @@ static_library("common") { if (is_win || is_mac) { sources += rebase_path(gypi_values.chrome_common_win_mac_sources, ".", "//chrome") - deps += [ "//breakpad:client" ] - } - if (is_win || is_mac || is_chromeos) { if (use_openssl) { - sources += rebase_path( - gypi_values.chrome_common_networking_private_sources_openssl, - ".", - "//chrome") + sources -= [ "extensions/api/networking_private/networking_private_crypto_nss.cc" ] # networking_private_crypto_openssl.cc depends on boringssl. deps += [ "//third_party/boringssl" ] } else { - sources += - rebase_path(gypi_values.chrome_common_networking_private_sources_nss, - ".", - "//chrome") + sources -= [ "extensions/api/networking_private/networking_private_crypto_openssl.cc" ] } + deps += [ "//breakpad:client" ] } if (is_mac) { sources += diff --git a/chrome/common/extensions/api/networking_private.json b/chrome/common/extensions/api/networking_private.json index 8e73463..bac9fea 100644 --- a/chrome/common/extensions/api/networking_private.json +++ b/chrome/common/extensions/api/networking_private.json @@ -27,17 +27,11 @@ "properties": { "certificate": { "type": "string", - "description": "A string containing a PEM-encoded (including the \"BEGIN CERTIFICATE\" header and \"END CERTIFICATE\" footer) X.509 certificate for use in verifying the signed data." - }, - "intermediateCertificates": { - "type": "array", - "items": { "type": "string" }, - "optional": true, - "description": "An array of PEM-encoded X.509 intermediate certificate authority certificates. Each PEM-encoded certificate is expected to have the \"BEGIN CERTIFICATE\" header and \"END CERTIFICATE\" footer." + "description": "A string containing a PEM-encoded X.509 certificate for use in verifying the signed data." }, "publicKey": { "type": "string", - "description": "A string containing a Base64-encoded RSAPublicKey ASN.1 structure, representing the public key to be used by verifyAndEncryptCredentials and verifyAndEncryptData methods." + "description": "A string containing a PEM-encoded RSA public key to be used to compare with the one in signedData" }, "nonce": { "type": "string", diff --git a/chrome/common/extensions/api/networking_private/networking_private_crypto.cc b/chrome/common/extensions/api/networking_private/networking_private_crypto.cc index 66af2f9..34c2776 100644 --- a/chrome/common/extensions/api/networking_private/networking_private_crypto.cc +++ b/chrome/common/extensions/api/networking_private/networking_private_crypto.cc @@ -4,82 +4,33 @@ #include "chrome/common/extensions/api/networking_private/networking_private_crypto.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_util.h" -#include "extensions/common/cast/cast_cert_validator.h" -#include "net/cert/pem_tokenizer.h" - -namespace { - -namespace cast_crypto = ::extensions::core_api::cast_crypto; - -} // namespace - namespace networking_private_crypto { -bool VerifyCredentials( - const std::string& certificate, - const std::vector<std::string>& intermediate_certificates, - const std::string& signature, - const std::string& data, - const std::string& connected_mac) { - static const char kErrorPrefix[] = "Device verification failed. "; - - std::vector<std::string> headers; - headers.push_back("CERTIFICATE"); - - // Convert certificate from PEM to raw DER - net::PEMTokenizer pem_tok(certificate, headers); - if (!pem_tok.GetNext()) { - LOG(ERROR) << kErrorPrefix << "Failed to parse device certificate."; - return false; - } - std::string der_certificate = pem_tok.data(); - - // Convert intermediate certificates from PEM to raw DER - std::vector<std::string> der_intermediate_certificates; - for (size_t idx = 0; idx < intermediate_certificates.size(); ++idx) { - net::PEMTokenizer ica_pem_tok(intermediate_certificates[idx], headers); - if (ica_pem_tok.GetNext()) { - der_intermediate_certificates.push_back(ica_pem_tok.data()); - } else { - LOG(WARNING) << "Failed to parse intermediate certificates."; - } - } - - // Verify device certificate - scoped_ptr<cast_crypto::CertVerificationContext> verification_context; - cast_crypto::VerificationResult verification_result = - cast_crypto::VerifyDeviceCert(der_certificate, - der_intermediate_certificates, - &verification_context); - - if (verification_result.Failure()) { - LOG(ERROR) << kErrorPrefix << verification_result.GetLogString(); - return false; - } - - // Check that the device listed in the certificate is correct. - // Something like evt_e161 001a11ffacdf - std::string common_name = verification_context->GetCommonName(); - std::string translated_mac; - base::RemoveChars(connected_mac, ":", &translated_mac); - if (!EndsWith(common_name, translated_mac, false)) { - LOG(ERROR) << kErrorPrefix << "MAC addresses don't match."; - return false; - } - - // Use the public key from verified certificate to verify |signature| over - // |data|. - verification_result = - verification_context->VerifySignatureOverData(signature, data); - - if (verification_result.Failure()) { - LOG(ERROR) << kErrorPrefix << verification_result.GetLogString(); - return false; - } - return true; -} +const uint8 kTrustedCAPublicKeyDER[] = { + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbc, 0x22, 0x80, + 0xbd, 0x80, 0xf6, 0x3a, 0x21, 0x00, 0x3b, 0xae, 0x76, 0x5e, 0x35, 0x7f, + 0x3d, 0xc3, 0x64, 0x5c, 0x55, 0x94, 0x86, 0x34, 0x2f, 0x05, 0x87, 0x28, + 0xcd, 0xf7, 0x69, 0x8c, 0x17, 0xb3, 0x50, 0xa7, 0xb8, 0x82, 0xfa, 0xdf, + 0xc7, 0x43, 0x2d, 0xd6, 0x7e, 0xab, 0xa0, 0x6f, 0xb7, 0x13, 0x72, 0x80, + 0xa4, 0x47, 0x15, 0xc1, 0x20, 0x99, 0x50, 0xcd, 0xec, 0x14, 0x62, 0x09, + 0x5b, 0xa4, 0x98, 0xcd, 0xd2, 0x41, 0xb6, 0x36, 0x4e, 0xff, 0xe8, 0x2e, + 0x32, 0x30, 0x4a, 0x81, 0xa8, 0x42, 0xa3, 0x6c, 0x9b, 0x33, 0x6e, 0xca, + 0xb2, 0xf5, 0x53, 0x66, 0xe0, 0x27, 0x53, 0x86, 0x1a, 0x85, 0x1e, 0xa7, + 0x39, 0x3f, 0x4a, 0x77, 0x8e, 0xfb, 0x54, 0x66, 0x66, 0xfb, 0x58, 0x54, + 0xc0, 0x5e, 0x39, 0xc7, 0xf5, 0x50, 0x06, 0x0b, 0xe0, 0x8a, 0xd4, 0xce, + 0xe1, 0x6a, 0x55, 0x1f, 0x8b, 0x17, 0x00, 0xe6, 0x69, 0xa3, 0x27, 0xe6, + 0x08, 0x25, 0x69, 0x3c, 0x12, 0x9d, 0x8d, 0x05, 0x2c, 0xd6, 0x2e, 0xa2, + 0x31, 0xde, 0xb4, 0x52, 0x50, 0xd6, 0x20, 0x49, 0xde, 0x71, 0xa0, 0xf9, + 0xad, 0x20, 0x40, 0x12, 0xf1, 0xdd, 0x25, 0xeb, 0xd5, 0xe6, 0xb8, 0x36, + 0xf4, 0xd6, 0x8f, 0x7f, 0xca, 0x43, 0xdc, 0xd7, 0x10, 0x5b, 0xe6, 0x3f, + 0x51, 0x8a, 0x85, 0xb3, 0xf3, 0xff, 0xf6, 0x03, 0x2d, 0xcb, 0x23, 0x4f, + 0x9c, 0xad, 0x18, 0xe7, 0x93, 0x05, 0x8c, 0xac, 0x52, 0x9a, 0xf7, 0x4c, + 0xe9, 0x99, 0x7a, 0xbe, 0x6e, 0x7e, 0x4d, 0x0a, 0xe3, 0xc6, 0x1c, 0xa9, + 0x93, 0xfa, 0x3a, 0xa5, 0x91, 0x5d, 0x1c, 0xbd, 0x66, 0xeb, 0xcc, 0x60, + 0xdc, 0x86, 0x74, 0xca, 0xcf, 0xf8, 0x92, 0x1c, 0x98, 0x7d, 0x57, 0xfa, + 0x61, 0x47, 0x9e, 0xab, 0x80, 0xb7, 0xe4, 0x48, 0x80, 0x2a, 0x92, 0xc5, + 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01}; + +const size_t kTrustedCAPublicKeyDERLength = sizeof(kTrustedCAPublicKeyDER); } // namespace networking_private_crypto diff --git a/chrome/common/extensions/api/networking_private/networking_private_crypto.h b/chrome/common/extensions/api/networking_private/networking_private_crypto.h index 8940c0b..e613293 100644 --- a/chrome/common/extensions/api/networking_private/networking_private_crypto.h +++ b/chrome/common/extensions/api/networking_private/networking_private_crypto.h @@ -20,12 +20,10 @@ namespace networking_private_crypto { // 2) The certificate is a valid PEM encoded certificate signed by trusted CA. // 3) |signature| is a valid signature for |data|, using the public key in // |certificate| -bool VerifyCredentials( - const std::string& certificate, - const std::vector<std::string>& intermediate_certificates, - const std::string& signature, - const std::string& data, - const std::string& connected_mac); +bool VerifyCredentials(const std::string& certificate, + const std::string& signature, + const std::string& data, + const std::string& connected_mac); // Encrypt |data| with |public_key|. |public_key| is a DER-encoded // RSAPublicKey. |data| is some string of bytes that is smaller than the @@ -46,6 +44,12 @@ bool DecryptByteString(const std::string& private_key_pem, const std::vector<uint8_t>& encrypted_data, std::string* decrypted_output); +// The trusted public key as a DER-encoded PKCS#1 RSAPublicKey structure. +extern const uint8_t kTrustedCAPublicKeyDER[]; + +// The length of |kTrustedCAPublicKeyDER| in bytes. +extern const size_t kTrustedCAPublicKeyDERLength; + } // namespace networking_private_crypto #endif // CHROME_COMMON_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_CRYPTO_H_ diff --git a/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc b/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc index 0839762..2cdc33b 100644 --- a/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc +++ b/chrome/common/extensions/api/networking_private/networking_private_crypto_nss.cc @@ -46,6 +46,94 @@ bool GetDERFromPEM(const std::string& pem_data, namespace networking_private_crypto { +bool VerifyCredentials(const std::string& certificate, + const std::string& signature, + const std::string& data, + const std::string& connected_mac) { + crypto::EnsureNSSInit(); + + std::vector<uint8_t> cert_data; + if (!GetDERFromPEM(certificate, "CERTIFICATE", &cert_data)) { + LOG(ERROR) << "Failed to parse certificate."; + return false; + } + SECItem der_cert; + der_cert.type = siDERCertBuffer; + der_cert.data = cert_data.data(); + der_cert.len = cert_data.size(); + + // Parse into a certificate structure. + typedef scoped_ptr< + CERTCertificate, + crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate> > + ScopedCERTCertificate; + ScopedCERTCertificate cert(CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE)); + if (!cert.get()) { + LOG(ERROR) << "Failed to parse certificate."; + return false; + } + + // Check that the certificate is signed by trusted CA. + SECItem trusted_ca_key_der_item; + trusted_ca_key_der_item.type = siDERCertBuffer; + trusted_ca_key_der_item.data = + const_cast<unsigned char*>(kTrustedCAPublicKeyDER); + trusted_ca_key_der_item.len = kTrustedCAPublicKeyDERLength; + crypto::ScopedSECKEYPublicKey ca_public_key( + SECKEY_ImportDERPublicKey(&trusted_ca_key_der_item, CKK_RSA)); + SECStatus verified = CERT_VerifySignedDataWithPublicKey( + &cert->signatureWrap, ca_public_key.get(), NULL); + if (verified != SECSuccess) { + LOG(ERROR) << "Certificate is not issued by the trusted CA."; + return false; + } + + // Check that the device listed in the certificate is correct. + // Something like evt_e161 001a11ffacdf + char* common_name = CERT_GetCommonName(&cert->subject); + if (!common_name) { + LOG(ERROR) << "Certificate does not have common name."; + return false; + } + + std::string subject_name(common_name); + PORT_Free(common_name); + std::string translated_mac; + base::RemoveChars(connected_mac, ":", &translated_mac); + if (!EndsWith(subject_name, translated_mac, false)) { + LOG(ERROR) << "MAC addresses don't match."; + return false; + } + + // Make sure that the certificate matches the unsigned data presented. + // Verify that the |signature| matches |data|. + crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert.get())); + if (!public_key.get()) { + LOG(ERROR) << "Unable to extract public key from certificate."; + return false; + } + SECItem signature_item; + signature_item.type = siBuffer; + signature_item.data = + reinterpret_cast<unsigned char*>(const_cast<char*>(signature.c_str())); + signature_item.len = static_cast<unsigned int>(signature.size()); + verified = VFY_VerifyDataDirect( + reinterpret_cast<unsigned char*>(const_cast<char*>(data.c_str())), + data.size(), + public_key.get(), + &signature_item, + SEC_OID_PKCS1_RSA_ENCRYPTION, + SEC_OID_SHA1, + NULL, + NULL); + if (verified != SECSuccess) { + LOG(ERROR) << "Signed blobs did not match."; + return false; + } + return true; +} + bool EncryptByteString(const std::vector<uint8_t>& pub_key_der, const std::string& data, std::vector<uint8_t>* encrypted_output) { diff --git a/chrome/common/extensions/api/networking_private/networking_private_crypto_openssl.cc b/chrome/common/extensions/api/networking_private/networking_private_crypto_openssl.cc index 2a22065..e08b51d 100644 --- a/chrome/common/extensions/api/networking_private/networking_private_crypto_openssl.cc +++ b/chrome/common/extensions/api/networking_private/networking_private_crypto_openssl.cc @@ -10,6 +10,7 @@ #include <openssl/x509.h> #include "base/logging.h" +#include "base/strings/string_util.h" #include "crypto/openssl_util.h" #include "crypto/rsa_private_key.h" #include "crypto/scoped_openssl_types.h" @@ -17,6 +18,8 @@ namespace { +typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509; + // Parses |pem_data| for a PEM block of |pem_type|. // Returns true if a |pem_type| block is found, storing the decoded result in // |der_output|. @@ -38,6 +41,106 @@ bool GetDERFromPEM(const std::string& pem_data, namespace networking_private_crypto { +bool VerifyCredentials(const std::string& certificate, + const std::string& signature, + const std::string& data, + const std::string& connected_mac) { + crypto::EnsureOpenSSLInit(); + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); + + std::vector<uint8_t> cert_data; + if (!GetDERFromPEM(certificate, "CERTIFICATE", &cert_data)) { + LOG(ERROR) << "Failed to parse certificate."; + return false; + } + + // Parse into an OpenSSL X509. + const uint8_t* ptr = cert_data.empty() ? NULL : &cert_data[0]; + const uint8_t* end = ptr + cert_data.size(); + ScopedX509 cert(d2i_X509(NULL, &ptr, cert_data.size())); + if (!cert || ptr != end) { + LOG(ERROR) << "Failed to parse certificate."; + return false; + } + + // Import the trusted public key. + ptr = kTrustedCAPublicKeyDER; + crypto::ScopedRSA ca_public_key_rsa( + d2i_RSAPublicKey(NULL, &ptr, kTrustedCAPublicKeyDERLength)); + if (!ca_public_key_rsa || + ptr != kTrustedCAPublicKeyDER + kTrustedCAPublicKeyDERLength) { + NOTREACHED(); + LOG(ERROR) << "Failed to import trusted public key."; + return false; + } + crypto::ScopedEVP_PKEY ca_public_key(EVP_PKEY_new()); + if (!ca_public_key || + !EVP_PKEY_set1_RSA(ca_public_key.get(), ca_public_key_rsa.get())) { + LOG(ERROR) << "Failed to initialize EVP_PKEY"; + return false; + } + + // Check that the certificate is signed by the trusted public key. + if (X509_verify(cert.get(), ca_public_key.get()) <= 0) { + LOG(ERROR) << "Certificate is not issued by the trusted CA."; + return false; + } + + // Check that the device listed in the certificate is correct. + // Something like evt_e161 001a11ffacdf + std::string common_name; + int common_name_length = X509_NAME_get_text_by_NID( + cert->cert_info->subject, NID_commonName, NULL, 0); + if (common_name_length < 0) { + LOG(ERROR) << "Certificate does not have common name."; + return false; + } + if (common_name_length > 0) { + common_name_length = X509_NAME_get_text_by_NID( + cert->cert_info->subject, + NID_commonName, + WriteInto(&common_name, common_name_length + 1), + common_name_length + 1); + DCHECK_EQ((int)common_name.size(), common_name_length); + if (common_name_length < 0) { + LOG(ERROR) << "Certificate does not have common name."; + return false; + } + common_name.resize(common_name_length); + } + + std::string translated_mac; + base::RemoveChars(connected_mac, ":", &translated_mac); + if (!EndsWith(common_name, translated_mac, false)) { + LOG(ERROR) << "MAC addresses don't match."; + return false; + } + + // Make sure that the certificate matches the unsigned data presented. + // Verify that the |signature| matches |data|. + crypto::ScopedEVP_PKEY public_key(X509_get_pubkey(cert.get())); + if (!public_key) { + LOG(ERROR) << "Unable to extract public key from certificate."; + return false; + } + + crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); + if (!ctx) { + LOG(ERROR) << "Unable to allocate EVP_MD_CTX."; + return false; + } + if (EVP_DigestVerifyInit( + ctx.get(), NULL, EVP_sha1(), NULL, public_key.get()) <= 0 || + EVP_DigestVerifyUpdate(ctx.get(), data.data(), data.size()) <= 0 || + EVP_DigestVerifyFinal(ctx.get(), + reinterpret_cast<const uint8_t*>(signature.data()), + signature.size()) <= 0) { + LOG(ERROR) << "Signed blobs did not match."; + return false; + } + return true; +} + bool EncryptByteString(const std::vector<uint8_t>& pub_key_der, const std::string& data, std::vector<uint8_t>* encrypted_output) { diff --git a/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc b/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc index 15bd935..d482d59 100644 --- a/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc +++ b/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc @@ -46,30 +46,6 @@ TEST_F(NetworkingPrivateCryptoTest, VerifyCredentials) { "wM9asRj3tJA5VRFbLbsit1VI7IaRCk9rsSKkpBUaVeKbPLz+y/Z6JonXXT6AxsfgUSKDd4B7" "MYLrTwMQfGuUaaaKko6ldKIrovjrcPloQr1Hxb2bipFcjLmG7nxQLoS6vQ==" "-----END CERTIFICATE-----"; - static const char kICAData[] = - "-----BEGIN CERTIFICATE-----" - "MIIDzTCCArWgAwIBAgIBAzANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJVUzET" - "MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEG" - "A1UECgwKR29vZ2xlIEluYzENMAsGA1UECwwEQ2FzdDEVMBMGA1UEAwwMQ2FzdCBS" - "b290IENBMB4XDTE0MDQwMjIwNTg1NFoXDTE5MDQwMjIwNTg1NFowfTELMAkGA1UE" - "BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZp" - "ZXcxEzARBgNVBAoMCkdvb2dsZSBJbmMxEjAQBgNVBAsMCUdvb2dsZSBUVjEYMBYG" - "A1UEAwwPRXVyZWthIEdlbjEgSUNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB" - "CgKCAQEAvCKAvYD2OiEAO652XjV/PcNkXFWUhjQvBYcozfdpjBezUKe4gvrfx0Mt" - "1n6roG+3E3KApEcVwSCZUM3sFGIJW6SYzdJBtjZO/+guMjBKgahCo2ybM27KsvVT" - "ZuAnU4YahR6nOT9Kd477VGZm+1hUwF45x/VQBgvgitTO4WpVH4sXAOZpoyfmCCVp" - "PBKdjQUs1i6iMd60UlDWIEnecaD5rSBAEvHdJevV5rg29NaPf8pD3NcQW+Y/UYqF" - "s/P/9gMtyyNPnK0Y55MFjKxSmvdM6Zl6vm5+TQrjxhypk/o6pZFdHL1m68xg3IZ0" - "ys/4khyYfVf6YUeeq4C35EiAKpLFGwIDAQABo2AwXjAPBgNVHRMECDAGAQH/AgEA" - "MB0GA1UdDgQWBBQyr35sod0oQuWz4VmnWjnJ/4pinzAfBgNVHSMEGDAWgBR8mh59" - "33lUvNfMXsqZhkV5ZXQoGTALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEB" - "ABPENY9iGt6qsc5yq4JOO6EEqYbKVtkSf1AqW2yJc4M4EZ65eA6bpj9EVIKvDxYq" - "NI7q40f7jCXiS+Y73OXFaC3Xue8+DV7WVjAvf9QYy79ohnbqadA4U/Sb7vw4AzwT" - "KCMlH2fUJ5PCNFfTj6lAkeZOhxtegnEMTIB8zvXEb42H0hN4UxRRhCeKS9tIlAmI" - "Ql1ib0jTDDN6IgQYslrx0dyZzBAsRocq/d3ycXX71iMykoIHZ7rNJ2bDMddRdFk2" - "D0Ljj4fZjrQNyD4mot/9mqSrF1Q2/AdWQO3pJONcXRWRynJ4Ian3sWdq2B5Dq8Iz" - "kqrjM7lOq9YEQ+hMRdmOHP4=" - "-----END CERTIFICATE-----"; static const char kName[] = "eureka8997"; static const char kSsdpUdn[] = "c5b2a83b-5958-7ce6-b179-e1f44699429b"; static const char kHotspotBssid[] = "00:1A:11:FF:AC:DF"; @@ -115,43 +91,26 @@ TEST_F(NetworkingPrivateCryptoTest, VerifyCredentials) { // Checking basic verification operation. EXPECT_TRUE(networking_private_crypto::VerifyCredentials( - kCertData, std::vector<std::string>(), signed_data, unsigned_data, - kHotspotBssid)); - - // Checking verification operation with an ICA - std::vector<std::string> icas; - icas.push_back(kICAData); - EXPECT_TRUE(networking_private_crypto::VerifyCredentials( - kCertData, icas, signed_data, unsigned_data, kHotspotBssid)); + kCertData, signed_data, unsigned_data, kHotspotBssid)); // Checking that verification fails when the certificate is signed, but // subject is malformed. EXPECT_FALSE(networking_private_crypto::VerifyCredentials( - kBadSubjectCertData, std::vector<std::string>(), signed_data, - unsigned_data, kHotspotBssid)); + kBadSubjectCertData, signed_data, unsigned_data, kHotspotBssid)); // Checking that verification fails when certificate has invalid format. EXPECT_FALSE(networking_private_crypto::VerifyCredentials( - kBadCertData, std::vector<std::string>(), signed_data, unsigned_data, - kHotspotBssid)); - - // Checking that verification fails if we supply a bad ICA. - std::vector<std::string> bad_icas; - bad_icas.push_back(kCertData); - EXPECT_FALSE(networking_private_crypto::VerifyCredentials( - kCertData, bad_icas, signed_data, unsigned_data, kHotspotBssid)); + kBadCertData, signed_data, unsigned_data, kHotspotBssid)); // Checking that verification fails when Hotspot Bssid is invalid. EXPECT_FALSE(networking_private_crypto::VerifyCredentials( - kCertData, std::vector<std::string>(), signed_data, unsigned_data, - kBadHotspotBssid)); + kCertData, signed_data, unsigned_data, kBadHotspotBssid)); // Checking that verification fails when there is bad nonce in unsigned_data. unsigned_data = base::StringPrintf( "%s,%s,%s,%s,%s", kName, kSsdpUdn, kHotspotBssid, kPublicKey, kBadNonce); EXPECT_FALSE(networking_private_crypto::VerifyCredentials( - kCertData, std::vector<std::string>(), signed_data, unsigned_data, - kHotspotBssid)); + kCertData, signed_data, unsigned_data, kHotspotBssid)); } // Test that networking_private_crypto::EncryptByteString behaves as expected. diff --git a/chrome/test/data/extensions/api_test/networking/test.js b/chrome/test/data/extensions/api_test/networking/test.js index 6bd2292..9024129 100644 --- a/chrome/test/data/extensions/api_test/networking/test.js +++ b/chrome/test/data/extensions/api_test/networking/test.js @@ -15,7 +15,6 @@ var assertEq = chrome.test.assertEq; // Test properties for the verification API. var verificationProperties = { "certificate": "certificate", - "intermediateCertificates": ["ica1", "ica2", "ica3"], "publicKey": "cHVibGljX2tleQ==", // Base64("public_key") "nonce": "nonce", "signedData": "c2lnbmVkX2RhdGE=", // Base64("signed_data") diff --git a/chrome/test/data/extensions/api_test/networking_private/test.js b/chrome/test/data/extensions/api_test/networking_private/test.js index 336018d..0af2e86 100644 --- a/chrome/test/data/extensions/api_test/networking_private/test.js +++ b/chrome/test/data/extensions/api_test/networking_private/test.js @@ -14,7 +14,6 @@ var kGuid = 'SOME_GUID'; // Test properties for the verification API. var verificationProperties = { "certificate": "certificate", - "intermediateCertificates": ["ica1", "ica2", "ica3"], "publicKey": "cHVibGljX2tleQ==", // Base64("public_key") "nonce": "nonce", "signedData": "c2lnbmVkX2RhdGE=", // Base64("signed_data") diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index 63eb6e0..a04436b 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn @@ -533,6 +533,12 @@ source_set("browser") { "//extensions/common/api/cast_channel:cast_channel_proto", ] + if (use_openssl) { + sources += [ "api/cast_channel/cast_auth_util_openssl.cc" ] + } else { + sources += [ "api/cast_channel/cast_auth_util_nss.cc" ] + } + if (is_chromeos) { deps += [ "//chromeos" ] sources += [ diff --git a/extensions/browser/api/cast_channel/cast_auth_util.cc b/extensions/browser/api/cast_channel/cast_auth_util.cc index e2beca1..e863a57 100644 --- a/extensions/browser/api/cast_channel/cast_auth_util.cc +++ b/extensions/browser/api/cast_channel/cast_auth_util.cc @@ -4,14 +4,11 @@ #include "extensions/browser/api/cast_channel/cast_auth_util.h" -#include <vector> - #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "extensions/browser/api/cast_channel/cast_message_util.h" #include "extensions/common/api/cast_channel/cast_channel.pb.h" -#include "extensions/common/cast/cast_cert_validator.h" namespace extensions { namespace core_api { @@ -23,8 +20,6 @@ const char* const kParseErrorPrefix = "Failed to parse auth message: "; const unsigned char kAudioOnlyPolicy[] = {0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79, 0x02, 0x05, 0x02}; -namespace cast_crypto = ::extensions::core_api::cast_crypto; - // Extracts an embedded DeviceAuthMessage payload from an auth challenge reply // message. AuthResult ParseAuthMessage(const CastMessage& challenge_reply, @@ -60,33 +55,6 @@ AuthResult ParseAuthMessage(const CastMessage& challenge_reply, return AuthResult(); } -AuthResult TranslateVerificationResult( - const cast_crypto::VerificationResult& result) { - AuthResult translated; - translated.error_message = result.error_message; - translated.nss_error_code = result.library_error_code; - switch (result.error_type) { - case cast_crypto::VerificationResult::ERROR_NONE: - translated.error_type = AuthResult::ERROR_NONE; - break; - case cast_crypto::VerificationResult::ERROR_CERT_INVALID: - translated.error_type = AuthResult::ERROR_CERT_PARSING_FAILED; - break; - case cast_crypto::VerificationResult::ERROR_CERT_UNTRUSTED: - translated.error_type = AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA; - break; - case cast_crypto::VerificationResult::ERROR_SIGNATURE_INVALID: - translated.error_type = AuthResult::ERROR_SIGNED_BLOBS_MISMATCH; - break; - case cast_crypto::VerificationResult::ERROR_INTERNAL: - translated.error_type = AuthResult::ERROR_UNEXPECTED_AUTH_LIBRARY_RESULT; - break; - default: - translated.error_type = AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA; - }; - return translated; -} - } // namespace AuthResult::AuthResult() @@ -145,31 +113,6 @@ AuthResult AuthenticateChallengeReply(const CastMessage& challenge_reply, return result; } -// This function does the following -// * Verifies that the trusted CA |response.intermediate_certificate| is -// whitelisted for use. -// * Verifies that |response.client_auth_certificate| is signed -// by the trusted CA certificate. -// * Verifies that |response.signature| matches the signature -// of |peer_cert| by |response.client_auth_certificate|'s public -// key. -AuthResult VerifyCredentials(const AuthResponse& response, - const std::string& peer_cert) { - // Verify the certificate - scoped_ptr<cast_crypto::CertVerificationContext> verification_context; - cast_crypto::VerificationResult ret = cast_crypto::VerifyDeviceCert( - response.client_auth_certificate(), - std::vector<std::string>(response.intermediate_certificate().begin(), - response.intermediate_certificate().end()), - &verification_context); - - if (ret.Success()) - ret = verification_context->VerifySignatureOverData(response.signature(), - peer_cert); - - return TranslateVerificationResult(ret); -} - } // namespace cast_channel } // namespace core_api } // namespace extensions diff --git a/extensions/browser/api/cast_channel/cast_auth_util_nss.cc b/extensions/browser/api/cast_channel/cast_auth_util_nss.cc new file mode 100644 index 0000000..97f16d7 --- /dev/null +++ b/extensions/browser/api/cast_channel/cast_auth_util_nss.cc @@ -0,0 +1,142 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/api/cast_channel/cast_auth_util.h" + +#include <cert.h> +#include <cryptohi.h> +#include <pk11pub.h> +#include <seccomon.h> +#include <string> + +#include "base/logging.h" +#include "base/strings/string_piece.h" +#include "crypto/nss_util.h" +#include "crypto/scoped_nss_types.h" +#include "extensions/browser/api/cast_channel/cast_auth_ica.h" +#include "extensions/browser/api/cast_channel/cast_message_util.h" +#include "extensions/common/api/cast_channel/cast_channel.pb.h" +#include "net/base/hash_value.h" +#include "net/cert/x509_certificate.h" + +namespace extensions { +namespace core_api { +namespace cast_channel { +namespace { + +typedef scoped_ptr< + CERTCertificate, + crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate> > + ScopedCERTCertificate; + +} // namespace + +// Authenticates the given credentials: +// 1. |signature| verification of |peer_cert| using |certificate|. +// 2. |certificate| is signed by a trusted CA. +AuthResult VerifyCredentials(const AuthResponse& response, + const std::string& peer_cert) { + const std::string kErrorPrefix("Failed to verify credentials: "); + const std::string& certificate = response.client_auth_certificate(); + const std::string& signature = response.signature(); + + // If the list of intermediates is empty then use kPublicKeyICA1 as + // the trusted CA (legacy case). + // Otherwise, use the first intermediate in the list as long as it + // is in the allowed list of intermediates. + int num_intermediates = response.intermediate_certificate_size(); + + VLOG(1) << "Response has " << num_intermediates << " intermediates"; + + base::StringPiece ica; + if (num_intermediates <= 0) { + ica = GetDefaultTrustedICAPublicKey(); + } else { + ica = GetTrustedICAPublicKey(response.intermediate_certificate(0)); + } + if (ica.empty()) { + return AuthResult::CreateWithParseError( + "Disallowed intermediate cert", + AuthResult::ERROR_FINGERPRINT_NOT_FOUND); + } + + SECItem trusted_ca_key_der; + trusted_ca_key_der.type = SECItemType::siDERCertBuffer; + trusted_ca_key_der.data = + const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(ica.data())); + trusted_ca_key_der.len = ica.size(); + + crypto::EnsureNSSInit(); + SECItem der_cert; + der_cert.type = siDERCertBuffer; + // Make a copy of certificate string so it is safe to type cast. + der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>( + certificate.data())); + der_cert.len = certificate.length(); + + // Parse into a certificate structure. + ScopedCERTCertificate cert(CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE)); + if (!cert.get()) { + return AuthResult::CreateWithNSSError( + "Failed to parse certificate.", + AuthResult::ERROR_CERT_PARSING_FAILED, PORT_GetError()); + } + + // Check that the certificate is signed by trusted CA. + // NOTE: We const_cast trusted_ca_key_der since on some platforms + // SECKEY_ImportDERPublicKey API takes in SECItem* and not const + // SECItem*. + crypto::ScopedSECKEYPublicKey ca_public_key( + SECKEY_ImportDERPublicKey(&trusted_ca_key_der, CKK_RSA)); + if (!ca_public_key) { + return AuthResult::CreateWithNSSError( + "Failed to import public key from CA certificate.", + AuthResult::ERROR_CERT_PARSING_FAILED, PORT_GetError()); + } + SECStatus verified = CERT_VerifySignedDataWithPublicKey( + &cert->signatureWrap, ca_public_key.get(), NULL); + if (verified != SECSuccess) { + return AuthResult::CreateWithNSSError( + "Cert not signed by trusted CA", + AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA, PORT_GetError()); + } + + VLOG(1) << "Cert signed by trusted CA"; + + // Verify that the |signature| matches |peer_cert|. + crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert.get())); + if (!public_key.get()) { + return AuthResult::CreateWithNSSError( + "Unable to extract public key from certificate", + AuthResult::ERROR_CANNOT_EXTRACT_PUBLIC_KEY, PORT_GetError()); + } + SECItem signature_item; + signature_item.type = siBuffer; + signature_item.data = reinterpret_cast<unsigned char*>( + const_cast<char*>(signature.data())); + signature_item.len = signature.length(); + verified = VFY_VerifyDataDirect( + reinterpret_cast<unsigned char*>(const_cast<char*>(peer_cert.data())), + peer_cert.size(), + public_key.get(), + &signature_item, + SEC_OID_PKCS1_RSA_ENCRYPTION, + SEC_OID_SHA1, NULL, NULL); + + if (verified != SECSuccess) { + return AuthResult::CreateWithNSSError( + "Signed blobs did not match", + AuthResult::ERROR_SIGNED_BLOBS_MISMATCH, + PORT_GetError()); + } + + VLOG(1) << "Signature verification succeeded"; + + return AuthResult(); +} + +} // namespace cast_channel +} // namespace core_api +} // namespace extensions diff --git a/extensions/browser/api/cast_channel/cast_auth_util_openssl.cc b/extensions/browser/api/cast_channel/cast_auth_util_openssl.cc new file mode 100644 index 0000000..b662840 --- /dev/null +++ b/extensions/browser/api/cast_channel/cast_auth_util_openssl.cc @@ -0,0 +1,144 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/api/cast_channel/cast_auth_util.h" + +#include <openssl/evp.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> +#include <stddef.h> + +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "crypto/openssl_util.h" +#include "crypto/scoped_openssl_types.h" +#include "extensions/browser/api/cast_channel/cast_auth_ica.h" +#include "extensions/browser/api/cast_channel/cast_message_util.h" +#include "extensions/common/api/cast_channel/cast_channel.pb.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util_openssl.h" + +namespace extensions { +namespace core_api { +namespace cast_channel { +namespace { + +typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509; + +} // namespace + +// This function does the following +// * Verifies that the trusted CA |response.intermediate_certificate| is +// whitelisted for use. +// * Verifies that |response.client_auth_certificate| is signed +// by the trusted CA certificate. +// * Verifies that |response.signature| matches the signature +// of |peer_cert| by |response.client_auth_certificate|'s public +// key. +// +// TODO(kmarshall): Report fine-grained errors from OpenSSL. +AuthResult VerifyCredentials(const AuthResponse& response, + const std::string& peer_cert) { + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); + + // Get the public key of the ICA that was used to sign the client's cert. + base::StringPiece ca_public_key_bytes; + if (response.intermediate_certificate().size() <= 0) { + ca_public_key_bytes = GetDefaultTrustedICAPublicKey(); + } else { + ca_public_key_bytes = + GetTrustedICAPublicKey(response.intermediate_certificate(0)); + if (ca_public_key_bytes.empty()) { + LOG(ERROR) << "Couldn't find trusted ICA."; + return AuthResult::CreateWithParseError( + "failed to verify credentials: cert not signed by trusted CA", + AuthResult::ERROR_FINGERPRINT_NOT_FOUND); + } + } + + // Parse the CA public key. + const uint8_t* ca_ptr = + reinterpret_cast<const uint8_t*>(ca_public_key_bytes.data()); + const uint8_t* ca_public_key_end = ca_ptr + ca_public_key_bytes.size(); + crypto::ScopedRSA ca_public_key_rsa( + d2i_RSAPublicKey(NULL, &ca_ptr, ca_public_key_bytes.size())); + if (!ca_public_key_rsa || ca_ptr != ca_public_key_end) { + LOG(ERROR) << "Failed to import trusted public key."; + return AuthResult::CreateWithParseError( + "failed to import trusted public key.", + AuthResult::ERROR_CERT_PARSING_FAILED); + } + crypto::ScopedEVP_PKEY ca_public_key(EVP_PKEY_new()); + if (!ca_public_key || + !EVP_PKEY_set1_RSA(ca_public_key.get(), ca_public_key_rsa.get())) { + LOG(ERROR) << "Failed to initialize EVP_PKEY"; + return AuthResult::CreateWithParseError( + "failed to initialize EVP_PKEY.", + AuthResult::ERROR_CANNOT_EXTRACT_PUBLIC_KEY); + } + + // Parse the client auth certificate. + const uint8_t* client_cert_ptr = reinterpret_cast<const uint8_t*>( + response.client_auth_certificate().data()); + const uint8_t* client_cert_end = + client_cert_ptr + + response.client_auth_certificate().size(); + const ScopedX509 client_cert( + d2i_X509(NULL, &client_cert_ptr, + response.client_auth_certificate().size())); + if (!client_cert || client_cert_ptr != client_cert_end) { + LOG(ERROR) << "Failed to parse certificate."; + return AuthResult::CreateWithParseError( + "failed to parse client_auth_certificate.", + AuthResult::ERROR_CERT_PARSING_FAILED); + } + + // Verify that the client auth certificate was signed by a trusted CA. + if (X509_verify(client_cert.get(), ca_public_key.get()) <= 0) { + LOG(ERROR) << "Certificate is not issued by a trusted CA."; + return AuthResult::CreateWithParseError( + "cert not signed by trusted CA", + AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA); + } + + // Get the client auth certificate's public key. + const crypto::ScopedEVP_PKEY client_public_key( + X509_get_pubkey(client_cert.get())); + const int client_public_key_type = EVP_PKEY_id(client_public_key.get()); + if (client_public_key_type != EVP_PKEY_RSA) { + LOG(ERROR) << "Expected RSA key type for client certificate, got " + << client_public_key_type << " instead."; + return AuthResult::CreateWithParseError( + "couldn't extract public_key from client cert.", + AuthResult::ERROR_CANNOT_EXTRACT_PUBLIC_KEY); + } + + // Check that the SSL peer certificate was signed using the client's public + // key. + const crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); + if (!ctx || + !EVP_DigestVerifyInit(ctx.get(), NULL, EVP_sha1(), NULL, + client_public_key.get()) || + !EVP_DigestVerifyUpdate(ctx.get(), peer_cert.data(), peer_cert.size())) { + return AuthResult::CreateWithParseError( + "error initializing payload verification operation.", + AuthResult::ERROR_UNEXPECTED_AUTH_LIBRARY_RESULT); + } + const std::string& signature = response.signature(); + if (EVP_DigestVerifyFinal( + ctx.get(), + reinterpret_cast<uint8_t*>(const_cast<char*>(signature.data())), + signature.size()) <= 0) { + return AuthResult::CreateWithParseError( + "payload verification failed.", + AuthResult::ERROR_SIGNED_BLOBS_MISMATCH); + } + + return AuthResult(); +} + +} // namespace cast_channel +} // namespace core_api +} // namespace extensions + diff --git a/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc b/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc index 6d56f683..0e3bcd3 100644 --- a/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc +++ b/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc @@ -354,7 +354,8 @@ TEST_F(CastAuthUtilTest, VerifyBadCA) { AuthResult result = VerifyCredentials( auth_response, CreatePeerCert()); EXPECT_FALSE(result.success()); - EXPECT_EQ(AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA, result.error_type); + EXPECT_EQ(AuthResult::ERROR_FINGERPRINT_NOT_FOUND, + result.error_type); } TEST_F(CastAuthUtilTest, VerifyBadClientAuthCert) { diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn index 76e932d..f6dcd00 100644 --- a/extensions/common/BUILD.gn +++ b/extensions/common/BUILD.gn @@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/crypto.gni") import("//build/config/features.gni") import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni") @@ -42,8 +41,6 @@ if (enable_extensions) { "api/sockets/sockets_manifest_handler.h", "api/sockets/sockets_manifest_permission.cc", "api/sockets/sockets_manifest_permission.h", - "cast/cast_cert_validator.cc", - "cast/cast_cert_validator.h", "common_manifest_handlers.cc", "common_manifest_handlers.h", "csp_validator.cc", @@ -252,12 +249,6 @@ if (enable_extensions) { "//url", ] - if (use_openssl) { - sources += [ "cast/cast_cert_validator_openssl.cc" ] - } else { - sources += [ "cast/cast_cert_validator_nss.cc" ] - } - if (enable_nacl) { sources += [ "manifest_handlers/nacl_modules_handler.cc", diff --git a/extensions/common/cast/cast_cert_validator.cc b/extensions/common/cast/cast_cert_validator.cc deleted file mode 100644 index e4f0440..0000000 --- a/extensions/common/cast/cast_cert_validator.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "extensions/common/cast/cast_cert_validator.h" - -namespace extensions { -namespace core_api { -namespace cast_crypto { - -VerificationResult::VerificationResult() - : VerificationResult("", ERROR_NONE, 0) { -} - -VerificationResult::VerificationResult(const std::string& in_error_message, - ErrorType in_error_type) - : VerificationResult(in_error_message, in_error_type, 0) { -} - -VerificationResult::VerificationResult(const std::string& in_error_message, - ErrorType in_error_type, - int in_error_code) - : error_type(in_error_type), - error_message(in_error_message), - library_error_code(in_error_code) { -} - -} // namespace cast_crypto -} // namespace core_api -} // namespace extensions diff --git a/extensions/common/cast/cast_cert_validator.h b/extensions/common/cast/cast_cert_validator.h deleted file mode 100644 index b9d2cf6..0000000 --- a/extensions/common/cast/cast_cert_validator.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EXTENSIONS_COMMON_CAST_CAST_CERT_VALIDATOR_H_ -#define EXTENSIONS_COMMON_CAST_CAST_CERT_VALIDATOR_H_ - -#include <string> -#include <vector> - -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_piece.h" - -namespace extensions { -namespace core_api { -namespace cast_crypto { - -// Status of a certificate or certificate verification operation. -struct VerificationResult { - // Mapped to extensions::core_api::cast_channel::AuthResult::ErrorType in - // cast_auto_util.cc. Update the mapping code when modifying this enum. - enum ErrorType { - // Verification has succeeded. - ERROR_NONE = 0, - // There was a problem with the certificate, such as invalid or corrupt - // certificate data or invalid issuing certificate signature. - ERROR_CERT_INVALID, - // Certificate may be valid, but not trusted in this context. - ERROR_CERT_UNTRUSTED, - // Signature verification failed - ERROR_SIGNATURE_INVALID, - // Catch-all for internal errors that are not covered by the other error - // types. - ERROR_INTERNAL - }; - - // Constructs a VerificationResult that corresponds to success. - VerificationResult(); - - // Construct error-related objects - VerificationResult(const std::string& error_message, ErrorType error_type); - VerificationResult(const std::string& error_message, - ErrorType error_type, - int error_code); - - bool Success() const { return error_type == ERROR_NONE; } - bool Failure() const { return error_type != ERROR_NONE; } - - // Generates a string representation of this object for logging. - std::string GetLogString() const; - - ErrorType error_type; - // Human-readable description of the problem if error_type != ERROR_NONE - std::string error_message; - // May contain the underlying crypto library error code. - int library_error_code; -}; - -// An object of this type is returned by the VerifyCert function, and can be -// used for additional certificate-related operations, using the verified -// certificate. -class CertVerificationContext { - public: - CertVerificationContext() {} - virtual ~CertVerificationContext() {} - - // Use the public key from the verified certificate to verify a - // sha1WithRSAEncryption |signature| over arbitrary |data|. Both |signature| - // and |data| hold raw binary data. - virtual VerificationResult VerifySignatureOverData( - const base::StringPiece& signature, - const base::StringPiece& data) const = 0; - - // Retrieve the Common Name attribute of the subject's distinguished name from - // the verified certificate, if present. Returns an empty string if no Common - // Name is found. - virtual std::string GetCommonName() const = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(CertVerificationContext); -}; - -// Verify a cast device certificate, using optional intermediate certificate -// authority certificates. |context| will be populated with an instance of -// CertVerificationContext, which allows to perform additional verification -// steps as required. -VerificationResult VerifyDeviceCert( - const base::StringPiece& device_cert, - const std::vector<std::string>& ica_certs, - scoped_ptr<CertVerificationContext>* context); - -} // namespace cast_crypto -} // namespace core_api -} // namespace extensions - -#endif // EXTENSIONS_COMMON_CAST_CAST_CERT_VALIDATOR_H_ diff --git a/extensions/common/cast/cast_cert_validator_nss.cc b/extensions/common/cast/cast_cert_validator_nss.cc deleted file mode 100644 index 425da28..0000000 --- a/extensions/common/cast/cast_cert_validator_nss.cc +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "extensions/common/cast/cast_cert_validator.h" - -#include <cert.h> -#include <cryptohi.h> -#include <pk11pub.h> -#include <seccomon.h> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_number_conversions.h" -#include "crypto/nss_util.h" -#include "crypto/scoped_nss_types.h" -#include "extensions/browser/api/cast_channel/cast_auth_ica.h" - -namespace extensions { -namespace core_api { -namespace cast_crypto { - -namespace { - -typedef scoped_ptr< - CERTCertificate, - crypto::NSSDestroyer<CERTCertificate, CERT_DestroyCertificate>> - ScopedCERTCertificate; - -class CertVerificationContextNSS : public CertVerificationContext { - public: - explicit CertVerificationContextNSS(CERTCertificate* certificate) - : certificate_(certificate) {} - - VerificationResult VerifySignatureOverData( - const base::StringPiece& signature, - const base::StringPiece& data) const override { - // Retrieve public key object - crypto::ScopedSECKEYPublicKey public_key_obj( - CERT_ExtractPublicKey(certificate_.get())); - if (!public_key_obj.get()) { - return VerificationResult( - "Failed to extract device certificate public key.", - VerificationResult::ERROR_CERT_INVALID); - } - // Verify signature. - SECItem signature_item; - signature_item.type = siBuffer; - signature_item.data = - reinterpret_cast<unsigned char*>(const_cast<char*>(signature.data())); - signature_item.len = signature.length(); - if (VFY_VerifyDataDirect( - reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())), - data.size(), public_key_obj.get(), &signature_item, - SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA1, NULL, - NULL) != SECSuccess) { - return VerificationResult("Signature verification failed.", - VerificationResult::ERROR_SIGNATURE_INVALID, - PORT_GetError()); - } - return VerificationResult(); - } - - std::string GetCommonName() const override { - char* common_name = CERT_GetCommonName(&certificate_->subject); - if (!common_name) - return std::string(); - - std::string result(common_name); - PORT_Free(common_name); - return result; - } - - private: - ScopedCERTCertificate certificate_; -}; - -} // namespace - -VerificationResult VerifyDeviceCert( - const base::StringPiece& device_cert, - const std::vector<std::string>& ica_certs, - scoped_ptr<CertVerificationContext>* context) { - crypto::EnsureNSSInit(); - - // If the list of intermediates is empty then use kPublicKeyICA1 as - // the trusted CA (legacy case). - // Otherwise, use the first intermediate in the list as long as it - // is in the allowed list of intermediates. - base::StringPiece ica_public_key_der = - (ica_certs.size() == 0) - ? cast_channel::GetDefaultTrustedICAPublicKey() - : cast_channel::GetTrustedICAPublicKey(ica_certs[0]); - - if (ica_public_key_der.empty()) { - return VerificationResult( - "Device certificate is not signed by a trusted CA", - VerificationResult::ERROR_CERT_UNTRUSTED); - } - // Initialize the ICA public key. - SECItem ica_public_key_der_item; - ica_public_key_der_item.type = SECItemType::siDERCertBuffer; - ica_public_key_der_item.data = const_cast<uint8_t*>( - reinterpret_cast<const uint8_t*>(ica_public_key_der.data())); - ica_public_key_der_item.len = ica_public_key_der.size(); - - crypto::ScopedSECKEYPublicKey ica_public_key_obj( - SECKEY_ImportDERPublicKey(&ica_public_key_der_item, CKK_RSA)); - if (!ica_public_key_obj) { - return VerificationResult("Failed to import trusted public key.", - VerificationResult::ERROR_INTERNAL, - PORT_GetError()); - } - SECItem device_cert_der_item; - device_cert_der_item.type = siDERCertBuffer; - // Make a copy of certificate string so it is safe to type cast. - device_cert_der_item.data = - reinterpret_cast<unsigned char*>(const_cast<char*>(device_cert.data())); - device_cert_der_item.len = device_cert.length(); - - // Parse into a certificate structure. - ScopedCERTCertificate device_cert_obj(CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), &device_cert_der_item, NULL, PR_FALSE, PR_TRUE)); - if (!device_cert_obj.get()) { - return VerificationResult("Failed to parse device certificate.", - VerificationResult::ERROR_CERT_INVALID, - PORT_GetError()); - } - if (CERT_VerifySignedDataWithPublicKey(&device_cert_obj->signatureWrap, - ica_public_key_obj.get(), - NULL) != SECSuccess) { - return VerificationResult("Signature verification failed.", - VerificationResult::ERROR_SIGNATURE_INVALID, - PORT_GetError()); - } - if (context) { - scoped_ptr<CertVerificationContext> tmp_context( - new CertVerificationContextNSS(device_cert_obj.release())); - tmp_context.swap(*context); - } - - return VerificationResult(); -} - -std::string VerificationResult::GetLogString() const { - std::string nssError = "NSS Error Code: "; - nssError += base::IntToString(library_error_code); - return error_message.size() - ? std::string("Error: ") + error_message + ", " + nssError - : nssError; -} - -} // namespace cast_crypto -} // namespace core_api -} // namespace extensions diff --git a/extensions/common/cast/cast_cert_validator_openssl.cc b/extensions/common/cast/cast_cert_validator_openssl.cc deleted file mode 100644 index 8c2e4c0..0000000 --- a/extensions/common/cast/cast_cert_validator_openssl.cc +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "extensions/common/cast/cast_cert_validator.h" - -#include <openssl/digest.h> -#include <openssl/evp.h> -#include <openssl/rsa.h> -#include <openssl/x509.h> - -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "crypto/openssl_util.h" -#include "crypto/scoped_openssl_types.h" -#include "extensions/browser/api/cast_channel/cast_auth_ica.h" -#include "net/cert/x509_certificate.h" -#include "net/cert/x509_util_openssl.h" - -namespace extensions { -namespace core_api { -namespace cast_crypto { -namespace { - -typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509; - -class CertVerificationContextOpenSSL : public CertVerificationContext { - public: - // Takes ownership of the passed-in x509 object - explicit CertVerificationContextOpenSSL(X509* x509) : x509_(x509) {} - - VerificationResult VerifySignatureOverData( - const base::StringPiece& signature, - const base::StringPiece& data) const override { - // Retrieve public key object. - crypto::ScopedEVP_PKEY public_key(X509_get_pubkey(x509_.get())); - if (!public_key) { - return VerificationResult( - "Failed to extract device certificate public key.", - VerificationResult::ERROR_CERT_INVALID); - } - // Make sure the key is RSA. - const int public_key_type = EVP_PKEY_id(public_key.get()); - if (public_key_type != EVP_PKEY_RSA) { - return VerificationResult( - std::string("Expected RSA key type for client certificate, got ") + - base::IntToString(public_key_type) + " instead.", - VerificationResult::ERROR_CERT_INVALID); - } - // Verify signature. - const crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); - if (!ctx || - !EVP_DigestVerifyInit(ctx.get(), NULL, EVP_sha1(), NULL, - public_key.get()) || - !EVP_DigestVerifyUpdate(ctx.get(), data.data(), data.size()) || - !EVP_DigestVerifyFinal( - ctx.get(), reinterpret_cast<const uint8_t*>(signature.data()), - signature.size())) { - return VerificationResult("Signature verification failed.", - VerificationResult::ERROR_SIGNATURE_INVALID); - } - return VerificationResult(); - } - - std::string GetCommonName() const override { - int common_name_length = X509_NAME_get_text_by_NID( - x509_->cert_info->subject, NID_commonName, NULL, 0); - if (common_name_length < 0) - return std::string(); - std::string common_name; - common_name_length = X509_NAME_get_text_by_NID( - x509_->cert_info->subject, NID_commonName, - WriteInto(&common_name, static_cast<size_t>(common_name_length) + 1), - common_name_length + 1); - if (common_name_length < 0) - return std::string(); - return common_name; - } - - private: - ScopedX509 x509_; -}; - -} // namespace - -VerificationResult VerifyDeviceCert( - const base::StringPiece& device_cert, - const std::vector<std::string>& ica_certs, - scoped_ptr<CertVerificationContext>* context) { - crypto::EnsureOpenSSLInit(); - crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); - - // If the list of intermediates is empty then use kPublicKeyICA1 as - // the trusted CA (legacy case). - // Otherwise, use the first intermediate in the list as long as it - // is in the allowed list of intermediates. - base::StringPiece ica_public_key_der = - (ica_certs.size() == 0) - ? cast_channel::GetDefaultTrustedICAPublicKey() - : cast_channel::GetTrustedICAPublicKey(ica_certs[0]); - - if (ica_public_key_der.empty()) { - return VerificationResult( - "Device certificate is not signed by a trusted CA", - VerificationResult::ERROR_CERT_UNTRUSTED); - } - // Initialize the ICA public key. - const uint8_t* ica_public_key_der_ptr = - reinterpret_cast<const uint8_t*>(ica_public_key_der.data()); - const uint8_t* ica_public_key_der_end = - ica_public_key_der_ptr + ica_public_key_der.size(); - crypto::ScopedRSA ica_public_key_rsa(d2i_RSAPublicKey( - NULL, &ica_public_key_der_ptr, ica_public_key_der.size())); - if (!ica_public_key_rsa || ica_public_key_der_ptr != ica_public_key_der_end) { - return VerificationResult("Failed to import trusted public key.", - VerificationResult::ERROR_INTERNAL); - } - crypto::ScopedEVP_PKEY ica_public_key_evp(EVP_PKEY_new()); - if (!ica_public_key_evp || - !EVP_PKEY_set1_RSA(ica_public_key_evp.get(), ica_public_key_rsa.get())) { - return VerificationResult("Failed to import trusted public key.", - VerificationResult::ERROR_INTERNAL); - } - // Parse the device certificate. - const uint8_t* device_cert_der_ptr = - reinterpret_cast<const uint8_t*>(device_cert.data()); - const uint8_t* device_cert_der_end = device_cert_der_ptr + device_cert.size(); - ScopedX509 device_cert_x509( - d2i_X509(NULL, &device_cert_der_ptr, device_cert.size())); - if (!device_cert_x509 || device_cert_der_ptr != device_cert_der_end) { - return VerificationResult("Failed to parse device certificate.", - VerificationResult::ERROR_CERT_INVALID); - } - // Verify device certificate. - if (X509_verify(device_cert_x509.get(), ica_public_key_evp.get()) != 1) { - return VerificationResult( - "Device certificate signature verification failed.", - VerificationResult::ERROR_CERT_INVALID); - } - - if (context) { - scoped_ptr<CertVerificationContext> tmp_context( - new CertVerificationContextOpenSSL(device_cert_x509.release())); - tmp_context.swap(*context); - } - - return VerificationResult(); -} - -std::string VerificationResult::GetLogString() const { - return error_message; -} - -} // namespace cast_crypto -} // namespace core_api -} // namespace extensions diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index 1015f9f..1d3a8c9 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -84,8 +84,6 @@ 'common/api/sockets/sockets_manifest_handler.h', 'common/api/sockets/sockets_manifest_permission.cc', 'common/api/sockets/sockets_manifest_permission.h', - 'common/cast/cast_cert_validator.cc', - 'common/cast/cast_cert_validator.h', 'common/common_manifest_handlers.cc', 'common/common_manifest_handlers.h', 'common/csp_validator.cc', @@ -283,31 +281,6 @@ 'common/manifest_handlers/nacl_modules_handler.h', ], }], - ['use_openssl==1', { - 'sources': [ - 'common/cast/cast_cert_validator_openssl.cc', - ], - 'dependencies': [ - '../third_party/boringssl/boringssl.gyp:boringssl', - ], - }, { - 'sources': [ - 'common/cast/cast_cert_validator_nss.cc', - ], - 'conditions': [ - ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', { - 'dependencies': [ - '../build/linux/system.gyp:ssl', - ], - }], - ['OS == "mac" or OS == "ios" or OS == "win"', { - 'dependencies': [ - '../third_party/nss/nss.gyp:nspr', - '../third_party/nss/nss.gyp:nss', - ], - }], - ], - }], ], }, { @@ -859,6 +832,32 @@ 'browser/api/vpn_provider/vpn_service_factory.h' ] }], + ['use_openssl==1', { + 'sources': [ + 'browser/api/cast_channel/cast_auth_util_openssl.cc', + ], + 'dependencies': [ + '../third_party/boringssl/boringssl.gyp:boringssl', + ], + }, { + 'sources': [ + # cast_auth_util_nss.cc uses NSS functions. + 'browser/api/cast_channel/cast_auth_util_nss.cc', + ], + 'conditions': [ + ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', { + 'dependencies': [ + '../build/linux/system.gyp:ssl', + ], + }], + ['OS == "mac" or OS == "ios" or OS == "win"', { + 'dependencies': [ + '../third_party/nss/nss.gyp:nspr', + '../third_party/nss/nss.gyp:nss', + ], + }], + ], + }], ['OS != "linux"', { 'sources': [ 'browser/api/audio/audio_service.cc', |