ssl_hmac_channel_authenticator_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Use of this source code is governed by a BSD-style license that can be 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// found in the LICENSE file. 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "remoting/protocol/ssl_hmac_channel_authenticator.h" 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "base/base64.h" 8971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include "base/bind.h" 9971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include "base/file_util.h" 10971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include "base/files/file_path.h" 11971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include "base/message_loop.h" 12cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "base/path_service.h" 13971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include "base/test/test_timeouts.h" 14971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include "base/timer.h" 15cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "crypto/rsa_private_key.h" 16cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "net/base/net_errors.h" 17cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "net/base/test_data_directory.h" 18cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "remoting/base/rsa_key_pair.h" 19cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "remoting/protocol/connection_tester.h" 20cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "remoting/protocol/fake_session.h" 21cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "testing/gmock/include/gmock/gmock.h" 22cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#include "testing/gtest/include/gtest/gtest.h" 23971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" 24971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com 25bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.comusing testing::_; 2682a7bfcb2dbd4f8845a85fc8bddf2c1e59528582bsalomon@google.comusing testing::NotNull; 2744b67b2ed16ecb6fe001b785498e20b13fa42d0cjunov@chromium.orgusing testing::SaveArg; 28f523e25da069e3e1af2cb73d37073a34f3bb9ea2reed@android.com 293a859a00342ed078af683fd1901fd26c93dd40f0reed@android.comnamespace remoting { 30b398fe863860b072306b5297c8095c6d973aba06reed@android.comnamespace protocol { 316c924ad46c89955e78e071c792ef00df9910b42freed@android.com 326c924ad46c89955e78e071c792ef00df9910b42freed@android.comnamespace { 33a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 34bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.comconst char kTestSharedSecret[] = "1234-1234-5678"; 35bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.comconst char kTestSharedSecretBad[] = "0000-0000-0001"; 36a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 37a2b32b80818adebfc028334e0095cb3218825188borenet@google.comclass MockChannelDoneCallback { 38a2b32b80818adebfc028334e0095cb3218825188borenet@google.com public: 39a2b32b80818adebfc028334e0095cb3218825188borenet@google.com MOCK_METHOD2(OnDone, void(net::Error error, net::StreamSocket* socket)); 40a2b32b80818adebfc028334e0095cb3218825188borenet@google.com}; 41a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 42a2b32b80818adebfc028334e0095cb3218825188borenet@google.comACTION_P(QuitThreadOnCounter, counter) { 43a2b32b80818adebfc028334e0095cb3218825188borenet@google.com --(*counter); 44a2b32b80818adebfc028334e0095cb3218825188borenet@google.com EXPECT_GE(*counter, 0); 45a2b32b80818adebfc028334e0095cb3218825188borenet@google.com if (*counter == 0) 46a2b32b80818adebfc028334e0095cb3218825188borenet@google.com base::MessageLoop::current()->Quit(); 47a2b32b80818adebfc028334e0095cb3218825188borenet@google.com} 48a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 49a2b32b80818adebfc028334e0095cb3218825188borenet@google.com} // namespace 50a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 51a2b32b80818adebfc028334e0095cb3218825188borenet@google.comclass SslHmacChannelAuthenticatorTest : public testing::Test { 52a2b32b80818adebfc028334e0095cb3218825188borenet@google.com public: 53a2b32b80818adebfc028334e0095cb3218825188borenet@google.com SslHmacChannelAuthenticatorTest() {} 54a2b32b80818adebfc028334e0095cb3218825188borenet@google.com virtual ~SslHmacChannelAuthenticatorTest() {} 55a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 56a2b32b80818adebfc028334e0095cb3218825188borenet@google.com protected: 57a2b32b80818adebfc028334e0095cb3218825188borenet@google.com virtual void SetUp() OVERRIDE { 58a2b32b80818adebfc028334e0095cb3218825188borenet@google.com base::FilePath certs_dir(net::GetTestCertsDirectory()); 59a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 60a2b32b80818adebfc028334e0095cb3218825188borenet@google.com base::FilePath cert_path = certs_dir.AppendASCII("unittest.selfsigned.der"); 61a2b32b80818adebfc028334e0095cb3218825188borenet@google.com ASSERT_TRUE(file_util::ReadFileToString(cert_path, &host_cert_)); 6256c69773aea56c6c6bd47bc7e7970dd081205184djsollen@google.com 63a2b32b80818adebfc028334e0095cb3218825188borenet@google.com base::FilePath key_path = certs_dir.AppendASCII("unittest.key.bin"); 64a2b32b80818adebfc028334e0095cb3218825188borenet@google.com std::string key_string; 6529348cb0612e19030d979156860946241e2ff4bdreed@android.com ASSERT_TRUE(file_util::ReadFileToString(key_path, &key_string)); 66a2b32b80818adebfc028334e0095cb3218825188borenet@google.com std::string key_base64; 67a2b32b80818adebfc028334e0095cb3218825188borenet@google.com base::Base64Encode(key_string, &key_base64); 6829348cb0612e19030d979156860946241e2ff4bdreed@android.com key_pair_ = RsaKeyPair::FromString(key_base64); 6929348cb0612e19030d979156860946241e2ff4bdreed@android.com ASSERT_TRUE(key_pair_.get()); 70a2b32b80818adebfc028334e0095cb3218825188borenet@google.com } 71a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 72a2b32b80818adebfc028334e0095cb3218825188borenet@google.com void RunChannelAuth(bool expected_fail) { 73a2b32b80818adebfc028334e0095cb3218825188borenet@google.com client_fake_socket_.reset(new FakeSocket()); 74a2b32b80818adebfc028334e0095cb3218825188borenet@google.com host_fake_socket_.reset(new FakeSocket()); 75a2b32b80818adebfc028334e0095cb3218825188borenet@google.com client_fake_socket_->PairWith(host_fake_socket_.get()); 76a2b32b80818adebfc028334e0095cb3218825188borenet@google.com 7729348cb0612e19030d979156860946241e2ff4bdreed@android.com client_auth_->SecureAndAuthenticate( 7829348cb0612e19030d979156860946241e2ff4bdreed@android.com client_fake_socket_.PassAs<net::StreamSocket>(), 7929348cb0612e19030d979156860946241e2ff4bdreed@android.com base::Bind(&SslHmacChannelAuthenticatorTest::OnClientConnected, 80fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org base::Unretained(this))); 81fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org 82fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org host_auth_->SecureAndAuthenticate( 83fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org host_fake_socket_.PassAs<net::StreamSocket>(), 84fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org base::Bind(&SslHmacChannelAuthenticatorTest::OnHostConnected, 85fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org base::Unretained(this))); 86fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org 87fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org // Expect two callbacks to be called - the client callback and the host 88fdd909ca000801aced49881558760170b5f1eb97keyar@chromium.org // callback. 896c924ad46c89955e78e071c792ef00df9910b42freed@android.com int callback_counter = 2; 906c924ad46c89955e78e071c792ef00df9910b42freed@android.com 916c924ad46c89955e78e071c792ef00df9910b42freed@android.com if (expected_fail) { 926c924ad46c89955e78e071c792ef00df9910b42freed@android.com EXPECT_CALL(client_callback_, OnDone(net::ERR_FAILED, NULL)) 936c924ad46c89955e78e071c792ef00df9910b42freed@android.com .WillOnce(QuitThreadOnCounter(&callback_counter)); 946c924ad46c89955e78e071c792ef00df9910b42freed@android.com EXPECT_CALL(host_callback_, OnDone(net::ERR_FAILED, NULL)) 956c924ad46c89955e78e071c792ef00df9910b42freed@android.com .WillOnce(QuitThreadOnCounter(&callback_counter)); 966c924ad46c89955e78e071c792ef00df9910b42freed@android.com } else { 97a9015f897cd32f549349994e8163ead1db442088mike@reedtribe.org EXPECT_CALL(client_callback_, OnDone(net::OK, NotNull())) 986c924ad46c89955e78e071c792ef00df9910b42freed@android.com .WillOnce(QuitThreadOnCounter(&callback_counter)); 996c924ad46c89955e78e071c792ef00df9910b42freed@android.com EXPECT_CALL(host_callback_, OnDone(net::OK, NotNull())) 1006c924ad46c89955e78e071c792ef00df9910b42freed@android.com .WillOnce(QuitThreadOnCounter(&callback_counter)); 1016c924ad46c89955e78e071c792ef00df9910b42freed@android.com } 1026c924ad46c89955e78e071c792ef00df9910b42freed@android.com 1036c924ad46c89955e78e071c792ef00df9910b42freed@android.com // Ensure that .Run() does not run unbounded if the callbacks are never 1046c924ad46c89955e78e071c792ef00df9910b42freed@android.com // called. 1056c924ad46c89955e78e071c792ef00df9910b42freed@android.com base::Timer shutdown_timer(false, false); 1066c924ad46c89955e78e071c792ef00df9910b42freed@android.com shutdown_timer.Start(FROM_HERE, 1076c924ad46c89955e78e071c792ef00df9910b42freed@android.com TestTimeouts::action_timeout(), 1086c924ad46c89955e78e071c792ef00df9910b42freed@android.com base::MessageLoop::QuitClosure()); 1096c924ad46c89955e78e071c792ef00df9910b42freed@android.com message_loop_.Run(); 1106c924ad46c89955e78e071c792ef00df9910b42freed@android.com } 1116c924ad46c89955e78e071c792ef00df9910b42freed@android.com 1126c924ad46c89955e78e071c792ef00df9910b42freed@android.com void OnHostConnected(net::Error error, 113a9015f897cd32f549349994e8163ead1db442088mike@reedtribe.org scoped_ptr<net::StreamSocket> socket) { 1146c924ad46c89955e78e071c792ef00df9910b42freed@android.com host_callback_.OnDone(error, socket.get()); 115bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com host_socket_ = socket.Pass(); 116bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com } 117e9d0060f4d7b5a07a220182d83aae3a140784c4breed@android.com 118bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com void OnClientConnected(net::Error error, 119e9d0060f4d7b5a07a220182d83aae3a140784c4breed@android.com scoped_ptr<net::StreamSocket> socket) { 120bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com client_callback_.OnDone(error, socket.get()); 121bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com client_socket_ = socket.Pass(); 122bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com } 123bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com 124bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com base::MessageLoop message_loop_; 125bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com 126e9d0060f4d7b5a07a220182d83aae3a140784c4breed@android.com scoped_refptr<RsaKeyPair> key_pair_; 127bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com std::string host_cert_; 128bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com scoped_ptr<FakeSocket> client_fake_socket_; 129bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com scoped_ptr<FakeSocket> host_fake_socket_; 130d1a416a97cac1769c1616cd3b092876dc6077e59bungeman@google.com scoped_ptr<ChannelAuthenticator> client_auth_; 131bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com scoped_ptr<ChannelAuthenticator> host_auth_; 132bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com MockChannelDoneCallback client_callback_; 133e9d0060f4d7b5a07a220182d83aae3a140784c4breed@android.com MockChannelDoneCallback host_callback_; 134bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com scoped_ptr<net::StreamSocket> client_socket_; 135bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com scoped_ptr<net::StreamSocket> host_socket_; 13630e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com 13730e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com DISALLOW_COPY_AND_ASSIGN(SslHmacChannelAuthenticatorTest); 13830e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com}; 13930e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com 14030e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com// Verify that a channel can be connected using a valid shared secret. 14130e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.comTEST_F(SslHmacChannelAuthenticatorTest, SuccessfulAuth) { 14230e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com client_auth_ = SslHmacChannelAuthenticator::CreateForClient( 14330e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com host_cert_, kTestSharedSecret); 14430e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com host_auth_ = SslHmacChannelAuthenticator::CreateForHost( 14530e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com host_cert_, key_pair_, kTestSharedSecret); 14630e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com 14730e6d2c2054c15f1cb6c0637bee6756261291751bsalomon@google.com RunChannelAuth(false); 148bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com 149bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com ASSERT_TRUE(client_socket_.get() != NULL); 150bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com ASSERT_TRUE(host_socket_.get() != NULL); 151bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com 152bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), 153bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com 100, 2); 154bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com 155bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com tester.Start(); 156bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com message_loop_.Run(); 157bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com tester.CheckResults(); 158bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com} 159bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com 160bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com// Verify that channels cannot be using invalid shared secret. 161bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.comTEST_F(SslHmacChannelAuthenticatorTest, InvalidChannelSecret) { 162bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com client_auth_ = SslHmacChannelAuthenticator::CreateForClient( 163bd700c391dd45acd8ea1a40321789c9d92a14bb8reed@android.com host_cert_, kTestSharedSecretBad); 1644c7d3d6828b103ada10201608bd6e116d0ac7e61reed@android.com host_auth_ = SslHmacChannelAuthenticator::CreateForHost( 1654c7d3d6828b103ada10201608bd6e116d0ac7e61reed@android.com host_cert_, key_pair_, kTestSharedSecret); 1664c7d3d6828b103ada10201608bd6e116d0ac7e61reed@android.com 1674c7d3d6828b103ada10201608bd6e116d0ac7e61reed@android.com RunChannelAuth(true); 1684c7d3d6828b103ada10201608bd6e116d0ac7e61reed@android.com 1694c7d3d6828b103ada10201608bd6e116d0ac7e61reed@android.com ASSERT_TRUE(host_socket_.get() == NULL); 170f523e25da069e3e1af2cb73d37073a34f3bb9ea2reed@android.com} 171f523e25da069e3e1af2cb73d37073a34f3bb9ea2reed@android.com 172f523e25da069e3e1af2cb73d37073a34f3bb9ea2reed@android.com} // namespace protocol 173f523e25da069e3e1af2cb73d37073a34f3bb9ea2reed@android.com} // namespace remoting 174f523e25da069e3e1af2cb73d37073a34f3bb9ea2reed@android.com