Bumping manifests a=b2g-bump
[gecko.git] / media / mtransport / transportlayerdtls.cpp
blobbec04ff3974afbbfb3e770210279e91f76e127c2
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/. */
7 // Original author: ekr@rtfm.com
9 #include <queue>
10 #include <algorithm>
12 #include "mozilla/UniquePtr.h"
14 #include "logging.h"
15 #include "ssl.h"
16 #include "sslerr.h"
17 #include "sslproto.h"
18 #include "keyhi.h"
20 #include "nsCOMPtr.h"
21 #include "nsComponentManagerUtils.h"
22 #include "nsIEventTarget.h"
23 #include "nsNetCID.h"
24 #include "nsComponentManagerUtils.h"
25 #include "nsServiceManagerUtils.h"
27 #include "dtlsidentity.h"
28 #include "transportflow.h"
29 #include "transportlayerdtls.h"
31 namespace mozilla {
33 MOZ_MTLOG_MODULE("mtransport")
35 static PRDescIdentity transport_layer_identity = PR_INVALID_IO_LAYER;
37 // TODO: Implement a mode for this where
38 // the channel is not ready until confirmed externally
39 // (e.g., after cert check).
41 #define UNIMPLEMENTED \
42 MOZ_MTLOG(ML_ERROR, \
43 "Call to unimplemented function "<< __FUNCTION__); \
44 MOZ_ASSERT(false); \
45 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0)
48 // We need to adapt the NSPR/libssl model to the TransportFlow model.
49 // The former wants pull semantics and TransportFlow wants push.
51 // - A TransportLayerDtls assumes it is sitting on top of another
52 // TransportLayer, which means that events come in asynchronously.
53 // - NSS (libssl) wants to sit on top of a PRFileDesc and poll.
54 // - The TransportLayerNSPRAdapter is a PRFileDesc containing a
55 // FIFO.
56 // - When TransportLayerDtls.PacketReceived() is called, we insert
57 // the packets in the FIFO and then do a PR_Recv() on the NSS
58 // PRFileDesc, which eventually reads off the FIFO.
60 // All of this stuff is assumed to happen solely in a single thread
61 // (generally the SocketTransportService thread)
62 struct Packet {
63 Packet() : data_(nullptr), len_(0) {}
65 void Assign(const void *data, int32_t len) {
66 data_.reset(new uint8_t[len]);
67 memcpy(data_.get(), data, len);
68 len_ = len;
71 UniquePtr<uint8_t[]> data_;
72 int32_t len_;
75 void TransportLayerNSPRAdapter::PacketReceived(const void *data, int32_t len) {
76 input_.push(new Packet());
77 input_.back()->Assign(data, len);
80 int32_t TransportLayerNSPRAdapter::Recv(void *buf, int32_t buflen) {
81 if (input_.empty()) {
82 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
83 return -1;
86 Packet* front = input_.front();
87 if (buflen < front->len_) {
88 MOZ_ASSERT(false, "Not enough buffer space to receive into");
89 PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
90 return -1;
93 int32_t count = front->len_;
94 memcpy(buf, front->data_.get(), count);
96 input_.pop();
97 delete front;
99 return count;
102 int32_t TransportLayerNSPRAdapter::Write(const void *buf, int32_t length) {
103 TransportResult r = output_->SendPacket(
104 static_cast<const unsigned char *>(buf), length);
105 if (r >= 0) {
106 return r;
109 if (r == TE_WOULDBLOCK) {
110 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
111 } else {
112 PR_SetError(PR_IO_ERROR, 0);
115 return -1;
119 // Implementation of NSPR methods
120 static PRStatus TransportLayerClose(PRFileDesc *f) {
121 f->secret = nullptr;
122 return PR_SUCCESS;
125 static int32_t TransportLayerRead(PRFileDesc *f, void *buf, int32_t length) {
126 UNIMPLEMENTED;
127 return -1;
130 static int32_t TransportLayerWrite(PRFileDesc *f, const void *buf, int32_t length) {
131 TransportLayerNSPRAdapter *io = reinterpret_cast<TransportLayerNSPRAdapter *>(f->secret);
132 return io->Write(buf, length);
135 static int32_t TransportLayerAvailable(PRFileDesc *f) {
136 UNIMPLEMENTED;
137 return -1;
140 int64_t TransportLayerAvailable64(PRFileDesc *f) {
141 UNIMPLEMENTED;
142 return -1;
145 static PRStatus TransportLayerSync(PRFileDesc *f) {
146 UNIMPLEMENTED;
147 return PR_FAILURE;
150 static int32_t TransportLayerSeek(PRFileDesc *f, int32_t offset,
151 PRSeekWhence how) {
152 UNIMPLEMENTED;
153 return -1;
156 static int64_t TransportLayerSeek64(PRFileDesc *f, int64_t offset,
157 PRSeekWhence how) {
158 UNIMPLEMENTED;
159 return -1;
162 static PRStatus TransportLayerFileInfo(PRFileDesc *f, PRFileInfo *info) {
163 UNIMPLEMENTED;
164 return PR_FAILURE;
167 static PRStatus TransportLayerFileInfo64(PRFileDesc *f, PRFileInfo64 *info) {
168 UNIMPLEMENTED;
169 return PR_FAILURE;
172 static int32_t TransportLayerWritev(PRFileDesc *f, const PRIOVec *iov,
173 int32_t iov_size, PRIntervalTime to) {
174 UNIMPLEMENTED;
175 return -1;
178 static PRStatus TransportLayerConnect(PRFileDesc *f, const PRNetAddr *addr,
179 PRIntervalTime to) {
180 UNIMPLEMENTED;
181 return PR_FAILURE;
184 static PRFileDesc *TransportLayerAccept(PRFileDesc *sd, PRNetAddr *addr,
185 PRIntervalTime to) {
186 UNIMPLEMENTED;
187 return nullptr;
190 static PRStatus TransportLayerBind(PRFileDesc *f, const PRNetAddr *addr) {
191 UNIMPLEMENTED;
192 return PR_FAILURE;
195 static PRStatus TransportLayerListen(PRFileDesc *f, int32_t depth) {
196 UNIMPLEMENTED;
197 return PR_FAILURE;
200 static PRStatus TransportLayerShutdown(PRFileDesc *f, int32_t how) {
201 UNIMPLEMENTED;
202 return PR_FAILURE;
205 // This function does not support peek, or waiting until `to`
206 static int32_t TransportLayerRecv(PRFileDesc *f, void *buf, int32_t buflen,
207 int32_t flags, PRIntervalTime to) {
208 MOZ_ASSERT(flags == 0);
209 if (flags != 0) {
210 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
211 return -1;
214 TransportLayerNSPRAdapter *io = reinterpret_cast<TransportLayerNSPRAdapter *>(f->secret);
215 return io->Recv(buf, buflen);
218 // Note: this is always nonblocking and assumes a zero timeout.
219 static int32_t TransportLayerSend(PRFileDesc *f, const void *buf, int32_t amount,
220 int32_t flags, PRIntervalTime to) {
221 int32_t written = TransportLayerWrite(f, buf, amount);
222 return written;
225 static int32_t TransportLayerRecvfrom(PRFileDesc *f, void *buf, int32_t amount,
226 int32_t flags, PRNetAddr *addr, PRIntervalTime to) {
227 UNIMPLEMENTED;
228 return -1;
231 static int32_t TransportLayerSendto(PRFileDesc *f, const void *buf, int32_t amount,
232 int32_t flags, const PRNetAddr *addr, PRIntervalTime to) {
233 UNIMPLEMENTED;
234 return -1;
237 static int16_t TransportLayerPoll(PRFileDesc *f, int16_t in_flags, int16_t *out_flags) {
238 UNIMPLEMENTED;
239 return -1;
242 static int32_t TransportLayerAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
243 PRNetAddr **raddr,
244 void *buf, int32_t amount, PRIntervalTime t) {
245 UNIMPLEMENTED;
246 return -1;
249 static int32_t TransportLayerTransmitFile(PRFileDesc *sd, PRFileDesc *f,
250 const void *headers, int32_t hlen,
251 PRTransmitFileFlags flags, PRIntervalTime t) {
252 UNIMPLEMENTED;
253 return -1;
256 static PRStatus TransportLayerGetpeername(PRFileDesc *f, PRNetAddr *addr) {
257 // TODO: Modify to return unique names for each channel
258 // somehow, as opposed to always the same static address. The current
259 // implementation messes up the session cache, which is why it's off
260 // elsewhere
261 addr->inet.family = PR_AF_INET;
262 addr->inet.port = 0;
263 addr->inet.ip = 0;
265 return PR_SUCCESS;
268 static PRStatus TransportLayerGetsockname(PRFileDesc *f, PRNetAddr *addr) {
269 UNIMPLEMENTED;
270 return PR_FAILURE;
273 static PRStatus TransportLayerGetsockoption(PRFileDesc *f, PRSocketOptionData *opt) {
274 switch (opt->option) {
275 case PR_SockOpt_Nonblocking:
276 opt->value.non_blocking = PR_TRUE;
277 return PR_SUCCESS;
278 default:
279 UNIMPLEMENTED;
280 break;
283 return PR_FAILURE;
286 // Imitate setting socket options. These are mostly noops.
287 static PRStatus TransportLayerSetsockoption(PRFileDesc *f,
288 const PRSocketOptionData *opt) {
289 switch (opt->option) {
290 case PR_SockOpt_Nonblocking:
291 return PR_SUCCESS;
292 case PR_SockOpt_NoDelay:
293 return PR_SUCCESS;
294 default:
295 UNIMPLEMENTED;
296 break;
299 return PR_FAILURE;
302 static int32_t TransportLayerSendfile(PRFileDesc *out, PRSendFileData *in,
303 PRTransmitFileFlags flags, PRIntervalTime to) {
304 UNIMPLEMENTED;
305 return -1;
308 static PRStatus TransportLayerConnectContinue(PRFileDesc *f, int16_t flags) {
309 UNIMPLEMENTED;
310 return PR_FAILURE;
313 static int32_t TransportLayerReserved(PRFileDesc *f) {
314 UNIMPLEMENTED;
315 return -1;
318 static const struct PRIOMethods TransportLayerMethods = {
319 PR_DESC_LAYERED,
320 TransportLayerClose,
321 TransportLayerRead,
322 TransportLayerWrite,
323 TransportLayerAvailable,
324 TransportLayerAvailable64,
325 TransportLayerSync,
326 TransportLayerSeek,
327 TransportLayerSeek64,
328 TransportLayerFileInfo,
329 TransportLayerFileInfo64,
330 TransportLayerWritev,
331 TransportLayerConnect,
332 TransportLayerAccept,
333 TransportLayerBind,
334 TransportLayerListen,
335 TransportLayerShutdown,
336 TransportLayerRecv,
337 TransportLayerSend,
338 TransportLayerRecvfrom,
339 TransportLayerSendto,
340 TransportLayerPoll,
341 TransportLayerAcceptRead,
342 TransportLayerTransmitFile,
343 TransportLayerGetsockname,
344 TransportLayerGetpeername,
345 TransportLayerReserved,
346 TransportLayerReserved,
347 TransportLayerGetsockoption,
348 TransportLayerSetsockoption,
349 TransportLayerSendfile,
350 TransportLayerConnectContinue,
351 TransportLayerReserved,
352 TransportLayerReserved,
353 TransportLayerReserved,
354 TransportLayerReserved
357 TransportLayerDtls::~TransportLayerDtls() {
358 if (timer_) {
359 timer_->Cancel();
363 nsresult TransportLayerDtls::InitInternal() {
364 // Get the transport service as an event target
365 nsresult rv;
366 target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
368 if (NS_FAILED(rv)) {
369 MOZ_MTLOG(ML_ERROR, "Couldn't get socket transport service");
370 return rv;
373 timer_ = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
374 if (NS_FAILED(rv)) {
375 MOZ_MTLOG(ML_ERROR, "Couldn't get timer");
376 return rv;
379 return NS_OK;
383 void TransportLayerDtls::WasInserted() {
384 // Connect to the lower layers
385 if (!Setup()) {
386 TL_SET_STATE(TS_ERROR);
391 nsresult TransportLayerDtls::SetVerificationAllowAll() {
392 // Defensive programming
393 if (verification_mode_ != VERIFY_UNSET)
394 return NS_ERROR_ALREADY_INITIALIZED;
396 verification_mode_ = VERIFY_ALLOW_ALL;
398 return NS_OK;
401 nsresult
402 TransportLayerDtls::SetVerificationDigest(const std::string digest_algorithm,
403 const unsigned char *digest_value,
404 size_t digest_len) {
405 // Defensive programming
406 if (verification_mode_ != VERIFY_UNSET &&
407 verification_mode_ != VERIFY_DIGEST) {
408 return NS_ERROR_ALREADY_INITIALIZED;
411 // Note that we do not sanity check these values for length.
412 // We merely ensure they will fit into the buffer.
413 // TODO: is there a Data construct we could use?
414 if (digest_len > kMaxDigestLength)
415 return NS_ERROR_INVALID_ARG;
417 digests_.push_back(new VerificationDigest(
418 digest_algorithm, digest_value, digest_len));
420 verification_mode_ = VERIFY_DIGEST;
422 return NS_OK;
425 // TODO: make sure this is called from STS. Otherwise
426 // we have thread safety issues
427 bool TransportLayerDtls::Setup() {
428 CheckThread();
429 SECStatus rv;
431 if (!downward_) {
432 MOZ_MTLOG(ML_ERROR, "DTLS layer with nothing below. This is useless");
433 return false;
435 nspr_io_adapter_ = new TransportLayerNSPRAdapter(downward_);
437 if (!identity_) {
438 MOZ_MTLOG(ML_ERROR, "Can't start DTLS without an identity");
439 return false;
442 if (verification_mode_ == VERIFY_UNSET) {
443 MOZ_MTLOG(ML_ERROR,
444 "Can't start DTLS without specifying a verification mode");
445 return false;
448 if (transport_layer_identity == PR_INVALID_IO_LAYER) {
449 transport_layer_identity = PR_GetUniqueIdentity("nssstreamadapter");
452 ScopedPRFileDesc pr_fd(PR_CreateIOLayerStub(transport_layer_identity,
453 &TransportLayerMethods));
454 MOZ_ASSERT(pr_fd != nullptr);
455 if (!pr_fd)
456 return false;
457 pr_fd->secret = reinterpret_cast<PRFilePrivate *>(nspr_io_adapter_.get());
459 ScopedPRFileDesc ssl_fd(DTLS_ImportFD(nullptr, pr_fd));
460 MOZ_ASSERT(ssl_fd != nullptr); // This should never happen
461 if (!ssl_fd) {
462 return false;
465 pr_fd.forget(); // ownership transfered to ssl_fd;
467 if (role_ == CLIENT) {
468 MOZ_MTLOG(ML_DEBUG, "Setting up DTLS as client");
469 rv = SSL_GetClientAuthDataHook(ssl_fd, GetClientAuthDataHook,
470 this);
471 if (rv != SECSuccess) {
472 MOZ_MTLOG(ML_ERROR, "Couldn't set identity");
473 return false;
475 } else {
476 MOZ_MTLOG(ML_DEBUG, "Setting up DTLS as server");
477 // Server side
478 rv = SSL_ConfigSecureServer(ssl_fd, identity_->cert(),
479 identity_->privkey(),
480 kt_rsa);
481 if (rv != SECSuccess) {
482 MOZ_MTLOG(ML_ERROR, "Couldn't set identity");
483 return false;
486 // Insist on a certificate from the client
487 rv = SSL_OptionSet(ssl_fd, SSL_REQUEST_CERTIFICATE, PR_TRUE);
488 if (rv != SECSuccess) {
489 MOZ_MTLOG(ML_ERROR, "Couldn't request certificate");
490 return false;
493 rv = SSL_OptionSet(ssl_fd, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
494 if (rv != SECSuccess) {
495 MOZ_MTLOG(ML_ERROR, "Couldn't require certificate");
496 return false;
500 // Require TLS 1.1 or 1.2. Perhaps some day in the future we will allow TLS
501 // 1.0 for stream modes.
502 SSLVersionRange version_range = {
503 SSL_LIBRARY_VERSION_TLS_1_1,
504 SSL_LIBRARY_VERSION_TLS_1_1 // version intolerance; bug 1052610
507 rv = SSL_VersionRangeSet(ssl_fd, &version_range);
508 if (rv != SECSuccess) {
509 MOZ_MTLOG(ML_ERROR, "Can't disable SSLv3");
510 return false;
513 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
514 if (rv != SECSuccess) {
515 MOZ_MTLOG(ML_ERROR, "Couldn't disable session tickets");
516 return false;
519 rv = SSL_OptionSet(ssl_fd, SSL_NO_CACHE, PR_TRUE);
520 if (rv != SECSuccess) {
521 MOZ_MTLOG(ML_ERROR, "Couldn't disable session caching");
522 return false;
525 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_DEFLATE, PR_FALSE);
526 if (rv != SECSuccess) {
527 MOZ_MTLOG(ML_ERROR, "Couldn't disable deflate");
528 return false;
531 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER);
532 if (rv != SECSuccess) {
533 MOZ_MTLOG(ML_ERROR, "Couldn't disable renegotiation");
534 return false;
537 rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_FALSE_START, PR_FALSE);
538 if (rv != SECSuccess) {
539 MOZ_MTLOG(ML_ERROR, "Couldn't disable false start");
540 return false;
543 rv = SSL_OptionSet(ssl_fd, SSL_NO_LOCKS, PR_TRUE);
544 if (rv != SECSuccess) {
545 MOZ_MTLOG(ML_ERROR, "Couldn't disable locks");
546 return false;
549 rv = SSL_OptionSet(ssl_fd, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
550 if (rv != SECSuccess) {
551 MOZ_MTLOG(ML_ERROR, "Couldn't disable ECDHE key reuse");
552 return false;
555 if (!SetupCipherSuites(ssl_fd)) {
556 return false;
559 // Certificate validation
560 rv = SSL_AuthCertificateHook(ssl_fd, AuthCertificateHook,
561 reinterpret_cast<void *>(this));
562 if (rv != SECSuccess) {
563 MOZ_MTLOG(ML_ERROR, "Couldn't set certificate validation hook");
564 return false;
567 // Now start the handshake
568 rv = SSL_ResetHandshake(ssl_fd, role_ == SERVER ? PR_TRUE : PR_FALSE);
569 if (rv != SECSuccess) {
570 MOZ_MTLOG(ML_ERROR, "Couldn't reset handshake");
571 return false;
573 ssl_fd_ = ssl_fd.forget();
575 // Finally, get ready to receive data
576 downward_->SignalStateChange.connect(this, &TransportLayerDtls::StateChange);
577 downward_->SignalPacketReceived.connect(this, &TransportLayerDtls::PacketReceived);
579 if (downward_->state() == TS_OPEN) {
580 Handshake();
583 return true;
586 // Ciphers we need to enable. These are on by default in standard firefox
587 // builds, but can be disabled with prefs and they aren't on in our unit tests
588 // since that uses NSS default configuration.
589 // Only override prefs to comply with MUST statements in the security-arch.
590 static const uint32_t EnabledCiphers[] = {
591 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
592 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
595 // Don't remove suites; TODO(mt@mozilla.com) restore; bug 1052610
596 #if 0
597 // Disable all NSS suites modes without PFS or with old and rusty ciphersuites.
598 // Anything outside this list is governed by the usual combination of policy
599 // and user preferences.
600 static const uint32_t DisabledCiphers[] = {
601 TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
602 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
603 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
604 TLS_ECDHE_RSA_WITH_RC4_128_SHA,
606 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
607 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
608 TLS_DHE_DSS_WITH_RC4_128_SHA,
610 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
611 TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
612 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
613 TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
614 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
615 TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
616 TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
617 TLS_ECDH_RSA_WITH_RC4_128_SHA,
619 TLS_RSA_WITH_AES_128_GCM_SHA256,
620 TLS_RSA_WITH_AES_128_CBC_SHA,
621 TLS_RSA_WITH_AES_128_CBC_SHA256,
622 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
623 TLS_RSA_WITH_AES_256_CBC_SHA,
624 TLS_RSA_WITH_AES_256_CBC_SHA256,
625 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
626 TLS_RSA_WITH_SEED_CBC_SHA,
627 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,
628 TLS_RSA_WITH_3DES_EDE_CBC_SHA,
629 TLS_RSA_WITH_RC4_128_SHA,
630 TLS_RSA_WITH_RC4_128_MD5,
632 TLS_DHE_RSA_WITH_DES_CBC_SHA,
633 TLS_DHE_DSS_WITH_DES_CBC_SHA,
634 SSL_RSA_FIPS_WITH_DES_CBC_SHA,
635 TLS_RSA_WITH_DES_CBC_SHA,
637 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
638 TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
640 TLS_RSA_EXPORT_WITH_RC4_40_MD5,
641 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
643 TLS_ECDHE_ECDSA_WITH_NULL_SHA,
644 TLS_ECDHE_RSA_WITH_NULL_SHA,
645 TLS_ECDH_ECDSA_WITH_NULL_SHA,
646 TLS_ECDH_RSA_WITH_NULL_SHA,
648 TLS_RSA_WITH_NULL_SHA,
649 TLS_RSA_WITH_NULL_SHA256,
650 TLS_RSA_WITH_NULL_MD5,
652 #endif // bug 1052610
654 bool TransportLayerDtls::SetupCipherSuites(PRFileDesc* ssl_fd) const {
655 SECStatus rv;
657 // Set the SRTP ciphers
658 if (!srtp_ciphers_.empty()) {
659 // Note: std::vector is guaranteed to contiguous
660 rv = SSL_SetSRTPCiphers(ssl_fd, &srtp_ciphers_[0], srtp_ciphers_.size());
662 if (rv != SECSuccess) {
663 MOZ_MTLOG(ML_ERROR, "Couldn't set SRTP cipher suite");
664 return false;
668 for (size_t i = 0; i < PR_ARRAY_SIZE(EnabledCiphers); ++i) {
669 MOZ_MTLOG(ML_INFO, LAYER_INFO << "Enabling: " << EnabledCiphers[i]);
670 rv = SSL_CipherPrefSet(ssl_fd, EnabledCiphers[i], PR_TRUE);
671 if (rv != SECSuccess) {
672 MOZ_MTLOG(ML_ERROR, LAYER_INFO <<
673 "Unable to enable suite: " << EnabledCiphers[i]);
674 return false;
678 // Don't remove suites; TODO(mt@mozilla.com) restore; bug 1052610
679 #if 0
680 for (size_t i = 0; i < PR_ARRAY_SIZE(DisabledCiphers); ++i) {
681 MOZ_MTLOG(ML_INFO, LAYER_INFO << "Disabling: " << DisabledCiphers[i]);
683 PRBool enabled = false;
684 rv = SSL_CipherPrefGet(ssl_fd, DisabledCiphers[i], &enabled);
685 if (rv != SECSuccess) {
686 MOZ_MTLOG(ML_NOTICE, LAYER_INFO <<
687 "Unable to check if suite is enabled: " << DisabledCiphers[i]);
688 return false;
690 if (enabled) {
691 rv = SSL_CipherPrefSet(ssl_fd, DisabledCiphers[i], PR_FALSE);
692 if (rv != SECSuccess) {
693 MOZ_MTLOG(ML_NOTICE, LAYER_INFO <<
694 "Unable to disable suite: " << DisabledCiphers[i]);
695 return false;
699 #endif
700 return true;
703 nsresult TransportLayerDtls::GetCipherSuite(uint16_t* cipherSuite) const {
704 CheckThread();
705 if (!cipherSuite) {
706 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "GetCipherSuite passed a nullptr");
707 return NS_ERROR_NULL_POINTER;
709 if (state_ != TS_OPEN) {
710 return NS_ERROR_NOT_AVAILABLE;
712 SSLChannelInfo info;
713 SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &info, sizeof(info));
714 if (rv != SECSuccess) {
715 MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "GetCipherSuite can't get channel info");
716 return NS_ERROR_FAILURE;
718 *cipherSuite = info.cipherSuite;
719 return NS_OK;
722 void TransportLayerDtls::StateChange(TransportLayer *layer, State state) {
723 if (state <= state_) {
724 MOZ_MTLOG(ML_ERROR, "Lower layer state is going backwards from ours");
725 TL_SET_STATE(TS_ERROR);
726 return;
729 switch (state) {
730 case TS_NONE:
731 MOZ_ASSERT(false); // Can't happen
732 break;
734 case TS_INIT:
735 MOZ_MTLOG(ML_ERROR,
736 LAYER_INFO << "State change of lower layer to INIT forbidden");
737 TL_SET_STATE(TS_ERROR);
738 break;
740 case TS_CONNECTING:
741 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Lower layer is connecting.");
742 break;
744 case TS_OPEN:
745 MOZ_MTLOG(ML_ERROR,
746 LAYER_INFO << "Lower layer is now open; starting TLS");
747 Handshake();
748 break;
750 case TS_CLOSED:
751 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Lower layer is now closed");
752 TL_SET_STATE(TS_CLOSED);
753 break;
755 case TS_ERROR:
756 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Lower layer experienced an error");
757 TL_SET_STATE(TS_ERROR);
758 break;
762 void TransportLayerDtls::Handshake() {
763 TL_SET_STATE(TS_CONNECTING);
765 // Clear the retransmit timer
766 timer_->Cancel();
768 SECStatus rv = SSL_ForceHandshake(ssl_fd_);
770 if (rv == SECSuccess) {
771 MOZ_MTLOG(ML_NOTICE,
772 LAYER_INFO << "****** SSL handshake completed ******");
773 if (!cert_ok_) {
774 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Certificate check never occurred");
775 TL_SET_STATE(TS_ERROR);
776 return;
778 TL_SET_STATE(TS_OPEN);
779 } else {
780 int32_t err = PR_GetError();
781 switch(err) {
782 case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
783 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Malformed DTLS message; ignoring");
784 // If this were TLS (and not DTLS), this would be fatal, but
785 // here we're required to ignore bad messages, so fall through
786 case PR_WOULD_BLOCK_ERROR:
787 MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "Handshake would have blocked");
788 PRIntervalTime timeout;
789 rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
790 if (rv == SECSuccess) {
791 uint32_t timeout_ms = PR_IntervalToMilliseconds(timeout);
793 MOZ_MTLOG(ML_DEBUG,
794 LAYER_INFO << "Setting DTLS timeout to " << timeout_ms);
795 timer_->SetTarget(target_);
796 timer_->InitWithFuncCallback(TimerCallback,
797 this, timeout_ms,
798 nsITimer::TYPE_ONE_SHOT);
800 break;
801 default:
802 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "SSL handshake error "<< err);
803 TL_SET_STATE(TS_ERROR);
804 break;
809 void TransportLayerDtls::PacketReceived(TransportLayer* layer,
810 const unsigned char *data,
811 size_t len) {
812 CheckThread();
813 MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << len << ")");
815 if (state_ != TS_CONNECTING && state_ != TS_OPEN) {
816 MOZ_MTLOG(ML_DEBUG,
817 LAYER_INFO << "Discarding packet in inappropriate state");
818 return;
821 nspr_io_adapter_->PacketReceived(data, len);
823 // If we're still connecting, try to handshake
824 if (state_ == TS_CONNECTING) {
825 Handshake();
828 // Now try a recv if we're open, since there might be data left
829 if (state_ == TS_OPEN) {
830 unsigned char buf[2000];
832 int32_t rv = PR_Recv(ssl_fd_, buf, sizeof(buf), 0, PR_INTERVAL_NO_WAIT);
833 if (rv > 0) {
834 // We have data
835 MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Read " << rv << " bytes from NSS");
836 SignalPacketReceived(this, buf, rv);
837 } else if (rv == 0) {
838 TL_SET_STATE(TS_CLOSED);
839 } else {
840 int32_t err = PR_GetError();
842 if (err == PR_WOULD_BLOCK_ERROR) {
843 // This gets ignored
844 MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Receive would have blocked");
845 } else {
846 MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "NSS Error " << err);
847 TL_SET_STATE(TS_ERROR);
853 TransportResult TransportLayerDtls::SendPacket(const unsigned char *data,
854 size_t len) {
855 CheckThread();
856 if (state_ != TS_OPEN) {
857 MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Can't call SendPacket() in state "
858 << state_);
859 return TE_ERROR;
862 int32_t rv = PR_Send(ssl_fd_, data, len, 0, PR_INTERVAL_NO_WAIT);
864 if (rv > 0) {
865 // We have data
866 MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Wrote " << rv << " bytes to SSL Layer");
867 return rv;
870 if (rv == 0) {
871 TL_SET_STATE(TS_CLOSED);
872 return 0;
875 int32_t err = PR_GetError();
877 if (err == PR_WOULD_BLOCK_ERROR) {
878 // This gets ignored
879 MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Send would have blocked");
880 return TE_WOULDBLOCK;
883 MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "NSS Error " << err);
884 TL_SET_STATE(TS_ERROR);
885 return TE_ERROR;
888 SECStatus TransportLayerDtls::GetClientAuthDataHook(void *arg, PRFileDesc *fd,
889 CERTDistNames *caNames,
890 CERTCertificate **pRetCert,
891 SECKEYPrivateKey **pRetKey) {
892 MOZ_MTLOG(ML_DEBUG, "Server requested client auth");
894 TransportLayerDtls *stream = reinterpret_cast<TransportLayerDtls *>(arg);
895 stream->CheckThread();
897 if (!stream->identity_) {
898 MOZ_MTLOG(ML_ERROR, "No identity available");
899 PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
900 return SECFailure;
903 *pRetCert = CERT_DupCertificate(stream->identity_->cert());
904 if (!*pRetCert) {
905 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
906 return SECFailure;
909 *pRetKey = SECKEY_CopyPrivateKey(stream->identity_->privkey());
910 if (!*pRetKey) {
911 CERT_DestroyCertificate(*pRetCert);
912 *pRetCert = nullptr;
913 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
914 return SECFailure;
917 return SECSuccess;
920 nsresult TransportLayerDtls::SetSrtpCiphers(std::vector<uint16_t> ciphers) {
921 // TODO: We should check these
922 srtp_ciphers_ = ciphers;
924 return NS_OK;
927 nsresult TransportLayerDtls::GetSrtpCipher(uint16_t *cipher) const {
928 CheckThread();
929 SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, cipher);
930 if (rv != SECSuccess) {
931 MOZ_MTLOG(ML_DEBUG, "No SRTP cipher negotiated");
932 return NS_ERROR_FAILURE;
935 return NS_OK;
938 nsresult TransportLayerDtls::ExportKeyingMaterial(const std::string& label,
939 bool use_context,
940 const std::string& context,
941 unsigned char *out,
942 unsigned int outlen) {
943 CheckThread();
944 SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_,
945 label.c_str(),
946 label.size(),
947 use_context,
948 reinterpret_cast<const unsigned char *>(
949 context.c_str()),
950 context.size(),
951 out,
952 outlen);
953 if (rv != SECSuccess) {
954 MOZ_MTLOG(ML_ERROR, "Couldn't export SSL keying material");
955 return NS_ERROR_FAILURE;
958 return NS_OK;
961 SECStatus TransportLayerDtls::AuthCertificateHook(void *arg,
962 PRFileDesc *fd,
963 PRBool checksig,
964 PRBool isServer) {
965 TransportLayerDtls *stream = reinterpret_cast<TransportLayerDtls *>(arg);
966 stream->CheckThread();
967 return stream->AuthCertificateHook(fd, checksig, isServer);
970 SECStatus
971 TransportLayerDtls::CheckDigest(const RefPtr<VerificationDigest>&
972 digest,
973 CERTCertificate *peer_cert) {
974 unsigned char computed_digest[kMaxDigestLength];
975 size_t computed_digest_len;
977 MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Checking digest, algorithm="
978 << digest->algorithm_);
979 nsresult res =
980 DtlsIdentity::ComputeFingerprint(peer_cert,
981 digest->algorithm_,
982 computed_digest,
983 sizeof(computed_digest),
984 &computed_digest_len);
985 if (NS_FAILED(res)) {
986 MOZ_MTLOG(ML_ERROR, "Could not compute peer fingerprint for digest " <<
987 digest->algorithm_);
988 // Go to end
989 PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0);
990 return SECFailure;
993 if (computed_digest_len != digest->len_) {
994 MOZ_MTLOG(ML_ERROR, "Digest is wrong length " << digest->len_ <<
995 " should be " << computed_digest_len << " for algorithm " <<
996 digest->algorithm_);
997 PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0);
998 return SECFailure;
1001 if (memcmp(digest->value_, computed_digest, computed_digest_len) != 0) {
1002 MOZ_MTLOG(ML_ERROR, "Digest does not match");
1003 PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0);
1004 return SECFailure;
1007 return SECSuccess;
1011 SECStatus TransportLayerDtls::AuthCertificateHook(PRFileDesc *fd,
1012 PRBool checksig,
1013 PRBool isServer) {
1014 CheckThread();
1015 ScopedCERTCertificate peer_cert;
1016 peer_cert = SSL_PeerCertificate(fd);
1019 // We are not set up to take this being called multiple
1020 // times. Change this if we ever add renegotiation.
1021 MOZ_ASSERT(!auth_hook_called_);
1022 if (auth_hook_called_) {
1023 PR_SetError(PR_UNKNOWN_ERROR, 0);
1024 return SECFailure;
1026 auth_hook_called_ = true;
1028 MOZ_ASSERT(verification_mode_ != VERIFY_UNSET);
1029 MOZ_ASSERT(peer_cert_ == nullptr);
1031 switch (verification_mode_) {
1032 case VERIFY_UNSET:
1033 // Break out to error exit
1034 PR_SetError(PR_UNKNOWN_ERROR, 0);
1035 break;
1037 case VERIFY_ALLOW_ALL:
1038 peer_cert_ = peer_cert.forget();
1039 cert_ok_ = true;
1040 return SECSuccess;
1042 case VERIFY_DIGEST:
1044 MOZ_ASSERT(digests_.size() != 0);
1045 // Check all the provided digests
1047 // Checking functions call PR_SetError()
1048 SECStatus rv = SECFailure;
1049 for (size_t i = 0; i < digests_.size(); i++) {
1050 RefPtr<VerificationDigest> digest = digests_[i];
1051 rv = CheckDigest(digest, peer_cert);
1053 if (rv != SECSuccess)
1054 break;
1057 if (rv == SECSuccess) {
1058 // Matches all digests, we are good to go
1059 cert_ok_ = true;
1060 peer_cert = peer_cert.forget();
1061 return SECSuccess;
1064 break;
1065 default:
1066 MOZ_CRASH(); // Can't happen
1069 return SECFailure;
1072 void TransportLayerDtls::TimerCallback(nsITimer *timer, void *arg) {
1073 TransportLayerDtls *dtls = reinterpret_cast<TransportLayerDtls *>(arg);
1075 MOZ_MTLOG(ML_DEBUG, "DTLS timer expired");
1077 dtls->Handshake();
1080 } // close namespace