diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-23 18:48:36 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-23 18:48:36 +0000 |
commit | f4ae0ed7eedbb35d59376c300a6147da2b41c2b7 (patch) | |
tree | 71142f08e29e7d4c1799ff6af4f74c3e799446a5 /remoting | |
parent | 59ba0142d4219a4ac6c5e3b463a1d5f923e0b568 (diff) | |
download | chromium_src-f4ae0ed7eedbb35d59376c300a6147da2b41c2b7.zip chromium_src-f4ae0ed7eedbb35d59376c300a6147da2b41c2b7.tar.gz chromium_src-f4ae0ed7eedbb35d59376c300a6147da2b41c2b7.tar.bz2 |
Add an extra SSL layer in JingleSession for Chromoting
Wrap the existing StreamSocketAdpaters in JingleSession with an extra of
SSLClientSocket and SSLServerSocket. Since the server certificate is
self-signed, SSLClientSocket will refuse to connect. An additional patch is
needed to transmit the certificate via other channels so client sSL socket can
accept this untrusted certificate.
BUG=None
TEST=remoting_unittests
Review URL: http://codereview.chromium.org/5675003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70074 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/jingle_glue/stream_socket_adapter.cc | 42 | ||||
-rw-r--r-- | remoting/jingle_glue/stream_socket_adapter.h | 19 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.cc | 268 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.h | 64 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_manager.cc | 7 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_manager.h | 13 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_unittest.cc | 55 |
7 files changed, 400 insertions, 68 deletions
diff --git a/remoting/jingle_glue/stream_socket_adapter.cc b/remoting/jingle_glue/stream_socket_adapter.cc index 3155328..4c5e6cf 100644 --- a/remoting/jingle_glue/stream_socket_adapter.cc +++ b/remoting/jingle_glue/stream_socket_adapter.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/message_loop.h" +#include "net/base/address_list.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "remoting/jingle_glue/utils.h" @@ -26,6 +27,47 @@ StreamSocketAdapter::StreamSocketAdapter(talk_base::StreamInterface* stream) StreamSocketAdapter::~StreamSocketAdapter() { } +int StreamSocketAdapter::Connect(net::CompletionCallback* callback) { + return net::OK; +} + +void StreamSocketAdapter::Disconnect() { +} + +bool StreamSocketAdapter::IsConnected() const { + return true; +} + +bool StreamSocketAdapter::IsConnectedAndIdle() const { + return true; +} + +int StreamSocketAdapter::GetPeerAddress(net::AddressList* address) const { + // We actually don't know the peer address. Returning so the upper layers + // won't complain. + net::IPAddressNumber ip_address(4); + *address = net::AddressList(ip_address, 0, false); + return net::OK; +} + +const net::BoundNetLog& StreamSocketAdapter::NetLog() const { + return net_log_; +} + +void StreamSocketAdapter::SetSubresourceSpeculation() { +} + +void StreamSocketAdapter::SetOmniboxSpeculation() { +} + +bool StreamSocketAdapter::WasEverUsed() const { + return true; +} + +bool StreamSocketAdapter::UsingTCPFastOpen() const { + return false; +} + int StreamSocketAdapter::Read( net::IOBuffer* buffer, int buffer_size, net::CompletionCallback* callback) { DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()); diff --git a/remoting/jingle_glue/stream_socket_adapter.h b/remoting/jingle_glue/stream_socket_adapter.h index 2387bdd..942aa45 100644 --- a/remoting/jingle_glue/stream_socket_adapter.h +++ b/remoting/jingle_glue/stream_socket_adapter.h @@ -6,7 +6,8 @@ #define REMOTING_JINGLE_GLUE_STREAM_SOCKET_ADAPTER_H_ #include "base/scoped_ptr.h" -#include "net/socket/socket.h" +#include "net/base/net_log.h" +#include "net/socket/client_socket.h" #include "third_party/libjingle/source/talk/base/sigslot.h" namespace talk_base { @@ -18,13 +19,25 @@ namespace remoting { // StreamSocketAdapter implements net::Socket interface on top of // libjingle's StreamInterface. It is used by JingleChromotocolConnection // to provide net::Socket interface for channels. -class StreamSocketAdapter : public net::Socket, +class StreamSocketAdapter : public net::ClientSocket, public sigslot::has_slots<> { public: // Ownership of the stream is passed to the adapter. explicit StreamSocketAdapter(talk_base::StreamInterface* stream); virtual ~StreamSocketAdapter(); + // ClientSocket interface. + virtual int Connect(net::CompletionCallback* callback); + virtual void Disconnect(); + virtual bool IsConnected() const; + virtual bool IsConnectedAndIdle() const; + virtual int GetPeerAddress(net::AddressList* address) const; + virtual const net::BoundNetLog& NetLog() const; + virtual void SetSubresourceSpeculation(); + virtual void SetOmniboxSpeculation(); + virtual bool WasEverUsed() const; + virtual bool UsingTCPFastOpen() const; + // Closes the stream. |error_code| specifies error code that will // be returned by Read() and Write() after the stream is closed. void Close(int error_code); @@ -62,6 +75,8 @@ class StreamSocketAdapter : public net::Socket, int closed_error_code_; + net::BoundNetLog net_log_; + DISALLOW_COPY_AND_ASSIGN(StreamSocketAdapter); }; diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc index f4acf8e..bf4b7d8 100644 --- a/remoting/protocol/jingle_session.cc +++ b/remoting/protocol/jingle_session.cc @@ -4,8 +4,16 @@ #include "remoting/protocol/jingle_session.h" +#include "base/crypto/rsa_private_key.h" #include "base/message_loop.h" +#include "net/base/cert_verifier.h" +#include "net/base/host_port_pair.h" #include "net/base/net_errors.h" +#include "net/base/ssl_config_service.h" +#include "net/base/x509_certificate.h" +#include "net/socket/client_socket_factory.h" +#include "net/socket/ssl_client_socket.h" +#include "net/socket/ssl_server_socket.h" #include "remoting/base/constants.h" #include "remoting/jingle_glue/channel_socket_adapter.h" #include "remoting/jingle_glue/jingle_thread.h" @@ -22,24 +30,77 @@ namespace remoting { namespace protocol { +const char JingleSession::kChromotingContentName[] = "chromoting"; + namespace { const char kControlChannelName[] = "control"; const char kEventChannelName[] = "event"; const char kVideoChannelName[] = "video"; const char kVideoRtpChannelName[] = "videortp"; const char kVideoRtcpChannelName[] = "videortcp"; + +// Helper method to create a SSL client socket. +net::SSLClientSocket* CreateSSLClientSocket( + net::ClientSocket* socket, scoped_refptr<net::X509Certificate> cert, + net::CertVerifier* cert_verifier) { + net::SSLConfig ssl_config; + ssl_config.false_start_enabled = false; + ssl_config.snap_start_enabled = false; + ssl_config.ssl3_enabled = true; + ssl_config.tls1_enabled = true; + ssl_config.session_resume_disabled = true; + + // Certificate provided by the host doesn't need authority. + net::SSLConfig::CertAndStatus cert_and_status; + cert_and_status.cert_status = net::ERR_CERT_AUTHORITY_INVALID; + cert_and_status.cert = cert; + ssl_config.allowed_bad_certs.push_back(cert_and_status); + + // SSLClientSocket takes ownership of the adapter. + net::HostPortPair host_and_pair(JingleSession::kChromotingContentName, 0); + net::SSLClientSocket* ssl_socket = + net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( + socket, host_and_pair, ssl_config, NULL, cert_verifier); + return ssl_socket; +} + } // namespace -const char JingleSession::kChromotingContentName[] = "chromoting"; +// static +JingleSession* JingleSession::CreateClientSession( + JingleSessionManager* manager, + scoped_refptr<net::X509Certificate> certificate) { + return new JingleSession(manager, certificate, NULL); +} + +// static +JingleSession* JingleSession::CreateServerSession( + JingleSessionManager* manager, + scoped_refptr<net::X509Certificate> certificate, + base::RSAPrivateKey* key) { + return new JingleSession(manager, certificate, key); +} JingleSession::JingleSession( - JingleSessionManager* jingle_session_manager) + JingleSessionManager* jingle_session_manager, + scoped_refptr<net::X509Certificate> server_cert, base::RSAPrivateKey* key) : jingle_session_manager_(jingle_session_manager), + server_cert_(server_cert), state_(INITIALIZING), closed_(false), cricket_session_(NULL), event_channel_(NULL), - video_channel_(NULL) { + video_channel_(NULL), + ssl_connections_(0), + ALLOW_THIS_IN_INITIALIZER_LIST(connect_callback_( + NewCallback(this, &JingleSession::OnSSLConnect))) { + // TODO(hclam): Need a better way to clone a key. + if (key) { + std::vector<uint8> key_bytes; + CHECK(key->ExportPrivateKey(&key_bytes)); + key_.reset(base::RSAPrivateKey::CreateFromPrivateKeyInfo(key_bytes)); + CHECK(key_.get()); + } } JingleSession::~JingleSession() { @@ -51,10 +112,73 @@ void JingleSession::Init(cricket::Session* cricket_session) { cricket_session_ = cricket_session; jid_ = cricket_session_->remote_name(); + cert_verifier_.reset(new net::CertVerifier()); cricket_session_->SignalState.connect( this, &JingleSession::OnSessionState); } +void JingleSession::CloseInternal(Task* closed_task, int result) { + if (MessageLoop::current() != jingle_session_manager_->message_loop()) { + jingle_session_manager_->message_loop()->PostTask( + FROM_HERE, NewRunnableMethod(this, &JingleSession::CloseInternal, + closed_task, result)); + return; + } + + if (!closed_) { + if (control_ssl_socket_.get()) + control_ssl_socket_.reset(); + + if (control_channel_adapter_.get()) + control_channel_adapter_->Close(result); + + if (control_channel_) { + control_channel_->OnSessionTerminate(cricket_session_); + control_channel_ = NULL; + } + + if (event_ssl_socket_.get()) + event_ssl_socket_.reset(); + + if (event_channel_adapter_.get()) + event_channel_adapter_->Close(result); + + if (event_channel_) { + event_channel_->OnSessionTerminate(cricket_session_); + event_channel_ = NULL; + } + + if (video_ssl_socket_.get()) + video_ssl_socket_.reset(); + + if (video_channel_adapter_.get()) + video_channel_adapter_->Close(result); + + if (video_channel_) { + video_channel_->OnSessionTerminate(cricket_session_); + video_channel_ = NULL; + } + + if (video_rtp_channel_.get()) + video_rtp_channel_->Close(result); + if (video_rtcp_channel_.get()) + video_rtcp_channel_->Close(result); + + if (cricket_session_) + cricket_session_->Terminate(); + + SetState(CLOSED); + + closed_ = true; + } + cert_verifier_.reset(); + + if (closed_task) { + closed_task->Run(); + delete closed_task; + } +} + bool JingleSession::HasSession(cricket::Session* cricket_session) { return cricket_session_ == cricket_session; } @@ -71,8 +195,7 @@ cricket::Session* JingleSession::ReleaseSession() { return session; } -void JingleSession::SetStateChangeCallback( - StateChangeCallback* callback) { +void JingleSession::SetStateChangeCallback(StateChangeCallback* callback) { DCHECK_EQ(jingle_session_manager_->message_loop(), MessageLoop::current()); DCHECK(callback); state_change_callback_.reset(callback); @@ -80,18 +203,18 @@ void JingleSession::SetStateChangeCallback( net::Socket* JingleSession::control_channel() { DCHECK_EQ(jingle_session_manager_->message_loop(), MessageLoop::current()); - return control_channel_adapter_.get(); + return control_ssl_socket_.get(); } net::Socket* JingleSession::event_channel() { DCHECK_EQ(jingle_session_manager_->message_loop(), MessageLoop::current()); - return event_channel_adapter_.get(); + return event_ssl_socket_.get(); } // TODO(sergeyu): Remove this method after we switch to RTP. net::Socket* JingleSession::video_channel() { DCHECK_EQ(jingle_session_manager_->message_loop(), MessageLoop::current()); - return video_channel_adapter_.get(); + return video_ssl_socket_.get(); } net::Socket* JingleSession::video_rtp_channel() { @@ -114,8 +237,7 @@ MessageLoop* JingleSession::message_loop() { return jingle_session_manager_->message_loop(); } -const CandidateSessionConfig* -JingleSession::candidate_config() { +const CandidateSessionConfig* JingleSession::candidate_config() { DCHECK(candidate_config_.get()); return candidate_config_.get(); } @@ -155,53 +277,7 @@ void JingleSession::set_receiver_token(const std::string& receiver_token) { } void JingleSession::Close(Task* closed_task) { - if (MessageLoop::current() != jingle_session_manager_->message_loop()) { - jingle_session_manager_->message_loop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &JingleSession::Close, - closed_task)); - return; - } - - if (!closed_) { - if (control_channel_adapter_.get()) - control_channel_adapter_->Close(net::ERR_CONNECTION_CLOSED); - - if (control_channel_) { - control_channel_->OnSessionTerminate(cricket_session_); - control_channel_ = NULL; - } - - if (event_channel_adapter_.get()) - event_channel_adapter_->Close(net::ERR_CONNECTION_CLOSED); - - if (event_channel_) { - event_channel_->OnSessionTerminate(cricket_session_); - event_channel_ = NULL; - } - - if (video_channel_adapter_.get()) - video_channel_adapter_->Close(net::ERR_CONNECTION_CLOSED); - - if (video_channel_) { - video_channel_->OnSessionTerminate(cricket_session_); - video_channel_ = NULL; - } - - if (video_rtp_channel_.get()) - video_rtp_channel_->Close(net::ERR_CONNECTION_CLOSED); - if (video_rtcp_channel_.get()) - video_rtcp_channel_->Close(net::ERR_CONNECTION_CLOSED); - - if (cricket_session_) - cricket_session_->Terminate(); - - SetState(CLOSED); - - closed_ = true; - } - - closed_task->Run(); - delete closed_task; + CloseInternal(closed_task, net::ERR_CONNECTION_CLOSED); } void JingleSession::OnSessionState( @@ -287,7 +363,48 @@ void JingleSession::OnInitiate() { SetState(CONNECTING); } +bool JingleSession::EstablishSSLConnection( + net::ClientSocket* adapter, scoped_ptr<net::Socket>* ssl_socket) { + if (cricket_session_->initiator()) { + // Create client SSL socket. + net::SSLClientSocket* socket = CreateSSLClientSocket(adapter, + server_cert_, + cert_verifier_.get()); + ssl_socket->reset(socket); + + int ret = socket->Connect(connect_callback_.get()); + if (ret == net::ERR_IO_PENDING) { + return true; + } else if (ret != net::OK) { + LOG(ERROR) << "Failed to establish SSL connection"; + cricket_session_->Terminate(); + return false; + } + } else { + // Create server SSL socket. + net::SSLConfig ssl_config; + net::SSLServerSocket* socket = net::CreateSSLServerSocket( + adapter, server_cert_, key_.get(), ssl_config); + ssl_socket->reset(socket); + + int ret = socket->Accept(connect_callback_.get()); + if (ret == net::ERR_IO_PENDING) { + return true; + } else if (ret != net::OK) { + LOG(ERROR) << "Failed to establish SSL connection"; + cricket_session_->Terminate(); + return true; + } + } + // Reach here if net::OK is received. + connect_callback_->Run(net::OK); + return true; +} + void JingleSession::OnAccept() { + // TODO(hclam): Need to close the adapters on failuire otherwise it will + // crash in the destructor. + // Set the config if we are the one who initiated the session. if (cricket_session_->initiator()) { const cricket::ContentInfo* content = @@ -307,11 +424,24 @@ void JingleSession::OnAccept() { cricket_session_->Terminate(); return; } - set_config(config); } - SetState(CONNECTED); + bool ret = EstablishSSLConnection(control_channel_adapter_.release(), + &control_ssl_socket_); + if (ret) { + ret = EstablishSSLConnection(event_channel_adapter_.release(), + &event_ssl_socket_); + } + if (ret) { + ret = EstablishSSLConnection(video_channel_adapter_.release(), + &video_ssl_socket_); + } + + if (!ret) { + LOG(ERROR) << "Failed to establish SSL connections"; + cricket_session_->Terminate(); + } } void JingleSession::OnTerminate() { @@ -346,6 +476,26 @@ void JingleSession::OnTerminate() { closed_ = true; } +void JingleSession::OnSSLConnect(int result) { + DCHECK(!closed_); + if (result != net::OK) { + LOG(ERROR) << "Error during SSL connection: " << result; + // TODO(hclam): Just setting the state is not enough. Need to invoke a + // callback to report failure. + CloseInternal(NULL, result); + return; + } + + // Number of channels for a jingle session. + const int kChannels = 3; + + // Set the state to connected only of all SSL sockets are connected. + if (++ssl_connections_ == kChannels) { + SetState(CONNECTED); + } + CHECK(ssl_connections_ <= kChannels) << "Unexpected SSL connect callback"; +} + void JingleSession::SetState(State new_state) { if (new_state != state_) { state_ = new_state; diff --git a/remoting/protocol/jingle_session.h b/remoting/protocol/jingle_session.h index cd5a602..284fb9c 100644 --- a/remoting/protocol/jingle_session.h +++ b/remoting/protocol/jingle_session.h @@ -5,8 +5,10 @@ #ifndef REMOTING_PROTOCOL_JINGLE_SESSION_H_ #define REMOTING_PROTOCOL_JINGLE_SESSION_H_ +#include "base/crypto/rsa_private_key.h" #include "base/lock.h" #include "base/ref_counted.h" +#include "net/base/completion_callback.h" #include "remoting/protocol/session.h" #include "third_party/libjingle/source/talk/base/sigslot.h" #include "third_party/libjingle/source/talk/p2p/base/session.h" @@ -16,7 +18,11 @@ class PseudoTcpChannel; } // namespace cricket namespace net { +class CertVerifier; +class ClientSocket; +class ClientSocketFactory; class Socket; +class X509Certificate; } // namespace net namespace remoting { @@ -36,7 +42,18 @@ class JingleSession : public protocol::Session, public: static const char kChromotingContentName[]; - explicit JingleSession(JingleSessionManager* client); + // Create a JingleSession used in client mode. A server certificate is + // required. + static JingleSession* CreateClientSession( + JingleSessionManager* manager, + scoped_refptr<net::X509Certificate> certificate); + + // Create a JingleSession used in server mode. A server certificate and + // private key is provided. |key| is copied in the constructor. + static JingleSession* CreateServerSession( + JingleSessionManager* manager, + scoped_refptr<net::X509Certificate> certificate, + base::RSAPrivateKey* key); // Chromotocol Session interface. virtual void SetStateChangeCallback(StateChangeCallback* callback); @@ -64,18 +81,30 @@ class JingleSession : public protocol::Session, virtual void Close(Task* closed_task); - protected: - virtual ~JingleSession(); - private: friend class JingleSessionManager; + JingleSession(JingleSessionManager* client, + scoped_refptr<net::X509Certificate> server_cert, + base::RSAPrivateKey* key); + virtual ~JingleSession(); + // Called by JingleSessionManager. void set_candidate_config(const CandidateSessionConfig* candidate_config); void Init(cricket::Session* cricket_session); + + // Close all the channels and terminate the session. + void CloseInternal(Task* closed_task, int result); + bool HasSession(cricket::Session* cricket_session); cricket::Session* ReleaseSession(); + // Helper method to create and initialize SSL socket using the adapter + // provided. The resultant SSL socket is written to |ssl_socket|. + // Return true if successful. + bool EstablishSSLConnection(net::ClientSocket* adapter, + scoped_ptr<net::Socket>* ssl_socket); + // Used for Session.SignalState sigslot. void OnSessionState(cricket::BaseSession* session, cricket::BaseSession::State state); @@ -84,11 +113,20 @@ class JingleSession : public protocol::Session, void OnAccept(); void OnTerminate(); + // Called by SSL socket to notify connect event. + void OnSSLConnect(int result); + void SetState(State new_state); // JingleSessionManager that created this session. scoped_refptr<JingleSessionManager> jingle_session_manager_; + // Server certificate used in SSL connections. + scoped_refptr<net::X509Certificate> server_cert_; + + // Private key used in SSL server sockets. + scoped_ptr<base::RSAPrivateKey> key_; + State state_; scoped_ptr<StateChangeCallback> state_change_callback_; @@ -109,15 +147,33 @@ class JingleSession : public protocol::Session, // These data members are only set on the receiving side. scoped_ptr<const CandidateSessionConfig> candidate_config_; + // A channel is the the base channel created by libjingle. + // A channel adapter is used to convert a jingle channel to net::Socket. + // A SSL socket is a wrapper over a net::Socket to provide SSL functionality. cricket::PseudoTcpChannel* control_channel_; scoped_ptr<StreamSocketAdapter> control_channel_adapter_; + scoped_ptr<net::Socket> control_ssl_socket_; + cricket::PseudoTcpChannel* event_channel_; scoped_ptr<StreamSocketAdapter> event_channel_adapter_; + scoped_ptr<net::Socket> event_ssl_socket_; + cricket::PseudoTcpChannel* video_channel_; scoped_ptr<StreamSocketAdapter> video_channel_adapter_; + scoped_ptr<net::Socket> video_ssl_socket_; + + // Count the number of SSL connections esblished. + int ssl_connections_; + + // Used to verify the certificate received in SSLClientSocket. + scoped_ptr<net::CertVerifier> cert_verifier_; + scoped_ptr<TransportChannelSocketAdapter> video_rtp_channel_; scoped_ptr<TransportChannelSocketAdapter> video_rtcp_channel_; + // Callback called by the SSL layer. + scoped_ptr<net::CompletionCallback> connect_callback_; + DISALLOW_COPY_AND_ASSIGN(JingleSession); }; diff --git a/remoting/protocol/jingle_session_manager.cc b/remoting/protocol/jingle_session_manager.cc index 12f9298..dbaed17 100644 --- a/remoting/protocol/jingle_session_manager.cc +++ b/remoting/protocol/jingle_session_manager.cc @@ -210,6 +210,7 @@ void JingleSessionManager::Close(Task* closed_task) { closed_ = true; } + key_.reset(); closed_task->Run(); delete closed_task; } @@ -224,7 +225,8 @@ scoped_refptr<protocol::Session> JingleSessionManager::Connect( CandidateSessionConfig* candidate_config, protocol::Session::StateChangeCallback* state_change_callback) { // Can be called from any thread. - scoped_refptr<JingleSession> jingle_session(new JingleSession(this)); + scoped_refptr<JingleSession> jingle_session( + JingleSession::CreateClientSession(this, server_cert_)); jingle_session->set_candidate_config(candidate_config); jingle_session->set_receiver_token(receiver_token); message_loop()->PostTask( @@ -272,7 +274,8 @@ void JingleSessionManager::OnSessionCreate( // If this is an outcoming session the connection object is already // created. if (incoming) { - JingleSession* jingle_session = new JingleSession(this); + JingleSession* jingle_session = + JingleSession::CreateServerSession(this, server_cert_, key_.get()); sessions_.push_back(make_scoped_refptr(jingle_session)); jingle_session->Init(cricket_session); } diff --git a/remoting/protocol/jingle_session_manager.h b/remoting/protocol/jingle_session_manager.h index 7bb0424..2a86c5f 100644 --- a/remoting/protocol/jingle_session_manager.h +++ b/remoting/protocol/jingle_session_manager.h @@ -10,6 +10,7 @@ #include "base/lock.h" #include "base/ref_counted.h" +#include "net/base/x509_certificate.h" #include "remoting/protocol/jingle_session.h" #include "remoting/protocol/session_manager.h" #include "third_party/libjingle/source/talk/p2p/base/session.h" @@ -93,6 +94,15 @@ class JingleSessionManager buzz::XmlElement** elem, cricket::WriteError* error); + // The following two methods are used in unit tests only. + void set_server_cert(scoped_refptr<net::X509Certificate> server_cert) { + server_cert_ = server_cert; + } + + void set_key(base::RSAPrivateKey* key) { + key_.reset(key); + } + protected: virtual ~JingleSessionManager(); @@ -128,6 +138,9 @@ class JingleSessionManager bool closed_; + scoped_refptr<net::X509Certificate> server_cert_; + scoped_ptr<base::RSAPrivateKey> key_; + std::list<scoped_refptr<JingleSession> > sessions_; DISALLOW_COPY_AND_ASSIGN(JingleSessionManager); diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc index 6b5a99d..148c19b 100644 --- a/remoting/protocol/jingle_session_unittest.cc +++ b/remoting/protocol/jingle_session_unittest.cc @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/nss_util.h" +#include "base/path_service.h" #include "base/time.h" #include "base/waitable_event.h" #include "base/test/test_timeouts.h" @@ -128,6 +132,35 @@ class JingleSessionTest : public testing::Test { session_manager_pair_->client_session_manager(), NewCallback(&client_server_callback_, &MockSessionManagerCallback::OnIncomingSession)); + + FilePath certs_dir; + PathService::Get(base::DIR_SOURCE_ROOT, &certs_dir); + certs_dir = certs_dir.AppendASCII("net"); + certs_dir = certs_dir.AppendASCII("data"); + certs_dir = certs_dir.AppendASCII("ssl"); + certs_dir = certs_dir.AppendASCII("certificates"); + + FilePath cert_path = certs_dir.AppendASCII("unittest.selfsigned.der"); + std::string cert_der; + ASSERT_TRUE(file_util::ReadFileToString(cert_path, &cert_der)); + + scoped_refptr<net::X509Certificate> cert = + net::X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size()); + + FilePath key_path = certs_dir.AppendASCII("unittest.key.bin"); + std::string key_string; + ASSERT_TRUE(file_util::ReadFileToString(key_path, &key_string)); + std::vector<uint8> key_vector( + reinterpret_cast<const uint8*>(key_string.data()), + reinterpret_cast<const uint8*>(key_string.data() + + key_string.length())); + + scoped_ptr<base::RSAPrivateKey> private_key( + base::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector)); + + host_server_->set_server_cert(cert); + host_server_->set_key(private_key.release()); + client_server_->set_server_cert(cert); } bool InitiateConnection() { @@ -516,12 +549,18 @@ class UDPChannelTester : public ChannelTesterBase { // Verify that we can create and destory server objects without a connection. TEST_F(JingleSessionTest, CreateAndDestoy) { + if (!base::CheckNSSVersion("3.12.8")) + return; + CreateServerPair(); } // Verify that incoming session can be rejected, and that the status // of the connection is set to CLOSED in this case. TEST_F(JingleSessionTest, RejectConnection) { + if (!base::CheckNSSVersion("3.12.8")) + return; + CreateServerPair(); // Reject incoming session. @@ -551,12 +590,18 @@ TEST_F(JingleSessionTest, RejectConnection) { // Verify that we can connect two endpoints. TEST_F(JingleSessionTest, Connect) { + if (!base::CheckNSSVersion("3.12.8")) + return; + CreateServerPair(); ASSERT_TRUE(InitiateConnection()); } // Verify that data can be transmitted over the event channel. TEST_F(JingleSessionTest, TestControlChannel) { + if (!base::CheckNSSVersion("3.12.8")) + return; + CreateServerPair(); ASSERT_TRUE(InitiateConnection()); scoped_refptr<TCPChannelTester> tester( @@ -570,9 +615,11 @@ TEST_F(JingleSessionTest, TestControlChannel) { CloseSessions(); } - // Verify that data can be transmitted over the video channel. TEST_F(JingleSessionTest, TestVideoChannel) { + if (!base::CheckNSSVersion("3.12.8")) + return; + CreateServerPair(); ASSERT_TRUE(InitiateConnection()); scoped_refptr<TCPChannelTester> tester( @@ -588,6 +635,9 @@ TEST_F(JingleSessionTest, TestVideoChannel) { // Verify that data can be transmitted over the event channel. TEST_F(JingleSessionTest, TestEventChannel) { + if (!base::CheckNSSVersion("3.12.8")) + return; + CreateServerPair(); ASSERT_TRUE(InitiateConnection()); scoped_refptr<TCPChannelTester> tester( @@ -603,6 +653,9 @@ TEST_F(JingleSessionTest, TestEventChannel) { // Verify that data can be transmitted over the video RTP channel. TEST_F(JingleSessionTest, TestVideoRtpChannel) { + if (!base::CheckNSSVersion("3.12.8")) + return; + CreateServerPair(); ASSERT_TRUE(InitiateConnection()); scoped_refptr<UDPChannelTester> tester( |