diff --git a/webrtc/api/api_tests.gyp b/webrtc/api/api_tests.gyp index e47a4b17bf..9e3a07490f 100644 --- a/webrtc/api/api_tests.gyp +++ b/webrtc/api/api_tests.gyp @@ -32,7 +32,6 @@ ], 'sources': [ 'datachannel_unittest.cc', - 'dtlsidentitystore_unittest.cc', 'dtmfsender_unittest.cc', 'fakemetricsobserver.cc', 'fakemetricsobserver.h', diff --git a/webrtc/api/dtlsidentitystore.cc b/webrtc/api/dtlsidentitystore.cc index 3652e21877..620b942102 100644 --- a/webrtc/api/dtlsidentitystore.cc +++ b/webrtc/api/dtlsidentitystore.cc @@ -10,282 +10,10 @@ #include "webrtc/api/dtlsidentitystore.h" -#include - -#include "webrtc/api/webrtcsessiondescriptionfactory.h" -#include "webrtc/base/logging.h" - -using webrtc::DtlsIdentityRequestObserver; - namespace webrtc { // Passed to SSLIdentity::Generate, "WebRTC". Used for the certificates' // subject and issuer name. const char kIdentityName[] = "WebRTC"; -namespace { - -enum { - MSG_DESTROY, - MSG_GENERATE_IDENTITY, - MSG_GENERATE_IDENTITY_RESULT -}; - -// A |DtlsIdentityRequestObserver| that informs an -// |RTCCertificateGeneratorCallback| of the result of an identity request. On -// success, a certificate is created using the identity before passing it to -// the callback. -class RTCCertificateStoreCallbackObserver - : public webrtc::DtlsIdentityRequestObserver { - public: - RTCCertificateStoreCallbackObserver( - const rtc::scoped_refptr& callback) - : callback_(callback) {} - - private: - void OnFailure(int error) override { - LOG(LS_WARNING) << "DtlsIdentityRequestObserver failure code: " << error; - Callback(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(der_cert.data()), - der_cert.length()); - std::string pem_key = rtc::SSLIdentity::DerToPem( - rtc::kPemTypeRsaPrivateKey, - reinterpret_cast(der_private_key.data()), - der_private_key.length()); - std::unique_ptr identity( - rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert)); - OnSuccess(std::move(identity)); - } - void OnSuccess(std::unique_ptr identity) override { - Callback(rtc::RTCCertificate::Create(std::move(identity))); - } - - void Callback(rtc::scoped_refptr certificate) { - if (certificate) - callback_->OnSuccess(certificate); - else - callback_->OnFailure(); - } - - rtc::scoped_refptr callback_; -}; - -} // namespace - -// This class runs on the worker thread to generate the identity. It's necessary -// to separate this class from DtlsIdentityStore so that it can live on the -// worker thread after DtlsIdentityStore is destroyed. -class DtlsIdentityStoreImpl::WorkerTask : public sigslot::has_slots<>, - public rtc::MessageHandler { - public: - WorkerTask(DtlsIdentityStoreImpl* store, rtc::KeyType key_type) - : signaling_thread_(rtc::Thread::Current()), - store_(store), - key_type_(key_type) { - store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed); - } - - virtual ~WorkerTask() { RTC_DCHECK(signaling_thread_->IsCurrent()); } - - private: - void GenerateIdentity_w() { - LOG(LS_INFO) << "Generating identity, using keytype " << key_type_; - std::unique_ptr identity( - rtc::SSLIdentity::Generate(kIdentityName, key_type_)); - - // Posting to |this| avoids touching |store_| on threads other than - // |signaling_thread_| and thus avoids having to use locks. - IdentityResultMessageData* msg = new IdentityResultMessageData( - new IdentityResult(key_type_, std::move(identity))); - signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg); - } - - void OnMessage(rtc::Message* msg) override { - switch (msg->message_id) { - case MSG_GENERATE_IDENTITY: - // This message always runs on the worker thread. - GenerateIdentity_w(); - - // Must delete |this|, owned by msg->pdata, on the signaling thread to - // avoid races on disconnecting the signal. - signaling_thread_->Post(this, MSG_DESTROY, msg->pdata); - break; - case MSG_GENERATE_IDENTITY_RESULT: - RTC_DCHECK(signaling_thread_->IsCurrent()); - { - std::unique_ptr pdata( - static_cast(msg->pdata)); - if (store_) { - store_->OnIdentityGenerated(pdata->data()->key_type_, - std::move(pdata->data()->identity_)); - } - } - break; - case MSG_DESTROY: - RTC_DCHECK(signaling_thread_->IsCurrent()); - delete msg->pdata; - // |this| has now been deleted. Don't touch member variables. - break; - default: - RTC_CHECK(false) << "Unexpected message type"; - } - } - - void OnStoreDestroyed() { - RTC_DCHECK(signaling_thread_->IsCurrent()); - store_ = nullptr; - } - - rtc::Thread* const signaling_thread_; - DtlsIdentityStoreImpl* store_; // Only touched on |signaling_thread_|. - const rtc::KeyType key_type_; -}; - -DtlsIdentityStoreImpl::DtlsIdentityStoreImpl(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread) - : signaling_thread_(signaling_thread), - worker_thread_(worker_thread), - request_info_() { - RTC_DCHECK(signaling_thread_->IsCurrent()); -} - -DtlsIdentityStoreImpl::~DtlsIdentityStoreImpl() { - RTC_DCHECK(signaling_thread_->IsCurrent()); - SignalDestroyed(); -} - -void DtlsIdentityStoreImpl::RequestIdentity( - const rtc::KeyParams& key_params, - const rtc::Optional& expires_ms, - const rtc::scoped_refptr& observer) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - RTC_DCHECK(observer); - - // Dropping parameterization and |expires_ms|. - // TODO(hbos,torbjorng): Use parameterizaton/expiration. webrtc:5092. - GenerateIdentity(key_params.type(), observer); -} - -void DtlsIdentityStoreImpl::OnMessage(rtc::Message* msg) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - switch (msg->message_id) { - case MSG_GENERATE_IDENTITY_RESULT: { - std::unique_ptr pdata( - static_cast(msg->pdata)); - OnIdentityGenerated(pdata->data()->key_type_, - std::move(pdata->data()->identity_)); - break; - } - } -} - -bool DtlsIdentityStoreImpl::HasFreeIdentityForTesting( - rtc::KeyType key_type) const { - RTC_DCHECK(signaling_thread_->IsCurrent()); - return request_info_[key_type].free_identity_.get() != nullptr; -} - -void DtlsIdentityStoreImpl::GenerateIdentity( - rtc::KeyType key_type, - const rtc::scoped_refptr& observer) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - - // Enqueue observer to be informed when generation of |key_type| is completed. - if (observer.get()) { - request_info_[key_type].request_observers_.push(observer); - - // Already have a free identity generated? - if (request_info_[key_type].free_identity_.get()) { - // Return identity async - post even though we are on |signaling_thread_|. - LOG(LS_VERBOSE) << "Using a free DTLS identity."; - ++request_info_[key_type].gen_in_progress_counts_; - IdentityResultMessageData* msg = - new IdentityResultMessageData(new IdentityResult( - key_type, std::move(request_info_[key_type].free_identity_))); - signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg); - return; - } - - // Free identity in the process of being generated? - if (request_info_[key_type].gen_in_progress_counts_ == - request_info_[key_type].request_observers_.size()) { - // No need to do anything, the free identity will be returned to the - // observer in a MSG_GENERATE_IDENTITY_RESULT. - return; - } - } - - // Enqueue/Post a worker task to do the generation. - ++request_info_[key_type].gen_in_progress_counts_; - WorkerTask* task = new WorkerTask(this, key_type); // Post 1 task/request. - // The WorkerTask is owned by the message data to make sure it will not be - // leaked even if the task does not get run. - WorkerTaskMessageData* msg = new WorkerTaskMessageData(task); - worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg); -} - -void DtlsIdentityStoreImpl::OnIdentityGenerated( - rtc::KeyType key_type, - std::unique_ptr identity) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - - RTC_DCHECK(request_info_[key_type].gen_in_progress_counts_); - --request_info_[key_type].gen_in_progress_counts_; - - rtc::scoped_refptr observer; - if (!request_info_[key_type].request_observers_.empty()) { - observer = request_info_[key_type].request_observers_.front(); - request_info_[key_type].request_observers_.pop(); - } - - if (observer.get() == nullptr) { - // No observer - store result in |free_identities_|. - RTC_DCHECK(!request_info_[key_type].free_identity_.get()); - request_info_[key_type].free_identity_.swap(identity); - if (request_info_[key_type].free_identity_.get()) - LOG(LS_VERBOSE) << "A free DTLS identity was saved."; - else - LOG(LS_WARNING) << "Failed to generate DTLS identity (preemptively)."; - } else { - // Return the result to the observer. - if (identity.get()) { - LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer."; - observer->OnSuccess(std::move(identity)); - } else { - LOG(LS_WARNING) << "Failed to generate DTLS identity."; - observer->OnFailure(0); - } - - // Preemptively generate another identity of the same type? - if (worker_thread_ != signaling_thread_ && // Only do in background thread. - key_type == rtc::KT_RSA && // Only necessary for RSA. - !request_info_[key_type].free_identity_.get() && - request_info_[key_type].request_observers_.size() == - request_info_[key_type].gen_in_progress_counts_) { - GenerateIdentity(key_type, nullptr); - } - } -} - -RTCCertificateGeneratorStoreWrapper::RTCCertificateGeneratorStoreWrapper( - std::unique_ptr store) - : store_(std::move(store)) { - RTC_DCHECK(store_); -} - -void RTCCertificateGeneratorStoreWrapper::GenerateCertificateAsync( - const rtc::KeyParams& key_params, - const rtc::Optional& expires_ms, - const rtc::scoped_refptr& callback) { - store_->RequestIdentity( - key_params, - expires_ms, - new rtc::RefCountedObject(callback)); -} - } // namespace webrtc diff --git a/webrtc/api/dtlsidentitystore.h b/webrtc/api/dtlsidentitystore.h index 3384341e6b..89644a75a3 100644 --- a/webrtc/api/dtlsidentitystore.h +++ b/webrtc/api/dtlsidentitystore.h @@ -27,7 +27,9 @@ namespace webrtc { -// Passed to SSLIdentity::Generate. +// TODO(hbos): Remove this constant (and dtlsidentitystore.cc) after +// RTCPeerConnectionInterface.mm stops using it. +// bugs.webrtc.org/5707, bugs.webrtc.org/5708 extern const char kIdentityName[]; class SSLIdentity; @@ -64,95 +66,6 @@ class DtlsIdentityStoreInterface { const rtc::scoped_refptr& observer) = 0; }; -// The WebRTC default implementation of DtlsIdentityStoreInterface. -// Identity generation is performed on the worker thread. -class DtlsIdentityStoreImpl : public DtlsIdentityStoreInterface, - public rtc::MessageHandler { - public: - // This will start to preemptively generating an RSA identity in the - // background if the worker thread is not the same as the signaling thread. - DtlsIdentityStoreImpl(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread); - ~DtlsIdentityStoreImpl() override; - - // DtlsIdentityStoreInterface override; - void RequestIdentity( - const rtc::KeyParams& key_params, - const rtc::Optional& expires_ms, - const rtc::scoped_refptr& observer) override; - - // rtc::MessageHandler override; - void OnMessage(rtc::Message* msg) override; - - // Returns true if there is a free RSA identity, used for unit tests. - bool HasFreeIdentityForTesting(rtc::KeyType key_type) const; - - private: - void GenerateIdentity( - rtc::KeyType key_type, - const rtc::scoped_refptr& observer); - void OnIdentityGenerated(rtc::KeyType key_type, - std::unique_ptr identity); - - class WorkerTask; - typedef rtc::ScopedMessageData - WorkerTaskMessageData; - - // A key type-identity pair. - struct IdentityResult { - IdentityResult(rtc::KeyType key_type, - std::unique_ptr identity) - : key_type_(key_type), identity_(std::move(identity)) {} - - rtc::KeyType key_type_; - std::unique_ptr identity_; - }; - - typedef rtc::ScopedMessageData IdentityResultMessageData; - - sigslot::signal0<> SignalDestroyed; - - rtc::Thread* const signaling_thread_; - // TODO(hbos): RSA generation is slow and would be VERY slow if we switch over - // to 2048, DtlsIdentityStore should use a new thread and not the "general - // purpose" worker thread. - rtc::Thread* const worker_thread_; - - struct RequestInfo { - RequestInfo() - : request_observers_(), gen_in_progress_counts_(0), free_identity_() {} - - std::queue> - request_observers_; - size_t gen_in_progress_counts_; - std::unique_ptr free_identity_; - }; - - // One RequestInfo per KeyType. Only touch on the |signaling_thread_|. - RequestInfo request_info_[rtc::KT_LAST]; -}; - -// Implements the |RTCCertificateGeneratorInterface| using the old |SSLIdentity| -// generator API, |DtlsIdentityStoreInterface|. This will be used while -// transitioning from store to generator, see bugs.webrtc.org/5707, -// bugs.webrtc.org/5708. Once those bugs have been fixed, this will be removed. -class RTCCertificateGeneratorStoreWrapper - : public rtc::RTCCertificateGeneratorInterface { - public: - RTCCertificateGeneratorStoreWrapper( - std::unique_ptr store); - - // |RTCCertificateGeneratorInterface| overrides. - void GenerateCertificateAsync( - const rtc::KeyParams& key_params, - const rtc::Optional& expires_ms, - const rtc::scoped_refptr& callback) - override; - - private: - const std::unique_ptr store_; -}; - } // namespace webrtc #endif // WEBRTC_API_DTLSIDENTITYSTORE_H_ diff --git a/webrtc/api/dtlsidentitystore_unittest.cc b/webrtc/api/dtlsidentitystore_unittest.cc deleted file mode 100644 index 31f0113f28..0000000000 --- a/webrtc/api/dtlsidentitystore_unittest.cc +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/api/dtlsidentitystore.h" - -#include - -#include "webrtc/api/webrtcsessiondescriptionfactory.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/ssladapter.h" - -using webrtc::DtlsIdentityStoreImpl; - -static const int kTimeoutMs = 10000; - -class MockDtlsIdentityRequestObserver : - public webrtc::DtlsIdentityRequestObserver { - public: - MockDtlsIdentityRequestObserver() - : call_back_called_(false), last_request_success_(false) {} - void OnFailure(int error) override { - EXPECT_FALSE(call_back_called_); - call_back_called_ = true; - last_request_success_ = false; - } - void OnSuccess(const std::string& der_cert, - const std::string& der_private_key) override { - LOG(LS_WARNING) << "The string version of OnSuccess is called unexpectedly"; - EXPECT_TRUE(false); - } - void OnSuccess(std::unique_ptr identity) override { - EXPECT_FALSE(call_back_called_); - call_back_called_ = true; - last_request_success_ = true; - } - - void Reset() { - call_back_called_ = false; - last_request_success_ = false; - } - - bool LastRequestSucceeded() const { - return call_back_called_ && last_request_success_; - } - - bool call_back_called() const { - return call_back_called_; - } - - private: - bool call_back_called_; - bool last_request_success_; -}; - -class DtlsIdentityStoreTest : public testing::Test { - protected: - DtlsIdentityStoreTest() - : worker_thread_(new rtc::Thread()), - store_(new DtlsIdentityStoreImpl(rtc::Thread::Current(), - worker_thread_.get())), - observer_( - new rtc::RefCountedObject()) { - RTC_CHECK(worker_thread_->Start()); - } - ~DtlsIdentityStoreTest() {} - - static void SetUpTestCase() { - rtc::InitializeSSL(); - } - static void TearDownTestCase() { - rtc::CleanupSSL(); - } - - std::unique_ptr worker_thread_; - std::unique_ptr store_; - rtc::scoped_refptr observer_; -}; - -TEST_F(DtlsIdentityStoreTest, RequestIdentitySuccessRSA) { - store_->RequestIdentity(rtc::KeyParams(rtc::KT_RSA), - rtc::Optional(), - observer_.get()); - EXPECT_TRUE_WAIT(observer_->LastRequestSucceeded(), kTimeoutMs); - - EXPECT_TRUE_WAIT(store_->HasFreeIdentityForTesting(rtc::KT_RSA), kTimeoutMs); - - observer_->Reset(); - - // Verifies that the callback is async when a free identity is ready. - store_->RequestIdentity(rtc::KeyParams(rtc::KT_RSA), - rtc::Optional(), - observer_.get()); - EXPECT_FALSE(observer_->call_back_called()); - EXPECT_TRUE_WAIT(observer_->LastRequestSucceeded(), kTimeoutMs); -} - -TEST_F(DtlsIdentityStoreTest, RequestIdentitySuccessECDSA) { - store_->RequestIdentity(rtc::KeyParams(rtc::KT_ECDSA), - rtc::Optional(), - observer_.get()); - EXPECT_TRUE_WAIT(observer_->LastRequestSucceeded(), kTimeoutMs); - - // Since store currently does not preemptively generate free ECDSA identities - // we do not invoke HasFreeIdentityForTesting between requests. - - observer_->Reset(); - - // Verifies that the callback is async when a free identity is ready. - store_->RequestIdentity(rtc::KeyParams(rtc::KT_ECDSA), - rtc::Optional(), - observer_.get()); - EXPECT_FALSE(observer_->call_back_called()); - EXPECT_TRUE_WAIT(observer_->LastRequestSucceeded(), kTimeoutMs); -} - -TEST_F(DtlsIdentityStoreTest, DeleteStoreEarlyNoCrashRSA) { - EXPECT_FALSE(store_->HasFreeIdentityForTesting(rtc::KT_RSA)); - - store_->RequestIdentity(rtc::KeyParams(rtc::KT_RSA), - rtc::Optional(), - observer_.get()); - store_.reset(); - - worker_thread_->Stop(); - EXPECT_FALSE(observer_->call_back_called()); -} - -TEST_F(DtlsIdentityStoreTest, DeleteStoreEarlyNoCrashECDSA) { - EXPECT_FALSE(store_->HasFreeIdentityForTesting(rtc::KT_ECDSA)); - - store_->RequestIdentity(rtc::KeyParams(rtc::KT_ECDSA), - rtc::Optional(), - observer_.get()); - store_.reset(); - - worker_thread_->Stop(); - EXPECT_FALSE(observer_->call_back_called()); -} -