1/*
2 * libjingle
3 * Copyright 2015 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef TALK_APP_WEBRTC_DTLSIDENTITYSTORE_H_
29#define TALK_APP_WEBRTC_DTLSIDENTITYSTORE_H_
30
31#include <queue>
32#include <string>
33#include <utility>
34
35#include "webrtc/base/messagehandler.h"
36#include "webrtc/base/messagequeue.h"
37#include "webrtc/base/refcount.h"
38#include "webrtc/base/scoped_ptr.h"
39#include "webrtc/base/scoped_ref_ptr.h"
40#include "webrtc/base/sslidentity.h"
41#include "webrtc/base/thread.h"
42
43namespace webrtc {
44
45// Passed to SSLIdentity::Generate.
46extern const char kIdentityName[];
47
48class SSLIdentity;
49class Thread;
50
51// Used to receive callbacks of DTLS identity requests.
52class DtlsIdentityRequestObserver : public rtc::RefCountInterface {
53 public:
54  virtual void OnFailure(int error) = 0;
55  // TODO(hbos): Unify the OnSuccess method once Chrome code is updated.
56  virtual void OnSuccess(const std::string& der_cert,
57                         const std::string& der_private_key) = 0;
58  // |identity| is a scoped_ptr because rtc::SSLIdentity is not copyable and the
59  // client has to get the ownership of the object to make use of it.
60  virtual void OnSuccess(rtc::scoped_ptr<rtc::SSLIdentity> identity) = 0;
61
62 protected:
63  virtual ~DtlsIdentityRequestObserver() {}
64};
65
66// This interface defines an in-memory DTLS identity store, which generates DTLS
67// identities.
68// APIs calls must be made on the signaling thread and the callbacks are also
69// called on the signaling thread.
70class DtlsIdentityStoreInterface {
71 public:
72  virtual ~DtlsIdentityStoreInterface() { }
73
74  // The |observer| will be called when the requested identity is ready, or when
75  // identity generation fails.
76  // TODO(torbjorng,hbos): The following RequestIdentity is about to be removed,
77  // see below todo.
78  virtual void RequestIdentity(
79      rtc::KeyType key_type,
80      const rtc::scoped_refptr<DtlsIdentityRequestObserver>& observer) {
81    // Add default parameterization.
82    RequestIdentity(rtc::KeyParams(key_type), observer);
83  }
84  // TODO(torbjorng,hbos): Parameterized key types! The following
85  // RequestIdentity should replace the old one that takes rtc::KeyType. When
86  // the new one is implemented by Chromium and WebRTC the old one should be
87  // removed. crbug.com/544902, webrtc:5092.
88  virtual void RequestIdentity(
89      rtc::KeyParams key_params,
90      const rtc::scoped_refptr<DtlsIdentityRequestObserver>& observer) {
91    // Drop parameterization.
92    RequestIdentity(key_params.type(), observer);
93  }
94};
95
96// The WebRTC default implementation of DtlsIdentityStoreInterface.
97// Identity generation is performed on the worker thread.
98class DtlsIdentityStoreImpl : public DtlsIdentityStoreInterface,
99                              public rtc::MessageHandler {
100 public:
101  // This will start to preemptively generating an RSA identity in the
102  // background if the worker thread is not the same as the signaling thread.
103  DtlsIdentityStoreImpl(rtc::Thread* signaling_thread,
104                        rtc::Thread* worker_thread);
105  ~DtlsIdentityStoreImpl() override;
106
107  // DtlsIdentityStoreInterface override;
108  void RequestIdentity(
109      rtc::KeyType key_type,
110      const rtc::scoped_refptr<DtlsIdentityRequestObserver>& observer) override;
111
112  // rtc::MessageHandler override;
113  void OnMessage(rtc::Message* msg) override;
114
115  // Returns true if there is a free RSA identity, used for unit tests.
116  bool HasFreeIdentityForTesting(rtc::KeyType key_type) const;
117
118 private:
119  void GenerateIdentity(
120      rtc::KeyType key_type,
121      const rtc::scoped_refptr<DtlsIdentityRequestObserver>& observer);
122  void OnIdentityGenerated(rtc::KeyType key_type,
123                           rtc::scoped_ptr<rtc::SSLIdentity> identity);
124
125  class WorkerTask;
126  typedef rtc::ScopedMessageData<DtlsIdentityStoreImpl::WorkerTask>
127      WorkerTaskMessageData;
128
129  // A key type-identity pair.
130  struct IdentityResult {
131    IdentityResult(rtc::KeyType key_type,
132                   rtc::scoped_ptr<rtc::SSLIdentity> identity)
133        : key_type_(key_type), identity_(std::move(identity)) {}
134
135    rtc::KeyType key_type_;
136    rtc::scoped_ptr<rtc::SSLIdentity> identity_;
137  };
138
139  typedef rtc::ScopedMessageData<IdentityResult> IdentityResultMessageData;
140
141  sigslot::signal0<> SignalDestroyed;
142
143  rtc::Thread* const signaling_thread_;
144  // TODO(hbos): RSA generation is slow and would be VERY slow if we switch over
145  // to 2048, DtlsIdentityStore should use a new thread and not the "general
146  // purpose" worker thread.
147  rtc::Thread* const worker_thread_;
148
149  struct RequestInfo {
150    RequestInfo()
151        : request_observers_(), gen_in_progress_counts_(0), free_identity_() {}
152
153    std::queue<rtc::scoped_refptr<DtlsIdentityRequestObserver>>
154        request_observers_;
155    size_t gen_in_progress_counts_;
156    rtc::scoped_ptr<rtc::SSLIdentity> free_identity_;
157  };
158
159  // One RequestInfo per KeyType. Only touch on the |signaling_thread_|.
160  RequestInfo request_info_[rtc::KT_LAST];
161};
162
163}  // namespace webrtc
164
165#endif  // TALK_APP_WEBRTC_DTLSIDENTITYSTORE_H_
166