15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/ssl_hmac_channel_authenticator.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/base64.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/path_service.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/test/test_timeouts.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/rsa_private_key.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/test_data_directory.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/base/rsa_key_pair.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/connection_tester.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/fake_session.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using testing::_;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using testing::NotNull;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using testing::SaveArg;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace protocol {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTestSharedSecret[] = "1234-1234-5678";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTestSharedSecretBad[] = "0000-0000-0001";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockChannelDoneCallback {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MOCK_METHOD2(OnDone, void(int error, net::StreamSocket* socket));
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ACTION_P(QuitThreadOnCounter, counter) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --(*counter);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_GE(*counter, 0);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*counter == 0)
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::MessageLoop::current()->Quit();
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SslHmacChannelAuthenticatorTest : public testing::Test {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SslHmacChannelAuthenticatorTest() {}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SslHmacChannelAuthenticatorTest() {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath certs_dir(net::GetTestCertsDirectory());
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath cert_path = certs_dir.AppendASCII("unittest.selfsigned.der");
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ASSERT_TRUE(base::ReadFileToString(cert_path, &host_cert_));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath key_path = certs_dir.AppendASCII("unittest.key.bin");
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string key_string;
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ASSERT_TRUE(base::ReadFileToString(key_path, &key_string));
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string key_base64;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Base64Encode(key_string, &key_base64);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    key_pair_ = RsaKeyPair::FromString(key_base64);
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ASSERT_TRUE(key_pair_.get());
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunChannelAuth(bool expected_fail) {
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    client_fake_socket_.reset(new FakeStreamSocket());
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    host_fake_socket_.reset(new FakeStreamSocket());
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_fake_socket_->PairWith(host_fake_socket_.get());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_auth_->SecureAndAuthenticate(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        client_fake_socket_.PassAs<net::StreamSocket>(),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SslHmacChannelAuthenticatorTest::OnClientConnected,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   base::Unretained(this)));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_auth_->SecureAndAuthenticate(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        host_fake_socket_.PassAs<net::StreamSocket>(),
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&SslHmacChannelAuthenticatorTest::OnHostConnected,
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Unretained(this), std::string("ref argument value")));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Expect two callbacks to be called - the client callback and the host
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // callback.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int callback_counter = 2;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (expected_fail) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_CALL(client_callback_, OnDone(net::ERR_FAILED, NULL))
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          .WillOnce(QuitThreadOnCounter(&callback_counter));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_CALL(host_callback_, OnDone(net::ERR_FAILED, NULL))
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          .WillOnce(QuitThreadOnCounter(&callback_counter));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_CALL(client_callback_, OnDone(net::OK, NotNull()))
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          .WillOnce(QuitThreadOnCounter(&callback_counter));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_CALL(host_callback_, OnDone(net::OK, NotNull()))
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          .WillOnce(QuitThreadOnCounter(&callback_counter));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure that .Run() does not run unbounded if the callbacks are never
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // called.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Timer shutdown_timer(false, false);
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shutdown_timer.Start(FROM_HERE,
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         TestTimeouts::action_timeout(),
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         base::MessageLoop::QuitClosure());
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop_.Run();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void OnHostConnected(const std::string& ref_argument,
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       int error,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       scoped_ptr<net::StreamSocket> socket) {
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Try deleting the authenticator and verify that this doesn't destroy
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // reference parameters.
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    host_auth_.reset();
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_EQ(ref_argument, "ref argument value");
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_callback_.OnDone(error, socket.get());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_socket_ = socket.Pass();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void OnClientConnected(int error, scoped_ptr<net::StreamSocket> socket) {
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    client_auth_.reset();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_callback_.OnDone(error, socket.get());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_socket_ = socket.Pass();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop message_loop_;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<RsaKeyPair> key_pair_;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string host_cert_;
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<FakeStreamSocket> client_fake_socket_;
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<FakeStreamSocket> host_fake_socket_;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ChannelAuthenticator> client_auth_;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ChannelAuthenticator> host_auth_;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockChannelDoneCallback client_callback_;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockChannelDoneCallback host_callback_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::StreamSocket> client_socket_;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::StreamSocket> host_socket_;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SslHmacChannelAuthenticatorTest);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verify that a channel can be connected using a valid shared secret.
14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)TEST_F(SslHmacChannelAuthenticatorTest, SuccessfulAuth) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_auth_ = SslHmacChannelAuthenticator::CreateForClient(
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_cert_, kTestSharedSecret);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host_auth_ = SslHmacChannelAuthenticator::CreateForHost(
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      host_cert_, key_pair_, kTestSharedSecret);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunChannelAuth(false);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(client_socket_.get() != NULL);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(host_socket_.get() != NULL);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StreamConnectionTester tester(host_socket_.get(), client_socket_.get(),
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                100, 2);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tester.Start();
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_.Run();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tester.CheckResults();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verify that channels cannot be using invalid shared secret.
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)TEST_F(SslHmacChannelAuthenticatorTest, InvalidChannelSecret) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_auth_ = SslHmacChannelAuthenticator::CreateForClient(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_cert_, kTestSharedSecretBad);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host_auth_ = SslHmacChannelAuthenticator::CreateForHost(
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      host_cert_, key_pair_, kTestSharedSecret);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunChannelAuth(true);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(host_socket_.get() == NULL);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace protocol
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
180