blob: bdccc10c1b03469a5995a047aae2198a83ba861b [file] [log] [blame]
jiayl@webrtc.org25484062015-02-18 23:58:16 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
jiayl@webrtc.org25484062015-02-18 23:58:16 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
jiayl@webrtc.org25484062015-02-18 23:58:16 +00009 */
10
Henrik Kjellander15583c12016-02-10 10:53:12 +010011#include "webrtc/api/dtlsidentitystore.h"
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000012
kwiberg0eb15ed2015-12-17 03:04:15 -080013#include <utility>
14
Henrik Kjellander15583c12016-02-10 10:53:12 +010015#include "webrtc/api/webrtcsessiondescriptionfactory.h"
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000016#include "webrtc/base/logging.h"
17
Henrik Boström5e56c592015-08-11 10:33:13 +020018using webrtc::DtlsIdentityRequestObserver;
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000019
20namespace webrtc {
21
Henrik Boström5e56c592015-08-11 10:33:13 +020022// Passed to SSLIdentity::Generate, "WebRTC". Used for the certificates'
23// subject and issuer name.
glaznev97579a42015-09-01 11:31:27 -070024const char kIdentityName[] = "WebRTC";
Henrik Boström5e56c592015-08-11 10:33:13 +020025
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000026namespace {
27
28enum {
Jiayang Liud61ebda2015-04-08 12:34:49 -070029 MSG_DESTROY,
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000030 MSG_GENERATE_IDENTITY,
Henrik Boström5e56c592015-08-11 10:33:13 +020031 MSG_GENERATE_IDENTITY_RESULT
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000032};
33
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000034} // namespace
35
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000036// This class runs on the worker thread to generate the identity. It's necessary
37// to separate this class from DtlsIdentityStore so that it can live on the
38// worker thread after DtlsIdentityStore is destroyed.
Henrik Boström5e56c592015-08-11 10:33:13 +020039class DtlsIdentityStoreImpl::WorkerTask : public sigslot::has_slots<>,
40 public rtc::MessageHandler {
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000041 public:
Henrik Boström5e56c592015-08-11 10:33:13 +020042 WorkerTask(DtlsIdentityStoreImpl* store, rtc::KeyType key_type)
43 : signaling_thread_(rtc::Thread::Current()),
44 store_(store),
45 key_type_(key_type) {
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000046 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed);
Tommi532caea2015-06-09 17:33:06 +020047 }
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000048
henrikg91d6ede2015-09-17 00:24:34 -070049 virtual ~WorkerTask() { RTC_DCHECK(signaling_thread_->IsCurrent()); }
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000050
Tommi532caea2015-06-09 17:33:06 +020051 private:
52 void GenerateIdentity_w() {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020053 LOG(LS_INFO) << "Generating identity, using keytype " << key_type_;
jbauch555604a2016-04-26 03:13:22 -070054 std::unique_ptr<rtc::SSLIdentity> identity(
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020055 rtc::SSLIdentity::Generate(kIdentityName, key_type_));
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000056
Henrik Boström5e56c592015-08-11 10:33:13 +020057 // Posting to |this| avoids touching |store_| on threads other than
58 // |signaling_thread_| and thus avoids having to use locks.
59 IdentityResultMessageData* msg = new IdentityResultMessageData(
kwiberg0eb15ed2015-12-17 03:04:15 -080060 new IdentityResult(key_type_, std::move(identity)));
Henrik Boström5e56c592015-08-11 10:33:13 +020061 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000062 }
63
64 void OnMessage(rtc::Message* msg) override {
Jiayang Liud61ebda2015-04-08 12:34:49 -070065 switch (msg->message_id) {
66 case MSG_GENERATE_IDENTITY:
Tommi532caea2015-06-09 17:33:06 +020067 // This message always runs on the worker thread.
68 GenerateIdentity_w();
Jiayang Liud61ebda2015-04-08 12:34:49 -070069
70 // Must delete |this|, owned by msg->pdata, on the signaling thread to
71 // avoid races on disconnecting the signal.
72 signaling_thread_->Post(this, MSG_DESTROY, msg->pdata);
73 break;
Henrik Boström5e56c592015-08-11 10:33:13 +020074 case MSG_GENERATE_IDENTITY_RESULT:
henrikg91d6ede2015-09-17 00:24:34 -070075 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström5e56c592015-08-11 10:33:13 +020076 {
kwibergd1fe2812016-04-27 06:47:29 -070077 std::unique_ptr<IdentityResultMessageData> pdata(
Henrik Boström5e56c592015-08-11 10:33:13 +020078 static_cast<IdentityResultMessageData*>(msg->pdata));
79 if (store_) {
80 store_->OnIdentityGenerated(pdata->data()->key_type_,
kwiberg0eb15ed2015-12-17 03:04:15 -080081 std::move(pdata->data()->identity_));
Henrik Boström5e56c592015-08-11 10:33:13 +020082 }
83 }
84 break;
Jiayang Liud61ebda2015-04-08 12:34:49 -070085 case MSG_DESTROY:
henrikg91d6ede2015-09-17 00:24:34 -070086 RTC_DCHECK(signaling_thread_->IsCurrent());
Jiayang Liud61ebda2015-04-08 12:34:49 -070087 delete msg->pdata;
Tommi532caea2015-06-09 17:33:06 +020088 // |this| has now been deleted. Don't touch member variables.
Jiayang Liud61ebda2015-04-08 12:34:49 -070089 break;
90 default:
henrikg91d6ede2015-09-17 00:24:34 -070091 RTC_CHECK(false) << "Unexpected message type";
Jiayang Liud61ebda2015-04-08 12:34:49 -070092 }
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000093 }
94
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000095 void OnStoreDestroyed() {
henrikg91d6ede2015-09-17 00:24:34 -070096 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström5e56c592015-08-11 10:33:13 +020097 store_ = nullptr;
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +000098 }
99
Tommi532caea2015-06-09 17:33:06 +0200100 rtc::Thread* const signaling_thread_;
Henrik Boström5e56c592015-08-11 10:33:13 +0200101 DtlsIdentityStoreImpl* store_; // Only touched on |signaling_thread_|.
102 const rtc::KeyType key_type_;
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +0000103};
104
Henrik Boström5e56c592015-08-11 10:33:13 +0200105DtlsIdentityStoreImpl::DtlsIdentityStoreImpl(rtc::Thread* signaling_thread,
106 rtc::Thread* worker_thread)
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000107 : signaling_thread_(signaling_thread),
108 worker_thread_(worker_thread),
Henrik Boström5e56c592015-08-11 10:33:13 +0200109 request_info_() {
henrikg91d6ede2015-09-17 00:24:34 -0700110 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström5e56c592015-08-11 10:33:13 +0200111}
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000112
Henrik Boström5e56c592015-08-11 10:33:13 +0200113DtlsIdentityStoreImpl::~DtlsIdentityStoreImpl() {
henrikg91d6ede2015-09-17 00:24:34 -0700114 RTC_DCHECK(signaling_thread_->IsCurrent());
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +0000115 SignalDestroyed();
116}
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000117
Henrik Boström5e56c592015-08-11 10:33:13 +0200118void DtlsIdentityStoreImpl::RequestIdentity(
hbos52913932016-03-07 15:14:40 -0800119 const rtc::KeyParams& key_params,
120 const rtc::Optional<uint64_t>& expires_ms,
hbos25359e02016-03-02 07:55:53 -0800121 const rtc::scoped_refptr<DtlsIdentityRequestObserver>& observer) {
henrikg91d6ede2015-09-17 00:24:34 -0700122 RTC_DCHECK(signaling_thread_->IsCurrent());
123 RTC_DCHECK(observer);
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000124
hbos52913932016-03-07 15:14:40 -0800125 // Dropping parameterization and |expires_ms|.
hbos25359e02016-03-02 07:55:53 -0800126 // TODO(hbos,torbjorng): Use parameterizaton/expiration. webrtc:5092.
127 GenerateIdentity(key_params.type(), observer);
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000128}
129
Henrik Boström5e56c592015-08-11 10:33:13 +0200130void DtlsIdentityStoreImpl::OnMessage(rtc::Message* msg) {
henrikg91d6ede2015-09-17 00:24:34 -0700131 RTC_DCHECK(signaling_thread_->IsCurrent());
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000132 switch (msg->message_id) {
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000133 case MSG_GENERATE_IDENTITY_RESULT: {
kwibergd1fe2812016-04-27 06:47:29 -0700134 std::unique_ptr<IdentityResultMessageData> pdata(
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000135 static_cast<IdentityResultMessageData*>(msg->pdata));
Henrik Boström5e56c592015-08-11 10:33:13 +0200136 OnIdentityGenerated(pdata->data()->key_type_,
kwiberg0eb15ed2015-12-17 03:04:15 -0800137 std::move(pdata->data()->identity_));
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000138 break;
139 }
140 }
141}
142
Henrik Boström5e56c592015-08-11 10:33:13 +0200143bool DtlsIdentityStoreImpl::HasFreeIdentityForTesting(
144 rtc::KeyType key_type) const {
henrikg91d6ede2015-09-17 00:24:34 -0700145 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström5e56c592015-08-11 10:33:13 +0200146 return request_info_[key_type].free_identity_.get() != nullptr;
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000147}
148
Henrik Boström5e56c592015-08-11 10:33:13 +0200149void DtlsIdentityStoreImpl::GenerateIdentity(
150 rtc::KeyType key_type,
151 const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
henrikg91d6ede2015-09-17 00:24:34 -0700152 RTC_DCHECK(signaling_thread_->IsCurrent());
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +0000153
Henrik Boström5e56c592015-08-11 10:33:13 +0200154 // Enqueue observer to be informed when generation of |key_type| is completed.
155 if (observer.get()) {
156 request_info_[key_type].request_observers_.push(observer);
157
158 // Already have a free identity generated?
159 if (request_info_[key_type].free_identity_.get()) {
160 // Return identity async - post even though we are on |signaling_thread_|.
161 LOG(LS_VERBOSE) << "Using a free DTLS identity.";
162 ++request_info_[key_type].gen_in_progress_counts_;
kwiberg0eb15ed2015-12-17 03:04:15 -0800163 IdentityResultMessageData* msg =
164 new IdentityResultMessageData(new IdentityResult(
165 key_type, std::move(request_info_[key_type].free_identity_)));
Henrik Boström5e56c592015-08-11 10:33:13 +0200166 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
167 return;
168 }
169
170 // Free identity in the process of being generated?
171 if (request_info_[key_type].gen_in_progress_counts_ ==
172 request_info_[key_type].request_observers_.size()) {
173 // No need to do anything, the free identity will be returned to the
174 // observer in a MSG_GENERATE_IDENTITY_RESULT.
175 return;
176 }
177 }
178
179 // Enqueue/Post a worker task to do the generation.
180 ++request_info_[key_type].gen_in_progress_counts_;
181 WorkerTask* task = new WorkerTask(this, key_type); // Post 1 task/request.
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +0000182 // The WorkerTask is owned by the message data to make sure it will not be
183 // leaked even if the task does not get run.
Henrik Boström5e56c592015-08-11 10:33:13 +0200184 WorkerTaskMessageData* msg = new WorkerTaskMessageData(task);
jiayl@webrtc.orgd83f4ef2015-03-13 21:26:12 +0000185 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg);
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000186}
187
Henrik Boström5e56c592015-08-11 10:33:13 +0200188void DtlsIdentityStoreImpl::OnIdentityGenerated(
jbauch555604a2016-04-26 03:13:22 -0700189 rtc::KeyType key_type,
190 std::unique_ptr<rtc::SSLIdentity> identity) {
henrikg91d6ede2015-09-17 00:24:34 -0700191 RTC_DCHECK(signaling_thread_->IsCurrent());
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000192
henrikg91d6ede2015-09-17 00:24:34 -0700193 RTC_DCHECK(request_info_[key_type].gen_in_progress_counts_);
Henrik Boström5e56c592015-08-11 10:33:13 +0200194 --request_info_[key_type].gen_in_progress_counts_;
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000195
Henrik Boström5e56c592015-08-11 10:33:13 +0200196 rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver> observer;
197 if (!request_info_[key_type].request_observers_.empty()) {
198 observer = request_info_[key_type].request_observers_.front();
199 request_info_[key_type].request_observers_.pop();
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000200 }
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000201
Henrik Boström5e56c592015-08-11 10:33:13 +0200202 if (observer.get() == nullptr) {
203 // No observer - store result in |free_identities_|.
henrikg91d6ede2015-09-17 00:24:34 -0700204 RTC_DCHECK(!request_info_[key_type].free_identity_.get());
Henrik Boström5e56c592015-08-11 10:33:13 +0200205 request_info_[key_type].free_identity_.swap(identity);
206 if (request_info_[key_type].free_identity_.get())
207 LOG(LS_VERBOSE) << "A free DTLS identity was saved.";
208 else
209 LOG(LS_WARNING) << "Failed to generate DTLS identity (preemptively).";
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000210 } else {
Henrik Boström5e56c592015-08-11 10:33:13 +0200211 // Return the result to the observer.
212 if (identity.get()) {
213 LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer.";
kwiberg0eb15ed2015-12-17 03:04:15 -0800214 observer->OnSuccess(std::move(identity));
Henrik Boström5e56c592015-08-11 10:33:13 +0200215 } else {
216 LOG(LS_WARNING) << "Failed to generate DTLS identity.";
217 observer->OnFailure(0);
218 }
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000219
Henrik Boström5e56c592015-08-11 10:33:13 +0200220 // Preemptively generate another identity of the same type?
221 if (worker_thread_ != signaling_thread_ && // Only do in background thread.
222 key_type == rtc::KT_RSA && // Only necessary for RSA.
223 !request_info_[key_type].free_identity_.get() &&
Taylor Brandstetter9cb23a32016-04-25 17:39:28 -0700224 request_info_[key_type].request_observers_.size() ==
Henrik Boström5e56c592015-08-11 10:33:13 +0200225 request_info_[key_type].gen_in_progress_counts_) {
226 GenerateIdentity(key_type, nullptr);
227 }
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000228 }
229}
230
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000231} // namespace webrtc