/src/mozilla-central/media/mtransport/transportlayerdtls.cpp
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 | | #include "transportlayerdtls.h" |
10 | | |
11 | | #include <algorithm> |
12 | | #include <queue> |
13 | | #include <sstream> |
14 | | |
15 | | #include "dtlsidentity.h" |
16 | | #include "keyhi.h" |
17 | | #include "logging.h" |
18 | | #include "mozilla/Telemetry.h" |
19 | | #include "mozilla/UniquePtr.h" |
20 | | #include "mozilla/Unused.h" |
21 | | #include "nsCOMPtr.h" |
22 | | #include "nsComponentManagerUtils.h" |
23 | | #include "nsComponentManagerUtils.h" |
24 | | #include "nsIEventTarget.h" |
25 | | #include "nsNetCID.h" |
26 | | #include "nsServiceManagerUtils.h" |
27 | | #include "sslexp.h" |
28 | | #include "sslproto.h" |
29 | | #include "transportflow.h" |
30 | | |
31 | | |
32 | | namespace mozilla { |
33 | | |
34 | | MOZ_MTLOG_MODULE("mtransport") |
35 | | |
36 | | static PRDescIdentity transport_layer_identity = PR_INVALID_IO_LAYER; |
37 | | |
38 | | // TODO: Implement a mode for this where |
39 | | // the channel is not ready until confirmed externally |
40 | | // (e.g., after cert check). |
41 | | |
42 | | #define UNIMPLEMENTED \ |
43 | 0 | MOZ_MTLOG(ML_ERROR, \ |
44 | 0 | "Call to unimplemented function "<< __FUNCTION__); \ |
45 | 0 | MOZ_ASSERT(false); \ |
46 | 0 | PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0) |
47 | | |
48 | | #define MAX_ALPN_LENGTH 255 |
49 | | |
50 | | // We need to adapt the NSPR/libssl model to the TransportFlow model. |
51 | | // The former wants pull semantics and TransportFlow wants push. |
52 | | // |
53 | | // - A TransportLayerDtls assumes it is sitting on top of another |
54 | | // TransportLayer, which means that events come in asynchronously. |
55 | | // - NSS (libssl) wants to sit on top of a PRFileDesc and poll. |
56 | | // - The TransportLayerNSPRAdapter is a PRFileDesc containing a |
57 | | // FIFO. |
58 | | // - When TransportLayerDtls.PacketReceived() is called, we insert |
59 | | // the packets in the FIFO and then do a PR_Recv() on the NSS |
60 | | // PRFileDesc, which eventually reads off the FIFO. |
61 | | // |
62 | | // All of this stuff is assumed to happen solely in a single thread |
63 | | // (generally the SocketTransportService thread) |
64 | | |
65 | 0 | void TransportLayerNSPRAdapter::PacketReceived(MediaPacket& packet) { |
66 | 0 | if (enabled_) { |
67 | 0 | input_.push(new MediaPacket(std::move(packet))); |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | 0 | int32_t TransportLayerNSPRAdapter::Recv(void *buf, int32_t buflen) { |
72 | 0 | if (input_.empty()) { |
73 | 0 | PR_SetError(PR_WOULD_BLOCK_ERROR, 0); |
74 | 0 | return -1; |
75 | 0 | } |
76 | 0 | |
77 | 0 | MediaPacket* front = input_.front(); |
78 | 0 | int32_t count = static_cast<int32_t>(front->len()); |
79 | 0 |
|
80 | 0 | if (buflen < count) { |
81 | 0 | MOZ_ASSERT(false, "Not enough buffer space to receive into"); |
82 | 0 | PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); |
83 | 0 | return -1; |
84 | 0 | } |
85 | 0 |
|
86 | 0 | memcpy(buf, front->data(), count); |
87 | 0 |
|
88 | 0 | input_.pop(); |
89 | 0 | delete front; |
90 | 0 |
|
91 | 0 | return count; |
92 | 0 | } |
93 | | |
94 | 0 | int32_t TransportLayerNSPRAdapter::Write(const void *buf, int32_t length) { |
95 | 0 | if (!enabled_) { |
96 | 0 | MOZ_MTLOG(ML_WARNING, "Writing to disabled transport layer"); |
97 | 0 | return -1; |
98 | 0 | } |
99 | 0 |
|
100 | 0 | MediaPacket packet; |
101 | 0 | // Copies. Oh well. |
102 | 0 | packet.Copy(static_cast<const uint8_t*>(buf), static_cast<size_t>(length)); |
103 | 0 |
|
104 | 0 | TransportResult r = output_->SendPacket(packet); |
105 | 0 | if (r >= 0) { |
106 | 0 | return r; |
107 | 0 | } |
108 | 0 | |
109 | 0 | if (r == TE_WOULDBLOCK) { |
110 | 0 | PR_SetError(PR_WOULD_BLOCK_ERROR, 0); |
111 | 0 | } else { |
112 | 0 | PR_SetError(PR_IO_ERROR, 0); |
113 | 0 | } |
114 | 0 |
|
115 | 0 | return -1; |
116 | 0 | } |
117 | | |
118 | | |
119 | | // Implementation of NSPR methods |
120 | 0 | static PRStatus TransportLayerClose(PRFileDesc *f) { |
121 | 0 | f->dtor(f); |
122 | 0 | return PR_SUCCESS; |
123 | 0 | } |
124 | | |
125 | 0 | static int32_t TransportLayerRead(PRFileDesc *f, void *buf, int32_t length) { |
126 | 0 | UNIMPLEMENTED; |
127 | 0 | return -1; |
128 | 0 | } |
129 | | |
130 | 0 | static int32_t TransportLayerWrite(PRFileDesc *f, const void *buf, int32_t length) { |
131 | 0 | TransportLayerNSPRAdapter *io = reinterpret_cast<TransportLayerNSPRAdapter *>(f->secret); |
132 | 0 | return io->Write(buf, length); |
133 | 0 | } |
134 | | |
135 | 0 | static int32_t TransportLayerAvailable(PRFileDesc *f) { |
136 | 0 | UNIMPLEMENTED; |
137 | 0 | return -1; |
138 | 0 | } |
139 | | |
140 | 0 | int64_t TransportLayerAvailable64(PRFileDesc *f) { |
141 | 0 | UNIMPLEMENTED; |
142 | 0 | return -1; |
143 | 0 | } |
144 | | |
145 | 0 | static PRStatus TransportLayerSync(PRFileDesc *f) { |
146 | 0 | UNIMPLEMENTED; |
147 | 0 | return PR_FAILURE; |
148 | 0 | } |
149 | | |
150 | | static int32_t TransportLayerSeek(PRFileDesc *f, int32_t offset, |
151 | 0 | PRSeekWhence how) { |
152 | 0 | UNIMPLEMENTED; |
153 | 0 | return -1; |
154 | 0 | } |
155 | | |
156 | | static int64_t TransportLayerSeek64(PRFileDesc *f, int64_t offset, |
157 | 0 | PRSeekWhence how) { |
158 | 0 | UNIMPLEMENTED; |
159 | 0 | return -1; |
160 | 0 | } |
161 | | |
162 | 0 | static PRStatus TransportLayerFileInfo(PRFileDesc *f, PRFileInfo *info) { |
163 | 0 | UNIMPLEMENTED; |
164 | 0 | return PR_FAILURE; |
165 | 0 | } |
166 | | |
167 | 0 | static PRStatus TransportLayerFileInfo64(PRFileDesc *f, PRFileInfo64 *info) { |
168 | 0 | UNIMPLEMENTED; |
169 | 0 | return PR_FAILURE; |
170 | 0 | } |
171 | | |
172 | | static int32_t TransportLayerWritev(PRFileDesc *f, const PRIOVec *iov, |
173 | 0 | int32_t iov_size, PRIntervalTime to) { |
174 | 0 | UNIMPLEMENTED; |
175 | 0 | return -1; |
176 | 0 | } |
177 | | |
178 | | static PRStatus TransportLayerConnect(PRFileDesc *f, const PRNetAddr *addr, |
179 | 0 | PRIntervalTime to) { |
180 | 0 | UNIMPLEMENTED; |
181 | 0 | return PR_FAILURE; |
182 | 0 | } |
183 | | |
184 | | static PRFileDesc *TransportLayerAccept(PRFileDesc *sd, PRNetAddr *addr, |
185 | 0 | PRIntervalTime to) { |
186 | 0 | UNIMPLEMENTED; |
187 | 0 | return nullptr; |
188 | 0 | } |
189 | | |
190 | 0 | static PRStatus TransportLayerBind(PRFileDesc *f, const PRNetAddr *addr) { |
191 | 0 | UNIMPLEMENTED; |
192 | 0 | return PR_FAILURE; |
193 | 0 | } |
194 | | |
195 | 0 | static PRStatus TransportLayerListen(PRFileDesc *f, int32_t depth) { |
196 | 0 | UNIMPLEMENTED; |
197 | 0 | return PR_FAILURE; |
198 | 0 | } |
199 | | |
200 | 0 | static PRStatus TransportLayerShutdown(PRFileDesc *f, int32_t how) { |
201 | 0 | // This is only called from NSS when we are the server and the client refuses |
202 | 0 | // to provide a certificate. In this case, the handshake is destined for |
203 | 0 | // failure, so we will just let this pass. |
204 | 0 | TransportLayerNSPRAdapter *io = reinterpret_cast<TransportLayerNSPRAdapter *>(f->secret); |
205 | 0 | io->SetEnabled(false); |
206 | 0 | return PR_SUCCESS; |
207 | 0 | } |
208 | | |
209 | | // This function does not support peek, or waiting until `to` |
210 | | static int32_t TransportLayerRecv(PRFileDesc *f, void *buf, int32_t buflen, |
211 | 0 | int32_t flags, PRIntervalTime to) { |
212 | 0 | MOZ_ASSERT(flags == 0); |
213 | 0 | if (flags != 0) { |
214 | 0 | PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); |
215 | 0 | return -1; |
216 | 0 | } |
217 | 0 | |
218 | 0 | TransportLayerNSPRAdapter *io = reinterpret_cast<TransportLayerNSPRAdapter *>(f->secret); |
219 | 0 | return io->Recv(buf, buflen); |
220 | 0 | } |
221 | | |
222 | | // Note: this is always nonblocking and assumes a zero timeout. |
223 | | static int32_t TransportLayerSend(PRFileDesc *f, const void *buf, int32_t amount, |
224 | 0 | int32_t flags, PRIntervalTime to) { |
225 | 0 | int32_t written = TransportLayerWrite(f, buf, amount); |
226 | 0 | return written; |
227 | 0 | } |
228 | | |
229 | | static int32_t TransportLayerRecvfrom(PRFileDesc *f, void *buf, int32_t amount, |
230 | 0 | int32_t flags, PRNetAddr *addr, PRIntervalTime to) { |
231 | 0 | UNIMPLEMENTED; |
232 | 0 | return -1; |
233 | 0 | } |
234 | | |
235 | | static int32_t TransportLayerSendto(PRFileDesc *f, const void *buf, int32_t amount, |
236 | 0 | int32_t flags, const PRNetAddr *addr, PRIntervalTime to) { |
237 | 0 | UNIMPLEMENTED; |
238 | 0 | return -1; |
239 | 0 | } |
240 | | |
241 | 0 | static int16_t TransportLayerPoll(PRFileDesc *f, int16_t in_flags, int16_t *out_flags) { |
242 | 0 | UNIMPLEMENTED; |
243 | 0 | return -1; |
244 | 0 | } |
245 | | |
246 | | static int32_t TransportLayerAcceptRead(PRFileDesc *sd, PRFileDesc **nd, |
247 | | PRNetAddr **raddr, |
248 | 0 | void *buf, int32_t amount, PRIntervalTime t) { |
249 | 0 | UNIMPLEMENTED; |
250 | 0 | return -1; |
251 | 0 | } |
252 | | |
253 | | static int32_t TransportLayerTransmitFile(PRFileDesc *sd, PRFileDesc *f, |
254 | | const void *headers, int32_t hlen, |
255 | 0 | PRTransmitFileFlags flags, PRIntervalTime t) { |
256 | 0 | UNIMPLEMENTED; |
257 | 0 | return -1; |
258 | 0 | } |
259 | | |
260 | 0 | static PRStatus TransportLayerGetpeername(PRFileDesc *f, PRNetAddr *addr) { |
261 | 0 | // TODO: Modify to return unique names for each channel |
262 | 0 | // somehow, as opposed to always the same static address. The current |
263 | 0 | // implementation messes up the session cache, which is why it's off |
264 | 0 | // elsewhere |
265 | 0 | addr->inet.family = PR_AF_INET; |
266 | 0 | addr->inet.port = 0; |
267 | 0 | addr->inet.ip = 0; |
268 | 0 |
|
269 | 0 | return PR_SUCCESS; |
270 | 0 | } |
271 | | |
272 | 0 | static PRStatus TransportLayerGetsockname(PRFileDesc *f, PRNetAddr *addr) { |
273 | 0 | UNIMPLEMENTED; |
274 | 0 | return PR_FAILURE; |
275 | 0 | } |
276 | | |
277 | 0 | static PRStatus TransportLayerGetsockoption(PRFileDesc *f, PRSocketOptionData *opt) { |
278 | 0 | switch (opt->option) { |
279 | 0 | case PR_SockOpt_Nonblocking: |
280 | 0 | opt->value.non_blocking = PR_TRUE; |
281 | 0 | return PR_SUCCESS; |
282 | 0 | default: |
283 | 0 | UNIMPLEMENTED; |
284 | 0 | break; |
285 | 0 | } |
286 | 0 |
|
287 | 0 | return PR_FAILURE; |
288 | 0 | } |
289 | | |
290 | | // Imitate setting socket options. These are mostly noops. |
291 | | static PRStatus TransportLayerSetsockoption(PRFileDesc *f, |
292 | 0 | const PRSocketOptionData *opt) { |
293 | 0 | switch (opt->option) { |
294 | 0 | case PR_SockOpt_Nonblocking: |
295 | 0 | return PR_SUCCESS; |
296 | 0 | case PR_SockOpt_NoDelay: |
297 | 0 | return PR_SUCCESS; |
298 | 0 | default: |
299 | 0 | UNIMPLEMENTED; |
300 | 0 | break; |
301 | 0 | } |
302 | 0 |
|
303 | 0 | return PR_FAILURE; |
304 | 0 | } |
305 | | |
306 | | static int32_t TransportLayerSendfile(PRFileDesc *out, PRSendFileData *in, |
307 | 0 | PRTransmitFileFlags flags, PRIntervalTime to) { |
308 | 0 | UNIMPLEMENTED; |
309 | 0 | return -1; |
310 | 0 | } |
311 | | |
312 | 0 | static PRStatus TransportLayerConnectContinue(PRFileDesc *f, int16_t flags) { |
313 | 0 | UNIMPLEMENTED; |
314 | 0 | return PR_FAILURE; |
315 | 0 | } |
316 | | |
317 | 0 | static int32_t TransportLayerReserved(PRFileDesc *f) { |
318 | 0 | UNIMPLEMENTED; |
319 | 0 | return -1; |
320 | 0 | } |
321 | | |
322 | | static const struct PRIOMethods TransportLayerMethods = { |
323 | | PR_DESC_LAYERED, |
324 | | TransportLayerClose, |
325 | | TransportLayerRead, |
326 | | TransportLayerWrite, |
327 | | TransportLayerAvailable, |
328 | | TransportLayerAvailable64, |
329 | | TransportLayerSync, |
330 | | TransportLayerSeek, |
331 | | TransportLayerSeek64, |
332 | | TransportLayerFileInfo, |
333 | | TransportLayerFileInfo64, |
334 | | TransportLayerWritev, |
335 | | TransportLayerConnect, |
336 | | TransportLayerAccept, |
337 | | TransportLayerBind, |
338 | | TransportLayerListen, |
339 | | TransportLayerShutdown, |
340 | | TransportLayerRecv, |
341 | | TransportLayerSend, |
342 | | TransportLayerRecvfrom, |
343 | | TransportLayerSendto, |
344 | | TransportLayerPoll, |
345 | | TransportLayerAcceptRead, |
346 | | TransportLayerTransmitFile, |
347 | | TransportLayerGetsockname, |
348 | | TransportLayerGetpeername, |
349 | | TransportLayerReserved, |
350 | | TransportLayerReserved, |
351 | | TransportLayerGetsockoption, |
352 | | TransportLayerSetsockoption, |
353 | | TransportLayerSendfile, |
354 | | TransportLayerConnectContinue, |
355 | | TransportLayerReserved, |
356 | | TransportLayerReserved, |
357 | | TransportLayerReserved, |
358 | | TransportLayerReserved |
359 | | }; |
360 | | |
361 | 0 | TransportLayerDtls::~TransportLayerDtls() { |
362 | 0 | // Destroy the NSS instance first so it can still send out an alert before |
363 | 0 | // we disable the nspr_io_adapter_. |
364 | 0 | ssl_fd_ = nullptr; |
365 | 0 | nspr_io_adapter_->SetEnabled(false); |
366 | 0 | if (timer_) { |
367 | 0 | timer_->Cancel(); |
368 | 0 | } |
369 | 0 | } |
370 | | |
371 | 0 | nsresult TransportLayerDtls::InitInternal() { |
372 | 0 | // Get the transport service as an event target |
373 | 0 | nsresult rv; |
374 | 0 | target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
375 | 0 |
|
376 | 0 | if (NS_FAILED(rv)) { |
377 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't get socket transport service"); |
378 | 0 | return rv; |
379 | 0 | } |
380 | 0 |
|
381 | 0 | timer_ = NS_NewTimer(); |
382 | 0 | if (!timer_) { |
383 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't get timer"); |
384 | 0 | return rv; |
385 | 0 | } |
386 | 0 |
|
387 | 0 | return NS_OK; |
388 | 0 | } |
389 | | |
390 | | |
391 | 0 | void TransportLayerDtls::WasInserted() { |
392 | 0 | // Connect to the lower layers |
393 | 0 | if (!Setup()) { |
394 | 0 | TL_SET_STATE(TS_ERROR); |
395 | 0 | } |
396 | 0 | } |
397 | | |
398 | | |
399 | | // Set the permitted and default ALPN identifiers. |
400 | | // The default is here to allow for peers that don't want to negotiate ALPN |
401 | | // in that case, the default string will be reported from GetNegotiatedAlpn(). |
402 | | // Setting the default to the empty string causes the transport layer to fail |
403 | | // if ALPN is not negotiated. |
404 | | // Note: we only support Unicode strings here, which are encoded into UTF-8, |
405 | | // even though ALPN ostensibly allows arbitrary octet sequences. |
406 | | nsresult TransportLayerDtls::SetAlpn( |
407 | | const std::set<std::string>& alpn_allowed, |
408 | 0 | const std::string& alpn_default) { |
409 | 0 |
|
410 | 0 | alpn_allowed_ = alpn_allowed; |
411 | 0 | alpn_default_ = alpn_default; |
412 | 0 |
|
413 | 0 | return NS_OK; |
414 | 0 | } |
415 | | |
416 | | |
417 | 0 | nsresult TransportLayerDtls::SetVerificationAllowAll() { |
418 | 0 | // Defensive programming |
419 | 0 | if (verification_mode_ != VERIFY_UNSET) |
420 | 0 | return NS_ERROR_ALREADY_INITIALIZED; |
421 | 0 | |
422 | 0 | verification_mode_ = VERIFY_ALLOW_ALL; |
423 | 0 |
|
424 | 0 | return NS_OK; |
425 | 0 | } |
426 | | |
427 | | nsresult |
428 | | TransportLayerDtls::SetVerificationDigest(const std::string digest_algorithm, |
429 | | const unsigned char *digest_value, |
430 | 0 | size_t digest_len) { |
431 | 0 | // Defensive programming |
432 | 0 | if (verification_mode_ != VERIFY_UNSET && |
433 | 0 | verification_mode_ != VERIFY_DIGEST) { |
434 | 0 | return NS_ERROR_ALREADY_INITIALIZED; |
435 | 0 | } |
436 | 0 | |
437 | 0 | // Note that we do not sanity check these values for length. |
438 | 0 | // We merely ensure they will fit into the buffer. |
439 | 0 | // TODO: is there a Data construct we could use? |
440 | 0 | if (digest_len > kMaxDigestLength) |
441 | 0 | return NS_ERROR_INVALID_ARG; |
442 | 0 | |
443 | 0 | digests_.push_back(new VerificationDigest( |
444 | 0 | digest_algorithm, digest_value, digest_len)); |
445 | 0 |
|
446 | 0 | verification_mode_ = VERIFY_DIGEST; |
447 | 0 |
|
448 | 0 | return NS_OK; |
449 | 0 | } |
450 | | |
451 | | // These are the named groups that we will allow. |
452 | | static const SSLNamedGroup NamedGroupPreferences[] = { |
453 | | ssl_grp_ec_curve25519, |
454 | | ssl_grp_ec_secp256r1, |
455 | | ssl_grp_ec_secp384r1, |
456 | | ssl_grp_ffdhe_2048, |
457 | | ssl_grp_ffdhe_3072 |
458 | | }; |
459 | | |
460 | | // TODO: make sure this is called from STS. Otherwise |
461 | | // we have thread safety issues |
462 | 0 | bool TransportLayerDtls::Setup() { |
463 | 0 | CheckThread(); |
464 | 0 | SECStatus rv; |
465 | 0 |
|
466 | 0 | if (!downward_) { |
467 | 0 | MOZ_MTLOG(ML_ERROR, "DTLS layer with nothing below. This is useless"); |
468 | 0 | return false; |
469 | 0 | } |
470 | 0 | nspr_io_adapter_ = MakeUnique<TransportLayerNSPRAdapter>(downward_); |
471 | 0 |
|
472 | 0 | if (!identity_) { |
473 | 0 | MOZ_MTLOG(ML_ERROR, "Can't start DTLS without an identity"); |
474 | 0 | return false; |
475 | 0 | } |
476 | 0 |
|
477 | 0 | if (verification_mode_ == VERIFY_UNSET) { |
478 | 0 | MOZ_MTLOG(ML_ERROR, |
479 | 0 | "Can't start DTLS without specifying a verification mode"); |
480 | 0 | return false; |
481 | 0 | } |
482 | 0 |
|
483 | 0 | if (transport_layer_identity == PR_INVALID_IO_LAYER) { |
484 | 0 | transport_layer_identity = PR_GetUniqueIdentity("nssstreamadapter"); |
485 | 0 | } |
486 | 0 |
|
487 | 0 | UniquePRFileDesc pr_fd(PR_CreateIOLayerStub(transport_layer_identity, |
488 | 0 | &TransportLayerMethods)); |
489 | 0 | MOZ_ASSERT(pr_fd != nullptr); |
490 | 0 | if (!pr_fd) |
491 | 0 | return false; |
492 | 0 | pr_fd->secret = reinterpret_cast<PRFilePrivate *>(nspr_io_adapter_.get()); |
493 | 0 |
|
494 | 0 | UniquePRFileDesc ssl_fd(DTLS_ImportFD(nullptr, pr_fd.get())); |
495 | 0 | MOZ_ASSERT(ssl_fd != nullptr); // This should never happen |
496 | 0 | if (!ssl_fd) { |
497 | 0 | return false; |
498 | 0 | } |
499 | 0 | |
500 | 0 | Unused << pr_fd.release(); // ownership transfered to ssl_fd; |
501 | 0 |
|
502 | 0 | if (role_ == CLIENT) { |
503 | 0 | MOZ_MTLOG(ML_INFO, "Setting up DTLS as client"); |
504 | 0 | rv = SSL_GetClientAuthDataHook(ssl_fd.get(), GetClientAuthDataHook, |
505 | 0 | this); |
506 | 0 | if (rv != SECSuccess) { |
507 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set identity"); |
508 | 0 | return false; |
509 | 0 | } |
510 | 0 | } else { |
511 | 0 | MOZ_MTLOG(ML_INFO, "Setting up DTLS as server"); |
512 | 0 | // Server side |
513 | 0 | rv = SSL_ConfigSecureServer(ssl_fd.get(), identity_->cert().get(), |
514 | 0 | identity_->privkey().get(), |
515 | 0 | identity_->auth_type()); |
516 | 0 | if (rv != SECSuccess) { |
517 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set identity"); |
518 | 0 | return false; |
519 | 0 | } |
520 | 0 |
|
521 | 0 | UniqueCERTCertList zero_certs(CERT_NewCertList()); |
522 | 0 | rv = SSL_SetTrustAnchors(ssl_fd.get(), zero_certs.get()); |
523 | 0 | if (rv != SECSuccess) { |
524 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set trust anchors"); |
525 | 0 | return false; |
526 | 0 | } |
527 | 0 |
|
528 | 0 | // Insist on a certificate from the client |
529 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_REQUEST_CERTIFICATE, PR_TRUE); |
530 | 0 | if (rv != SECSuccess) { |
531 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't request certificate"); |
532 | 0 | return false; |
533 | 0 | } |
534 | 0 |
|
535 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_REQUIRE_CERTIFICATE, PR_TRUE); |
536 | 0 | if (rv != SECSuccess) { |
537 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't require certificate"); |
538 | 0 | return false; |
539 | 0 | } |
540 | 0 | } |
541 | 0 |
|
542 | 0 | // Require TLS 1.1 or 1.2. Perhaps some day in the future we will allow TLS |
543 | 0 | // 1.0 for stream modes. |
544 | 0 | SSLVersionRange version_range = { |
545 | 0 | SSL_LIBRARY_VERSION_TLS_1_1, |
546 | 0 | SSL_LIBRARY_VERSION_TLS_1_2 |
547 | 0 | }; |
548 | 0 |
|
549 | 0 | rv = SSL_VersionRangeSet(ssl_fd.get(), &version_range); |
550 | 0 | if (rv != SECSuccess) { |
551 | 0 | MOZ_MTLOG(ML_ERROR, "Can't disable SSLv3"); |
552 | 0 | return false; |
553 | 0 | } |
554 | 0 |
|
555 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_SESSION_TICKETS, PR_FALSE); |
556 | 0 | if (rv != SECSuccess) { |
557 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable session tickets"); |
558 | 0 | return false; |
559 | 0 | } |
560 | 0 |
|
561 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_NO_CACHE, PR_TRUE); |
562 | 0 | if (rv != SECSuccess) { |
563 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable session caching"); |
564 | 0 | return false; |
565 | 0 | } |
566 | 0 |
|
567 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_DEFLATE, PR_FALSE); |
568 | 0 | if (rv != SECSuccess) { |
569 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable deflate"); |
570 | 0 | return false; |
571 | 0 | } |
572 | 0 |
|
573 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_RENEGOTIATION, |
574 | 0 | SSL_RENEGOTIATE_NEVER); |
575 | 0 | if (rv != SECSuccess) { |
576 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable renegotiation"); |
577 | 0 | return false; |
578 | 0 | } |
579 | 0 |
|
580 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_FALSE_START, PR_FALSE); |
581 | 0 | if (rv != SECSuccess) { |
582 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable false start"); |
583 | 0 | return false; |
584 | 0 | } |
585 | 0 |
|
586 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_NO_LOCKS, PR_TRUE); |
587 | 0 | if (rv != SECSuccess) { |
588 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable locks"); |
589 | 0 | return false; |
590 | 0 | } |
591 | 0 |
|
592 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE); |
593 | 0 | if (rv != SECSuccess) { |
594 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable ECDHE key reuse"); |
595 | 0 | return false; |
596 | 0 | } |
597 | 0 |
|
598 | 0 | if (!SetupCipherSuites(ssl_fd)) { |
599 | 0 | return false; |
600 | 0 | } |
601 | 0 | |
602 | 0 | rv = SSL_NamedGroupConfig(ssl_fd.get(), NamedGroupPreferences, |
603 | 0 | mozilla::ArrayLength(NamedGroupPreferences)); |
604 | 0 | if (rv != SECSuccess) { |
605 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set named groups"); |
606 | 0 | return false; |
607 | 0 | } |
608 | 0 |
|
609 | 0 | // Certificate validation |
610 | 0 | rv = SSL_AuthCertificateHook(ssl_fd.get(), AuthCertificateHook, |
611 | 0 | reinterpret_cast<void *>(this)); |
612 | 0 | if (rv != SECSuccess) { |
613 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set certificate validation hook"); |
614 | 0 | return false; |
615 | 0 | } |
616 | 0 |
|
617 | 0 | if (!SetupAlpn(ssl_fd)) { |
618 | 0 | return false; |
619 | 0 | } |
620 | 0 | |
621 | 0 | // Now start the handshake |
622 | 0 | rv = SSL_ResetHandshake(ssl_fd.get(), role_ == SERVER ? PR_TRUE : PR_FALSE); |
623 | 0 | if (rv != SECSuccess) { |
624 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't reset handshake"); |
625 | 0 | return false; |
626 | 0 | } |
627 | 0 | ssl_fd_ = std::move(ssl_fd); |
628 | 0 |
|
629 | 0 | // Finally, get ready to receive data |
630 | 0 | downward_->SignalStateChange.connect(this, &TransportLayerDtls::StateChange); |
631 | 0 | downward_->SignalPacketReceived.connect(this, &TransportLayerDtls::PacketReceived); |
632 | 0 |
|
633 | 0 | if (downward_->state() == TS_OPEN) { |
634 | 0 | TL_SET_STATE(TS_CONNECTING); |
635 | 0 | Handshake(); |
636 | 0 | } |
637 | 0 |
|
638 | 0 | return true; |
639 | 0 | } |
640 | | |
641 | 0 | bool TransportLayerDtls::SetupAlpn(UniquePRFileDesc& ssl_fd) const { |
642 | 0 | if (alpn_allowed_.empty()) { |
643 | 0 | return true; |
644 | 0 | } |
645 | 0 | |
646 | 0 | SECStatus rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_NPN, PR_FALSE); |
647 | 0 | if (rv != SECSuccess) { |
648 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't disable NPN"); |
649 | 0 | return false; |
650 | 0 | } |
651 | 0 |
|
652 | 0 | rv = SSL_OptionSet(ssl_fd.get(), SSL_ENABLE_ALPN, PR_TRUE); |
653 | 0 | if (rv != SECSuccess) { |
654 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't enable ALPN"); |
655 | 0 | return false; |
656 | 0 | } |
657 | 0 |
|
658 | 0 | unsigned char buf[MAX_ALPN_LENGTH]; |
659 | 0 | size_t offset = 0; |
660 | 0 | for (const auto& tag : alpn_allowed_) { |
661 | 0 | if ((offset + 1 + tag.length()) >= sizeof(buf)) { |
662 | 0 | MOZ_MTLOG(ML_ERROR, "ALPN too long"); |
663 | 0 | return false; |
664 | 0 | } |
665 | 0 | buf[offset++] = tag.length(); |
666 | 0 | memcpy(buf + offset, tag.c_str(), tag.length()); |
667 | 0 | offset += tag.length(); |
668 | 0 | } |
669 | 0 | rv = SSL_SetNextProtoNego(ssl_fd.get(), buf, offset); |
670 | 0 | if (rv != SECSuccess) { |
671 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set ALPN string"); |
672 | 0 | return false; |
673 | 0 | } |
674 | 0 | return true; |
675 | 0 | } |
676 | | |
677 | | // Ciphers we need to enable. These are on by default in standard firefox |
678 | | // builds, but can be disabled with prefs and they aren't on in our unit tests |
679 | | // since that uses NSS default configuration. |
680 | | // |
681 | | // Only override prefs to comply with MUST statements in the security-arch doc. |
682 | | // Anything outside this list is governed by the usual combination of policy |
683 | | // and user preferences. |
684 | | static const uint32_t EnabledCiphers[] = { |
685 | | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
686 | | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA |
687 | | }; |
688 | | |
689 | | // Disable all NSS suites modes without PFS or with old and rusty ciphersuites. |
690 | | // Anything outside this list is governed by the usual combination of policy |
691 | | // and user preferences. |
692 | | static const uint32_t DisabledCiphers[] = { |
693 | | // Bug 1310061: disable all SHA384 ciphers until fixed |
694 | | TLS_AES_256_GCM_SHA384, |
695 | | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, |
696 | | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, |
697 | | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, |
698 | | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, |
699 | | TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, |
700 | | TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, |
701 | | |
702 | | TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, |
703 | | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, |
704 | | TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, |
705 | | TLS_ECDHE_RSA_WITH_RC4_128_SHA, |
706 | | |
707 | | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, |
708 | | TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, |
709 | | TLS_DHE_DSS_WITH_RC4_128_SHA, |
710 | | |
711 | | TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, |
712 | | TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, |
713 | | TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, |
714 | | TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, |
715 | | TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, |
716 | | TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, |
717 | | TLS_ECDH_ECDSA_WITH_RC4_128_SHA, |
718 | | TLS_ECDH_RSA_WITH_RC4_128_SHA, |
719 | | |
720 | | TLS_RSA_WITH_AES_128_GCM_SHA256, |
721 | | TLS_RSA_WITH_AES_256_GCM_SHA384, |
722 | | TLS_RSA_WITH_AES_128_CBC_SHA, |
723 | | TLS_RSA_WITH_AES_128_CBC_SHA256, |
724 | | TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, |
725 | | TLS_RSA_WITH_AES_256_CBC_SHA, |
726 | | TLS_RSA_WITH_AES_256_CBC_SHA256, |
727 | | TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, |
728 | | TLS_RSA_WITH_SEED_CBC_SHA, |
729 | | TLS_RSA_WITH_3DES_EDE_CBC_SHA, |
730 | | TLS_RSA_WITH_RC4_128_SHA, |
731 | | TLS_RSA_WITH_RC4_128_MD5, |
732 | | |
733 | | TLS_DHE_RSA_WITH_DES_CBC_SHA, |
734 | | TLS_DHE_DSS_WITH_DES_CBC_SHA, |
735 | | TLS_RSA_WITH_DES_CBC_SHA, |
736 | | |
737 | | TLS_ECDHE_ECDSA_WITH_NULL_SHA, |
738 | | TLS_ECDHE_RSA_WITH_NULL_SHA, |
739 | | TLS_ECDH_ECDSA_WITH_NULL_SHA, |
740 | | TLS_ECDH_RSA_WITH_NULL_SHA, |
741 | | TLS_RSA_WITH_NULL_SHA, |
742 | | TLS_RSA_WITH_NULL_SHA256, |
743 | | TLS_RSA_WITH_NULL_MD5, |
744 | | }; |
745 | | |
746 | 0 | bool TransportLayerDtls::SetupCipherSuites(UniquePRFileDesc& ssl_fd) { |
747 | 0 | SECStatus rv; |
748 | 0 |
|
749 | 0 | // Set the SRTP ciphers |
750 | 0 | if (!enabled_srtp_ciphers_.empty()) { |
751 | 0 | rv = SSL_InstallExtensionHooks(ssl_fd.get(), ssl_use_srtp_xtn, |
752 | 0 | TransportLayerDtls::WriteSrtpXtn, this, |
753 | 0 | TransportLayerDtls::HandleSrtpXtn, this); |
754 | 0 | if (rv != SECSuccess) { |
755 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "unable to set SRTP extension handler"); |
756 | 0 | return false; |
757 | 0 | } |
758 | 0 | } |
759 | 0 |
|
760 | 0 | for (const auto& cipher : EnabledCiphers) { |
761 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Enabling: " << cipher); |
762 | 0 | rv = SSL_CipherPrefSet(ssl_fd.get(), cipher, PR_TRUE); |
763 | 0 | if (rv != SECSuccess) { |
764 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << |
765 | 0 | "Unable to enable suite: " << cipher); |
766 | 0 | return false; |
767 | 0 | } |
768 | 0 | } |
769 | 0 |
|
770 | 0 | for (const auto& cipher : DisabledCiphers) { |
771 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Disabling: " << cipher); |
772 | 0 |
|
773 | 0 | PRBool enabled = false; |
774 | 0 | rv = SSL_CipherPrefGet(ssl_fd.get(), cipher, &enabled); |
775 | 0 | if (rv != SECSuccess) { |
776 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << |
777 | 0 | "Unable to check if suite is enabled: " << cipher); |
778 | 0 | return false; |
779 | 0 | } |
780 | 0 | if (enabled) { |
781 | 0 | rv = SSL_CipherPrefSet(ssl_fd.get(), cipher, PR_FALSE); |
782 | 0 | if (rv != SECSuccess) { |
783 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << |
784 | 0 | "Unable to disable suite: " << cipher); |
785 | 0 | return false; |
786 | 0 | } |
787 | 0 | } |
788 | 0 | } |
789 | 0 |
|
790 | 0 | return true; |
791 | 0 | } |
792 | | |
793 | 0 | nsresult TransportLayerDtls::GetCipherSuite(uint16_t* cipherSuite) const { |
794 | 0 | CheckThread(); |
795 | 0 | if (!cipherSuite) { |
796 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "GetCipherSuite passed a nullptr"); |
797 | 0 | return NS_ERROR_NULL_POINTER; |
798 | 0 | } |
799 | 0 | if (state_ != TS_OPEN) { |
800 | 0 | return NS_ERROR_NOT_AVAILABLE; |
801 | 0 | } |
802 | 0 | SSLChannelInfo info; |
803 | 0 | SECStatus rv = SSL_GetChannelInfo(ssl_fd_.get(), &info, sizeof(info)); |
804 | 0 | if (rv != SECSuccess) { |
805 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "GetCipherSuite can't get channel info"); |
806 | 0 | return NS_ERROR_FAILURE; |
807 | 0 | } |
808 | 0 | *cipherSuite = info.cipherSuite; |
809 | 0 | return NS_OK; |
810 | 0 | } |
811 | | |
812 | 0 | void TransportLayerDtls::StateChange(TransportLayer *layer, State state) { |
813 | 0 | if (state <= state_) { |
814 | 0 | MOZ_MTLOG(ML_ERROR, "Lower layer state is going backwards from ours"); |
815 | 0 | TL_SET_STATE(TS_ERROR); |
816 | 0 | return; |
817 | 0 | } |
818 | 0 |
|
819 | 0 | switch (state) { |
820 | 0 | case TS_NONE: |
821 | 0 | MOZ_ASSERT(false); // Can't happen |
822 | 0 | break; |
823 | 0 |
|
824 | 0 | case TS_INIT: |
825 | 0 | MOZ_MTLOG(ML_ERROR, |
826 | 0 | LAYER_INFO << "State change of lower layer to INIT forbidden"); |
827 | 0 | TL_SET_STATE(TS_ERROR); |
828 | 0 | break; |
829 | 0 |
|
830 | 0 | case TS_CONNECTING: |
831 | 0 | MOZ_MTLOG(ML_INFO, LAYER_INFO << "Lower layer is connecting."); |
832 | 0 | break; |
833 | 0 |
|
834 | 0 | case TS_OPEN: |
835 | 0 | MOZ_MTLOG(ML_INFO, |
836 | 0 | LAYER_INFO << "Lower layer is now open; starting TLS"); |
837 | 0 | // Async, since the ICE layer might need to send a STUN response, and we |
838 | 0 | // don't want the handshake to start until that is sent. |
839 | 0 | TL_SET_STATE(TS_CONNECTING); |
840 | 0 | timer_->Cancel(); |
841 | 0 | timer_->SetTarget(target_); |
842 | 0 | timer_->InitWithNamedFuncCallback(TimerCallback, |
843 | 0 | this, |
844 | 0 | 0, |
845 | 0 | nsITimer::TYPE_ONE_SHOT, |
846 | 0 | "TransportLayerDtls::TimerCallback"); |
847 | 0 | break; |
848 | 0 |
|
849 | 0 | case TS_CLOSED: |
850 | 0 | MOZ_MTLOG(ML_INFO, LAYER_INFO << "Lower layer is now closed"); |
851 | 0 | TL_SET_STATE(TS_CLOSED); |
852 | 0 | break; |
853 | 0 |
|
854 | 0 | case TS_ERROR: |
855 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Lower layer experienced an error"); |
856 | 0 | TL_SET_STATE(TS_ERROR); |
857 | 0 | break; |
858 | 0 | } |
859 | 0 | } |
860 | | |
861 | 0 | void TransportLayerDtls::Handshake() { |
862 | 0 | // Clear the retransmit timer |
863 | 0 | timer_->Cancel(); |
864 | 0 |
|
865 | 0 | MOZ_ASSERT(state_ == TS_CONNECTING); |
866 | 0 |
|
867 | 0 | SECStatus rv = SSL_ForceHandshake(ssl_fd_.get()); |
868 | 0 |
|
869 | 0 | if (rv == SECSuccess) { |
870 | 0 | MOZ_MTLOG(ML_NOTICE, |
871 | 0 | LAYER_INFO << "****** SSL handshake completed ******"); |
872 | 0 | if (!cert_ok_) { |
873 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Certificate check never occurred"); |
874 | 0 | TL_SET_STATE(TS_ERROR); |
875 | 0 | return; |
876 | 0 | } |
877 | 0 | if (!CheckAlpn()) { |
878 | 0 | // Despite connecting, the connection doesn't have a valid ALPN label. |
879 | 0 | // Forcibly close the connection so that the peer isn't left hanging |
880 | 0 | // (assuming the close_notify isn't dropped). |
881 | 0 | ssl_fd_ = nullptr; |
882 | 0 | TL_SET_STATE(TS_ERROR); |
883 | 0 | return; |
884 | 0 | } |
885 | 0 | if (!enabled_srtp_ciphers_.empty() && srtp_cipher_ == 0) { |
886 | 0 | // We enabled SRTP, but got no cipher, this should have failed. |
887 | 0 | ssl_fd_ = nullptr; |
888 | 0 | TL_SET_STATE(TS_ERROR); |
889 | 0 | return; |
890 | 0 | } |
891 | 0 |
|
892 | 0 | TL_SET_STATE(TS_OPEN); |
893 | 0 |
|
894 | 0 | RecordCipherTelemetry(); |
895 | 0 | } else { |
896 | 0 | int32_t err = PR_GetError(); |
897 | 0 | switch(err) { |
898 | 0 | case SSL_ERROR_RX_MALFORMED_HANDSHAKE: |
899 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Malformed DTLS message; ignoring"); |
900 | 0 | // If this were TLS (and not DTLS), this would be fatal, but |
901 | 0 | // here we're required to ignore bad messages, so fall through |
902 | 0 | MOZ_FALLTHROUGH; |
903 | 0 | case PR_WOULD_BLOCK_ERROR: |
904 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "Handshake would have blocked"); |
905 | 0 | PRIntervalTime timeout; |
906 | 0 | rv = DTLS_GetHandshakeTimeout(ssl_fd_.get(), &timeout); |
907 | 0 | if (rv == SECSuccess) { |
908 | 0 | uint32_t timeout_ms = PR_IntervalToMilliseconds(timeout); |
909 | 0 |
|
910 | 0 | MOZ_MTLOG(ML_DEBUG, |
911 | 0 | LAYER_INFO << "Setting DTLS timeout to " << timeout_ms); |
912 | 0 | timer_->SetTarget(target_); |
913 | 0 | timer_->InitWithNamedFuncCallback(TimerCallback, |
914 | 0 | this, timeout_ms, |
915 | 0 | nsITimer::TYPE_ONE_SHOT, |
916 | 0 | "TransportLayerDtls::TimerCallback"); |
917 | 0 | } |
918 | 0 | break; |
919 | 0 | default: |
920 | 0 | const char *err_msg = PR_ErrorToName(err); |
921 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "DTLS handshake error " << err << " (" |
922 | 0 | << err_msg << ")"); |
923 | 0 | TL_SET_STATE(TS_ERROR); |
924 | 0 | break; |
925 | 0 | } |
926 | 0 | } |
927 | 0 | } |
928 | | |
929 | | // Checks if ALPN was negotiated correctly and returns false if it wasn't. |
930 | | // After this returns successfully, alpn_ will be set to the negotiated |
931 | | // protocol. |
932 | 0 | bool TransportLayerDtls::CheckAlpn() { |
933 | 0 | if (alpn_allowed_.empty()) { |
934 | 0 | return true; |
935 | 0 | } |
936 | 0 | |
937 | 0 | SSLNextProtoState alpnState; |
938 | 0 | char chosenAlpn[MAX_ALPN_LENGTH]; |
939 | 0 | unsigned int chosenAlpnLen; |
940 | 0 | SECStatus rv = SSL_GetNextProto(ssl_fd_.get(), &alpnState, |
941 | 0 | reinterpret_cast<unsigned char*>(chosenAlpn), |
942 | 0 | &chosenAlpnLen, sizeof(chosenAlpn)); |
943 | 0 | if (rv != SECSuccess) { |
944 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "ALPN error"); |
945 | 0 | return false; |
946 | 0 | } |
947 | 0 | switch (alpnState) { |
948 | 0 | case SSL_NEXT_PROTO_SELECTED: |
949 | 0 | case SSL_NEXT_PROTO_NEGOTIATED: |
950 | 0 | break; // OK |
951 | 0 |
|
952 | 0 | case SSL_NEXT_PROTO_NO_SUPPORT: |
953 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "ALPN not negotiated, " |
954 | 0 | << (alpn_default_.empty() ? "failing" : "selecting default")); |
955 | 0 | alpn_ = alpn_default_; |
956 | 0 | return !alpn_.empty(); |
957 | 0 |
|
958 | 0 | case SSL_NEXT_PROTO_NO_OVERLAP: |
959 | 0 | // This only happens if there is a custom NPN/ALPN callback installed and |
960 | 0 | // that callback doesn't properly handle ALPN. |
961 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "error in ALPN selection callback"); |
962 | 0 | return false; |
963 | 0 |
|
964 | 0 | case SSL_NEXT_PROTO_EARLY_VALUE: |
965 | 0 | MOZ_CRASH("Unexpected 0-RTT ALPN value"); |
966 | 0 | return false; |
967 | 0 | } |
968 | 0 | |
969 | 0 | // Warning: NSS won't null terminate the ALPN string for us. |
970 | 0 | std::string chosen(chosenAlpn, chosenAlpnLen); |
971 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "Selected ALPN string: " << chosen); |
972 | 0 | if (alpn_allowed_.find(chosen) == alpn_allowed_.end()) { |
973 | 0 | // Maybe our peer chose a protocol we didn't offer (when we are client), or |
974 | 0 | // something is seriously wrong. |
975 | 0 | std::ostringstream ss; |
976 | 0 | for (auto i = alpn_allowed_.begin(); i != alpn_allowed_.end(); ++i) { |
977 | 0 | ss << (i == alpn_allowed_.begin() ? " '" : ", '") << *i << "'"; |
978 | 0 | } |
979 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Bad ALPN string: '" << chosen |
980 | 0 | << "'; permitted:" << ss.str()); |
981 | 0 | return false; |
982 | 0 | } |
983 | 0 | alpn_ = chosen; |
984 | 0 | return true; |
985 | 0 | } |
986 | | |
987 | | |
988 | | void TransportLayerDtls::PacketReceived(TransportLayer* layer, |
989 | 0 | MediaPacket& packet) { |
990 | 0 | CheckThread(); |
991 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << packet.len() << ")"); |
992 | 0 |
|
993 | 0 | if (state_ != TS_CONNECTING && state_ != TS_OPEN) { |
994 | 0 | MOZ_MTLOG(ML_DEBUG, |
995 | 0 | LAYER_INFO << "Discarding packet in inappropriate state"); |
996 | 0 | return; |
997 | 0 | } |
998 | 0 |
|
999 | 0 | if (!packet.data()) { |
1000 | 0 | // Something ate this, probably the SRTP layer |
1001 | 0 | return; |
1002 | 0 | } |
1003 | 0 | |
1004 | 0 | // not DTLS per RFC 7983 |
1005 | 0 | if (packet.data()[0] < 20 || packet.data()[0] > 63) { |
1006 | 0 | return; |
1007 | 0 | } |
1008 | 0 | |
1009 | 0 | nspr_io_adapter_->PacketReceived(packet); |
1010 | 0 | GetDecryptedPackets(); |
1011 | 0 | } |
1012 | | |
1013 | | void |
1014 | | TransportLayerDtls::GetDecryptedPackets() |
1015 | 0 | { |
1016 | 0 | // If we're still connecting, try to handshake |
1017 | 0 | if (state_ == TS_CONNECTING) { |
1018 | 0 | Handshake(); |
1019 | 0 | } |
1020 | 0 |
|
1021 | 0 | // Now try a recv if we're open, since there might be data left |
1022 | 0 | if (state_ == TS_OPEN) { |
1023 | 0 | int32_t rv; |
1024 | 0 | // One packet might contain several DTLS packets |
1025 | 0 | do { |
1026 | 0 | // nICEr uses a 9216 bytes buffer to allow support for jumbo frames |
1027 | 0 | // Can we peek to get a better idea of the actual size? |
1028 | 0 | static const size_t kBufferSize = 9216; |
1029 | 0 | auto buffer = MakeUnique<uint8_t[]>(kBufferSize); |
1030 | 0 | rv = PR_Recv(ssl_fd_.get(), buffer.get(), kBufferSize, 0, PR_INTERVAL_NO_WAIT); |
1031 | 0 | if (rv > 0) { |
1032 | 0 | // We have data |
1033 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Read " << rv << " bytes from NSS"); |
1034 | 0 | MediaPacket packet; |
1035 | 0 | packet.Take(std::move(buffer), static_cast<size_t>(rv)); |
1036 | 0 | SignalPacketReceived(this, packet); |
1037 | 0 | } else if (rv == 0) { |
1038 | 0 | TL_SET_STATE(TS_CLOSED); |
1039 | 0 | } else { |
1040 | 0 | int32_t err = PR_GetError(); |
1041 | 0 |
|
1042 | 0 | if (err == PR_WOULD_BLOCK_ERROR) { |
1043 | 0 | // This gets ignored |
1044 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Receive would have blocked"); |
1045 | 0 | } else { |
1046 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "NSS Error " << err); |
1047 | 0 | TL_SET_STATE(TS_ERROR); |
1048 | 0 | } |
1049 | 0 | } |
1050 | 0 | } while (rv > 0); |
1051 | 0 | } |
1052 | 0 | } |
1053 | | |
1054 | | void TransportLayerDtls::SetState(State state, |
1055 | | const char *file, |
1056 | 0 | unsigned line) { |
1057 | 0 | if (state > state_) { |
1058 | 0 | switch (state) { |
1059 | 0 | case TS_NONE: |
1060 | 0 | case TS_INIT: |
1061 | 0 | MOZ_ASSERT(false); |
1062 | 0 | break; |
1063 | 0 | case TS_CONNECTING: |
1064 | 0 | handshake_started_ = TimeStamp::Now(); |
1065 | 0 | break; |
1066 | 0 | case TS_OPEN: |
1067 | 0 | case TS_CLOSED: |
1068 | 0 | case TS_ERROR: |
1069 | 0 | timer_->Cancel(); |
1070 | 0 | if (state_ == TS_CONNECTING) { |
1071 | 0 | RecordHandshakeCompletionTelemetry(state); |
1072 | 0 | } |
1073 | 0 | break; |
1074 | 0 | } |
1075 | 0 | } else { |
1076 | 0 | MOZ_ASSERT(false, "Invalid state transition"); |
1077 | 0 | } |
1078 | 0 |
|
1079 | 0 | TransportLayer::SetState(state, file, line); |
1080 | 0 | } |
1081 | | |
1082 | 0 | TransportResult TransportLayerDtls::SendPacket(MediaPacket& packet) { |
1083 | 0 | CheckThread(); |
1084 | 0 | if (state_ != TS_OPEN) { |
1085 | 0 | MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Can't call SendPacket() in state " |
1086 | 0 | << state_); |
1087 | 0 | return TE_ERROR; |
1088 | 0 | } |
1089 | 0 |
|
1090 | 0 | int32_t rv = PR_Send(ssl_fd_.get(), packet.data(), packet.len(), 0, |
1091 | 0 | PR_INTERVAL_NO_WAIT); |
1092 | 0 |
|
1093 | 0 | if (rv > 0) { |
1094 | 0 | // We have data |
1095 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Wrote " << rv << " bytes to SSL Layer"); |
1096 | 0 | return rv; |
1097 | 0 | } |
1098 | 0 |
|
1099 | 0 | if (rv == 0) { |
1100 | 0 | TL_SET_STATE(TS_CLOSED); |
1101 | 0 | return 0; |
1102 | 0 | } |
1103 | 0 |
|
1104 | 0 | int32_t err = PR_GetError(); |
1105 | 0 |
|
1106 | 0 | if (err == PR_WOULD_BLOCK_ERROR) { |
1107 | 0 | // This gets ignored |
1108 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Send would have blocked"); |
1109 | 0 | return TE_WOULDBLOCK; |
1110 | 0 | } |
1111 | 0 |
|
1112 | 0 | MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "NSS Error " << err); |
1113 | 0 | TL_SET_STATE(TS_ERROR); |
1114 | 0 | return TE_ERROR; |
1115 | 0 | } |
1116 | | |
1117 | | SECStatus TransportLayerDtls::GetClientAuthDataHook(void *arg, PRFileDesc *fd, |
1118 | | CERTDistNames *caNames, |
1119 | | CERTCertificate **pRetCert, |
1120 | 0 | SECKEYPrivateKey **pRetKey) { |
1121 | 0 | MOZ_MTLOG(ML_DEBUG, "Server requested client auth"); |
1122 | 0 |
|
1123 | 0 | TransportLayerDtls *stream = reinterpret_cast<TransportLayerDtls *>(arg); |
1124 | 0 | stream->CheckThread(); |
1125 | 0 |
|
1126 | 0 | if (!stream->identity_) { |
1127 | 0 | MOZ_MTLOG(ML_ERROR, "No identity available"); |
1128 | 0 | PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0); |
1129 | 0 | return SECFailure; |
1130 | 0 | } |
1131 | 0 |
|
1132 | 0 | *pRetCert = CERT_DupCertificate(stream->identity_->cert().get()); |
1133 | 0 | if (!*pRetCert) { |
1134 | 0 | PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
1135 | 0 | return SECFailure; |
1136 | 0 | } |
1137 | 0 | |
1138 | 0 | *pRetKey = SECKEY_CopyPrivateKey(stream->identity_->privkey().get()); |
1139 | 0 | if (!*pRetKey) { |
1140 | 0 | CERT_DestroyCertificate(*pRetCert); |
1141 | 0 | *pRetCert = nullptr; |
1142 | 0 | PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
1143 | 0 | return SECFailure; |
1144 | 0 | } |
1145 | 0 | |
1146 | 0 | return SECSuccess; |
1147 | 0 | } |
1148 | | |
1149 | 0 | nsresult TransportLayerDtls::SetSrtpCiphers(const std::vector<uint16_t>& ciphers) { |
1150 | 0 | enabled_srtp_ciphers_ = std::move(ciphers); |
1151 | 0 | return NS_OK; |
1152 | 0 | } |
1153 | | |
1154 | 0 | nsresult TransportLayerDtls::GetSrtpCipher(uint16_t *cipher) const { |
1155 | 0 | CheckThread(); |
1156 | 0 | if (srtp_cipher_ == 0) { |
1157 | 0 | return NS_ERROR_NOT_AVAILABLE; |
1158 | 0 | } |
1159 | 0 | *cipher = srtp_cipher_; |
1160 | 0 | return NS_OK; |
1161 | 0 | } |
1162 | | |
1163 | 0 | static uint8_t* WriteUint16(uint8_t* cursor, uint16_t v) { |
1164 | 0 | *cursor++ = v >> 8; |
1165 | 0 | *cursor++ = v & 0xff; |
1166 | 0 | return cursor; |
1167 | 0 | } |
1168 | | |
1169 | 0 | static SSLHandshakeType SrtpXtnServerMessage(PRFileDesc* fd) { |
1170 | 0 | SSLPreliminaryChannelInfo preinfo; |
1171 | 0 | SECStatus rv = SSL_GetPreliminaryChannelInfo(fd, &preinfo, sizeof(preinfo)); |
1172 | 0 | if (rv != SECSuccess) { |
1173 | 0 | MOZ_ASSERT(false, "Can't get version info"); |
1174 | 0 | return ssl_hs_client_hello; |
1175 | 0 | } |
1176 | 0 | return (preinfo.protocolVersion >= SSL_LIBRARY_VERSION_TLS_1_3) |
1177 | 0 | ? ssl_hs_encrypted_extensions |
1178 | 0 | : ssl_hs_server_hello; |
1179 | 0 | } |
1180 | | |
1181 | | /* static */ PRBool TransportLayerDtls::WriteSrtpXtn( |
1182 | | PRFileDesc* fd, SSLHandshakeType message, uint8_t* data, |
1183 | 0 | unsigned int* len, unsigned int max_len, void* arg) { |
1184 | 0 | auto self = reinterpret_cast<TransportLayerDtls*>(arg); |
1185 | 0 |
|
1186 | 0 | // ClientHello: send all supported versions. |
1187 | 0 | if (message == ssl_hs_client_hello) { |
1188 | 0 | MOZ_ASSERT(self->role_ == CLIENT); |
1189 | 0 | MOZ_ASSERT(self->enabled_srtp_ciphers_.size(), "Haven't enabled SRTP"); |
1190 | 0 | // We will take 2 octets for each cipher, plus a 2 octet length and 1 octet |
1191 | 0 | // for the length of the empty MKI. |
1192 | 0 | if (max_len < self->enabled_srtp_ciphers_.size() * 2 + 3) { |
1193 | 0 | MOZ_ASSERT(false, "Not enough space to send SRTP extension"); |
1194 | 0 | return false; |
1195 | 0 | } |
1196 | 0 | uint8_t* cursor = WriteUint16(data, self->enabled_srtp_ciphers_.size() * 2); |
1197 | 0 | for (auto cs : self->enabled_srtp_ciphers_) { |
1198 | 0 | cursor = WriteUint16(cursor, cs); |
1199 | 0 | } |
1200 | 0 | *cursor++ = 0; // MKI is empty |
1201 | 0 | *len = cursor - data; |
1202 | 0 | return true; |
1203 | 0 | } |
1204 | 0 |
|
1205 | 0 | if (message == SrtpXtnServerMessage(fd)) { |
1206 | 0 | MOZ_ASSERT(self->role_ == SERVER); |
1207 | 0 | if (!self->srtp_cipher_) { |
1208 | 0 | // Not negotiated. Definitely bad, but the connection can fail later. |
1209 | 0 | return false; |
1210 | 0 | } |
1211 | 0 | if (max_len < 5) { |
1212 | 0 | MOZ_ASSERT(false, "Not enough space to send SRTP extension"); |
1213 | 0 | return false; |
1214 | 0 | } |
1215 | 0 |
|
1216 | 0 | uint8_t* cursor = WriteUint16(data, 2); // Length = 2. |
1217 | 0 | cursor = WriteUint16(cursor, self->srtp_cipher_); |
1218 | 0 | *cursor++ = 0; // No MKI |
1219 | 0 | *len = cursor - data; |
1220 | 0 | return true; |
1221 | 0 | } |
1222 | 0 | |
1223 | 0 | return false; |
1224 | 0 | } |
1225 | | |
1226 | | class TlsParser { |
1227 | | public: |
1228 | | TlsParser(const uint8_t* data, size_t len) |
1229 | 0 | : cursor_(data), remaining_(len) {} |
1230 | | |
1231 | 0 | bool error() const { return error_; } |
1232 | 0 | size_t remaining() const { return remaining_; } |
1233 | | |
1234 | | template<typename T, |
1235 | | class = typename std::enable_if<std::is_unsigned<T>::value>::type> |
1236 | 0 | void Read(T* v, size_t sz = sizeof(T)) { |
1237 | 0 | MOZ_ASSERT(sz <= sizeof(T), "Type is too small to hold the value requested"); |
1238 | 0 | if (remaining_ < sz) { |
1239 | 0 | error_ = true; |
1240 | 0 | return; |
1241 | 0 | } |
1242 | 0 | |
1243 | 0 | T result = 0; |
1244 | 0 | for (size_t i = 0; i < sz; ++i) { |
1245 | 0 | result = (result << 8) | *cursor_++; |
1246 | 0 | remaining_--; |
1247 | 0 | } |
1248 | 0 | *v = result; |
1249 | 0 | } Unexecuted instantiation: void mozilla::TlsParser::Read<unsigned int, void>(unsigned int*, unsigned long) Unexecuted instantiation: void mozilla::TlsParser::Read<unsigned short, void>(unsigned short*, unsigned long) |
1250 | | |
1251 | | template<typename T, |
1252 | | class = typename std::enable_if<std::is_unsigned<T>::value>::type> |
1253 | 0 | void ReadVector(std::vector<T>* v, size_t w) { |
1254 | 0 | MOZ_ASSERT(v->empty(), "vector needs to be empty"); |
1255 | 0 |
|
1256 | 0 | uint32_t len; |
1257 | 0 | Read(&len, w); |
1258 | 0 | if (error_ || len % sizeof(T) != 0 || len > remaining_) { |
1259 | 0 | error_ = true; |
1260 | 0 | return; |
1261 | 0 | } |
1262 | 0 | |
1263 | 0 | size_t count = len / sizeof(T); |
1264 | 0 | v->reserve(count); |
1265 | 0 | for (T i = 0; !error_ && i < count; ++i) { |
1266 | 0 | T item; |
1267 | 0 | Read(&item); |
1268 | 0 | if (!error_) { |
1269 | 0 | v->push_back(item); |
1270 | 0 | } |
1271 | 0 | } |
1272 | 0 | } |
1273 | | |
1274 | 0 | void Skip(size_t n) { |
1275 | 0 | if (remaining_ < n) { |
1276 | 0 | error_ = true; |
1277 | 0 | } else { |
1278 | 0 | cursor_ += n; |
1279 | 0 | remaining_ -= n; |
1280 | 0 | } |
1281 | 0 | } |
1282 | | |
1283 | 0 | size_t SkipVector(size_t w) { |
1284 | 0 | uint32_t len = 0; |
1285 | 0 | Read(&len, w); |
1286 | 0 | Skip(len); |
1287 | 0 | return len; |
1288 | 0 | } |
1289 | | |
1290 | | private: |
1291 | | const uint8_t* cursor_; |
1292 | | size_t remaining_; |
1293 | | bool error_ = false; |
1294 | | }; |
1295 | | |
1296 | | /* static */ SECStatus TransportLayerDtls::HandleSrtpXtn( |
1297 | | PRFileDesc* fd, SSLHandshakeType message, const uint8_t* data, |
1298 | 0 | unsigned int len, SSLAlertDescription* alert, void* arg) { |
1299 | 0 | static const uint8_t kTlsAlertHandshakeFailure = 40; |
1300 | 0 | static const uint8_t kTlsAlertIllegalParameter = 47; |
1301 | 0 | static const uint8_t kTlsAlertDecodeError = 50; |
1302 | 0 | static const uint8_t kTlsAlertUnsupportedExtension = 110; |
1303 | 0 |
|
1304 | 0 | auto self = reinterpret_cast<TransportLayerDtls*>(arg); |
1305 | 0 |
|
1306 | 0 | // Parse the extension. |
1307 | 0 | TlsParser parser(data, len); |
1308 | 0 | std::vector<uint16_t> advertised; |
1309 | 0 | parser.ReadVector(&advertised, 2); |
1310 | 0 | size_t mki_len = parser.SkipVector(1); |
1311 | 0 | if (parser.error() || parser.remaining() > 0) { |
1312 | 0 | *alert = kTlsAlertDecodeError; |
1313 | 0 | return SECFailure; |
1314 | 0 | } |
1315 | 0 | |
1316 | 0 | if (message == ssl_hs_client_hello) { |
1317 | 0 | MOZ_ASSERT(self->role_ == SERVER); |
1318 | 0 | if (self->enabled_srtp_ciphers_.empty()) { |
1319 | 0 | // We don't have SRTP enabled, which is probably bad, but no sense in |
1320 | 0 | // having the handshake fail at this point, let the client decide if this |
1321 | 0 | // is a problem. |
1322 | 0 | return SECSuccess; |
1323 | 0 | } |
1324 | 0 | |
1325 | 0 | for (auto supported : self->enabled_srtp_ciphers_) { |
1326 | 0 | auto it = std::find(advertised.begin(), advertised.end(), supported); |
1327 | 0 | if (it != advertised.end()) { |
1328 | 0 | self->srtp_cipher_ = supported; |
1329 | 0 | return SECSuccess; |
1330 | 0 | } |
1331 | 0 | } |
1332 | 0 |
|
1333 | 0 | // No common cipher. |
1334 | 0 | *alert = kTlsAlertHandshakeFailure; |
1335 | 0 | return SECFailure; |
1336 | 0 | } |
1337 | 0 | |
1338 | 0 | if (message == SrtpXtnServerMessage(fd)) { |
1339 | 0 | MOZ_ASSERT(self->role_ == CLIENT); |
1340 | 0 | if (advertised.size() != 1 || mki_len > 0) { |
1341 | 0 | *alert = kTlsAlertIllegalParameter; |
1342 | 0 | return SECFailure; |
1343 | 0 | } |
1344 | 0 | self->srtp_cipher_ = advertised[0]; |
1345 | 0 | return SECSuccess; |
1346 | 0 | } |
1347 | 0 | |
1348 | 0 | *alert = kTlsAlertUnsupportedExtension; |
1349 | 0 | return SECFailure; |
1350 | 0 | } |
1351 | | |
1352 | | nsresult TransportLayerDtls::ExportKeyingMaterial(const std::string& label, |
1353 | | bool use_context, |
1354 | | const std::string& context, |
1355 | | unsigned char *out, |
1356 | 0 | unsigned int outlen) { |
1357 | 0 | CheckThread(); |
1358 | 0 | if (state_ != TS_OPEN) { |
1359 | 0 | MOZ_ASSERT(false, "Transport must be open for ExportKeyingMaterial"); |
1360 | 0 | return NS_ERROR_NOT_AVAILABLE; |
1361 | 0 | } |
1362 | 0 | SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_.get(), |
1363 | 0 | label.c_str(), |
1364 | 0 | label.size(), |
1365 | 0 | use_context, |
1366 | 0 | reinterpret_cast<const unsigned char *>( |
1367 | 0 | context.c_str()), |
1368 | 0 | context.size(), |
1369 | 0 | out, |
1370 | 0 | outlen); |
1371 | 0 | if (rv != SECSuccess) { |
1372 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't export SSL keying material"); |
1373 | 0 | return NS_ERROR_FAILURE; |
1374 | 0 | } |
1375 | 0 |
|
1376 | 0 | return NS_OK; |
1377 | 0 | } |
1378 | | |
1379 | | SECStatus TransportLayerDtls::AuthCertificateHook(void *arg, |
1380 | | PRFileDesc *fd, |
1381 | | PRBool checksig, |
1382 | 0 | PRBool isServer) { |
1383 | 0 | TransportLayerDtls *stream = reinterpret_cast<TransportLayerDtls *>(arg); |
1384 | 0 | stream->CheckThread(); |
1385 | 0 | return stream->AuthCertificateHook(fd, checksig, isServer); |
1386 | 0 | } |
1387 | | |
1388 | | SECStatus |
1389 | | TransportLayerDtls::CheckDigest(const RefPtr<VerificationDigest>& digest, |
1390 | 0 | UniqueCERTCertificate& peer_cert) const { |
1391 | 0 | unsigned char computed_digest[kMaxDigestLength]; |
1392 | 0 | size_t computed_digest_len; |
1393 | 0 |
|
1394 | 0 | MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Checking digest, algorithm=" |
1395 | 0 | << digest->algorithm_); |
1396 | 0 | nsresult res = |
1397 | 0 | DtlsIdentity::ComputeFingerprint(peer_cert, |
1398 | 0 | digest->algorithm_, |
1399 | 0 | computed_digest, |
1400 | 0 | sizeof(computed_digest), |
1401 | 0 | &computed_digest_len); |
1402 | 0 | if (NS_FAILED(res)) { |
1403 | 0 | MOZ_MTLOG(ML_ERROR, "Could not compute peer fingerprint for digest " << |
1404 | 0 | digest->algorithm_); |
1405 | 0 | // Go to end |
1406 | 0 | PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0); |
1407 | 0 | return SECFailure; |
1408 | 0 | } |
1409 | 0 |
|
1410 | 0 | if (computed_digest_len != digest->len_) { |
1411 | 0 | MOZ_MTLOG(ML_ERROR, "Digest is wrong length " << digest->len_ << |
1412 | 0 | " should be " << computed_digest_len << " for algorithm " << |
1413 | 0 | digest->algorithm_); |
1414 | 0 | PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0); |
1415 | 0 | return SECFailure; |
1416 | 0 | } |
1417 | 0 |
|
1418 | 0 | if (memcmp(digest->value_, computed_digest, computed_digest_len) != 0) { |
1419 | 0 | MOZ_MTLOG(ML_ERROR, "Digest does not match"); |
1420 | 0 | PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0); |
1421 | 0 | return SECFailure; |
1422 | 0 | } |
1423 | 0 |
|
1424 | 0 | return SECSuccess; |
1425 | 0 | } |
1426 | | |
1427 | | |
1428 | | SECStatus TransportLayerDtls::AuthCertificateHook(PRFileDesc *fd, |
1429 | | PRBool checksig, |
1430 | 0 | PRBool isServer) { |
1431 | 0 | CheckThread(); |
1432 | 0 | UniqueCERTCertificate peer_cert(SSL_PeerCertificate(fd)); |
1433 | 0 |
|
1434 | 0 | // We are not set up to take this being called multiple |
1435 | 0 | // times. Change this if we ever add renegotiation. |
1436 | 0 | MOZ_ASSERT(!auth_hook_called_); |
1437 | 0 | if (auth_hook_called_) { |
1438 | 0 | PR_SetError(PR_UNKNOWN_ERROR, 0); |
1439 | 0 | return SECFailure; |
1440 | 0 | } |
1441 | 0 | auth_hook_called_ = true; |
1442 | 0 |
|
1443 | 0 | MOZ_ASSERT(verification_mode_ != VERIFY_UNSET); |
1444 | 0 |
|
1445 | 0 | switch (verification_mode_) { |
1446 | 0 | case VERIFY_UNSET: |
1447 | 0 | // Break out to error exit |
1448 | 0 | PR_SetError(PR_UNKNOWN_ERROR, 0); |
1449 | 0 | break; |
1450 | 0 |
|
1451 | 0 | case VERIFY_ALLOW_ALL: |
1452 | 0 | cert_ok_ = true; |
1453 | 0 | return SECSuccess; |
1454 | 0 |
|
1455 | 0 | case VERIFY_DIGEST: |
1456 | 0 | { |
1457 | 0 | MOZ_ASSERT(digests_.size() != 0); |
1458 | 0 | // Check all the provided digests |
1459 | 0 |
|
1460 | 0 | // Checking functions call PR_SetError() |
1461 | 0 | SECStatus rv = SECFailure; |
1462 | 0 | for (auto digest : digests_) { |
1463 | 0 | rv = CheckDigest(digest, peer_cert); |
1464 | 0 |
|
1465 | 0 | // Matches a digest, we are good to go |
1466 | 0 | if (rv == SECSuccess) { |
1467 | 0 | cert_ok_ = true; |
1468 | 0 | return SECSuccess; |
1469 | 0 | } |
1470 | 0 | } |
1471 | 0 | } |
1472 | 0 | break; |
1473 | 0 | default: |
1474 | 0 | MOZ_CRASH(); // Can't happen |
1475 | 0 | } |
1476 | 0 |
|
1477 | 0 | return SECFailure; |
1478 | 0 | } |
1479 | | |
1480 | 0 | void TransportLayerDtls::TimerCallback(nsITimer *timer, void *arg) { |
1481 | 0 | TransportLayerDtls *dtls = reinterpret_cast<TransportLayerDtls *>(arg); |
1482 | 0 |
|
1483 | 0 | MOZ_MTLOG(ML_DEBUG, "DTLS timer expired"); |
1484 | 0 |
|
1485 | 0 | dtls->Handshake(); |
1486 | 0 | } |
1487 | | |
1488 | | void |
1489 | | TransportLayerDtls::RecordHandshakeCompletionTelemetry( |
1490 | 0 | TransportLayer::State endState) { |
1491 | 0 | int32_t delta = (TimeStamp::Now() - handshake_started_).ToMilliseconds(); |
1492 | 0 |
|
1493 | 0 | switch (endState) { |
1494 | 0 | case TransportLayer::State::TS_OPEN: |
1495 | 0 | if (role_ == TransportLayerDtls::CLIENT) { |
1496 | 0 | Telemetry::Accumulate(Telemetry::WEBRTC_DTLS_CLIENT_SUCCESS_TIME, |
1497 | 0 | delta); |
1498 | 0 | } else { |
1499 | 0 | Telemetry::Accumulate(Telemetry::WEBRTC_DTLS_SERVER_SUCCESS_TIME, |
1500 | 0 | delta); |
1501 | 0 | } |
1502 | 0 | return; |
1503 | 0 | case TransportLayer::State::TS_ERROR: |
1504 | 0 | if (role_ == TransportLayerDtls::CLIENT) { |
1505 | 0 | Telemetry::Accumulate(Telemetry::WEBRTC_DTLS_CLIENT_FAILURE_TIME, |
1506 | 0 | delta); |
1507 | 0 | } else { |
1508 | 0 | Telemetry::Accumulate(Telemetry::WEBRTC_DTLS_SERVER_FAILURE_TIME, |
1509 | 0 | delta); |
1510 | 0 | } |
1511 | 0 | return; |
1512 | 0 | case TransportLayer::State::TS_CLOSED: |
1513 | 0 | if (role_ == TransportLayerDtls::CLIENT) { |
1514 | 0 | Telemetry::Accumulate(Telemetry::WEBRTC_DTLS_CLIENT_ABORT_TIME, delta); |
1515 | 0 | } else { |
1516 | 0 | Telemetry::Accumulate(Telemetry::WEBRTC_DTLS_SERVER_ABORT_TIME, delta); |
1517 | 0 | } |
1518 | 0 | return; |
1519 | 0 | default: |
1520 | 0 | MOZ_ASSERT(false); |
1521 | 0 | } |
1522 | 0 | } |
1523 | | |
1524 | | void |
1525 | 0 | TransportLayerDtls::RecordCipherTelemetry() { |
1526 | 0 | uint16_t cipher; |
1527 | 0 |
|
1528 | 0 | nsresult rv = GetCipherSuite(&cipher); |
1529 | 0 |
|
1530 | 0 | if (NS_FAILED(rv)) { |
1531 | 0 | MOZ_MTLOG(ML_ERROR, "Failed to get DTLS cipher suite"); |
1532 | 0 | return; |
1533 | 0 | } |
1534 | 0 |
|
1535 | 0 | uint16_t t_cipher = 0; |
1536 | 0 |
|
1537 | 0 | switch (cipher) { |
1538 | 0 | /* Old DHE ciphers: candidates for removal, see bug 1227519 */ |
1539 | 0 | case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: |
1540 | 0 | t_cipher = 1; |
1541 | 0 | break; |
1542 | 0 | case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: |
1543 | 0 | t_cipher = 2; |
1544 | 0 | break; |
1545 | 0 | /* Current ciphers */ |
1546 | 0 | case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: |
1547 | 0 | t_cipher = 3; |
1548 | 0 | break; |
1549 | 0 | case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: |
1550 | 0 | t_cipher = 4; |
1551 | 0 | break; |
1552 | 0 | case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: |
1553 | 0 | t_cipher = 5; |
1554 | 0 | break; |
1555 | 0 | case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: |
1556 | 0 | t_cipher = 6; |
1557 | 0 | break; |
1558 | 0 | case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: |
1559 | 0 | t_cipher = 7; |
1560 | 0 | break; |
1561 | 0 | case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: |
1562 | 0 | t_cipher = 8; |
1563 | 0 | break; |
1564 | 0 | case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: |
1565 | 0 | t_cipher = 9; |
1566 | 0 | break; |
1567 | 0 | case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: |
1568 | 0 | t_cipher = 10; |
1569 | 0 | break; |
1570 | 0 | /* TLS 1.3 ciphers */ |
1571 | 0 | case TLS_AES_128_GCM_SHA256: |
1572 | 0 | t_cipher = 11; |
1573 | 0 | break; |
1574 | 0 | case TLS_CHACHA20_POLY1305_SHA256: |
1575 | 0 | t_cipher = 12; |
1576 | 0 | break; |
1577 | 0 | case TLS_AES_256_GCM_SHA384: |
1578 | 0 | t_cipher = 13; |
1579 | 0 | break; |
1580 | 0 | } |
1581 | 0 | |
1582 | 0 | Telemetry::Accumulate(Telemetry::WEBRTC_DTLS_CIPHER, t_cipher); |
1583 | 0 |
|
1584 | 0 | rv = GetSrtpCipher(&cipher); |
1585 | 0 |
|
1586 | 0 | if (NS_FAILED(rv)) { |
1587 | 0 | MOZ_MTLOG(ML_ERROR, "Failed to get SRTP cipher suite"); |
1588 | 0 | return; |
1589 | 0 | } |
1590 | 0 |
|
1591 | 0 | mozilla::Telemetry::LABELS_WEBRTC_SRTP_CIPHER label = |
1592 | 0 | mozilla::Telemetry::LABELS_WEBRTC_SRTP_CIPHER::Unknown; |
1593 | 0 |
|
1594 | 0 | switch (cipher) { |
1595 | 0 | case kDtlsSrtpAes128CmHmacSha1_80: |
1596 | 0 | label = Telemetry::LABELS_WEBRTC_SRTP_CIPHER::Aes128CmHmacSha1_80; |
1597 | 0 | break; |
1598 | 0 | case kDtlsSrtpAes128CmHmacSha1_32: |
1599 | 0 | label = Telemetry::LABELS_WEBRTC_SRTP_CIPHER::Aes128CmHmacSha1_32; |
1600 | 0 | break; |
1601 | 0 | case kDtlsSrtpAeadAes128Gcm: |
1602 | 0 | label = Telemetry::LABELS_WEBRTC_SRTP_CIPHER::AeadAes128Gcm; |
1603 | 0 | break; |
1604 | 0 | case kDtlsSrtpAeadAes256Gcm: |
1605 | 0 | label = Telemetry::LABELS_WEBRTC_SRTP_CIPHER::AeadAes256Gcm; |
1606 | 0 | break; |
1607 | 0 | } |
1608 | 0 | |
1609 | 0 | Telemetry::AccumulateCategorical(label); |
1610 | 0 |
|
1611 | 0 | } |
1612 | | |
1613 | | } // close namespace |