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 20 using testing::_; 21 using testing::DeleteArg; 22 using testing::SaveArg; 23 24 namespace remoting { 25 namespace protocol { 26 27 namespace { 28 29 const int kMessageSize = 100; 30 const int kMessages = 1; 31 32 const char kNoClientId[] = ""; 33 const char kNoPairedSecret[] = ""; 34 const char kTestClientName[] = "client-name"; 35 const char kTestClientId[] = "client-id"; 36 const char kTestHostId[] = "12345678910123456"; 37 38 const char kTestPairedSecret[] = "1111-2222-3333"; 39 const char kTestPairedSecretBad[] = "4444-5555-6666"; 40 const char kTestPin[] = "123456"; 41 const char kTestPinBad[] = "654321"; 42 43 } // namespace 44 45 class 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 150 TEST_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 158 TEST_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 165 TEST_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 174 TEST_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 183 TEST_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 192 TEST_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 201 TEST_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 210 TEST_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 219 TEST_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 228 TEST_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 237 TEST_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 247 TEST_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