diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 05:55:02 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-23 05:55:02 +0000 |
commit | 4aa41f22d029f0d163f30d2b259301c9c479dfc3 (patch) | |
tree | 64856bb49b56b278503893c6161607b69e2d09b4 /remoting | |
parent | 34a43dba701101a39624b488a821666643088e35 (diff) | |
download | chromium_src-4aa41f22d029f0d163f30d2b259301c9c479dfc3.zip chromium_src-4aa41f22d029f0d163f30d2b259301c9c479dfc3.tar.gz chromium_src-4aa41f22d029f0d163f30d2b259301c9c479dfc3.tar.bz2 |
Add implementation for current IT2Me auth.
The new SimpleClientAuthenticator and SimpleHostAuthenticator implement
the current IT2Me authentication mechanism.
Review URL: http://codereview.chromium.org/8647001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111321 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/protocol/authenticator.h | 17 | ||||
-rw-r--r-- | remoting/protocol/v1_authenticator.cc | 174 | ||||
-rw-r--r-- | remoting/protocol/v1_authenticator.h | 89 | ||||
-rw-r--r-- | remoting/protocol/v1_authenticator_unittest.cc | 121 | ||||
-rw-r--r-- | remoting/remoting.gyp | 3 |
5 files changed, 399 insertions, 5 deletions
diff --git a/remoting/protocol/authenticator.h b/remoting/protocol/authenticator.h index 4140e5a..0f382ed 100644 --- a/remoting/protocol/authenticator.h +++ b/remoting/protocol/authenticator.h @@ -14,6 +14,8 @@ class XmlElement; namespace remoting { namespace protocol { +class ChannelAuthenticator; + // Authenticator is an abstract interface for authentication protocol // implementations. Different implementations of this interface may be // used on each side of the connection depending of type of the auth @@ -37,7 +39,6 @@ class Authenticator { // When GetNextMessage() is called: // MESSAGE_READY -> WAITING_MESSAGE // MESSAGE_READY -> ACCEPTED - // MESSAGE_READY -> REJECTED enum State { // Waiting for the next message from the peer. WAITING_MESSAGE, @@ -59,12 +60,13 @@ class Authenticator { virtual State state() const = 0; // Called in response to incoming message received from the peer. - // Should only be called when in WAITING_MESSAGE state. - virtual void ProcessMessage(talk_base::XmlElement* message) = 0; + // Should only be called when in WAITING_MESSAGE state. Caller + // retains ownership of |message|. + virtual void ProcessMessage(const buzz::XmlElement* message) = 0; // Must be called when in MESSAGE_READY state. Returns next // authentication message that needs to be sent to the peer. - virtual talk_base::XmlElement* GetNextMessage() = 0; + virtual buzz::XmlElement* GetNextMessage() = 0; // Creates new authenticator for a channel. Caller must take // ownership of the result. Can be called only in the ACCEPTED @@ -74,6 +76,10 @@ class Authenticator { // Factory for Authenticator instances. class AuthenticatorFactory { + public: + AuthenticatorFactory() {} + virtual ~AuthenticatorFactory() {} + // Called when session-initiate stanza is received to create // authenticator for the new session. |first_message| specifies // authentication part of the session-initiate stanza so that @@ -83,7 +89,8 @@ class AuthenticatorFactory { // rejected. ProcessMessage() should be called with |first_message| // for the result of this method. virtual Authenticator* CreateAuthenticator( - const talk_base::XmlElement* first_message) = 0; + const std::string& remote_jid, + const buzz::XmlElement* first_message) = 0; }; } // namespace protocol diff --git a/remoting/protocol/v1_authenticator.cc b/remoting/protocol/v1_authenticator.cc new file mode 100644 index 0000000..2daf246 --- /dev/null +++ b/remoting/protocol/v1_authenticator.cc @@ -0,0 +1,174 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/protocol/v1_authenticator.h" + +#include "base/base64.h" +#include "base/logging.h" +#include "crypto/rsa_private_key.h" +#include "remoting/base/constants.h" +#include "remoting/protocol/auth_util.h" +#include "remoting/protocol/v1_client_channel_authenticator.h" +#include "remoting/protocol/v1_host_channel_authenticator.h" +#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" + +using buzz::QName; +using buzz::XmlElement; + +namespace remoting { +namespace protocol { + +namespace { +const char kAuthenticationTag[] = "authentication"; +const char kAuthTokenTag[] = "auth-token"; +const char kCertificateTag[] = "certificate"; +} // namespace + +V1ClientAuthenticator::V1ClientAuthenticator( + const std::string& local_jid, + const std::string& shared_secret) + : local_jid_(local_jid), + shared_secret_(shared_secret), + state_(MESSAGE_READY) { +} + +V1ClientAuthenticator::~V1ClientAuthenticator() { +} + +Authenticator::State V1ClientAuthenticator::state() const { + return state_; +} + +void V1ClientAuthenticator::ProcessMessage(const XmlElement* message) { + DCHECK_EQ(state_, WAITING_MESSAGE); + + // Parse the certificate. + const XmlElement* cert_tag = + message->FirstNamed(QName(kChromotingXmlNamespace, kCertificateTag)); + if (cert_tag) { + std::string base64_cert = cert_tag->BodyText(); + if (!base::Base64Decode(base64_cert, &remote_cert_)) { + LOG(ERROR) << "Failed to decode certificate received from the peer."; + remote_cert_.clear(); + } + } + + if (remote_cert_.empty()) { + state_ = REJECTED; + } else { + state_ = ACCEPTED; + } +} + +XmlElement* V1ClientAuthenticator::GetNextMessage() { + DCHECK_EQ(state_, MESSAGE_READY); + + XmlElement* authentication_tag = new XmlElement( + QName(kChromotingXmlNamespace, kAuthenticationTag)); + + std::string token = + protocol::GenerateSupportAuthToken(local_jid_, shared_secret_); + + XmlElement* auth_token_tag = new XmlElement( + QName(kChromotingXmlNamespace, kAuthTokenTag)); + auth_token_tag->SetBodyText(token); + authentication_tag->AddElement(auth_token_tag); + + state_ = WAITING_MESSAGE; + return authentication_tag; +} + +ChannelAuthenticator* +V1ClientAuthenticator::CreateChannelAuthenticator() const { + DCHECK_EQ(state_, ACCEPTED); + return new V1ClientChannelAuthenticator(remote_cert_, shared_secret_); +}; + +V1HostAuthenticator::V1HostAuthenticator( + const std::string& local_cert, + crypto::RSAPrivateKey* local_private_key, + const std::string& shared_secret, + const std::string& remote_jid) + : local_cert_(local_cert), + local_private_key_(local_private_key), + shared_secret_(shared_secret), + remote_jid_(remote_jid), + state_(WAITING_MESSAGE) { +} + +V1HostAuthenticator::~V1HostAuthenticator() { +} + +Authenticator::State V1HostAuthenticator::state() const { + return state_; +} + +void V1HostAuthenticator::ProcessMessage(const XmlElement* message) { + DCHECK_EQ(state_, WAITING_MESSAGE); + + std::string auth_token = + message->TextNamed(buzz::QName(kChromotingXmlNamespace, kAuthTokenTag)); + + if (!protocol::VerifySupportAuthToken( + remote_jid_, shared_secret_, auth_token)) { + state_ = REJECTED; + } else { + state_ = MESSAGE_READY; + } +} + +XmlElement* V1HostAuthenticator::GetNextMessage() { + DCHECK_EQ(state_, MESSAGE_READY); + + XmlElement* message = new XmlElement( + QName(kChromotingXmlNamespace, kAuthenticationTag)); + + buzz::XmlElement* certificate_tag = new XmlElement( + buzz::QName(kChromotingXmlNamespace, kCertificateTag)); + std::string base64_cert; + if (!base::Base64Encode(local_cert_, &base64_cert)) { + LOG(DFATAL) << "Cannot perform base64 encode on certificate"; + } + certificate_tag->SetBodyText(base64_cert); + message->AddElement(certificate_tag); + + state_ = ACCEPTED; + return message; +} + +ChannelAuthenticator* +V1HostAuthenticator::CreateChannelAuthenticator() const { + DCHECK_EQ(state_, ACCEPTED); + return new V1HostChannelAuthenticator( + local_cert_, local_private_key_, shared_secret_); +}; + +V1HostAuthenticatorFactory::V1HostAuthenticatorFactory( + const std::string& local_cert, + crypto::RSAPrivateKey* local_private_key, + const std::string& shared_secret) + : local_cert_(local_cert), + shared_secret_(shared_secret) { + DCHECK(local_private_key); + + // TODO(hclam): Need a better way to clone a key. See crbug.com/105220 . + std::vector<uint8> key_bytes; + CHECK(local_private_key->ExportPrivateKey(&key_bytes)); + local_private_key_.reset( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_bytes)); + CHECK(local_private_key_.get()); +} + +V1HostAuthenticatorFactory::~V1HostAuthenticatorFactory() { +} + +Authenticator* V1HostAuthenticatorFactory::CreateAuthenticator( + const std::string& remote_jid, + const buzz::XmlElement* first_message) { + return new V1HostAuthenticator(local_cert_, local_private_key_.get(), + shared_secret_, remote_jid); +} + +} // namespace remoting +} // namespace protocol diff --git a/remoting/protocol/v1_authenticator.h b/remoting/protocol/v1_authenticator.h new file mode 100644 index 0000000..d53c5bf --- /dev/null +++ b/remoting/protocol/v1_authenticator.h @@ -0,0 +1,89 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_PROTOCOL_V1_AUTHENTICATOR_H_ +#define REMOTING_PROTOCOL_V1_AUTHENTICATOR_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "remoting/protocol/authenticator.h" + +namespace crypto { +class RSAPrivateKey; +} // namespace base + +namespace remoting { +namespace protocol { + +class V1ClientAuthenticator : public Authenticator { + public: + explicit V1ClientAuthenticator(const std::string& local_jid, + const std::string& shared_secret); + virtual ~V1ClientAuthenticator(); + + // Authenticator interface. + virtual State state() const OVERRIDE; + virtual void ProcessMessage(const buzz::XmlElement* message) OVERRIDE; + virtual buzz::XmlElement* GetNextMessage() OVERRIDE; + virtual ChannelAuthenticator* CreateChannelAuthenticator() const OVERRIDE; + + private: + std::string local_jid_; + std::string shared_secret_; + std::string remote_cert_; + State state_; + + DISALLOW_COPY_AND_ASSIGN(V1ClientAuthenticator); +}; + +class V1HostAuthenticator : public Authenticator { + public: + explicit V1HostAuthenticator(const std::string& local_cert, + crypto::RSAPrivateKey* local_private_key, + const std::string& shared_secret, + const std::string& remote_jid); + virtual ~V1HostAuthenticator(); + + // Authenticator interface. + virtual State state() const OVERRIDE; + virtual void ProcessMessage(const buzz::XmlElement* message) OVERRIDE; + virtual buzz::XmlElement* GetNextMessage() OVERRIDE; + virtual ChannelAuthenticator* CreateChannelAuthenticator() const OVERRIDE; + + private: + std::string local_cert_; + crypto::RSAPrivateKey* local_private_key_; + std::string shared_secret_; + std::string remote_jid_; + State state_; + + DISALLOW_COPY_AND_ASSIGN(V1HostAuthenticator); +}; + +class V1HostAuthenticatorFactory : public AuthenticatorFactory { + public: + // Doesn't take ownership of |local_private_key|. + V1HostAuthenticatorFactory(const std::string& local_cert, + crypto::RSAPrivateKey* local_private_key, + const std::string& shared_secret); + virtual ~V1HostAuthenticatorFactory(); + + // AuthenticatorFactory interface. + virtual Authenticator* CreateAuthenticator( + const std::string& remote_jid, + const buzz::XmlElement* first_message) OVERRIDE; + + private: + std::string local_cert_; + scoped_ptr<crypto::RSAPrivateKey> local_private_key_; + std::string shared_secret_; + + DISALLOW_COPY_AND_ASSIGN(V1HostAuthenticatorFactory); +}; + +} // namespace protocol +} // namespace remoting + +#endif // REMOTING_PROTOCOL_V1_AUTHENTICATOR_H_ diff --git a/remoting/protocol/v1_authenticator_unittest.cc b/remoting/protocol/v1_authenticator_unittest.cc new file mode 100644 index 0000000..0ba9e51 --- /dev/null +++ b/remoting/protocol/v1_authenticator_unittest.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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/path_service.h" +#include "crypto/rsa_private_key.h" +#include "remoting/protocol/v1_authenticator.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" + +namespace remoting { +namespace protocol { + +namespace { +const char kHostJid[] = "host1@gmail.com/123"; +const char kClientJid[] = "host2@gmail.com/321"; + +const char kTestSharedSecret[] = "1234-1234-5678"; +const char kTestSharedSecretBad[] = "0000-0000-0001"; +} // namespace + +class V1AuthenticatorTest : public testing::Test { + public: + V1AuthenticatorTest() { + } + virtual ~V1AuthenticatorTest() { + } + + protected: + void InitAuthenticators(const std::string& client_secret, + const std::string& host_secret) { + 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)); + + 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())); + private_key_.reset( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector)); + + host_.reset(new V1HostAuthenticator( + cert_der, private_key_.get(), host_secret, kClientJid)); + client_.reset(new V1ClientAuthenticator(kClientJid, client_secret)); + } + + void RunAuthExchange() { + do { + scoped_ptr<buzz::XmlElement> message; + + // Pass message from client to host. + ASSERT_EQ(Authenticator::MESSAGE_READY, client_->state()); + message.reset(client_->GetNextMessage()); + ASSERT_TRUE(message.get()); + ASSERT_NE(Authenticator::MESSAGE_READY, client_->state()); + + ASSERT_EQ(Authenticator::WAITING_MESSAGE, host_->state()); + host_->ProcessMessage(message.get()); + ASSERT_NE(Authenticator::WAITING_MESSAGE, host_->state()); + + // Are we done yet? + if (host_->state() == Authenticator::ACCEPTED || + host_->state() == Authenticator::REJECTED) { + break; + } + + // Pass message from host to client. + ASSERT_EQ(Authenticator::MESSAGE_READY, host_->state()); + message.reset(host_->GetNextMessage()); + ASSERT_TRUE(message.get()); + ASSERT_NE(Authenticator::MESSAGE_READY, host_->state()); + + ASSERT_EQ(Authenticator::WAITING_MESSAGE, client_->state()); + client_->ProcessMessage(message.get()); + ASSERT_NE(Authenticator::WAITING_MESSAGE, client_->state()); + } while (host_->state() != Authenticator::ACCEPTED && + host_->state() != Authenticator::REJECTED); + } + + scoped_ptr<crypto::RSAPrivateKey> private_key_; + scoped_ptr<V1HostAuthenticator> host_; + scoped_ptr<V1ClientAuthenticator> client_; + + DISALLOW_COPY_AND_ASSIGN(V1AuthenticatorTest); +}; + +TEST_F(V1AuthenticatorTest, SuccessfulAuth) { + { + SCOPED_TRACE("RunAuthExchange"); + InitAuthenticators(kTestSharedSecret, kTestSharedSecret); + RunAuthExchange(); + } + ASSERT_EQ(Authenticator::ACCEPTED, host_->state()); + ASSERT_EQ(Authenticator::ACCEPTED, client_->state()); +} + +TEST_F(V1AuthenticatorTest, InvalidSecret) { + { + SCOPED_TRACE("RunAuthExchange"); + InitAuthenticators(kTestSharedSecretBad, kTestSharedSecret); + RunAuthExchange(); + } + ASSERT_EQ(Authenticator::REJECTED, host_->state()); +} + +} // namespace protocol +} // namespace remoting diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 0a4b8e3..de106f7 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -814,6 +814,8 @@ 'protocol/transport_config.h', 'protocol/util.cc', 'protocol/util.h', + 'protocol/v1_authenticator.cc', + 'protocol/v1_authenticator.h', 'protocol/v1_client_channel_authenticator.cc', 'protocol/v1_client_channel_authenticator.h', 'protocol/v1_host_channel_authenticator.cc', @@ -932,6 +934,7 @@ 'protocol/protocol_mock_objects.h', 'protocol/rtp_video_reader_unittest.cc', 'protocol/rtp_video_writer_unittest.cc', + 'protocol/v1_authenticator_unittest.cc', 'run_all_unittests.cc', ], 'conditions': [ |