diff options
19 files changed, 718 insertions, 10 deletions
diff --git a/content/browser/media/webrtc_identity_store.cc b/content/browser/media/webrtc_identity_store.cc new file mode 100644 index 0000000..17827cb --- /dev/null +++ b/content/browser/media/webrtc_identity_store.cc @@ -0,0 +1,180 @@ +// Copyright 2013 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 "content/browser/media/webrtc_identity_store.h" + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/logging.h" +#include "base/rand_util.h" +#include "base/threading/worker_pool.h" +#include "content/public/browser/browser_thread.h" +#include "crypto/rsa_private_key.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_errors.h" +#include "net/cert/x509_util.h" + +namespace content { + +struct WebRTCIdentityRequestResult { + int error; + std::string certificate; + std::string private_key; +}; + +static void GenerateIdentityWorker(const std::string& common_name, + WebRTCIdentityRequestResult* result) { + result->error = net::OK; + int serial_number = base::RandInt(0, std::numeric_limits<int>::max()); + + scoped_ptr<crypto::RSAPrivateKey> key(crypto::RSAPrivateKey::Create(1024)); + if (!key.get()) { + DLOG(ERROR) << "Unable to create key pair for client"; + result->error = net::ERR_KEY_GENERATION_FAILED; + return; + } + + base::Time now = base::Time::Now(); + bool success = + net::x509_util::CreateSelfSignedCert(key.get(), + "CN=" + common_name, + serial_number, + now, + now + base::TimeDelta::FromDays(30), + &result->certificate); + if (!success) { + DLOG(ERROR) << "Unable to create x509 cert for client"; + result->error = net::ERR_SELF_SIGNED_CERT_GENERATION_FAILED; + return; + } + + std::vector<uint8> private_key_info; + if (!key->ExportPrivateKey(&private_key_info)) { + DLOG(ERROR) << "Unable to export private key"; + result->error = net::ERR_PRIVATE_KEY_EXPORT_FAILED; + return; + } + + result->private_key = + std::string(private_key_info.begin(), private_key_info.end()); +} + +// The class represents an identity request internal to WebRTCIdentityStore. +// It has a one-to-one mapping to the external version of the request +// WebRTCIdentityRequestHandle, which is the target of the +// WebRTCIdentityRequest's completion callback. +// It's deleted automatically when the request is completed. +class WebRTCIdentityRequest { + public: + WebRTCIdentityRequest(const WebRTCIdentityStore::CompletionCallback& callback) + : callback_(callback) {} + + void Cancel() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + callback_.Reset(); + } + + private: + friend class WebRTCIdentityStore; + + void Post(WebRTCIdentityRequestResult* result) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (callback_.is_null()) + return; + callback_.Run(result->error, result->certificate, result->private_key); + // "this" will be deleted after this point. + } + + WebRTCIdentityStore::CompletionCallback callback_; +}; + +// The class represents an identity request which calls back to the external +// client when the request completes. +// Its lifetime is tied with the Callback held by the corresponding +// WebRTCIdentityRequest. +class WebRTCIdentityRequestHandle { + public: + WebRTCIdentityRequestHandle( + WebRTCIdentityStore* store, + const WebRTCIdentityStore::CompletionCallback& callback) + : store_(store), request_(NULL), callback_(callback) {} + + private: + friend class WebRTCIdentityStore; + + // Cancel the request. Does nothing if the request finished or was already + // cancelled. + void Cancel() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (!request_) + return; + + callback_.Reset(); + WebRTCIdentityRequest* request = request_; + request_ = NULL; + // "this" will be deleted after the following call, because "this" is + // owned by the Callback held by |request|. + request->Cancel(); + } + + void OnRequestStarted(WebRTCIdentityRequest* request) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(request); + request_ = request; + } + + void OnRequestComplete(int error, + const std::string& certificate, + const std::string& private_key) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK(request_); + request_ = NULL; + base::ResetAndReturn(&callback_).Run(error, certificate, private_key); + } + + WebRTCIdentityStore* store_; + WebRTCIdentityRequest* request_; + WebRTCIdentityStore::CompletionCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(WebRTCIdentityRequestHandle); +}; + +WebRTCIdentityStore::WebRTCIdentityStore() + : task_runner_(base::WorkerPool::GetTaskRunner(true)) {} + +WebRTCIdentityStore::~WebRTCIdentityStore() {} + +base::Closure WebRTCIdentityStore::RequestIdentity( + const GURL& origin, + const std::string& identity_name, + const std::string& common_name, + const CompletionCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + WebRTCIdentityRequestHandle* handle = + new WebRTCIdentityRequestHandle(this, callback); + + WebRTCIdentityRequest* request = new WebRTCIdentityRequest(base::Bind( + &WebRTCIdentityRequestHandle::OnRequestComplete, base::Owned(handle))); + handle->OnRequestStarted(request); + + WebRTCIdentityRequestResult* result = new WebRTCIdentityRequestResult(); + if (!task_runner_->PostTaskAndReply( + FROM_HERE, + base::Bind(&GenerateIdentityWorker, common_name, result), + base::Bind(&WebRTCIdentityRequest::Post, + base::Owned(request), + base::Owned(result)))) + return base::Closure(); + + return base::Bind(&WebRTCIdentityRequestHandle::Cancel, + base::Unretained(handle)); +} + +void WebRTCIdentityStore::SetTaskRunnerForTesting( + const scoped_refptr<base::TaskRunner>& task_runner) { + task_runner_ = task_runner; +} + +} // namespace content diff --git a/content/browser/media/webrtc_identity_store.h b/content/browser/media/webrtc_identity_store.h new file mode 100644 index 0000000..9b3b444 --- /dev/null +++ b/content/browser/media/webrtc_identity_store.h @@ -0,0 +1,74 @@ +// Copyright 2013 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 CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_ +#define CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_ + +#include <string> + +#include "base/callback.h" +#include "content/common/content_export.h" + +class GURL; + +namespace base { +class TaskRunner; +} // namespace base + +namespace content { + +class WebRTCIdentityStoreTest; + +// A class for creating and fetching DTLS identities, i.e. the private key and +// the self-signed certificate. +class CONTENT_EXPORT WebRTCIdentityStore { + public: + typedef base::Callback<void(int error, + const std::string& certificate, + const std::string& private_key)> + CompletionCallback; + + WebRTCIdentityStore(); + ~WebRTCIdentityStore(); + + // Retrieve the cached DTLS private key and certificate, i.e. identity, for + // the |origin| and |identity_name| pair, or generate a new identity using + // |common_name| if such an identity does not exist. + // If the given |common_name| is different from the common name in the cached + // identity that has the same origin and identity_name, a new private key and + // a new certificate will be generated, overwriting the old one. + // TODO(jiayl): implement identity caching through a persistent storage. + // + // |origin| is the origin of the DTLS connection; + // |identity_name| is used to identify an identity within an origin; it is + // opaque to WebRTCIdentityStore and remains private to the caller, i.e. not + // present in the certificate; + // |common_name| is the common name used to generate the certificate and will + // be shared with the peer of the DTLS connection. Identities created for + // different origins or different identity names may have the same common + // name. + // |callback| is the callback to return the result. + // + // Returns the Closure used to cancel the request if the request is accepted. + // The Closure can only be called before the request completes. + base::Closure RequestIdentity(const GURL& origin, + const std::string& identity_name, + const std::string& common_name, + const CompletionCallback& callback); + + private: + friend class WebRTCIdentityStoreTest; + + void SetTaskRunnerForTesting( + const scoped_refptr<base::TaskRunner>& task_runner); + + // The TaskRunner for doing work on a worker thread. + scoped_refptr<base::TaskRunner> task_runner_; + + DISALLOW_COPY_AND_ASSIGN(WebRTCIdentityStore); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_ diff --git a/content/browser/media/webrtc_identity_store_unittest.cc b/content/browser/media/webrtc_identity_store_unittest.cc new file mode 100644 index 0000000..d68528e --- /dev/null +++ b/content/browser/media/webrtc_identity_store_unittest.cc @@ -0,0 +1,104 @@ +// Copyright 2013 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 "base/bind.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/sequenced_worker_pool.h" +#include "content/browser/media/webrtc_identity_store.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "content/public/test/test_utils.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +// TODO(jiayl): the tests fail on Android since the openssl version of +// CreateSelfSignedCert is not implemented. We should mock out this dependency +// and remove the if-defined. + +#if !defined(OS_ANDROID) +class WebRTCIdentityStoreTest : public testing::Test { + public: + WebRTCIdentityStoreTest() + : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), + sequenced_worker_pool_( + new base::SequencedWorkerPool(3, "WebRTCIdentityStoreTest")), + webrtc_identity_store_(new WebRTCIdentityStore()) { + webrtc_identity_store_->SetTaskRunnerForTesting(sequenced_worker_pool_); + } + + virtual ~WebRTCIdentityStoreTest() { sequenced_worker_pool_->Shutdown(); } + + protected: + TestBrowserThreadBundle browser_thread_bundle_; + scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool_; + scoped_ptr<WebRTCIdentityStore> webrtc_identity_store_; +}; + +static void OnRequestCompleted(bool* completed, + int error, + const std::string& certificate, + const std::string& private_key) { + ASSERT_EQ(net::OK, error); + ASSERT_NE("", certificate); + ASSERT_NE("", private_key); + *completed = true; +} + +TEST_F(WebRTCIdentityStoreTest, RequestIdentity) { + bool completed = false; + base::Closure cancel_callback = + webrtc_identity_store_->RequestIdentity( + GURL("http://google.com"), + "a", + "b", + base::Bind(&OnRequestCompleted, &completed)); + ASSERT_FALSE(cancel_callback.is_null()); + sequenced_worker_pool_->FlushForTesting(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(completed); +} + +TEST_F(WebRTCIdentityStoreTest, CancelRequest) { + bool completed = false; + base::Closure cancel_callback = + webrtc_identity_store_->RequestIdentity( + GURL("http://google.com"), + "a", + "b", + base::Bind(&OnRequestCompleted, &completed)); + ASSERT_FALSE(cancel_callback.is_null()); + cancel_callback.Run(); + sequenced_worker_pool_->FlushForTesting(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(completed); +} + +TEST_F(WebRTCIdentityStoreTest, MultipleRequests) { + bool completed_1 = false; + bool completed_2 = false; + base::Closure cancel_callback_1 = + webrtc_identity_store_->RequestIdentity( + GURL("http://foo.com"), + "a", + "b", + base::Bind(&OnRequestCompleted, &completed_1)); + ASSERT_FALSE(cancel_callback_1.is_null()); + + base::Closure cancel_callback_2 = + webrtc_identity_store_->RequestIdentity( + GURL("http://bar.com"), + "a", + "b", + base::Bind(&OnRequestCompleted, &completed_2)); + ASSERT_FALSE(cancel_callback_2.is_null()); + + sequenced_worker_pool_->FlushForTesting(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(completed_1); + EXPECT_TRUE(completed_2); +} +#endif +} // namespace content diff --git a/content/browser/renderer_host/media/webrtc_identity_service_host.cc b/content/browser/renderer_host/media/webrtc_identity_service_host.cc new file mode 100644 index 0000000..9956b86 --- /dev/null +++ b/content/browser/renderer_host/media/webrtc_identity_service_host.cc @@ -0,0 +1,80 @@ +// Copyright 2013 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 "content/browser/renderer_host/media/webrtc_identity_service_host.h" + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "content/browser/media/webrtc_identity_store.h" +#include "content/common/media/webrtc_identity_messages.h" +#include "net/base/net_errors.h" + +namespace content { + +WebRTCIdentityServiceHost::WebRTCIdentityServiceHost( + WebRTCIdentityStore* identity_store) + : identity_store_(identity_store) {} + +WebRTCIdentityServiceHost::~WebRTCIdentityServiceHost() { + if (cancel_callback_.is_null()) + return; + cancel_callback_.Run(); +} + +bool WebRTCIdentityServiceHost::OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(WebRTCIdentityServiceHost, message, *message_was_ok) + IPC_MESSAGE_HANDLER(WebRTCIdentityMsg_RequestIdentity, OnRequestIdentity) + IPC_MESSAGE_HANDLER(WebRTCIdentityMsg_CancelRequest, OnCancelRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP_EX() + return handled; +} + +void WebRTCIdentityServiceHost::OnRequestIdentity( + int request_id, + const GURL& origin, + const std::string& identity_name, + const std::string& common_name) { + if (!cancel_callback_.is_null()) { + DLOG(WARNING) + << "The request is rejected because there is already a pending request"; + SendErrorMessage(request_id, net::ERR_INSUFFICIENT_RESOURCES); + return; + } + cancel_callback_ = identity_store_->RequestIdentity( + origin, + identity_name, + common_name, + base::Bind(&WebRTCIdentityServiceHost::OnComplete, + base::Unretained(this), + request_id)); + if (cancel_callback_.is_null()) { + SendErrorMessage(request_id, net::ERR_UNEXPECTED); + } +} + +void WebRTCIdentityServiceHost::OnCancelRequest(int request_id) { + base::ResetAndReturn(&cancel_callback_); +} + +void WebRTCIdentityServiceHost::OnComplete(int request_id, + int error, + const std::string& certificate, + const std::string& private_key) { + cancel_callback_.Reset(); + if (error == net::OK) { + Send(new WebRTCIdentityHostMsg_IdentityReady( + request_id, certificate, private_key)); + } else { + SendErrorMessage(request_id, error); + } +} + +void WebRTCIdentityServiceHost::SendErrorMessage(int request_id, int error) { + Send(new WebRTCIdentityHostMsg_RequestFailed(request_id, error)); +} + +} // namespace content diff --git a/content/browser/renderer_host/media/webrtc_identity_service_host.h b/content/browser/renderer_host/media/webrtc_identity_service_host.h new file mode 100644 index 0000000..9d903cd --- /dev/null +++ b/content/browser/renderer_host/media/webrtc_identity_service_host.h @@ -0,0 +1,66 @@ +// Copyright 2013 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 CONTENT_BROWSER_RENDERER_HOST_MEDIA_WEBRTC_IDENTITY_SERVICE_HOST_H_ +#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_WEBRTC_IDENTITY_SERVICE_HOST_H_ + +#include <string> + +#include "base/basictypes.h" +#include "content/public/browser/browser_message_filter.h" + +class GURL; + +namespace content { + +class WebRTCIdentityStore; + +// This class is the host for WebRTCIdentityService in the browser process. +// It converts the IPC messages for requesting a WebRTC DTLS identity and +// cancelling a pending request into calls of WebRTCIdentityStore. It also sends +// the request result back to the renderer through IPC. +// Only one outstanding request is allowed per renderer at a time. If a second +// request is made before the first one completes, an IPC with error +// ERR_INSUFFICIENT_RESOURCES will be sent back to the renderer. +class WebRTCIdentityServiceHost : public BrowserMessageFilter { + public: + explicit WebRTCIdentityServiceHost(WebRTCIdentityStore* identity_store); + + private: + virtual ~WebRTCIdentityServiceHost(); + + // content::BrowserMessageFilter override. + virtual bool OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) OVERRIDE; + + void OnComplete(int request_id, + int error, + const std::string& certificate, + const std::string& private_key); + + // Requests a DTLS identity from the DTLS identity store for the given + // |origin| and |identity_name|. If no such identity exists, a new one will be + // generated using the given |common_name|. + // |request_id| is a unique id chosen by the client and used to cancel a + // pending request. + void OnRequestIdentity(int request_id, + const GURL& origin, + const std::string& identity_name, + const std::string& common_name); + + // Cancels a pending request by its id. If there is no pending request having + // the same id, the call is ignored. + void OnCancelRequest(int request_id); + + void SendErrorMessage(int request_id, int error); + + base::Closure cancel_callback_; + WebRTCIdentityStore* identity_store_; + + DISALLOW_COPY_AND_ASSIGN(WebRTCIdentityServiceHost); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_WEBRTC_IDENTITY_SERVICE_HOST_H_ diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 6a80195..fe0e947 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -74,7 +74,6 @@ #include "content/browser/renderer_host/media/audio_renderer_host.h" #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h" #include "content/browser/renderer_host/media/midi_host.h" -#include "content/browser/renderer_host/media/peer_connection_tracker_host.h" #include "content/browser/renderer_host/media/video_capture_host.h" #include "content/browser/renderer_host/memory_benchmark_message_filter.h" #include "content/browser/renderer_host/p2p/socket_dispatcher_host.h" @@ -137,6 +136,11 @@ #include "content/public/common/sandboxed_process_launcher_delegate.h" #endif +#if defined(ENABLE_WEBRTC) +#include "content/browser/renderer_host/media/peer_connection_tracker_host.h" +#include "content/browser/renderer_host/media/webrtc_identity_service_host.h" +#endif + #include "third_party/skia/include/core/SkBitmap.h" extern bool g_exited_main_message_loop; @@ -632,6 +636,8 @@ void RenderProcessHostImpl::CreateMessageFilters() { gpu_message_filter_ = new GpuMessageFilter(GetID(), widget_helper_.get()); channel_->AddFilter(gpu_message_filter_); #if defined(ENABLE_WEBRTC) + channel_->AddFilter(new WebRTCIdentityServiceHost( + storage_partition_impl_->GetWebRTCIdentityStore())); peer_connection_tracker_host_ = new PeerConnectionTrackerHost(GetID()); channel_->AddFilter(peer_connection_tracker_host_.get()); channel_->AddFilter(new MediaStreamDispatcherHost( diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 8b3000e..691a40f 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc @@ -159,15 +159,16 @@ StoragePartitionImpl::StoragePartitionImpl( fileapi::FileSystemContext* filesystem_context, webkit_database::DatabaseTracker* database_tracker, DOMStorageContextImpl* dom_storage_context, - IndexedDBContextImpl* indexed_db_context) + IndexedDBContextImpl* indexed_db_context, + scoped_ptr<WebRTCIdentityStore> webrtc_identity_store) : partition_path_(partition_path), quota_manager_(quota_manager), appcache_service_(appcache_service), filesystem_context_(filesystem_context), database_tracker_(database_tracker), dom_storage_context_(dom_storage_context), - indexed_db_context_(indexed_db_context) { -} + indexed_db_context_(indexed_db_context), + webrtc_identity_store_(webrtc_identity_store.Pass()) {} StoragePartitionImpl::~StoragePartitionImpl() { // These message loop checks are just to avoid leaks in unittests. @@ -243,13 +244,17 @@ StoragePartitionImpl* StoragePartitionImpl::Create( scoped_refptr<ChromeAppCacheService> appcache_service = new ChromeAppCacheService(quota_manager->proxy()); + scoped_ptr<WebRTCIdentityStore> webrtc_identity_store( + new WebRTCIdentityStore()); + return new StoragePartitionImpl(partition_path, quota_manager.get(), appcache_service.get(), filesystem_context.get(), database_tracker.get(), dom_storage_context.get(), - indexed_db_context.get()); + indexed_db_context.get(), + webrtc_identity_store.Pass()); } base::FilePath StoragePartitionImpl::GetPath() { @@ -344,6 +349,10 @@ void StoragePartitionImpl::AsyncClearDataBetween(uint32 storage_mask, } } +WebRTCIdentityStore* StoragePartitionImpl::GetWebRTCIdentityStore() { + return webrtc_identity_store_.get(); +} + void StoragePartitionImpl::SetURLRequestContext( net::URLRequestContextGetter* url_request_context) { url_request_context_ = url_request_context; diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index af206f5..9dcdfec 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h @@ -11,6 +11,7 @@ #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/dom_storage/dom_storage_context_impl.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" +#include "content/browser/media/webrtc_identity_store.h" #include "content/common/content_export.h" #include "content/public/browser/storage_partition.h" @@ -41,6 +42,8 @@ class StoragePartitionImpl : public StoragePartition { const base::Time& end, const base::Closure& callback) OVERRIDE; + WebRTCIdentityStore* GetWebRTCIdentityStore(); + private: friend class StoragePartitionImplMap; FRIEND_TEST_ALL_PREFIXES(StoragePartitionShaderClearTest, ClearShaderCache); @@ -62,7 +65,8 @@ class StoragePartitionImpl : public StoragePartition { fileapi::FileSystemContext* filesystem_context, webkit_database::DatabaseTracker* database_tracker, DOMStorageContextImpl* dom_storage_context, - IndexedDBContextImpl* indexed_db_context); + IndexedDBContextImpl* indexed_db_context, + scoped_ptr<WebRTCIdentityStore> webrtc_identity_store); // Used by StoragePartitionImplMap. // @@ -89,6 +93,7 @@ class StoragePartitionImpl : public StoragePartition { scoped_refptr<webkit_database::DatabaseTracker> database_tracker_; scoped_refptr<DOMStorageContextImpl> dom_storage_context_; scoped_refptr<IndexedDBContextImpl> indexed_db_context_; + scoped_ptr<WebRTCIdentityStore> webrtc_identity_store_; DISALLOW_COPY_AND_ASSIGN(StoragePartitionImpl); }; diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc index 0298513..36af638 100644 --- a/content/browser/storage_partition_impl_unittest.cc +++ b/content/browser/storage_partition_impl_unittest.cc @@ -107,10 +107,16 @@ TEST_F(StoragePartitionShaderClearTest, ClearShaderCache) { EXPECT_EQ(1u, Size()); TestClosureCallback clear_cb; - StoragePartitionImpl sp(cache_path(), NULL, NULL, NULL, NULL, NULL, NULL); + StoragePartitionImpl sp(cache_path(), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + scoped_ptr<WebRTCIdentityStore>()); base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&ClearData, &sp, clear_cb.callback())); + FROM_HERE, base::Bind(&ClearData, &sp, clear_cb.callback())); clear_cb.WaitForResult(); EXPECT_EQ(0u, Size()); } diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h index 35927dd..174a63b 100644 --- a/content/common/content_message_generator.h +++ b/content/common/content_message_generator.h @@ -38,6 +38,7 @@ #include "content/common/media/media_stream_messages.h" #include "content/common/media/peer_connection_tracker_messages.h" #include "content/common/media/video_capture_messages.h" +#include "content/common/media/webrtc_identity_messages.h" #include "content/common/memory_benchmark_messages.h" #include "content/common/mime_registry_messages.h" #include "content/common/p2p_messages.h" diff --git a/content/common/media/webrtc_identity_messages.h b/content/common/media/webrtc_identity_messages.h new file mode 100644 index 0000000..4f115bcb --- /dev/null +++ b/content/common/media/webrtc_identity_messages.h @@ -0,0 +1,32 @@ +// Copyright 2013 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. + +// IPC messages for requesting WebRTC identity. +// Multiply-included message file, hence no include guard. + +#include "googleurl/src/gurl.h" +#include "ipc/ipc_message_macros.h" + +#define IPC_MESSAGE_START WebRTCIdentityMsgStart + +// Messages sent from the renderer to the browser. +// Request a WebRTC identity. +IPC_MESSAGE_CONTROL4(WebRTCIdentityMsg_RequestIdentity, + int /* request_id */, + GURL /* origin */, + std::string /* identity_name */, + std::string /* common_name */) +// Cancel a WebRTC identity request. +IPC_MESSAGE_CONTROL1(WebRTCIdentityMsg_CancelRequest, int /* request_id */) + +// Messages sent from the browser to the renderer. +// Return a WebRTC identity. +IPC_MESSAGE_CONTROL3(WebRTCIdentityHostMsg_IdentityReady, + int /* request_id */, + std::string /* certificate */, + std::string /* private_key */) +// Notifies an error from the identity request. +IPC_MESSAGE_CONTROL2(WebRTCIdentityHostMsg_RequestFailed, + int /* request_id */, + int /* error */) diff --git a/content/content_browser.gypi b/content/content_browser.gypi index cc9284e..735e951 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -658,6 +658,8 @@ 'browser/media/media_internals_proxy.h', 'browser/media/media_internals_ui.cc', 'browser/media/media_internals_ui.h', + 'browser/media/webrtc_identity_store.cc', + 'browser/media/webrtc_identity_store.h', 'browser/media/webrtc_internals.cc', 'browser/media/webrtc_internals.h', 'browser/media/webrtc_internals_message_handler.cc', @@ -1195,6 +1197,8 @@ 'sources': [ 'browser/renderer_host/media/peer_connection_tracker_host.cc', 'browser/renderer_host/media/peer_connection_tracker_host.h', + 'browser/renderer_host/media/webrtc_identity_service_host.cc', + 'browser/renderer_host/media/webrtc_identity_service_host.h', 'browser/renderer_host/p2p/socket_host.cc', 'browser/renderer_host/p2p/socket_host.h', 'browser/renderer_host/p2p/socket_host_tcp.cc', diff --git a/content/content_common.gypi b/content/content_common.gypi index ff57dc7..85762d1 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -268,6 +268,7 @@ 'common/media/midi_messages.h', 'common/media/video_capture.h', 'common/media/video_capture_messages.h', + 'common/media/webrtc_identity_messages.h', 'common/memory_benchmark_messages.h', 'common/message_router.cc', 'common/message_router.h', diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index f14f4a6..0c70df5 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -471,6 +471,8 @@ 'renderer/media/webrtc_audio_device_not_impl.h', 'renderer/media/webrtc_audio_renderer.cc', 'renderer/media/webrtc_audio_renderer.h', + 'renderer/media/webrtc_identity_service.cc', + 'renderer/media/webrtc_identity_service.h', 'renderer/media/webrtc_local_audio_renderer.cc', 'renderer/media/webrtc_local_audio_renderer.h', 'renderer/media/webrtc_local_audio_track.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 33ca270..edf06a8 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -321,6 +321,7 @@ 'browser/loader/upload_data_stream_builder_unittest.cc', 'browser/mach_broker_mac_unittest.cc', 'browser/media/media_internals_unittest.cc', + 'browser/media/webrtc_identity_store_unittest.cc', 'browser/net/sqlite_persistent_cookie_store_unittest.cc', 'browser/notification_service_impl_unittest.cc', 'browser/plugin_loader_posix_unittest.cc', diff --git a/content/renderer/media/webrtc_identity_service.cc b/content/renderer/media/webrtc_identity_service.cc new file mode 100644 index 0000000..7042c93 --- /dev/null +++ b/content/renderer/media/webrtc_identity_service.cc @@ -0,0 +1,82 @@ +// Copyright 2013 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 "content/renderer/media/webrtc_identity_service.h" + +#include "base/atomic_sequence_num.h" +#include "content/common/media/webrtc_identity_messages.h" +#include "content/public/renderer/render_thread.h" + +namespace content { + +WebRTCIdentityService::WebRTCIdentityService(const GURL& origin) + : origin_(origin), pending_observer_(NULL), pending_request_id_(0) { + RenderThread::Get()->AddObserver(this); +} + +WebRTCIdentityService::~WebRTCIdentityService() { + RenderThread::Get()->RemoveObserver(this); + if (pending_observer_) { + RenderThread::Get()->Send( + new WebRTCIdentityMsg_CancelRequest(pending_request_id_)); + } +} + +bool WebRTCIdentityService::RequestIdentity( + const std::string& identity_name, + const std::string& common_name, + webrtc::DTLSIdentityRequestObserver* observer) { + // Static because the request id needs to be unique per renderer process + // across WebRTCIdentityService instances. + static base::AtomicSequenceNumber s_next_request_id; + + DCHECK(observer); + if (pending_observer_) + return false; + + pending_observer_ = observer; + pending_request_id_ = s_next_request_id.GetNext(); + RenderThread::Get()->Send(new WebRTCIdentityMsg_RequestIdentity( + pending_request_id_, origin_, identity_name, common_name)); + return true; +} + +bool WebRTCIdentityService::OnControlMessageReceived( + const IPC::Message& message) { + if (!pending_observer_) + return false; + + int old_pending_request_id = pending_request_id_; + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(WebRTCIdentityService, message) + IPC_MESSAGE_HANDLER(WebRTCIdentityHostMsg_IdentityReady, OnIdentityReady) + IPC_MESSAGE_HANDLER(WebRTCIdentityHostMsg_RequestFailed, OnRequestFailed) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + if (pending_request_id_ == old_pending_request_id) + handled = false; + + return handled; +} + +void WebRTCIdentityService::OnIdentityReady(int request_id, + const std::string& certificate, + const std::string& private_key) { + if (request_id != pending_request_id_) + return; + pending_observer_->OnSuccess(certificate, private_key); + pending_observer_ = NULL; + pending_request_id_ = 0; +} + +void WebRTCIdentityService::OnRequestFailed(int request_id, int error) { + if (request_id != pending_request_id_) + return; + pending_observer_->OnFailure(error); + pending_observer_ = NULL; + pending_request_id_ = 0; +} + +} // namespace content diff --git a/content/renderer/media/webrtc_identity_service.h b/content/renderer/media/webrtc_identity_service.h new file mode 100644 index 0000000..6e22671 --- /dev/null +++ b/content/renderer/media/webrtc_identity_service.h @@ -0,0 +1,51 @@ +// Copyright 2013 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 CONTENT_RENDERER_MEDIA_WEBRTC_IDENTITY_SERVICE_H_ +#define CONTENT_RENDERER_MEDIA_WEBRTC_IDENTITY_SERVICE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "content/public/renderer/render_process_observer.h" +#include "googleurl/src/gurl.h" +#include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h" + +namespace content { + +// This class handles WebRTC DTLS identity requests by sending IPC messages to +// the browser process. +class WebRTCIdentityService : public webrtc::DTLSIdentityServiceInterface, + public RenderProcessObserver { + public: + explicit WebRTCIdentityService(const GURL& origin); + virtual ~WebRTCIdentityService(); + + // WebRTCIdentityServiceInterface implementation. + virtual bool RequestIdentity(const std::string& identity_name, + const std::string& common_name, + webrtc::DTLSIdentityRequestObserver* observer) + OVERRIDE; + + private: + // RenderProcessObserver implementation. + virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE; + + void OnIdentityReady(int request_id, + const std::string& certificate, + const std::string& private_key); + + void OnRequestFailed(int request_id, int error); + + // The origin of the DTLS connection. + GURL origin_; + talk_base::scoped_refptr<webrtc::DTLSIdentityRequestObserver> + pending_observer_; + int pending_request_id_; + DISALLOW_COPY_AND_ASSIGN(WebRTCIdentityService); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_WEBRTC_IDENTITY_SERVICE_H_ diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index 3e1e59c..bf80df0 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h @@ -85,7 +85,8 @@ enum IPCMessageStart { MemoryBenchmarkMsgStart, WebSocketMsgStart, NaClHostMsgStart, - LastIPCMsgStart // Must come last. + WebRTCIdentityMsgStart, + LastIPCMsgStart // Must come last. }; #endif // IPC_IPC_MESSAGE_START_H_ diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 9ebb25a..234b3a9 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -660,6 +660,9 @@ NET_ERROR(ORIGIN_BOUND_CERT_GENERATION_FAILED, -711) // Failure to export private key. NET_ERROR(PRIVATE_KEY_EXPORT_FAILED, -712) +// Self-signed certificate generation failed. +NET_ERROR(SELF_SIGNED_CERT_GENERATION_FAILED, -713) + // DNS error codes. // DNS resolver received a malformed response. |