1 /*
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 
11 #include "rtc_base/rtc_certificate_generator.h"
12 
13 #include <time.h>
14 
15 #include <algorithm>
16 #include <memory>
17 #include <utility>
18 
19 #include "rtc_base/checks.h"
20 #include "rtc_base/location.h"
21 #include "rtc_base/message_handler.h"
22 #include "rtc_base/ref_counted_object.h"
23 #include "rtc_base/ssl_identity.h"
24 
25 namespace rtc {
26 
27 namespace {
28 
29 // A certificates' subject and issuer name.
30 const char kIdentityName[] = "WebRTC";
31 const uint64_t kYearInSeconds = 365 * 24 * 60 * 60;
32 
33 enum {
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.
42 class RTCCertificateGenerationTask : public RefCountInterface,
43                                      public MessageHandler {
44  public:
RTCCertificateGenerationTask(Thread * signaling_thread,Thread * worker_thread,const KeyParams & key_params,const absl::optional<uint64_t> & expires_ms,const scoped_refptr<RTCCertificateGeneratorCallback> & callback)45   RTCCertificateGenerationTask(
46       Thread* signaling_thread,
47       Thread* worker_thread,
48       const KeyParams& key_params,
49       const absl::optional<uint64_t>& expires_ms,
50       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   }
~RTCCertificateGenerationTask()60   ~RTCCertificateGenerationTask() override {}
61 
62   // Handles |MSG_GENERATE| and its follow-up |MSG_GENERATE_DONE|.
OnMessage(Message * msg)63   void OnMessage(Message* msg) override {
64     switch (msg->message_id) {
65       case MSG_GENERATE:
66         RTC_DCHECK(worker_thread_->IsCurrent());
67         // Perform the certificate generation work here on the worker thread.
68         certificate_ = RTCCertificateGenerator::GenerateCertificate(
69             key_params_, expires_ms_);
70         // Handle callbacks on signaling thread. Pass on the |msg->pdata|
71         // (which references |this| with ref counting) to that thread.
72         signaling_thread_->Post(RTC_FROM_HERE, this, MSG_GENERATE_DONE,
73                                 msg->pdata);
74         break;
75       case MSG_GENERATE_DONE:
76         RTC_DCHECK(signaling_thread_->IsCurrent());
77         // Perform callback with result here on the signaling thread.
78         if (certificate_) {
79           callback_->OnSuccess(certificate_);
80         } else {
81           callback_->OnFailure();
82         }
83         // 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_;
97   const absl::optional<uint64_t> expires_ms_;
98   const scoped_refptr<RTCCertificateGeneratorCallback> callback_;
99   scoped_refptr<RTCCertificate> certificate_;
100 };
101 
102 }  // namespace
103 
104 // static
GenerateCertificate(const KeyParams & key_params,const absl::optional<uint64_t> & expires_ms)105 scoped_refptr<RTCCertificate> RTCCertificateGenerator::GenerateCertificate(
106     const KeyParams& key_params,
107     const absl::optional<uint64_t>& expires_ms) {
108   if (!key_params.IsValid()) {
109     return nullptr;
110   }
111 
112   std::unique_ptr<SSLIdentity> identity;
113   if (!expires_ms) {
114     identity = SSLIdentity::Create(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);
126     identity = SSLIdentity::Create(kIdentityName, key_params, cert_lifetime_s);
127   }
128   if (!identity) {
129     return nullptr;
130   }
131   return RTCCertificate::Create(std::move(identity));
132 }
133 
RTCCertificateGenerator(Thread * signaling_thread,Thread * worker_thread)134 RTCCertificateGenerator::RTCCertificateGenerator(Thread* signaling_thread,
135                                                  Thread* worker_thread)
136     : signaling_thread_(signaling_thread), worker_thread_(worker_thread) {
137   RTC_DCHECK(signaling_thread_);
138   RTC_DCHECK(worker_thread_);
139 }
140 
GenerateCertificateAsync(const KeyParams & key_params,const absl::optional<uint64_t> & expires_ms,const scoped_refptr<RTCCertificateGeneratorCallback> & callback)141 void RTCCertificateGenerator::GenerateCertificateAsync(
142     const KeyParams& key_params,
143     const absl::optional<uint64_t>& expires_ms,
144     const scoped_refptr<RTCCertificateGeneratorCallback>& callback) {
145   RTC_DCHECK(signaling_thread_->IsCurrent());
146   RTC_DCHECK(callback);
147 
148   // Create a new |RTCCertificateGenerationTask| for this generation request. It
149   // is reference counted and referenced by the message data, ensuring it lives
150   // until the task has completed (independent of |RTCCertificateGenerator|).
151   ScopedRefMessageData<RTCCertificateGenerationTask>* msg_data =
152       new ScopedRefMessageData<RTCCertificateGenerationTask>(
153           new RefCountedObject<RTCCertificateGenerationTask>(
154               signaling_thread_, worker_thread_, key_params, expires_ms,
155               callback));
156   worker_thread_->Post(RTC_FROM_HERE, msg_data->data().get(), MSG_GENERATE,
157                        msg_data);
158 }
159 
160 }  // namespace rtc
161