blob: c6f432dc6c465c0553ca3fd97c04beab9657e4fa [file] [log] [blame]
// Copyright 2015 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/peer_connection_identity_store.h"
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/thread_task_runner_handle.h"
#include "content/renderer/media/webrtc_identity_service.h"
#include "content/renderer/render_thread_impl.h"
namespace content {
namespace {
const char kIdentityName[] = "WebRTC";
static unsigned int kRSAChromiumKeyLength = 1024;
static unsigned int kRSAChromiumPubExp = 0x10001;
// Bridges identity requests between the main render thread and libjingle's
// signaling thread.
class RequestHandler : public base::RefCountedThreadSafe<RequestHandler> {
public:
explicit RequestHandler(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread,
webrtc::DtlsIdentityRequestObserver* observer)
: main_thread_(main_thread),
signaling_thread_(signaling_thread),
observer_(observer) {
DCHECK(main_thread_);
DCHECK(signaling_thread_);
DCHECK(observer_);
}
void RequestIdentityOnMainThread(const GURL& url,
const GURL& first_party_for_cookies) {
DCHECK(main_thread_->BelongsToCurrentThread());
int request_id =
RenderThreadImpl::current()
->get_webrtc_identity_service()
->RequestIdentity(
url, first_party_for_cookies, kIdentityName, kIdentityName,
base::Bind(&RequestHandler::OnIdentityReady, this),
base::Bind(&RequestHandler::OnRequestFailed, this));
DCHECK_NE(request_id, 0);
}
private:
friend class base::RefCountedThreadSafe<RequestHandler>;
~RequestHandler() {
DCHECK(!observer_);
}
void OnIdentityReady(
const std::string& certificate,
const std::string& private_key) {
DCHECK(main_thread_->BelongsToCurrentThread());
signaling_thread_->PostTask(FROM_HERE,
base::Bind(static_cast<void (webrtc::DtlsIdentityRequestObserver::*)(
const std::string&, const std::string&)>(
&webrtc::DtlsIdentityRequestObserver::OnSuccess),
observer_, certificate, private_key));
signaling_thread_->PostTask(FROM_HERE,
base::Bind(&RequestHandler::EnsureReleaseObserverOnSignalingThread,
this));
}
void OnRequestFailed(int error) {
DCHECK(main_thread_->BelongsToCurrentThread());
signaling_thread_->PostTask(FROM_HERE,
base::Bind(&webrtc::DtlsIdentityRequestObserver::OnFailure, observer_,
error));
signaling_thread_->PostTask(FROM_HERE,
base::Bind(&RequestHandler::EnsureReleaseObserverOnSignalingThread,
this));
}
void EnsureReleaseObserverOnSignalingThread() {
DCHECK(signaling_thread_->BelongsToCurrentThread());
observer_ = nullptr;
}
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
scoped_refptr<webrtc::DtlsIdentityRequestObserver> observer_;
};
// Helper function for PeerConnectionIdentityStore::RequestIdentity.
// Used to invoke |observer|->OnSuccess in a PostTask.
void ObserverOnSuccess(
const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer,
scoped_ptr<rtc::SSLIdentity> identity) {
observer->OnSuccess(rtc::scoped_ptr<rtc::SSLIdentity>(identity.release()));
}
} // namespace
PeerConnectionIdentityStore::PeerConnectionIdentityStore(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread,
const GURL& url,
const GURL& first_party_for_cookies)
: main_thread_(main_thread),
signaling_thread_(signaling_thread),
url_(url),
first_party_for_cookies_(first_party_for_cookies) {
DCHECK(main_thread_);
DCHECK(signaling_thread_);
}
PeerConnectionIdentityStore::~PeerConnectionIdentityStore() {
// Typically destructed on libjingle's signaling thread.
}
void PeerConnectionIdentityStore::RequestIdentity(
rtc::KeyParams key_params,
const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
DCHECK(signaling_thread_->BelongsToCurrentThread());
DCHECK(observer);
// TODO(torbjorng): crbug.com/544902. RequestIdentityOnUIThread uses Chromium
// key generation code with the assumption that it will generate with the
// following rsa_params(). This assumption should not be implicit! Either pass
// the parameters along or check against constants exported from relevant
// header file(s).
if (key_params.type() == rtc::KT_RSA &&
key_params.rsa_params().mod_size == kRSAChromiumKeyLength &&
key_params.rsa_params().pub_exp == kRSAChromiumPubExp) {
// Use Chromium identity generation code for its hardwired parameters (RSA,
// 1024, 0x10001). This generation code is preferred over WebRTC generation
// code due to the performance benefits of caching.
scoped_refptr<RequestHandler> handler(
new RequestHandler(main_thread_, signaling_thread_, observer));
main_thread_->PostTask(
FROM_HERE,
base::Bind(&RequestHandler::RequestIdentityOnMainThread, handler, url_,
first_party_for_cookies_));
} else {
// Fall back on WebRTC identity generation code for everything else, e.g.
// RSA with any other parameters or ECDSA. These will not be cached.
scoped_ptr<rtc::SSLIdentity> identity(rtc::SSLIdentity::Generate(
kIdentityName, key_params));
// Invoke |observer| callbacks asynchronously. The callbacks of
// DtlsIdentityStoreInterface implementations have to be async.
if (identity) {
// Async call to |observer|->OnSuccess.
// Helper function necessary because OnSuccess takes an rtc::scoped_ptr
// argument which has to be Pass()-ed. base::Passed gets around this for
// scoped_ptr (without rtc namespace), but not for rtc::scoped_ptr.
signaling_thread_->PostTask(FROM_HERE,
base::Bind(&ObserverOnSuccess, observer, base::Passed(&identity)));
} else {
// Async call to |observer|->OnFailure.
signaling_thread_->PostTask(FROM_HERE,
base::Bind(&webrtc::DtlsIdentityRequestObserver::OnFailure,
observer, 0));
}
}
}
} // namespace content