blob: 83e17cb8dbedfee14495cd1f28e433ef7b950ab1 [file] [log] [blame]
// Copyright (c) 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/rtc_certificate_generator.h"
#include <utility>
#include "base/macros.h"
#include "content/renderer/media/peer_connection_identity_store.h"
#include "content/renderer/media/rtc_certificate.h"
#include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
#include "content/renderer/render_thread_impl.h"
#include "third_party/webrtc/base/rtccertificate.h"
#include "third_party/webrtc/base/scoped_ref_ptr.h"
#include "url/gurl.h"
namespace content {
namespace {
rtc::KeyParams WebRTCKeyParamsToKeyParams(
const blink::WebRTCKeyParams& key_params) {
switch (key_params.keyType()) {
case blink::WebRTCKeyTypeRSA:
return rtc::KeyParams::RSA(key_params.rsaParams().modLength,
key_params.rsaParams().pubExp);
case blink::WebRTCKeyTypeECDSA:
return rtc::KeyParams::ECDSA(
static_cast<rtc::ECCurve>(key_params.ecCurve()));
default:
NOTREACHED();
return rtc::KeyParams();
}
}
// Observer used by RTCCertificateGenerator::generateCertificate.
class RTCCertificateIdentityObserver
: public webrtc::DtlsIdentityRequestObserver {
public:
RTCCertificateIdentityObserver(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
const scoped_refptr<base::SingleThreadTaskRunner>& signaling_thread)
: main_thread_(main_thread),
signaling_thread_(signaling_thread),
observer_(nullptr) {
DCHECK(main_thread_);
DCHECK(signaling_thread_);
}
~RTCCertificateIdentityObserver() override {}
// Perform |store|->RequestIdentity with this identity observer and ensure
// that this identity observer is not deleted until the request has completed
// by holding on to a reference to itself for the duration of the request.
void RequestIdentity(
const blink::WebRTCKeyParams& key_params,
const GURL& url,
const GURL& first_party_for_cookies,
blink::WebCallbacks<blink::WebRTCCertificate*, void>* observer) {
DCHECK(main_thread_->BelongsToCurrentThread());
DCHECK(!observer_) << "Already have a RequestIdentity in progress.";
DCHECK(observer);
key_params_ = key_params;
observer_ = observer;
// Identity request must be performed on the WebRTC signaling thread.
signaling_thread_->PostTask(FROM_HERE, base::Bind(
&RTCCertificateIdentityObserver::RequestIdentityOnWebRtcSignalingThread,
this, url, first_party_for_cookies));
}
private:
void RequestIdentityOnWebRtcSignalingThread(
GURL url,
GURL first_party_for_cookies) {
DCHECK(signaling_thread_->BelongsToCurrentThread());
rtc::scoped_ptr<PeerConnectionIdentityStore> store(
new PeerConnectionIdentityStore(
main_thread_, signaling_thread_, url, first_party_for_cookies));
// Request identity with |this| as the observer. OnSuccess/OnFailure will be
// called asynchronously.
store->RequestIdentity(WebRTCKeyParamsToKeyParams(key_params_), this);
}
// webrtc::DtlsIdentityRequestObserver implementation.
void OnFailure(int error) override {
DCHECK(signaling_thread_->BelongsToCurrentThread());
DCHECK(observer_);
main_thread_->PostTask(FROM_HERE, base::Bind(
&RTCCertificateIdentityObserver::DoCallbackOnMainThread,
this, nullptr));
}
void OnSuccess(const std::string& der_cert,
const std::string& der_private_key) override {
std::string pem_cert = rtc::SSLIdentity::DerToPem(
rtc::kPemTypeCertificate,
reinterpret_cast<const unsigned char*>(der_cert.data()),
der_cert.length());
std::string pem_key = rtc::SSLIdentity::DerToPem(
rtc::kPemTypeRsaPrivateKey,
reinterpret_cast<const unsigned char*>(der_private_key.data()),
der_private_key.length());
OnSuccess(rtc::scoped_ptr<rtc::SSLIdentity>(
rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert)));
}
void OnSuccess(rtc::scoped_ptr<rtc::SSLIdentity> identity) override {
DCHECK(signaling_thread_->BelongsToCurrentThread());
DCHECK(observer_);
rtc::scoped_refptr<rtc::RTCCertificate> certificate =
rtc::RTCCertificate::Create(std::move(identity));
main_thread_->PostTask(FROM_HERE, base::Bind(
&RTCCertificateIdentityObserver::DoCallbackOnMainThread,
this, new RTCCertificate(key_params_, certificate)));
}
void DoCallbackOnMainThread(blink::WebRTCCertificate* certificate) {
DCHECK(main_thread_->BelongsToCurrentThread());
DCHECK(observer_);
if (certificate)
observer_->onSuccess(certificate);
else
observer_->onError();
}
// The main thread is the renderer thread.
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
// The signaling thread is a WebRTC thread used to invoke
// PeerConnectionIdentityStore::RequestIdentity on, as is required.
const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
blink::WebRTCKeyParams key_params_;
blink::WebCallbacks<blink::WebRTCCertificate*, void>* observer_;
DISALLOW_COPY_AND_ASSIGN(RTCCertificateIdentityObserver);
};
} // namespace
void RTCCertificateGenerator::generateCertificate(
const blink::WebRTCKeyParams& key_params,
const blink::WebURL& url,
const blink::WebURL& first_party_for_cookies,
blink::WebCallbacks<blink::WebRTCCertificate*, void>* observer) {
DCHECK(isSupportedKeyParams(key_params));
#if defined(ENABLE_WEBRTC)
const scoped_refptr<base::SingleThreadTaskRunner> main_thread =
base::ThreadTaskRunnerHandle::Get();
PeerConnectionDependencyFactory* pc_dependency_factory =
RenderThreadImpl::current()->GetPeerConnectionDependencyFactory();
pc_dependency_factory->EnsureInitialized();
const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread =
pc_dependency_factory->GetWebRtcSignalingThread();
rtc::scoped_refptr<RTCCertificateIdentityObserver> identity_observer(
new rtc::RefCountedObject<RTCCertificateIdentityObserver>(
main_thread, signaling_thread));
// |identity_observer| lives until request has completed.
identity_observer->RequestIdentity(
key_params, url, first_party_for_cookies, observer);
#else
observer->onError();
#endif
}
bool RTCCertificateGenerator::isSupportedKeyParams(
const blink::WebRTCKeyParams& key_params) {
return WebRTCKeyParamsToKeyParams(key_params).IsValid();
}
} // namespace content