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