| /* |
| * Copyright 2016 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 "rtc_base/rtc_certificate_generator.h" |
| |
| #include <time.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <utility> |
| |
| #include "rtc_base/checks.h" |
| #include "rtc_base/location.h" |
| #include "rtc_base/message_handler.h" |
| #include "rtc_base/ref_counted_object.h" |
| #include "rtc_base/ssl_identity.h" |
| |
| namespace rtc { |
| |
| namespace { |
| |
| // A certificates' subject and issuer name. |
| const char kIdentityName[] = "WebRTC"; |
| const uint64_t kYearInSeconds = 365 * 24 * 60 * 60; |
| |
| enum { |
| MSG_GENERATE, |
| MSG_GENERATE_DONE, |
| }; |
| |
| // Helper class for generating certificates asynchronously; a single task |
| // instance is responsible for a single asynchronous certificate generation |
| // request. We are using a separate helper class so that a generation request |
| // can outlive the |RTCCertificateGenerator| that spawned it. |
| class RTCCertificateGenerationTask : public RefCountInterface, |
| public MessageHandler { |
| public: |
| RTCCertificateGenerationTask( |
| Thread* signaling_thread, |
| Thread* worker_thread, |
| const KeyParams& key_params, |
| const absl::optional<uint64_t>& expires_ms, |
| const scoped_refptr<RTCCertificateGeneratorCallback>& callback) |
| : signaling_thread_(signaling_thread), |
| worker_thread_(worker_thread), |
| key_params_(key_params), |
| expires_ms_(expires_ms), |
| callback_(callback) { |
| RTC_DCHECK(signaling_thread_); |
| RTC_DCHECK(worker_thread_); |
| RTC_DCHECK(callback_); |
| } |
| ~RTCCertificateGenerationTask() override {} |
| |
| // Handles |MSG_GENERATE| and its follow-up |MSG_GENERATE_DONE|. |
| void OnMessage(Message* msg) override { |
| switch (msg->message_id) { |
| case MSG_GENERATE: |
| RTC_DCHECK(worker_thread_->IsCurrent()); |
| // Perform the certificate generation work here on the worker thread. |
| certificate_ = RTCCertificateGenerator::GenerateCertificate( |
| key_params_, expires_ms_); |
| // Handle callbacks on signaling thread. Pass on the |msg->pdata| |
| // (which references |this| with ref counting) to that thread. |
| signaling_thread_->Post(RTC_FROM_HERE, this, MSG_GENERATE_DONE, |
| msg->pdata); |
| break; |
| case MSG_GENERATE_DONE: |
| RTC_DCHECK(signaling_thread_->IsCurrent()); |
| // Perform callback with result here on the signaling thread. |
| if (certificate_) { |
| callback_->OnSuccess(certificate_); |
| } else { |
| callback_->OnFailure(); |
| } |
| // Destroy |msg->pdata| which references |this| with ref counting. This |
| // may result in |this| being deleted - do not touch member variables |
| // after this line. |
| delete msg->pdata; |
| return; |
| default: |
| RTC_NOTREACHED(); |
| } |
| } |
| |
| private: |
| Thread* const signaling_thread_; |
| Thread* const worker_thread_; |
| const KeyParams key_params_; |
| const absl::optional<uint64_t> expires_ms_; |
| const scoped_refptr<RTCCertificateGeneratorCallback> callback_; |
| scoped_refptr<RTCCertificate> certificate_; |
| }; |
| |
| } // namespace |
| |
| // static |
| scoped_refptr<RTCCertificate> RTCCertificateGenerator::GenerateCertificate( |
| const KeyParams& key_params, |
| const absl::optional<uint64_t>& expires_ms) { |
| if (!key_params.IsValid()) { |
| return nullptr; |
| } |
| |
| SSLIdentity* identity = nullptr; |
| if (!expires_ms) { |
| identity = SSLIdentity::Generate(kIdentityName, key_params); |
| } else { |
| uint64_t expires_s = *expires_ms / 1000; |
| // Limit the expiration time to something reasonable (a year). This was |
| // somewhat arbitrarily chosen. It also ensures that the value is not too |
| // large for the unspecified |time_t|. |
| expires_s = std::min(expires_s, kYearInSeconds); |
| // TODO(torbjorng): Stop using |time_t|, its type is unspecified. It it safe |
| // to assume it can hold up to a year's worth of seconds (and more), but |
| // |SSLIdentity::Generate| should stop relying on |time_t|. |
| // See bugs.webrtc.org/5720. |
| time_t cert_lifetime_s = static_cast<time_t>(expires_s); |
| identity = SSLIdentity::GenerateWithExpiration(kIdentityName, key_params, |
| cert_lifetime_s); |
| } |
| if (!identity) { |
| return nullptr; |
| } |
| std::unique_ptr<SSLIdentity> identity_sptr(identity); |
| return RTCCertificate::Create(std::move(identity_sptr)); |
| } |
| |
| RTCCertificateGenerator::RTCCertificateGenerator(Thread* signaling_thread, |
| Thread* worker_thread) |
| : signaling_thread_(signaling_thread), worker_thread_(worker_thread) { |
| RTC_DCHECK(signaling_thread_); |
| RTC_DCHECK(worker_thread_); |
| } |
| |
| void RTCCertificateGenerator::GenerateCertificateAsync( |
| const KeyParams& key_params, |
| const absl::optional<uint64_t>& expires_ms, |
| const scoped_refptr<RTCCertificateGeneratorCallback>& callback) { |
| RTC_DCHECK(signaling_thread_->IsCurrent()); |
| RTC_DCHECK(callback); |
| |
| // Create a new |RTCCertificateGenerationTask| for this generation request. It |
| // is reference counted and referenced by the message data, ensuring it lives |
| // until the task has completed (independent of |RTCCertificateGenerator|). |
| ScopedRefMessageData<RTCCertificateGenerationTask>* msg_data = |
| new ScopedRefMessageData<RTCCertificateGenerationTask>( |
| new RefCountedObject<RTCCertificateGenerationTask>( |
| signaling_thread_, worker_thread_, key_params, expires_ms, |
| callback)); |
| worker_thread_->Post(RTC_FROM_HERE, msg_data->data().get(), MSG_GENERATE, |
| msg_data); |
| } |
| |
| } // namespace rtc |