diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-23 18:49:18 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-23 18:49:18 +0000 |
commit | 40d33caad15e6c989f569a011f9803563d93c529 (patch) | |
tree | ccea729b503749063ca5e003409689bc4edc0fb7 /remoting | |
parent | f4ae0ed7eedbb35d59376c300a6147da2b41c2b7 (diff) | |
download | chromium_src-40d33caad15e6c989f569a011f9803563d93c529.zip chromium_src-40d33caad15e6c989f569a011f9803563d93c529.tar.gz chromium_src-40d33caad15e6c989f569a011f9803563d93c529.tar.bz2 |
Send certificate in content description in jingle for Chromoting
Transmit the server certificate to the client via content description. This
allow secure encryption between Chromoting host and client.
BUG=None
TEST=remoting_unittests
Review URL: http://codereview.chromium.org/5804001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70075 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/protocol/jingle_session.cc | 12 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.h | 5 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_manager.cc | 81 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_manager.h | 24 | ||||
-rw-r--r-- | remoting/protocol/jingle_session_unittest.cc | 35 |
5 files changed, 96 insertions, 61 deletions
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc index bf4b7d8..b151c1df 100644 --- a/remoting/protocol/jingle_session.cc +++ b/remoting/protocol/jingle_session.cc @@ -68,9 +68,8 @@ net::SSLClientSocket* CreateSSLClientSocket( // static JingleSession* JingleSession::CreateClientSession( - JingleSessionManager* manager, - scoped_refptr<net::X509Certificate> certificate) { - return new JingleSession(manager, certificate, NULL); + JingleSessionManager* manager) { + return new JingleSession(manager, NULL, NULL); } // static @@ -249,6 +248,10 @@ void JingleSession::set_candidate_config( candidate_config_.reset(candidate_config); } +scoped_refptr<net::X509Certificate> JingleSession::server_certificate() const { + return server_cert_; +} + const SessionConfig* JingleSession::config() { DCHECK(config_.get()); return config_.get(); @@ -414,6 +417,9 @@ void JingleSession::OnAccept() { const protocol::ContentDescription* content_description = static_cast<const protocol::ContentDescription*>(content->description); + server_cert_ = content_description->certificate(); + CHECK(server_cert_); + SessionConfig* config = content_description->config()->GetFinalConfig(); // Terminate the session if the config we received is invalid. diff --git a/remoting/protocol/jingle_session.h b/remoting/protocol/jingle_session.h index 284fb9c..f8689cc 100644 --- a/remoting/protocol/jingle_session.h +++ b/remoting/protocol/jingle_session.h @@ -44,9 +44,7 @@ class JingleSession : public protocol::Session, // Create a JingleSession used in client mode. A server certificate is // required. - static JingleSession* CreateClientSession( - JingleSessionManager* manager, - scoped_refptr<net::X509Certificate> certificate); + static JingleSession* CreateClientSession(JingleSessionManager* manager); // Create a JingleSession used in server mode. A server certificate and // private key is provided. |key| is copied in the constructor. @@ -91,6 +89,7 @@ class JingleSession : public protocol::Session, // Called by JingleSessionManager. void set_candidate_config(const CandidateSessionConfig* candidate_config); + scoped_refptr<net::X509Certificate> server_certificate() const; void Init(cricket::Session* cricket_session); // Close all the channels and terminate the session. diff --git a/remoting/protocol/jingle_session_manager.cc b/remoting/protocol/jingle_session_manager.cc index dbaed17..5a99a3f 100644 --- a/remoting/protocol/jingle_session_manager.cc +++ b/remoting/protocol/jingle_session_manager.cc @@ -4,6 +4,7 @@ #include "remoting/protocol/jingle_session_manager.h" +#include "base/base64.h" #include "base/message_loop.h" #include "base/string_number_conversions.h" #include "remoting/base/constants.h" @@ -31,6 +32,8 @@ const char kControlTag[] = "control"; const char kEventTag[] = "event"; const char kVideoTag[] = "video"; const char kResolutionTag[] = "initial-resolution"; +const char kAuthenticationTag[] = "authentication"; +const char kCertificateTag[] = "certificate"; const char kTransportAttr[] = "transport"; const char kVersionAttr[] = "version"; @@ -150,9 +153,11 @@ bool ParseChannelConfig(const XmlElement* element, bool codec_required, ContentDescription::ContentDescription( const CandidateSessionConfig* candidate_config, - const std::string& auth_token) + const std::string& auth_token, + scoped_refptr<net::X509Certificate> certificate) : candidate_config_(candidate_config), - auth_token_(auth_token) { + auth_token_(auth_token), + certificate_(certificate) { } ContentDescription::~ContentDescription() { } @@ -210,7 +215,6 @@ void JingleSessionManager::Close(Task* closed_task) { closed_ = true; } - key_.reset(); closed_task->Run(); delete closed_task; } @@ -226,7 +230,7 @@ scoped_refptr<protocol::Session> JingleSessionManager::Connect( protocol::Session::StateChangeCallback* state_change_callback) { // Can be called from any thread. scoped_refptr<JingleSession> jingle_session( - JingleSession::CreateClientSession(this, server_cert_)); + JingleSession::CreateClientSession(this)); jingle_session->set_candidate_config(candidate_config); jingle_session->set_receiver_token(receiver_token); message_loop()->PostTask( @@ -253,7 +257,7 @@ void JingleSessionManager::DoConnect( cricket_session->Initiate( host_jid, CreateSessionDescription(jingle_session->candidate_config()->Clone(), - receiver_token)); + receiver_token, NULL)); } JingleThread* JingleSessionManager::jingle_thread() { @@ -271,11 +275,20 @@ void JingleSessionManager::OnSessionCreate( // Allow local connections if neccessary. cricket_session->set_allow_local_ips(allow_local_ips_); - // If this is an outcoming session the connection object is already - // created. + // If this is an outcoming session the session object is already created. if (incoming) { + // Generate private key and certificate. + // TODO(hclam): Instead of generating we should restore them from the disk. + scoped_ptr<base::RSAPrivateKey> private_key( + base::RSAPrivateKey::Create(1024)); + std::string subject = "CN=chromoting"; + scoped_refptr<net::X509Certificate> x509_certificate = + net::X509Certificate::CreateSelfSigned( + private_key.get(), subject, 1, base::TimeDelta::FromDays(1)); + CHECK(x509_certificate); JingleSession* jingle_session = - JingleSession::CreateServerSession(this, server_cert_, key_.get()); + JingleSession::CreateServerSession(this, x509_certificate, + private_key.get()); sessions_.push_back(make_scoped_refptr(jingle_session)); jingle_session->Init(cricket_session); } @@ -318,6 +331,8 @@ void JingleSessionManager::AcceptConnection( // Always reject connection if there is no callback. IncomingSessionResponse response = protocol::SessionManager::DECLINE; + + // Use the callback to generate a response. if (incoming_session_callback_.get()) incoming_session_callback_->Run(jingle_session, &response); @@ -329,7 +344,8 @@ void JingleSessionManager::AcceptConnection( CandidateSessionConfig::CreateFrom(jingle_session->config()); cricket_session->Accept( CreateSessionDescription(candidate_config, - jingle_session->initiator_token())); + jingle_session->initiator_token(), + jingle_session->server_certificate())); break; } @@ -415,7 +431,25 @@ bool JingleSessionManager::ParseContent( std::string auth_token; // TODO(ajwong): Parse this out. - *content = new ContentDescription(config.release(), auth_token); + // Parse the certificate. + scoped_refptr<net::X509Certificate> certificate; + child = element->FirstNamed(QName(kChromotingXmlNamespace, + kAuthenticationTag)); + if (child) + child = child->FirstNamed(QName(kChromotingXmlNamespace, + kCertificateTag)); + + if (child) { + std::string base64_cert = child->BodyText(); + std::string der_cert; + bool ret = base::Base64Decode(base64_cert, &der_cert); + DCHECK(ret) << "Failed to decode certificate"; + certificate = net::X509Certificate::CreateFromBytes(der_cert.data(), + der_cert.length()); + } + + *content = new ContentDescription(config.release(), auth_token, + certificate); return true; } LOG(ERROR) << "Invalid description: " << element->Str(); @@ -429,6 +463,9 @@ bool JingleSessionManager::ParseContent( // <event transport="datagram" version="1" /> // <video transport="srtp" codec="vp8" version="1" /> // <initial-resolution width="800" height="600" /> +// <authentication> +// <certificate>[BASE64 Encoded Certificate]</certificate> +// </authentication>" /> // </description> // bool JingleSessionManager::WriteContent( @@ -470,17 +507,37 @@ bool JingleSessionManager::WriteContent( config->initial_resolution().height)); root->AddElement(resolution_tag); + if (desc->certificate()) { + XmlElement* authentication_tag = new XmlElement( + QName(kChromotingXmlNamespace, kAuthenticationTag)); + XmlElement* certificate_tag = new XmlElement( + QName(kChromotingXmlNamespace, kCertificateTag)); + + std::string der_cert; + bool ret = desc->certificate()->GetDEREncoded(&der_cert); + DCHECK(ret) << "Cannot obtain DER encoded certificate"; + + std::string base64_cert; + ret = base::Base64Encode(der_cert, &base64_cert); + DCHECK(ret) << "Cannot perform base64 encode on certificate"; + + certificate_tag->SetBodyText(base64_cert); + authentication_tag->AddElement(certificate_tag); + root->AddElement(authentication_tag); + } + *elem = root; return true; } cricket::SessionDescription* JingleSessionManager::CreateSessionDescription( const CandidateSessionConfig* config, - const std::string& auth_token) { + const std::string& auth_token, + scoped_refptr<net::X509Certificate> certificate) { cricket::SessionDescription* desc = new cricket::SessionDescription(); desc->AddContent(JingleSession::kChromotingContentName, kChromotingXmlNamespace, - new ContentDescription(config, auth_token)); + new ContentDescription(config, auth_token, certificate)); return desc; } diff --git a/remoting/protocol/jingle_session_manager.h b/remoting/protocol/jingle_session_manager.h index 2a86c5f..8dcce03 100644 --- a/remoting/protocol/jingle_session_manager.h +++ b/remoting/protocol/jingle_session_manager.h @@ -37,7 +37,8 @@ namespace protocol { class ContentDescription : public cricket::ContentDescription { public: explicit ContentDescription(const CandidateSessionConfig* config, - const std::string& auth_token); + const std::string& auth_token, + scoped_refptr<net::X509Certificate> certificate); ~ContentDescription(); const CandidateSessionConfig* config() const { @@ -46,12 +47,18 @@ class ContentDescription : public cricket::ContentDescription { const std::string& auth_token() const { return auth_token_; } + scoped_refptr<net::X509Certificate> certificate() const { + return certificate_; + } + private: scoped_ptr<const CandidateSessionConfig> candidate_config_; // This may contain the initiating, or the accepting token depending on // context. std::string auth_token_; + + scoped_refptr<net::X509Certificate> certificate_; }; // This class implements SessionClient for Chromoting sessions. It acts as a @@ -94,15 +101,6 @@ 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,7 +126,8 @@ class JingleSessionManager // Creates outgoing session description for an incoming session. cricket::SessionDescription* CreateSessionDescription( const CandidateSessionConfig* candidate_config, - const std::string& auth_token); + const std::string& auth_token, + scoped_refptr<net::X509Certificate> certificate); std::string local_jid_; // Full jid for the local side of the session. JingleThread* jingle_thread_; @@ -138,9 +137,6 @@ 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 148c19b..cdcd069 100644 --- a/remoting/protocol/jingle_session_unittest.cc +++ b/remoting/protocol/jingle_session_unittest.cc @@ -132,35 +132,6 @@ 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() { @@ -547,6 +518,10 @@ class UDPChannelTester : public ChannelTesterBase { int broken_packets_; }; +// Mac needs to implement X509Certificate::CreateSelfSigned to enable these +// tests. +#if defined(USE_NSS) || defined(OS_WIN) + // Verify that we can create and destory server objects without a connection. TEST_F(JingleSessionTest, CreateAndDestoy) { if (!base::CheckNSSVersion("3.12.8")) @@ -669,5 +644,7 @@ TEST_F(JingleSessionTest, TestVideoRtpChannel) { CloseSessions(); } +#endif + } // namespace protocol } // namespace remoting |