Index: webrtc/base/rtccertificategenerator.cc |
diff --git a/webrtc/base/rtccertificategenerator.cc b/webrtc/base/rtccertificategenerator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a2d6870587490fe4e6c170be4ca9c85d6d3b6824 |
--- /dev/null |
+++ b/webrtc/base/rtccertificategenerator.cc |
@@ -0,0 +1,156 @@ |
+/* |
+ * 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 "webrtc/base/rtccertificategenerator.h" |
+ |
+#include "webrtc/base/checks.h" |
+#include "webrtc/base/sslidentity.h" |
+ |
+namespace rtc { |
+ |
+namespace { |
+ |
+// A certificates' subject and issuer name. |
+const char kIdentityName[] = "WebRTC"; |
+ |
+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 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(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 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 Optional<uint64_t>& expires_ms) { |
+ if (!key_params.IsValid()) |
+ return nullptr; |
+ SSLIdentity* identity; |
+ 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|. |
+ if (expires_s > kYearInSeconds) |
torbjorng (webrtc)
2016/04/15 12:17:48
Consider using std::max.
hbos
2016/04/15 13:24:14
Done. (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; |
+ scoped_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 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(msg_data->data().get(), MSG_GENERATE, msg_data); |
+} |
+ |
+} // namespace rtc |