ControllerPtr ControllerTable::GetControllerByName(const std::string & name) { boost::lock_guard<boost::mutex> lck(m_lock); for (ControllerMap::iterator it=m_controllers.begin(); it != m_controllers.end(); ++it) { if (it->second != NULL) { const char* tmpName; //if it is not connected there is no connection name to get if (it->second->IsConnected()) { tmpName = it->second->GetConnectionName(); CheckThread(it->first); //check the threading if we're in debug build if (name == std::string(tmpName)) { return it->second; } } } } ENSURE(false, << "An unknown controller name was used! " << name.c_str()); return ControllerPtr(); //Keep compiler happy }
SECStatus TransportLayerDtls::AuthCertificateHook(PRFileDesc *fd, PRBool checksig, PRBool isServer) { CheckThread(); ScopedCERTCertificate peer_cert; peer_cert = SSL_PeerCertificate(fd); // We are not set up to take this being called multiple // times. Change this if we ever add renegotiation. MOZ_ASSERT(!auth_hook_called_); if (auth_hook_called_) { PR_SetError(PR_UNKNOWN_ERROR, 0); return SECFailure; } auth_hook_called_ = true; MOZ_ASSERT(verification_mode_ != VERIFY_UNSET); MOZ_ASSERT(peer_cert_ == nullptr); switch (verification_mode_) { case VERIFY_UNSET: // Break out to error exit PR_SetError(PR_UNKNOWN_ERROR, 0); break; case VERIFY_ALLOW_ALL: peer_cert_ = peer_cert.forget(); cert_ok_ = true; return SECSuccess; case VERIFY_DIGEST: { MOZ_ASSERT(digests_.size() != 0); // Check all the provided digests // Checking functions call PR_SetError() SECStatus rv = SECFailure; for (size_t i = 0; i < digests_.size(); i++) { RefPtr<VerificationDigest> digest = digests_[i]; rv = CheckDigest(digest, peer_cert); if (rv != SECSuccess) break; } if (rv == SECSuccess) { // Matches all digests, we are good to go cert_ok_ = true; peer_cert = peer_cert.forget(); return SECSuccess; } } break; default: MOZ_CRASH(); // Can't happen } return SECFailure; }
TransportResult TransportLayerDtls::SendPacket(const unsigned char *data, size_t len) { CheckThread(); if (state_ != TS_OPEN) { MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Can't call SendPacket() in state " << state_); return TE_ERROR; } int32_t rv = PR_Send(ssl_fd_, data, len, 0, PR_INTERVAL_NO_WAIT); if (rv > 0) { // We have data MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Wrote " << rv << " bytes to SSL Layer"); return rv; } if (rv == 0) { TL_SET_STATE(TS_CLOSED); return 0; } int32_t err = PR_GetError(); if (err == PR_WOULD_BLOCK_ERROR) { // This gets ignored MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Send would have blocked"); return TE_WOULDBLOCK; } MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "NSS Error " << err); TL_SET_STATE(TS_ERROR); return TE_ERROR; }
nsresult TransportLayerDtls::ExportKeyingMaterial(const std::string& label, bool use_context, const std::string& context, unsigned char *out, unsigned int outlen) { CheckThread(); if (state_ != TS_OPEN) { MOZ_ASSERT(false, "Transport must be open for ExportKeyingMaterial"); return NS_ERROR_NOT_AVAILABLE; } SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_, label.c_str(), label.size(), use_context, reinterpret_cast<const unsigned char *>( context.c_str()), context.size(), out, outlen); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't export SSL keying material"); return NS_ERROR_FAILURE; } return NS_OK; }
void TransportLayerIce::IceFailed(NrIceMediaStream *stream) { CheckThread(); // only handle the current stream (not the old stream during restart) if (stream != stream_) { return; } MOZ_MTLOG(ML_INFO, LAYER_INFO << "ICE Failed(" << stream->name() << "," << component_ << ")"); TL_SET_STATE(TS_ERROR); }
nsresult TransportLayerDtls::GetSrtpCipher(uint16_t *cipher) const { CheckThread(); SECStatus rv = SSL_GetSRTPCipher(ssl_fd_, cipher); if (rv != SECSuccess) { MOZ_MTLOG(ML_DEBUG, "No SRTP cipher negotiated"); return NS_ERROR_FAILURE; } return NS_OK; }
void TransportLayerIce::IcePacketReceived(NrIceMediaStream *stream, int component, const unsigned char *data, int len) { CheckThread(); // We get packets for both components, so ignore the ones that aren't // for us. if (component_ != component) return; MOZ_MTLOG(PR_LOG_DEBUG, LAYER_INFO << "PacketReceived(" << stream->name() << "," << component << "," << len << ")"); SignalPacketReceived(this, data, len); }
void Scheduler::WaitForWritable(const util::TaskCallback& callback, int pollable, bool oneshot) { /* Unlike timers, Qt (4.4) doesn't support QSocketNotifiers * constructed on the wrong thread. */ CheckThread(); m_notifiermap[pollable] = new SocketNotifier(pollable, QSocketNotifier::Write, this, callback, oneshot); }
TransportResult TransportLayerIce::SendPacket(const unsigned char *data, size_t len) { CheckThread(); nsresult res = stream_->SendPacket(component_, data, len); if (!NS_SUCCEEDED(res)) { return (res == NS_BASE_STREAM_WOULD_BLOCK) ? TE_WOULDBLOCK : TE_ERROR; } MOZ_MTLOG(PR_LOG_DEBUG, LAYER_INFO << " SendPacket(" << len << ") succeeded"); return len; }
void TransportLayerDtls::PacketReceived(TransportLayer* layer, const unsigned char *data, size_t len) { CheckThread(); MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << len << ")"); if (state_ != TS_CONNECTING && state_ != TS_OPEN) { MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Discarding packet in inappropriate state"); return; } nspr_io_adapter_->PacketReceived(data, len); // If we're still connecting, try to handshake if (state_ == TS_CONNECTING) { Handshake(); } // Now try a recv if we're open, since there might be data left if (state_ == TS_OPEN) { // nICEr uses a 9216 bytes buffer to allow support for jumbo frames unsigned char buf[9216]; int32_t rv; // One packet might contain several DTLS packets do { rv = PR_Recv(ssl_fd_, buf, sizeof(buf), 0, PR_INTERVAL_NO_WAIT); if (rv > 0) { // We have data MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Read " << rv << " bytes from NSS"); SignalPacketReceived(this, buf, rv); } else if (rv == 0) { TL_SET_STATE(TS_CLOSED); } else { int32_t err = PR_GetError(); if (err == PR_WOULD_BLOCK_ERROR) { // This gets ignored MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Receive would have blocked"); } else { MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "NSS Error " << err); TL_SET_STATE(TS_ERROR); } } } while (rv > 0); } }
nsresult TransportLayerDtls::GetCipherSuite(uint16_t* cipherSuite) const { CheckThread(); if (!cipherSuite) { MOZ_MTLOG(ML_ERROR, LAYER_INFO << "GetCipherSuite passed a nullptr"); return NS_ERROR_NULL_POINTER; } if (state_ != TS_OPEN) { return NS_ERROR_NOT_AVAILABLE; } SSLChannelInfo info; SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &info, sizeof(info)); if (rv != SECSuccess) { MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "GetCipherSuite can't get channel info"); return NS_ERROR_FAILURE; } *cipherSuite = info.cipherSuite; return NS_OK; }
void TransportLayerDtls::PacketReceived(TransportLayer* layer, const unsigned char *data, size_t len) { CheckThread(); MOZ_MTLOG(PR_LOG_DEBUG, LAYER_INFO << "PacketReceived(" << len << ")"); if (state_ != TS_CONNECTING && state_ != TS_OPEN) { MOZ_MTLOG(PR_LOG_DEBUG, LAYER_INFO << "Discarding packet in inappropriate state"); return; } nspr_io_adapter_->PacketReceived(data, len); // If we're still connecting, try to handshake if (state_ == TS_CONNECTING) { Handshake(); } // Now try a recv if we're open, since there might be data left if (state_ == TS_OPEN) { unsigned char buf[2000]; int32_t rv = PR_Recv(ssl_fd_, buf, sizeof(buf), 0, PR_INTERVAL_NO_WAIT); if (rv > 0) { // We have data MOZ_MTLOG(PR_LOG_DEBUG, LAYER_INFO << "Read " << rv << " bytes from NSS"); SignalPacketReceived(this, buf, rv); } else if (rv == 0) { SetState(TS_CLOSED); } else { int32_t err = PR_GetError(); if (err == PR_WOULD_BLOCK_ERROR) { // This gets ignored MOZ_MTLOG(PR_LOG_NOTICE, LAYER_INFO << "Would have blocked"); } else { MOZ_MTLOG(PR_LOG_NOTICE, LAYER_INFO << "NSS Error " << err); SetState(TS_ERROR); } } } }
nsresult TransportLayerDtls::ExportKeyingMaterial(const std::string& label, bool use_context, const std::string& context, unsigned char *out, unsigned int outlen) { CheckThread(); SECStatus rv = SSL_ExportKeyingMaterial(ssl_fd_, label.c_str(), label.size(), use_context, reinterpret_cast<const unsigned char *>( context.c_str()), context.size(), out, outlen); if (rv != SECSuccess) { MOZ_MTLOG(PR_LOG_ERROR, "Couldn't export SSL keying material"); return NS_ERROR_FAILURE; } return NS_OK; }
void TransportLayerIce::IceFailed(NrIceMediaStream *stream) { CheckThread(); SetState(TS_ERROR); }
void TransportLayerIce::IceReady(NrIceMediaStream *stream) { CheckThread(); SetState(TS_OPEN); }
// TODO: make sure this is called from STS. Otherwise // we have thread safety issues bool TransportLayerDtls::Setup() { CheckThread(); SECStatus rv; if (!downward_) { MOZ_MTLOG(ML_ERROR, "DTLS layer with nothing below. This is useless"); return false; } nspr_io_adapter_ = new TransportLayerNSPRAdapter(downward_); if (!identity_) { MOZ_MTLOG(ML_ERROR, "Can't start DTLS without an identity"); return false; } if (verification_mode_ == VERIFY_UNSET) { MOZ_MTLOG(ML_ERROR, "Can't start DTLS without specifying a verification mode"); return false; } if (transport_layer_identity == PR_INVALID_IO_LAYER) { transport_layer_identity = PR_GetUniqueIdentity("nssstreamadapter"); } ScopedPRFileDesc pr_fd(PR_CreateIOLayerStub(transport_layer_identity, &TransportLayerMethods)); MOZ_ASSERT(pr_fd != nullptr); if (!pr_fd) return false; pr_fd->secret = reinterpret_cast<PRFilePrivate *>(nspr_io_adapter_.get()); ScopedPRFileDesc ssl_fd(DTLS_ImportFD(nullptr, pr_fd)); MOZ_ASSERT(ssl_fd != nullptr); // This should never happen if (!ssl_fd) { return false; } pr_fd.forget(); // ownership transfered to ssl_fd; if (role_ == CLIENT) { MOZ_MTLOG(ML_DEBUG, "Setting up DTLS as client"); rv = SSL_GetClientAuthDataHook(ssl_fd, GetClientAuthDataHook, this); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't set identity"); return false; } } else { MOZ_MTLOG(ML_DEBUG, "Setting up DTLS as server"); // Server side rv = SSL_ConfigSecureServer(ssl_fd, identity_->cert(), identity_->privkey(), kt_rsa); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't set identity"); return false; } // Insist on a certificate from the client rv = SSL_OptionSet(ssl_fd, SSL_REQUEST_CERTIFICATE, PR_TRUE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't request certificate"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_REQUIRE_CERTIFICATE, PR_TRUE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't require certificate"); return false; } } // Require TLS 1.1 or 1.2. Perhaps some day in the future we will allow TLS // 1.0 for stream modes. SSLVersionRange version_range = { SSL_LIBRARY_VERSION_TLS_1_1, SSL_LIBRARY_VERSION_TLS_1_2 }; rv = SSL_VersionRangeSet(ssl_fd, &version_range); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Can't disable SSLv3"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_SESSION_TICKETS, PR_FALSE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't disable session tickets"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_NO_CACHE, PR_TRUE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't disable session caching"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_DEFLATE, PR_FALSE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't disable deflate"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't disable renegotiation"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_ENABLE_FALSE_START, PR_FALSE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't disable false start"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_NO_LOCKS, PR_TRUE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't disable locks"); return false; } rv = SSL_OptionSet(ssl_fd, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't disable ECDHE key reuse"); return false; } if (!SetupCipherSuites(ssl_fd)) { return false; } // Certificate validation rv = SSL_AuthCertificateHook(ssl_fd, AuthCertificateHook, reinterpret_cast<void *>(this)); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't set certificate validation hook"); return false; } // Now start the handshake rv = SSL_ResetHandshake(ssl_fd, role_ == SERVER ? PR_TRUE : PR_FALSE); if (rv != SECSuccess) { MOZ_MTLOG(ML_ERROR, "Couldn't reset handshake"); return false; } ssl_fd_ = ssl_fd.forget(); // Finally, get ready to receive data downward_->SignalStateChange.connect(this, &TransportLayerDtls::StateChange); downward_->SignalPacketReceived.connect(this, &TransportLayerDtls::PacketReceived); if (downward_->state() == TS_OPEN) { Handshake(); } return true; }