/src/mozilla-central/media/mtransport/transportlayerdtls.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | // Original author: ekr@rtfm.com |
8 | | |
9 | | #ifndef transportlayerdtls_h__ |
10 | | #define transportlayerdtls_h__ |
11 | | |
12 | | #include <queue> |
13 | | #include <set> |
14 | | |
15 | | #include "sigslot.h" |
16 | | |
17 | | #include "mozilla/RefPtr.h" |
18 | | #include "mozilla/UniquePtr.h" |
19 | | #include "mozilla/TimeStamp.h" |
20 | | #include "nsCOMPtr.h" |
21 | | #include "nsIEventTarget.h" |
22 | | #include "nsITimer.h" |
23 | | #include "ScopedNSSTypes.h" |
24 | | #include "m_cpp_utils.h" |
25 | | #include "dtlsidentity.h" |
26 | | #include "transportlayer.h" |
27 | | #include "ssl.h" |
28 | | |
29 | | namespace mozilla { |
30 | | |
31 | | // RFC 5764 (we don't support the NULL cipher) |
32 | | static const uint16_t kDtlsSrtpAes128CmHmacSha1_80 = 0x0001; |
33 | | static const uint16_t kDtlsSrtpAes128CmHmacSha1_32 = 0x0002; |
34 | | // RFC 7714 |
35 | | static const uint16_t kDtlsSrtpAeadAes128Gcm = 0x0007; |
36 | | static const uint16_t kDtlsSrtpAeadAes256Gcm = 0x0008; |
37 | | |
38 | | struct Packet; |
39 | | |
40 | | class TransportLayerNSPRAdapter { |
41 | | public: |
42 | | explicit TransportLayerNSPRAdapter(TransportLayer *output) : |
43 | | output_(output), |
44 | | input_(), |
45 | 0 | enabled_(true) {} |
46 | | |
47 | | void PacketReceived(MediaPacket& packet); |
48 | | int32_t Recv(void *buf, int32_t buflen); |
49 | | int32_t Write(const void *buf, int32_t length); |
50 | 0 | void SetEnabled(bool enabled) { enabled_ = enabled; } |
51 | | |
52 | | private: |
53 | | DISALLOW_COPY_ASSIGN(TransportLayerNSPRAdapter); |
54 | | |
55 | | TransportLayer *output_; |
56 | | std::queue<MediaPacket *> input_; |
57 | | bool enabled_; |
58 | | }; |
59 | | |
60 | | class TransportLayerDtls final : public TransportLayer { |
61 | | public: |
62 | 0 | TransportLayerDtls() = default; |
63 | | |
64 | | virtual ~TransportLayerDtls(); |
65 | | |
66 | | enum Role { CLIENT, SERVER}; |
67 | | enum Verification { VERIFY_UNSET, VERIFY_ALLOW_ALL, VERIFY_DIGEST}; |
68 | | const static size_t kMaxDigestLength = HASH_LENGTH_MAX; |
69 | | |
70 | | // DTLS-specific operations |
71 | 0 | void SetRole(Role role) { role_ = role;} |
72 | | Role role() { return role_; } |
73 | | |
74 | 0 | void SetIdentity(const RefPtr<DtlsIdentity>& identity) { |
75 | 0 | identity_ = identity; |
76 | 0 | } |
77 | | nsresult SetAlpn(const std::set<std::string>& allowedAlpn, |
78 | | const std::string& alpnDefault); |
79 | 0 | const std::string& GetNegotiatedAlpn() const { return alpn_; } |
80 | | |
81 | | nsresult SetVerificationAllowAll(); |
82 | | nsresult SetVerificationDigest(const std::string digest_algorithm, |
83 | | const unsigned char *digest_value, |
84 | | size_t digest_len); |
85 | | |
86 | | nsresult GetCipherSuite(uint16_t* cipherSuite) const; |
87 | | |
88 | | nsresult SetSrtpCiphers(const std::vector<uint16_t>& ciphers); |
89 | | nsresult GetSrtpCipher(uint16_t *cipher) const; |
90 | | |
91 | | nsresult ExportKeyingMaterial(const std::string& label, |
92 | | bool use_context, |
93 | | const std::string& context, |
94 | | unsigned char *out, |
95 | | unsigned int outlen); |
96 | | |
97 | | // Transport layer overrides. |
98 | | nsresult InitInternal() override; |
99 | | void WasInserted() override; |
100 | | TransportResult SendPacket(MediaPacket& packet) override; |
101 | | |
102 | | // Signals |
103 | | void StateChange(TransportLayer *layer, State state); |
104 | | void PacketReceived(TransportLayer* layer, MediaPacket& packet); |
105 | | |
106 | | // For testing use only. Returns the fd. |
107 | 0 | PRFileDesc* internal_fd() { CheckThread(); return ssl_fd_.get(); } |
108 | | |
109 | | TRANSPORT_LAYER_ID("dtls") |
110 | | |
111 | | protected: |
112 | | void SetState(State state, const char *file, unsigned line) override; |
113 | | |
114 | | private: |
115 | | DISALLOW_COPY_ASSIGN(TransportLayerDtls); |
116 | | |
117 | | // A single digest to check |
118 | | class VerificationDigest { |
119 | | public: |
120 | | VerificationDigest(std::string algorithm, |
121 | 0 | const unsigned char *value, size_t len) { |
122 | 0 | MOZ_ASSERT(len <= sizeof(value_)); |
123 | 0 |
|
124 | 0 | algorithm_ = algorithm; |
125 | 0 | memcpy(value_, value, len); |
126 | 0 | len_ = len; |
127 | 0 | } |
128 | | |
129 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VerificationDigest) |
130 | | |
131 | | std::string algorithm_; |
132 | | size_t len_; |
133 | | unsigned char value_[kMaxDigestLength]; |
134 | | |
135 | | private: |
136 | 0 | ~VerificationDigest() {} |
137 | | DISALLOW_COPY_ASSIGN(VerificationDigest); |
138 | | }; |
139 | | |
140 | | |
141 | | bool Setup(); |
142 | | bool SetupCipherSuites(UniquePRFileDesc& ssl_fd); |
143 | | bool SetupAlpn(UniquePRFileDesc& ssl_fd) const; |
144 | | void GetDecryptedPackets(); |
145 | | void Handshake(); |
146 | | |
147 | | bool CheckAlpn(); |
148 | | |
149 | | static SECStatus GetClientAuthDataHook(void *arg, PRFileDesc *fd, |
150 | | CERTDistNames *caNames, |
151 | | CERTCertificate **pRetCert, |
152 | | SECKEYPrivateKey **pRetKey); |
153 | | static SECStatus AuthCertificateHook(void *arg, |
154 | | PRFileDesc *fd, |
155 | | PRBool checksig, |
156 | | PRBool isServer); |
157 | | SECStatus AuthCertificateHook(PRFileDesc *fd, |
158 | | PRBool checksig, |
159 | | PRBool isServer); |
160 | | |
161 | | static void TimerCallback(nsITimer *timer, void *arg); |
162 | | |
163 | | SECStatus CheckDigest(const RefPtr<VerificationDigest>& digest, |
164 | | UniqueCERTCertificate& cert) const; |
165 | | |
166 | | void RecordHandshakeCompletionTelemetry(TransportLayer::State endState); |
167 | | void RecordCipherTelemetry(); |
168 | | |
169 | | static PRBool WriteSrtpXtn(PRFileDesc* fd, SSLHandshakeType message, |
170 | | uint8_t* data, unsigned int* len, |
171 | | unsigned int max_len, void* arg); |
172 | | |
173 | | static SECStatus HandleSrtpXtn(PRFileDesc* fd, SSLHandshakeType message, |
174 | | const uint8_t* data, unsigned int len, |
175 | | SSLAlertDescription* alert, void* arg); |
176 | | |
177 | | RefPtr<DtlsIdentity> identity_; |
178 | | // What ALPN identifiers are permitted. |
179 | | std::set<std::string> alpn_allowed_; |
180 | | // What ALPN identifier is used if ALPN is not supported. |
181 | | // The empty string indicates that ALPN is required. |
182 | | std::string alpn_default_; |
183 | | // What ALPN string was negotiated. |
184 | | std::string alpn_; |
185 | | std::vector<uint16_t> enabled_srtp_ciphers_; |
186 | | uint16_t srtp_cipher_ = 0; |
187 | | |
188 | | Role role_ = CLIENT; |
189 | | Verification verification_mode_ = VERIFY_UNSET; |
190 | | std::vector<RefPtr<VerificationDigest> > digests_; |
191 | | |
192 | | // Must delete nspr_io_adapter after ssl_fd_ b/c ssl_fd_ causes an alert |
193 | | // (ssl_fd_ contains an un-owning pointer to nspr_io_adapter_) |
194 | | UniquePtr<TransportLayerNSPRAdapter> nspr_io_adapter_ = nullptr; |
195 | | UniquePRFileDesc ssl_fd_ = nullptr; |
196 | | |
197 | | nsCOMPtr<nsITimer> timer_ = nullptr; |
198 | | bool auth_hook_called_ = false; |
199 | | bool cert_ok_ = false; |
200 | | TimeStamp handshake_started_; |
201 | | }; |
202 | | |
203 | | |
204 | | } // close namespace |
205 | | #endif |