blob: 114b35c6658fcc9e55725e7a3444549bc12df896 [file] [log] [blame]
Henrik Boströmda3a1da2016-04-15 17:55:21 +02001/*
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * 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.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/rtccertificategenerator.h"
Henrik Boströmda3a1da2016-04-15 17:55:21 +020012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <time.h>
Henrik Boströmda3a1da2016-04-15 17:55:21 +020014#include <algorithm>
jbauch555604a2016-04-26 03:13:22 -070015#include <memory>
Yves Gerey988cc082018-10-23 12:03:01 +020016#include <utility>
Henrik Boströmda3a1da2016-04-15 17:55:21 +020017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/checks.h"
Yves Gerey988cc082018-10-23 12:03:01 +020019#include "rtc_base/location.h"
20#include "rtc_base/messagehandler.h"
21#include "rtc_base/messagequeue.h"
Niels Möller84255bb2017-10-06 13:43:23 +020022#include "rtc_base/refcountedobject.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/sslidentity.h"
Henrik Boströmda3a1da2016-04-15 17:55:21 +020024
25namespace rtc {
26
27namespace {
28
29// A certificates' subject and issuer name.
30const char kIdentityName[] = "WebRTC";
agrieve26622d32017-08-08 10:48:15 -070031const uint64_t kYearInSeconds = 365 * 24 * 60 * 60;
Henrik Boströmda3a1da2016-04-15 17:55:21 +020032
33enum {
34 MSG_GENERATE,
35 MSG_GENERATE_DONE,
36};
37
38// Helper class for generating certificates asynchronously; a single task
39// instance is responsible for a single asynchronous certificate generation
40// request. We are using a separate helper class so that a generation request
41// can outlive the |RTCCertificateGenerator| that spawned it.
42class RTCCertificateGenerationTask : public RefCountInterface,
43 public MessageHandler {
44 public:
45 RTCCertificateGenerationTask(
46 Thread* signaling_thread,
47 Thread* worker_thread,
48 const KeyParams& key_params,
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020049 const absl::optional<uint64_t>& expires_ms,
Henrik Boströmda3a1da2016-04-15 17:55:21 +020050 const scoped_refptr<RTCCertificateGeneratorCallback>& callback)
51 : signaling_thread_(signaling_thread),
52 worker_thread_(worker_thread),
53 key_params_(key_params),
54 expires_ms_(expires_ms),
55 callback_(callback) {
56 RTC_DCHECK(signaling_thread_);
57 RTC_DCHECK(worker_thread_);
58 RTC_DCHECK(callback_);
59 }
60 ~RTCCertificateGenerationTask() override {}
61
62 // Handles |MSG_GENERATE| and its follow-up |MSG_GENERATE_DONE|.
63 void OnMessage(Message* msg) override {
64 switch (msg->message_id) {
65 case MSG_GENERATE:
66 RTC_DCHECK(worker_thread_->IsCurrent());
Henrik Boströmda3a1da2016-04-15 17:55:21 +020067 // Perform the certificate generation work here on the worker thread.
68 certificate_ = RTCCertificateGenerator::GenerateCertificate(
69 key_params_, expires_ms_);
Henrik Boströmda3a1da2016-04-15 17:55:21 +020070 // Handle callbacks on signaling thread. Pass on the |msg->pdata|
71 // (which references |this| with ref counting) to that thread.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070072 signaling_thread_->Post(RTC_FROM_HERE, this, MSG_GENERATE_DONE,
73 msg->pdata);
Henrik Boströmda3a1da2016-04-15 17:55:21 +020074 break;
75 case MSG_GENERATE_DONE:
76 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boströmda3a1da2016-04-15 17:55:21 +020077 // Perform callback with result here on the signaling thread.
78 if (certificate_) {
79 callback_->OnSuccess(certificate_);
80 } else {
81 callback_->OnFailure();
82 }
Henrik Boströmda3a1da2016-04-15 17:55:21 +020083 // Destroy |msg->pdata| which references |this| with ref counting. This
84 // may result in |this| being deleted - do not touch member variables
85 // after this line.
86 delete msg->pdata;
87 return;
88 default:
89 RTC_NOTREACHED();
90 }
91 }
92
93 private:
94 Thread* const signaling_thread_;
95 Thread* const worker_thread_;
96 const KeyParams key_params_;
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020097 const absl::optional<uint64_t> expires_ms_;
Henrik Boströmda3a1da2016-04-15 17:55:21 +020098 const scoped_refptr<RTCCertificateGeneratorCallback> callback_;
99 scoped_refptr<RTCCertificate> certificate_;
100};
101
102} // namespace
103
104// static
Yves Gerey665174f2018-06-19 15:03:05 +0200105scoped_refptr<RTCCertificate> RTCCertificateGenerator::GenerateCertificate(
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200106 const KeyParams& key_params,
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200107 const absl::optional<uint64_t>& expires_ms) {
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700108 if (!key_params.IsValid()) {
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200109 return nullptr;
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700110 }
111
112 SSLIdentity* identity = nullptr;
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200113 if (!expires_ms) {
114 identity = SSLIdentity::Generate(kIdentityName, key_params);
115 } else {
116 uint64_t expires_s = *expires_ms / 1000;
117 // Limit the expiration time to something reasonable (a year). This was
118 // somewhat arbitrarily chosen. It also ensures that the value is not too
119 // large for the unspecified |time_t|.
120 expires_s = std::min(expires_s, kYearInSeconds);
121 // TODO(torbjorng): Stop using |time_t|, its type is unspecified. It it safe
122 // to assume it can hold up to a year's worth of seconds (and more), but
123 // |SSLIdentity::Generate| should stop relying on |time_t|.
124 // See bugs.webrtc.org/5720.
125 time_t cert_lifetime_s = static_cast<time_t>(expires_s);
Yves Gerey665174f2018-06-19 15:03:05 +0200126 identity = SSLIdentity::GenerateWithExpiration(kIdentityName, key_params,
127 cert_lifetime_s);
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200128 }
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700129 if (!identity) {
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200130 return nullptr;
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700131 }
jbauch555604a2016-04-26 03:13:22 -0700132 std::unique_ptr<SSLIdentity> identity_sptr(identity);
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200133 return RTCCertificate::Create(std::move(identity_sptr));
134}
135
Yves Gerey665174f2018-06-19 15:03:05 +0200136RTCCertificateGenerator::RTCCertificateGenerator(Thread* signaling_thread,
137 Thread* worker_thread)
138 : signaling_thread_(signaling_thread), worker_thread_(worker_thread) {
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200139 RTC_DCHECK(signaling_thread_);
140 RTC_DCHECK(worker_thread_);
141}
142
143void RTCCertificateGenerator::GenerateCertificateAsync(
144 const KeyParams& key_params,
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200145 const absl::optional<uint64_t>& expires_ms,
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200146 const scoped_refptr<RTCCertificateGeneratorCallback>& callback) {
147 RTC_DCHECK(signaling_thread_->IsCurrent());
148 RTC_DCHECK(callback);
149
150 // Create a new |RTCCertificateGenerationTask| for this generation request. It
151 // is reference counted and referenced by the message data, ensuring it lives
152 // until the task has completed (independent of |RTCCertificateGenerator|).
153 ScopedRefMessageData<RTCCertificateGenerationTask>* msg_data =
154 new ScopedRefMessageData<RTCCertificateGenerationTask>(
155 new RefCountedObject<RTCCertificateGenerationTask>(
156 signaling_thread_, worker_thread_, key_params, expires_ms,
157 callback));
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700158 worker_thread_->Post(RTC_FROM_HERE, msg_data->data().get(), MSG_GENERATE,
159 msg_data);
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200160}
161
162} // namespace rtc