1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/bind.h"
6#include "net/base/net_errors.h"
7#include "remoting/base/rsa_key_pair.h"
8#include "remoting/protocol/authenticator_test_base.h"
9#include "remoting/protocol/channel_authenticator.h"
10#include "remoting/protocol/connection_tester.h"
11#include "remoting/protocol/negotiating_authenticator_base.h"
12#include "remoting/protocol/negotiating_client_authenticator.h"
13#include "remoting/protocol/negotiating_host_authenticator.h"
14#include "remoting/protocol/pairing_registry.h"
15#include "remoting/protocol/protocol_mock_objects.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
19
20using testing::_;
21using testing::DeleteArg;
22using testing::SaveArg;
23
24namespace remoting {
25namespace protocol {
26
27namespace {
28
29const int kMessageSize = 100;
30const int kMessages = 1;
31
32const char kNoClientId[] = "";
33const char kNoPairedSecret[] = "";
34const char kTestClientName[] = "client-name";
35const char kTestClientId[] = "client-id";
36const char kTestHostId[] = "12345678910123456";
37
38const char kTestPairedSecret[] = "1111-2222-3333";
39const char kTestPairedSecretBad[] = "4444-5555-6666";
40const char kTestPin[] = "123456";
41const char kTestPinBad[] = "654321";
42
43}  // namespace
44
45class NegotiatingAuthenticatorTest : public AuthenticatorTestBase {
46 public:
47  NegotiatingAuthenticatorTest() {
48  }
49  virtual ~NegotiatingAuthenticatorTest() {
50  }
51
52 protected:
53  void InitAuthenticators(
54      const std::string& client_id,
55      const std::string& client_paired_secret,
56      const std::string& client_interactive_pin,
57      const std::string& host_secret,
58      AuthenticationMethod::HashFunction hash_function,
59      bool client_hmac_only) {
60    std::string host_secret_hash = AuthenticationMethod::ApplyHashFunction(
61        hash_function, kTestHostId, host_secret);
62    host_ = NegotiatingHostAuthenticator::CreateWithSharedSecret(
63        host_cert_, key_pair_, host_secret_hash, hash_function,
64        pairing_registry_);
65
66    std::vector<AuthenticationMethod> methods;
67    methods.push_back(AuthenticationMethod::Spake2Pair());
68    methods.push_back(AuthenticationMethod::Spake2(
69        AuthenticationMethod::HMAC_SHA256));
70    if (!client_hmac_only) {
71      methods.push_back(AuthenticationMethod::Spake2(
72          AuthenticationMethod::NONE));
73    }
74    bool pairing_expected = pairing_registry_.get() != NULL;
75    FetchSecretCallback fetch_secret_callback =
76        base::Bind(&NegotiatingAuthenticatorTest::FetchSecret,
77                   client_interactive_pin,
78                   pairing_expected);
79    client_as_negotiating_authenticator_ = new NegotiatingClientAuthenticator(
80        client_id, client_paired_secret,
81        kTestHostId, fetch_secret_callback,
82        scoped_ptr<ThirdPartyClientAuthenticator::TokenFetcher>(), methods);
83    client_.reset(client_as_negotiating_authenticator_);
84  }
85
86  void CreatePairingRegistry(bool with_paired_client) {
87    pairing_registry_ = new SynchronousPairingRegistry(
88        scoped_ptr<PairingRegistry::Delegate>(
89            new MockPairingRegistryDelegate()));
90    if (with_paired_client) {
91      PairingRegistry::Pairing pairing(
92          base::Time(), kTestClientName, kTestClientId, kTestPairedSecret);
93      pairing_registry_->AddPairing(pairing);
94    }
95  }
96
97  static void FetchSecret(
98      const std::string& client_secret,
99      bool pairing_supported,
100      bool pairing_expected,
101      const protocol::SecretFetchedCallback& secret_fetched_callback) {
102    secret_fetched_callback.Run(client_secret);
103    ASSERT_EQ(pairing_supported, pairing_expected);
104  }
105
106  void VerifyRejected(Authenticator::RejectionReason reason) {
107    ASSERT_TRUE(client_->state() == Authenticator::REJECTED ||
108                host_->state() == Authenticator::REJECTED);
109    if (client_->state() == Authenticator::REJECTED) {
110      ASSERT_EQ(client_->rejection_reason(), reason);
111    }
112    if (host_->state() == Authenticator::REJECTED) {
113      ASSERT_EQ(host_->rejection_reason(), reason);
114    }
115  }
116
117  void VerifyAccepted(const AuthenticationMethod& expected_method) {
118    ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
119
120    ASSERT_EQ(Authenticator::ACCEPTED, host_->state());
121    ASSERT_EQ(Authenticator::ACCEPTED, client_->state());
122
123    client_auth_ = client_->CreateChannelAuthenticator();
124    host_auth_ = host_->CreateChannelAuthenticator();
125    RunChannelAuth(false);
126
127    EXPECT_TRUE(client_socket_.get() != NULL);
128    EXPECT_TRUE(host_socket_.get() != NULL);
129
130    StreamConnectionTester tester(host_socket_.get(), client_socket_.get(),
131                                  kMessageSize, kMessages);
132
133    tester.Start();
134    message_loop_.Run();
135    tester.CheckResults();
136    EXPECT_EQ(
137        expected_method,
138        client_as_negotiating_authenticator_->current_method_for_testing());
139  }
140
141  // Use a bare pointer because the storage is managed by the base class.
142  NegotiatingClientAuthenticator* client_as_negotiating_authenticator_;
143
144 private:
145  scoped_refptr<PairingRegistry> pairing_registry_;
146
147  DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticatorTest);
148};
149
150TEST_F(NegotiatingAuthenticatorTest, SuccessfulAuthHmac) {
151  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
152      kNoClientId, kNoPairedSecret, kTestPin, kTestPin,
153      AuthenticationMethod::HMAC_SHA256, false));
154  VerifyAccepted(
155      AuthenticationMethod::Spake2(AuthenticationMethod::HMAC_SHA256));
156}
157
158TEST_F(NegotiatingAuthenticatorTest, SuccessfulAuthPlain) {
159  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
160      kNoClientId, kNoPairedSecret, kTestPin, kTestPin,
161      AuthenticationMethod::NONE, false));
162  VerifyAccepted(AuthenticationMethod::Spake2(AuthenticationMethod::NONE));
163}
164
165TEST_F(NegotiatingAuthenticatorTest, InvalidSecretHmac) {
166  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
167      kNoClientId, kNoPairedSecret, kTestPinBad, kTestPin,
168      AuthenticationMethod::HMAC_SHA256, false));
169  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
170
171  VerifyRejected(Authenticator::INVALID_CREDENTIALS);
172}
173
174TEST_F(NegotiatingAuthenticatorTest, InvalidSecretPlain) {
175  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
176      kNoClientId, kNoPairedSecret, kTestPin, kTestPinBad,
177      AuthenticationMethod::NONE, false));
178  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
179
180  VerifyRejected(Authenticator::INVALID_CREDENTIALS);
181}
182
183TEST_F(NegotiatingAuthenticatorTest, IncompatibleMethods) {
184  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
185      kNoClientId, kNoPairedSecret, kTestPin, kTestPinBad,
186      AuthenticationMethod::NONE, true));
187  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
188
189  VerifyRejected(Authenticator::PROTOCOL_ERROR);
190}
191
192TEST_F(NegotiatingAuthenticatorTest, PairingNotSupported) {
193  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
194      kTestClientId, kTestPairedSecret, kTestPin, kTestPin,
195      AuthenticationMethod::HMAC_SHA256, false));
196  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
197  VerifyAccepted(
198      AuthenticationMethod::Spake2(AuthenticationMethod::HMAC_SHA256));
199}
200
201TEST_F(NegotiatingAuthenticatorTest, PairingSupportedButNotPaired) {
202  CreatePairingRegistry(false);
203  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
204      kNoClientId, kNoPairedSecret, kTestPin, kTestPin,
205      AuthenticationMethod::HMAC_SHA256, false));
206  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
207  VerifyAccepted(AuthenticationMethod::Spake2Pair());
208}
209
210TEST_F(NegotiatingAuthenticatorTest, PairingRevokedPinOkay) {
211  CreatePairingRegistry(false);
212  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
213      kTestClientId, kTestPairedSecret, kTestPin, kTestPin,
214      AuthenticationMethod::HMAC_SHA256, false));
215  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
216  VerifyAccepted(AuthenticationMethod::Spake2Pair());
217}
218
219TEST_F(NegotiatingAuthenticatorTest, PairingRevokedPinBad) {
220  CreatePairingRegistry(false);
221  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
222      kTestClientId, kTestPairedSecret, kTestPinBad, kTestPin,
223      AuthenticationMethod::HMAC_SHA256, false));
224  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
225  VerifyRejected(Authenticator::INVALID_CREDENTIALS);
226}
227
228TEST_F(NegotiatingAuthenticatorTest, PairingSucceeded) {
229  CreatePairingRegistry(true);
230  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
231      kTestClientId, kTestPairedSecret, kTestPinBad, kTestPin,
232      AuthenticationMethod::HMAC_SHA256, false));
233  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
234  VerifyAccepted(AuthenticationMethod::Spake2Pair());
235}
236
237TEST_F(NegotiatingAuthenticatorTest,
238       PairingSucceededInvalidSecretButPinOkay) {
239  CreatePairingRegistry(true);
240  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
241      kTestClientId, kTestPairedSecretBad, kTestPin, kTestPin,
242      AuthenticationMethod::HMAC_SHA256, false));
243  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
244  VerifyAccepted(AuthenticationMethod::Spake2Pair());
245}
246
247TEST_F(NegotiatingAuthenticatorTest, PairingFailedInvalidSecretAndPin) {
248  CreatePairingRegistry(true);
249  ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
250      kTestClientId, kTestPairedSecretBad, kTestPinBad, kTestPin,
251      AuthenticationMethod::HMAC_SHA256, false));
252  ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
253  VerifyRejected(Authenticator::INVALID_CREDENTIALS);
254}
255
256}  // namespace protocol
257}  // namespace remoting
258