blob: 2a84fbdb44f407f867cc3365840e5247a83b1e1f [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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "rtc_base/rtc_certificate_generator.h"
Henrik Boströmda3a1da2016-04-15 17:55:21 +020012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <time.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Henrik Boströmda3a1da2016-04-15 17:55:21 +020015#include <algorithm>
jbauch555604a2016-04-26 03:13:22 -070016#include <memory>
Yves Gerey988cc082018-10-23 12:03:01 +020017#include <utility>
Henrik Boströmda3a1da2016-04-15 17:55:21 +020018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/checks.h"
Yves Gerey988cc082018-10-23 12:03:01 +020020#include "rtc_base/location.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "rtc_base/message_handler.h"
22#include "rtc_base/message_queue.h"
23#include "rtc_base/ref_counted_object.h"
24#include "rtc_base/ssl_identity.h"
Henrik Boströmda3a1da2016-04-15 17:55:21 +020025
26namespace rtc {
27
28namespace {
29
30// A certificates' subject and issuer name.
31const char kIdentityName[] = "WebRTC";
agrieve26622d32017-08-08 10:48:15 -070032const uint64_t kYearInSeconds = 365 * 24 * 60 * 60;
Henrik Boströmda3a1da2016-04-15 17:55:21 +020033
34enum {
35 MSG_GENERATE,
36 MSG_GENERATE_DONE,
37};
38
39// Helper class for generating certificates asynchronously; a single task
40// instance is responsible for a single asynchronous certificate generation
41// request. We are using a separate helper class so that a generation request
42// can outlive the |RTCCertificateGenerator| that spawned it.
43class RTCCertificateGenerationTask : public RefCountInterface,
44 public MessageHandler {
45 public:
46 RTCCertificateGenerationTask(
47 Thread* signaling_thread,
48 Thread* worker_thread,
49 const KeyParams& key_params,
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020050 const absl::optional<uint64_t>& expires_ms,
Henrik Boströmda3a1da2016-04-15 17:55:21 +020051 const scoped_refptr<RTCCertificateGeneratorCallback>& callback)
52 : signaling_thread_(signaling_thread),
53 worker_thread_(worker_thread),
54 key_params_(key_params),
55 expires_ms_(expires_ms),
56 callback_(callback) {
57 RTC_DCHECK(signaling_thread_);
58 RTC_DCHECK(worker_thread_);
59 RTC_DCHECK(callback_);
60 }
61 ~RTCCertificateGenerationTask() override {}
62
63 // Handles |MSG_GENERATE| and its follow-up |MSG_GENERATE_DONE|.
64 void OnMessage(Message* msg) override {
65 switch (msg->message_id) {
66 case MSG_GENERATE:
67 RTC_DCHECK(worker_thread_->IsCurrent());
Henrik Boströmda3a1da2016-04-15 17:55:21 +020068 // Perform the certificate generation work here on the worker thread.
69 certificate_ = RTCCertificateGenerator::GenerateCertificate(
70 key_params_, expires_ms_);
Henrik Boströmda3a1da2016-04-15 17:55:21 +020071 // Handle callbacks on signaling thread. Pass on the |msg->pdata|
72 // (which references |this| with ref counting) to that thread.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070073 signaling_thread_->Post(RTC_FROM_HERE, this, MSG_GENERATE_DONE,
74 msg->pdata);
Henrik Boströmda3a1da2016-04-15 17:55:21 +020075 break;
76 case MSG_GENERATE_DONE:
77 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boströmda3a1da2016-04-15 17:55:21 +020078 // Perform callback with result here on the signaling thread.
79 if (certificate_) {
80 callback_->OnSuccess(certificate_);
81 } else {
82 callback_->OnFailure();
83 }
Henrik Boströmda3a1da2016-04-15 17:55:21 +020084 // Destroy |msg->pdata| which references |this| with ref counting. This
85 // may result in |this| being deleted - do not touch member variables
86 // after this line.
87 delete msg->pdata;
88 return;
89 default:
90 RTC_NOTREACHED();
91 }
92 }
93
94 private:
95 Thread* const signaling_thread_;
96 Thread* const worker_thread_;
97 const KeyParams key_params_;
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020098 const absl::optional<uint64_t> expires_ms_;
Henrik Boströmda3a1da2016-04-15 17:55:21 +020099 const scoped_refptr<RTCCertificateGeneratorCallback> callback_;
100 scoped_refptr<RTCCertificate> certificate_;
101};
102
103} // namespace
104
105// static
Yves Gerey665174f2018-06-19 15:03:05 +0200106scoped_refptr<RTCCertificate> RTCCertificateGenerator::GenerateCertificate(
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200107 const KeyParams& key_params,
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200108 const absl::optional<uint64_t>& expires_ms) {
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700109 if (!key_params.IsValid()) {
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200110 return nullptr;
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700111 }
112
113 SSLIdentity* identity = nullptr;
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200114 if (!expires_ms) {
115 identity = SSLIdentity::Generate(kIdentityName, key_params);
116 } else {
117 uint64_t expires_s = *expires_ms / 1000;
118 // Limit the expiration time to something reasonable (a year). This was
119 // somewhat arbitrarily chosen. It also ensures that the value is not too
120 // large for the unspecified |time_t|.
121 expires_s = std::min(expires_s, kYearInSeconds);
122 // TODO(torbjorng): Stop using |time_t|, its type is unspecified. It it safe
123 // to assume it can hold up to a year's worth of seconds (and more), but
124 // |SSLIdentity::Generate| should stop relying on |time_t|.
125 // See bugs.webrtc.org/5720.
126 time_t cert_lifetime_s = static_cast<time_t>(expires_s);
Yves Gerey665174f2018-06-19 15:03:05 +0200127 identity = SSLIdentity::GenerateWithExpiration(kIdentityName, key_params,
128 cert_lifetime_s);
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200129 }
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700130 if (!identity) {
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200131 return nullptr;
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700132 }
jbauch555604a2016-04-26 03:13:22 -0700133 std::unique_ptr<SSLIdentity> identity_sptr(identity);
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200134 return RTCCertificate::Create(std::move(identity_sptr));
135}
136
Yves Gerey665174f2018-06-19 15:03:05 +0200137RTCCertificateGenerator::RTCCertificateGenerator(Thread* signaling_thread,
138 Thread* worker_thread)
139 : signaling_thread_(signaling_thread), worker_thread_(worker_thread) {
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200140 RTC_DCHECK(signaling_thread_);
141 RTC_DCHECK(worker_thread_);
142}
143
144void RTCCertificateGenerator::GenerateCertificateAsync(
145 const KeyParams& key_params,
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200146 const absl::optional<uint64_t>& expires_ms,
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200147 const scoped_refptr<RTCCertificateGeneratorCallback>& callback) {
148 RTC_DCHECK(signaling_thread_->IsCurrent());
149 RTC_DCHECK(callback);
150
151 // Create a new |RTCCertificateGenerationTask| for this generation request. It
152 // is reference counted and referenced by the message data, ensuring it lives
153 // until the task has completed (independent of |RTCCertificateGenerator|).
154 ScopedRefMessageData<RTCCertificateGenerationTask>* msg_data =
155 new ScopedRefMessageData<RTCCertificateGenerationTask>(
156 new RefCountedObject<RTCCertificateGenerationTask>(
157 signaling_thread_, worker_thread_, key_params, expires_ms,
158 callback));
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700159 worker_thread_->Post(RTC_FROM_HERE, msg_data->data().get(), MSG_GENERATE,
160 msg_data);
Henrik Boströmda3a1da2016-04-15 17:55:21 +0200161}
162
163} // namespace rtc